From d6bbfad1e7eaea7828a1a1c7d8ff21359e15c8e1 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Sat, 5 Mar 2022 02:34:13 +0200 Subject: [PATCH 01/22] baseaddr --- src/client/game/game.cpp | 13 +++++++++++++ src/client/game/game.hpp | 9 +++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index 9045761b..95fb0793 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -3,6 +3,14 @@ namespace game { + uint64_t base_address; + + void load_base_address() + { + const auto module = GetModuleHandle(NULL); + base_address = uint64_t(module); + } + int Cmd_Argc() { return cmd_args->argc[cmd_args->nesting]; @@ -102,3 +110,8 @@ namespace game } } } + +uintptr_t operator"" _b(const uintptr_t ptr) +{ + return game::base_address + ptr; +} \ No newline at end of file diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 47041ca9..0442fece 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -9,6 +9,9 @@ namespace game { + extern uint64_t base_address; + void load_base_address(); + namespace environment { launcher::mode get_mode(); @@ -37,10 +40,10 @@ namespace game { if (environment::is_sp()) { - return sp_object_; + return reinterpret_cast((uint64_t)sp_object_ + base_address); } - return mp_object_; + return reinterpret_cast((uint64_t)mp_object_ + base_address); } operator T* () const @@ -67,4 +70,6 @@ namespace game bool VirtualLobby_Loaded(); } +uintptr_t operator"" _b(const uintptr_t ptr); + #include "symbols.hpp" From 5fe6b85a1a3524eab43871d55168fbe69eb5061b Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Sat, 5 Mar 2022 02:35:20 +0200 Subject: [PATCH 02/22] Revert "baseaddr" This reverts commit 05696f1ec509684d4cb496581e1eddf437c4278a. --- src/client/game/game.cpp | 13 ------------- src/client/game/game.hpp | 9 ++------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index 95fb0793..9045761b 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -3,14 +3,6 @@ namespace game { - uint64_t base_address; - - void load_base_address() - { - const auto module = GetModuleHandle(NULL); - base_address = uint64_t(module); - } - int Cmd_Argc() { return cmd_args->argc[cmd_args->nesting]; @@ -110,8 +102,3 @@ namespace game } } } - -uintptr_t operator"" _b(const uintptr_t ptr) -{ - return game::base_address + ptr; -} \ No newline at end of file diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 0442fece..47041ca9 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -9,9 +9,6 @@ namespace game { - extern uint64_t base_address; - void load_base_address(); - namespace environment { launcher::mode get_mode(); @@ -40,10 +37,10 @@ namespace game { if (environment::is_sp()) { - return reinterpret_cast((uint64_t)sp_object_ + base_address); + return sp_object_; } - return reinterpret_cast((uint64_t)mp_object_ + base_address); + return mp_object_; } operator T* () const @@ -70,6 +67,4 @@ namespace game bool VirtualLobby_Loaded(); } -uintptr_t operator"" _b(const uintptr_t ptr); - #include "symbols.hpp" From 46df4fa4dfb22475e516d392f7925ca7956170ae Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Sat, 5 Mar 2022 02:44:16 +0200 Subject: [PATCH 03/22] baseaddr [skip ci] --- src/client/game/game.cpp | 13 +++++++++++++ src/client/game/game.hpp | 9 +++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index 9045761b..95fb0793 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -3,6 +3,14 @@ namespace game { + uint64_t base_address; + + void load_base_address() + { + const auto module = GetModuleHandle(NULL); + base_address = uint64_t(module); + } + int Cmd_Argc() { return cmd_args->argc[cmd_args->nesting]; @@ -102,3 +110,8 @@ namespace game } } } + +uintptr_t operator"" _b(const uintptr_t ptr) +{ + return game::base_address + ptr; +} \ No newline at end of file diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 47041ca9..0442fece 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -9,6 +9,9 @@ namespace game { + extern uint64_t base_address; + void load_base_address(); + namespace environment { launcher::mode get_mode(); @@ -37,10 +40,10 @@ namespace game { if (environment::is_sp()) { - return sp_object_; + return reinterpret_cast((uint64_t)sp_object_ + base_address); } - return mp_object_; + return reinterpret_cast((uint64_t)mp_object_ + base_address); } operator T* () const @@ -67,4 +70,6 @@ namespace game bool VirtualLobby_Loaded(); } +uintptr_t operator"" _b(const uintptr_t ptr); + #include "symbols.hpp" From 971ed0c5f002356eff83d7ff4a08f336505573f3 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Sat, 5 Mar 2022 03:36:18 +0200 Subject: [PATCH 04/22] should be full [skip ci] --- src/client/component/auth.cpp | 41 +-- src/client/component/input.cpp | 4 +- src/client/component/localized_strings.cpp | 2 +- src/client/component/network.cpp | 84 +++--- src/client/component/scheduler.cpp | 6 +- src/client/component/splash.cpp | 6 +- src/client/game/symbols.hpp | 303 ++++++++++----------- 7 files changed, 222 insertions(+), 224 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index f0950e96..346c8d80 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -177,21 +177,22 @@ namespace auth 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); + // CAN'T FIND + //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.pushad64(); + // a.mov(rdx, rsi); + // a.call_aligned(direct_connect); + // a.popad64(); - a.jmp(0x140488CE2); // H1MP64(1.4) - }); - } + // a.jmp(0x140488CE2); // H1MP64(1.4) + // }); + //} } uint64_t get_guid() @@ -218,14 +219,14 @@ namespace auth } else { - utils::hook::jump(0x140571E07, 0x140571E5A); // H1(1.4) - utils::hook::jump(0x14004B223, 0x14004B4F2); // H1(1.4) - utils::hook::jump(0x14004B4AD, 0x14004B4F2); // H1(1.4) - utils::hook::jump(0x140572F6F, 0x140572FB0); // H1(1.4) - utils::hook::jump(0x140573470, 0x1405734B6); // H1(1.4) + utils::hook::jump(0x1D6193_b, 0x1D61FA_b); // STEAM + utils::hook::jump(0x60153_b, 0x60426_b); // STEAM + utils::hook::jump(0x603E1_b, 0x60426_b); // STEAM + utils::hook::jump(0x1D7542_b, 0x1D7587_b); // STEAM MAYBE `1401D7553` ON FIRST + utils::hook::jump(0x1D7A82_b, 0x1D7AC8_b); // STEAM - utils::hook::jump(0x140488BC1, get_direct_connect_stub(), true); // H1(1.4) - utils::hook::call(0x140250ED2, send_connect_data_stub); // H1(1.4) + //utils::hook::jump(0x140488BC1, get_direct_connect_stub(), true); // H1(1.4) can't find + utils::hook::call(0x12D437_b, send_connect_data_stub); // H1(1.4) // Skip checks for sending connect packet utils::hook::jump(0x1402508FC, 0x140250946); diff --git a/src/client/component/input.cpp b/src/client/component/input.cpp index 4fc59741..6d28f601 100644 --- a/src/client/component/input.cpp +++ b/src/client/component/input.cpp @@ -45,8 +45,8 @@ namespace input return; } - cl_char_event_hook.create(SELECT_VALUE(0x1401871A0, 0x14024E810), cl_char_event_stub); // H1(1.4) - cl_key_event_hook.create(SELECT_VALUE(0x1401874D0, 0x14024EA60), cl_key_event_stub); // H1(1.4) + cl_char_event_hook.create(SELECT_VALUE(0, 0x12C8F0_b), cl_char_event_stub); // H1-STEAM(1.15) + cl_key_event_hook.create(SELECT_VALUE(0, 0x135A70_b), cl_key_event_stub); // H1-STEAM(1.15) } }; } diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp index 975c76f3..55b41d65 100644 --- a/src/client/component/localized_strings.cpp +++ b/src/client/component/localized_strings.cpp @@ -44,7 +44,7 @@ namespace localized_strings void post_unpack() override { // Change some localized strings - seh_string_ed_get_string_hook.create(SELECT_VALUE(0x1403924A0, 0x1404BB2A0), &seh_string_ed_get_string); + seh_string_ed_get_string_hook.create(SELECT_VALUE(0, 0x585DA0_b), &seh_string_ed_get_string); // H1-STEAM(1.15) } }; } diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 47ca2b20..fb2a6f55 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -67,11 +67,11 @@ namespace network // Command handled a.popad64(); a.mov(al, 1); - a.jmp(0x140252AF8); // H1MP64(1.4) + a.jmp(0x252AF8_b); // STEAM a.bind(return_unhandled); a.popad64(); - a.jmp(0x14025234C); // H1MP64(1.4) + a.jmp(0x25234C_b); // STEAM } int net_compare_base_address(const game::netadr_s* a1, const game::netadr_s* a2) @@ -117,7 +117,7 @@ namespace network if (net_interface && net_interface != "localhost"s) { // Sys_StringToSockaddr - utils::hook::invoke(0x1404F6580, net_interface, &address); + utils::hook::invoke(0x59E810_b, net_interface, &address); } address.sin_family = AF_INET; @@ -237,52 +237,52 @@ namespace network // redirect dw_sendto to raw socket //utils::hook::jump(0x1404D850A, reinterpret_cast(0x1404D849A)); - utils::hook::call(0x140513467, dw_send_to_stub); // H1MP64(1.4) - utils::hook::jump(game::Sys_SendPacket, dw_send_to_stub); // H1MP64(1.4) + utils::hook::call(0x5BDB47_b, dw_send_to_stub); // STEAM + utils::hook::jump(game::Sys_SendPacket, dw_send_to_stub); // STEAM // intercept command handling - utils::hook::jump(0x140252327, utils::hook::assemble(handle_command_stub), true); // H1MP64(1.4) + utils::hook::jump(0x12F387_b, utils::hook::assemble(handle_command_stub), true); // STEAM // handle xuid without secure connection - utils::hook::nop(0x140486AAF, 6); // H1MP64(1.4) + utils::hook::nop(0x554222_b, 6); // STEAM - utils::hook::jump(0x140424F20, net_compare_address); // H1MP64(1.4) - utils::hook::jump(0x140424F70, net_compare_base_address); // H1MP64(1.4) + utils::hook::jump(0x4F1800_b, net_compare_address); // STEAM + utils::hook::jump(0x4F1850_b, net_compare_base_address); // STEAM // don't establish secure conenction - utils::hook::set(0x14027EA4D, 0xEB); // H1MP64(1.4) - utils::hook::set(0x14027EB1E, 0xEB); // H1MP64(1.4) - utils::hook::set(0x14027EF8D, 0xEB); // H1MP64(1.4) - utils::hook::set(0x14025081F, 0xEB); // H1MP64(1.4) + utils::hook::set(0x358C8D_b, 0xEB); // STEAM + utils::hook::set(0x358D5E_b, 0xEB); // STEAM + utils::hook::set(0x3591CD_b, 0xEB); // STEAM + utils::hook::set(0x12CD0F_b, 0xEB); // STEAM // ignore unregistered connection - utils::hook::jump(0x140480F46, 0x140480EE5); // H1MP64(1.4) - utils::hook::set(0x140480F3B, 0xEB); // H1MP64(1.4) + utils::hook::jump(0x54E2D1_b, 0x54E270_b); // STEAM + utils::hook::set(0x54E2C6_b, 0xEB); // STEAM // disable xuid verification - utils::hook::set(0x14005B62D, 0xEB); // H1MP64(1.4) - utils::hook::set(0x14005B649, 0xEB); // H1MP64(1.4) + utils::hook::set(0x728BF_b, 0xEB); // STEAM NOT SURE AT ALL + utils::hook::set(0x72903_b, 0xEB); // STEAM NOT SURE AT FKING ALL // disable xuid verification - utils::hook::nop(0x14048382C, 2); - utils::hook::set(0x140483889, 0xEB); // H1MP64(1.4) + utils::hook::nop(0x5509D9_b, 2); // STEAM SHOULD + utils::hook::set(0x550A36_b, 0xEB); // STEAM SHOULD // ignore configstring mismatch - utils::hook::set(0x1402591C9, 0xEB); // H1MP64(1.4) + utils::hook::set(0x341261_b, 0xEB); // STEAM // ignore dw handle in SV_PacketEvent - utils::hook::set(0x1404898E2, 0xEB); - utils::hook::call(0x1404898D6, &net_compare_address); // H1MP64(1.4) + utils::hook::set(0x1CBC22_b, 0xEB); // STEAM + utils::hook::call(0x1CBC16_b, &net_compare_address); // STEAM // ignore dw handle in SV_FindClientByAddress - utils::hook::set(0x140488EFD, 0xEB); - utils::hook::call(0x140488EF1, &net_compare_address); // H1MP64(1.4) + utils::hook::set(0x1CB24D_b, 0xEB); // STEAM + utils::hook::call(0x1CB241_b, &net_compare_address); // STEAM // ignore dw handle in SV_DirectConnect - utils::hook::set(0x140480C58, 0xEB); - utils::hook::set(0x140480E6F, 0xEB); - utils::hook::call(0x140480C4B, &net_compare_address); - utils::hook::call(0x140480E62, &net_compare_address); + utils::hook::set(0x54DFE8_b, 0xEB); // STEAM + utils::hook::set(0x54E1FD_b, 0xEB); // STEAM NOT_SURE + utils::hook::call(0x54DFDB_b, &net_compare_address); // STEAM + utils::hook::call(0x54E1F0_b, &net_compare_address); // STEAM // increase cl_maxpackets dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED); @@ -291,32 +291,32 @@ namespace network dvars::override::register_int("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE); // ignore impure client - utils::hook::jump(0x140481B58, reinterpret_cast(0x140481BEE)); // H1MP64(1.4) + utils::hook::jump(0x481B58_b, reinterpret_cast(0x54EE69_b)); // STEAM // don't send checksum - utils::hook::set(0x140513433, 0); // H1MP64(1.4) mov: r8d, edi ; LEN - utils::hook::set(0x14051345A, 0); // H1MP64(1.4) + utils::hook::set(0x513433_b, 0); // STEAM mov: r8d, edi ; LEN + utils::hook::set(0x51345A_b, 0); // STEAM // don't read checksum - utils::hook::set(0x1404F6620, 0xC301B0); // H1MP64(1.4) + utils::hook::set(0x513389_b, 0xC301B0); // STEAM // don't try to reconnect client - utils::hook::call(0x140480DFF, reconnect_migratated_client); // H1MP64(1.4) - utils::hook::nop(0x140480DDB, 4); // H1MP64(1.4) this crashes when reconnecting for some reason + utils::hook::call(0x480DFF_b, reconnect_migratated_client); // STEAM + utils::hook::nop(0x480DDB_b, 4); // STEAM this crashes when reconnecting for some reason // allow server owner to modify net_port before the socket bind - utils::hook::call(0x140512BE5, register_netport_stub); // H1MP64(1.4) - utils::hook::call(0x140512D20, register_netport_stub); // H1MP64(1.4) + utils::hook::call(0x512BE5_b, register_netport_stub); // STEAM + utils::hook::call(0x512D20_b, register_netport_stub); // STEAM // increase allowed packet size const auto max_packet_size = 0x20000; - utils::hook::set(0x1404255F1, max_packet_size); // H1MP64(1.4) - utils::hook::set(0x140425630, max_packet_size); // H1MP64(1.4) - utils::hook::set(0x140425522, max_packet_size); // H1MP64(1.4) - utils::hook::set(0x140425545, max_packet_size); // H1MP64(1.4) + utils::hook::set(0x4255F0_b, max_packet_size); // STEAM + utils::hook::set(0x42562E_b, max_packet_size); // STEAM + utils::hook::set(0x425521_b, max_packet_size); // STEAM + utils::hook::set(0x425549_b, max_packet_size); // STEAM // ignore built in "print" oob command and add in our own - utils::hook::set(0x14025280E, 0xEB); // H1MP64(1.4) + utils::hook::set(0x25280E_b, 0xEB); // STEAM on("print", [](const game::netadr_s&, const std::string_view& data) { const std::string message{data}; @@ -325,7 +325,7 @@ namespace network // Use our own socket since the game's socket doesn't work with non localhost addresses // why? no idea - utils::hook::jump(0x140512B40, create_socket); + utils::hook::jump(0x5BD210_b, create_socket); } } }; diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index de9b4983..ac837128 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -180,9 +180,9 @@ namespace scheduler void post_unpack() override { - r_end_frame_hook.create(SELECT_VALUE(0x1404F7310, 0x1405FE470), scheduler::r_end_frame_stub); - g_run_frame_hook.create(SELECT_VALUE(0x1402772D0, 0x14033A640), scheduler::server_frame_stub); - main_frame_hook.create(SELECT_VALUE(0x1401CE8D0, 0x1400D8310), scheduler::main_frame_stub); + r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); // H1-STEAM(1.15) + g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); // H1(1.15) + //main_frame_hook.create(SELECT_VALUE(0x1401CE8D0, 0x1400D8310), scheduler::main_frame_stub); can't find } void pre_destroy() override diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp index 79d23bd1..3dfd6541 100644 --- a/src/client/component/splash.cpp +++ b/src/client/component/splash.cpp @@ -30,9 +30,9 @@ namespace splash void post_unpack() override { // Disable native splash screen - utils::hook::nop(SELECT_VALUE(0x1403E192E, 0x1405123E2), 5); // H1(1.4) - utils::hook::jump(SELECT_VALUE(0x1403E2E70, 0x140513AF0), destroy_stub); // H1(1.4) - utils::hook::jump(SELECT_VALUE(0x1403E2EB0, 0x140513B30), destroy_stub); // H1(1.4) + //utils::hook::nop(SELECT_VALUE(0x1403E192E, 0x1405123E2), 5); // winmain doesn't even exist in 1.15? lmao + utils::hook::jump(SELECT_VALUE(0, 0x5BE1D0_b), destroy_stub); // H1-STEAM(1.15) + utils::hook::jump(SELECT_VALUE(0, 0x5BE210_b), destroy_stub); // H1-STEAM(1.15) } void pre_destroy() override diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 72a3d2bd..01c5cadd 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -8,99 +8,96 @@ namespace game * Functions **************************************************************/ - WEAK symbol AddRefToValue{0x14036E600, 0x14043C580}; - WEAK symbol RemoveRefToValue{0x1403700F0, 0x14043E090}; - WEAK symbol AddRefToObject{0x14036E5F0, 0x14043C570}; - WEAK symbol RemoveRefToObject{0x14036FFE0, 0x14043DF80}; - WEAK symbol AllocThread{0x14036E960, 0x14043C8E0}; + WEAK symbol AddRefToValue{0x36E600, 0x43C580}; + WEAK symbol RemoveRefToValue{0x3700F0, 0x43E090}; + WEAK symbol AddRefToObject{0x36E5F0, 0x43C570}; + WEAK symbol RemoveRefToObject{0x36FFE0, 0x43DF80}; + WEAK symbol AllocThread{0x36E960, 0x43C8E0}; - WEAK symbol Cbuf_AddText{0x140342EB0, 0x1404033B0}; + WEAK symbol Cbuf_AddText{ 0x342EB0, 0x1CF480 }; // H1MP(1.15) WEAK symbol Cbuf_ExecuteBufferInternal{0x140342FC0, 0x1404034C0}; - WEAK symbol Conbuf_AppendText{0x1403E3300, 0x140513FF0}; - WEAK symbol ConcatArgs{0x1402697F0, 0x140335D70}; - WEAK symbol Cmd_ExecuteSingleCommand{0x140343980, 0x140403F60}; - WEAK symbol Cmd_AddCommandInternal{0x1403433E0, 0x140403950}; - WEAK symbol Cmd_RemoveCommand{0x140343FF0, 0x1404045D0}; - WEAK symbol Cmd_TokenizeString{0x140344110, 0x1404046F0}; - WEAK symbol Cmd_EndTokenizeString{0x140343630, 0x140403C20}; + void (int, int, const char*))> Cbuf_ExecuteBufferInternal{0x342FC0, 0x4034C0}; + WEAK symbol Conbuf_AppendText{0x3E3300, 0x513FF0}; + WEAK symbol ConcatArgs{0x2697F0, 0x335D70}; + WEAK symbol Cmd_ExecuteSingleCommand{0x343980, 0x403F60}; + WEAK symbol Cmd_AddCommandInternal{0x3433E0, 0x403950}; + WEAK symbol Cmd_RemoveCommand{0x343FF0, 0x4045D0}; + WEAK symbol Cmd_TokenizeString{0x344110, 0x4046F0}; + WEAK symbol Cmd_EndTokenizeString{0x343630, 0x403C20}; - WEAK symbol AimAssist_AddToTargetList{0, 0x14009D0F0}; + WEAK symbol AimAssist_AddToTargetList{0, 0x9D0F0}; WEAK symbol BG_GetWeaponNameComplete{0x140430550, 0x1401F9670}; + char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0x430550, 0x1F9670}; - WEAK symbol Com_Frame_Try_Block_Function{0x1401CE8D0, 0x1400D8310}; - WEAK symbol Com_GetCurrentCoDPlayMode{0, 0x1405039A0}; - WEAK symbol Com_InFrontEnd{0x1400E4B30, 0x140176A30}; - WEAK symbol Com_SetSlowMotion{0, 0x1400DB790}; - WEAK symbol Com_Error{0x1403509C0, 0x1400D78A0}; - WEAK symbol Com_Quit_f{0x140352BE0, 0x1400DA830}; - WEAK symbol Quit{0x140352D90, 0x1400DA830}; + WEAK symbol Com_Frame_Try_Block_Function{0x1CE8D0, 0xD8310}; + WEAK symbol Com_GetCurrentCoDPlayMode{0, 0x5039A0}; + WEAK symbol Com_InFrontEnd{0xE4B30, 0x176A30}; + WEAK symbol Com_SetSlowMotion{0, 0xDB790}; + WEAK symbol Com_Error{0x3509C0, 0xD78A0}; + WEAK symbol Com_Quit_f{0x352BE0, 0xDA830}; + WEAK symbol Quit{0x352D90, 0xDA830}; - WEAK symbol CG_GameMessage{0x1401389A0, 0x140220CC0}; - WEAK symbol CG_GameMessageBold{0x140138750, 0x140220620}; + WEAK symbol CG_GameMessage{0x1389A0, 0x220CC0}; + WEAK symbol CG_GameMessageBold{0x138750, 0x220620}; - WEAK symbol CL_IsCgameInitialized{0x14017EE30, 0x140245650}; + WEAK symbol CL_IsCgameInitialized{0x17EE30, 0x245650}; - WEAK symbol Dvar_SetCommand{0x1403C72B0, 0x1404FD0A0}; - WEAK symbol Dvar_FindVar{0x1403C5D50, 0x1404FBB00}; - WEAK symbol Dvar_GetCombinedString{0x140354DF0, 0x14041D830}; - WEAK symbol Dvar_ValueToString{0x1403C8560, 0x1404FE660}; + WEAK symbol Dvar_SetCommand{0x3C72B0, 0x4FD0A0}; + WEAK symbol Dvar_FindVar{0x3C5D50, 0x4FBB00}; + WEAK symbol Dvar_GetCombinedString{0x354DF0, 0x41D830}; + WEAK symbol Dvar_ValueToString{0x3C8560, 0x4FE660}; WEAK symbol Dvar_RegisterBool{0x1403C47E0, 0x1404FA540}; + unsigned int flags)> Dvar_RegisterBool{0x3C47E0, 0x4FA540}; WEAK symbol Dvar_RegisterInt{0x1403C4CC0, 0x1404FAA20}; + unsigned int flags)> Dvar_RegisterInt{0x3C4CC0, 0x4FAA20}; WEAK symbol Dvar_RegisterFloat{0x1403C4BB0, 0x1404FA910}; + float max, unsigned int flags)> Dvar_RegisterFloat{0x3C4BB0, 0x4FA910}; WEAK symbol Dvar_RegisterString{0x1403C4DA0, 0x1404FAB00}; + unsigned int flags)> Dvar_RegisterString{0x3C4DA0, 0x4FAB00}; WEAK symbol Dvar_RegisterVec4{0x1403C5220, 0x1404FAF40}; + float w, float min, float max, unsigned int flags)> Dvar_RegisterVec4{0x3C5220, 0x4FAF40}; - WEAK symbol FS_ReadFile{0x1403B9020, 0x1404EE720}; - WEAK symbol FS_FreeFile{0x1403B9010, 0x1404EE710}; - WEAK symbol FS_Startup{0x1403B85D0, 0x1404EDD30}; - WEAK symbol FS_AddLocalizedGameDirectory{0x1403B6030, 0x1404EBE20}; + WEAK symbol FS_ReadFile{0x3B9020, 0x4EE720}; + WEAK symbol FS_FreeFile{0x3B9010, 0x4EE710}; + WEAK symbol FS_Startup{0x3B85D0, 0x4EDD30}; + WEAK symbol FS_AddLocalizedGameDirectory{0x3B6030, 0x4EBE20}; - WEAK symbol GetVariable{0x14036FDD0, 0x1403F3730}; + WEAK symbol GetVariable{0x36FDD0, 0x3F3730}; - WEAK symbol GScr_LoadConsts{0x1402D13E0, 0x140393810}; - WEAK symbol FindVariable{0x14036F4B0, 0x14043D430}; - WEAK symbol FindEntityId{0x14036F3B0, 0x14043D330}; - WEAK symbol RemoveVariableValue{0x140370190, 0x14043E130}; + WEAK symbol GScr_LoadConsts{0x2D13E0, 0x393810}; + WEAK symbol FindVariable{0x36F4B0, 0x43D430}; + WEAK symbol FindEntityId{0x36F3B0, 0x43D330}; + WEAK symbol RemoveVariableValue{0x370190, 0x43E130}; WEAK symbol GetEntityFieldValue{0x140373780, 0x140441780}; + int entnum, int offset)> GetEntityFieldValue{0x373780, 0x441780}; - WEAK symbol generateHashValue{0x1400FE8A0, 0x1401B1010}; + WEAK symbol generateHashValue{ 0xFE8A0, 0x183F80 }; // STEEEEEEEEEEEEAM - WEAK symbol G_Glass_Update{0x14026C570, 0x14033A640}; - WEAK symbol G_GetClientScore{0, 0x140342F90}; + WEAK symbol G_Glass_Update{0x26C570, 0x33A640}; + WEAK symbol G_GetClientScore{0, 0x342F90}; - WEAK symbol I_CleanStr{0x1403CD230, 0x140503D00}; + WEAK symbol I_CleanStr{0x3CD230, 0x503D00}; - WEAK symbol Key_KeynumToString{0x140187CC0, 0x14024FE10}; + WEAK symbol Key_KeynumToString{0x187CC0, 0x24FE10}; - WEAK symbol Live_SyncOnlineDataFlags{0, 0x14059A700}; + WEAK symbol Live_SyncOnlineDataFlags{0, 0x59A700}; - WEAK symbol Material_RegisterHandle{0x1404E48B0, 0x1405EAB30}; + WEAK symbol Material_RegisterHandle{0x4E48B0, 0x5EAB30}; - WEAK symbol NetadrToSockadr{0x1403C11C0, 0x1404F62F0}; - WEAK symbol NET_OutOfBandPrint{0x140357560, 0x1404255D0}; - WEAK symbol NET_SendLoopPacket{0, 0x140425790}; - WEAK symbol NET_StringToAdr{0, 0x140425870}; + WEAK symbol NetadrToSockadr{0x3C11C0, 0x4F62F0}; + WEAK symbol NET_OutOfBandPrint{ 0x357560, 0x4F1DE0 }; // STEEAM + WEAK symbol NET_SendLoopPacket{0, 0x425790}; + WEAK symbol NET_StringToAdr{0, 0x425870}; WEAK symbol R_AddCmdDrawStretchPic{0x14017E5C0, 0x1402443A0}; - WEAK symbol R_RegisterFont{0x1404D4100, 0x1405D91E0}; - WEAK symbol R_TextWidth{0x1404D43B0, 0x1405D94A0}; - WEAK symbol R_GetFontHeight{0x1405EA360, 0x1405D92C0}; - WEAK symbol R_DrawSomething{0x1404D37B0, 0x1405D8890}; - WEAK symbol R_SyncRenderThread{0x1404F8240, 0x1405FF3A0}; - WEAK symbol H1_AddBaseDrawTextCmd{0x1404F3DC0, 0x1405FB1F0}; + float* color, Material* material)> R_AddCmdDrawStretchPic{0x17E5C0, 0x2443A0}; + WEAK symbol R_RegisterFont{ 0x4D4100, 0x67F630 }; // H1MP(1.15) + WEAK symbol R_TextWidth{0x4D43B0, 0x5D94A0}; + WEAK symbol R_GetFontHeight{0x5EA360, 0x5D92C0}; + WEAK symbol R_DrawSomething{0x4D37B0, 0x5D8890}; + WEAK symbol R_SyncRenderThread{0x4F8240, 0x5FF3A0}; + WEAK symbol H1_AddBaseDrawTextCmd{ 0x4F3DC0,0x6A3080 }; // H1MP(1.15) #define R_AddCmdDrawText(TXT, MC, F, X, Y, XS, YS, R, C, S) \ H1_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, S,-1, 0, game::R_DrawSomething(S)) @@ -108,140 +105,140 @@ namespace game H1_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, S, CP, CC, game::R_DrawSomething(S)) WEAK symbol VM_Execute{0x140376360, 0x140444350}; + unsigned int paramcount)> VM_Execute{0x376360, 0x444350}; WEAK symbol Scr_NotifyId{0x140375800, 0x1404437E0}; - WEAK symbol Scr_AllocVector{0x140370930, 0x14043E7D0}; - WEAK symbol Scr_GetFloat{0x140374D20, 0x140442D10}; - WEAK symbol Scr_GetString{0x140375210, 0x140443150}; - WEAK symbol Scr_GetNumParam{0x140374F30, 0x140442E70}; - WEAK symbol Scr_ClearOutParams{0x140374460, 0x140442510}; - WEAK symbol Scr_GetEntityIdRef{0x140372D50, 0x140440D80}; - WEAK symbol Scr_GetEntityId{0x140372CA0, 0x140440CD0}; + unsigned int paramcount)> Scr_NotifyId{0x375800, 0x4437E0}; + WEAK symbol Scr_AllocVector{0x370930, 0x43E7D0}; + WEAK symbol Scr_GetFloat{0x374D20, 0x442D10}; + WEAK symbol Scr_GetString{0x375210, 0x443150}; + WEAK symbol Scr_GetNumParam{0x374F30, 0x442E70}; + WEAK symbol Scr_ClearOutParams{0x374460, 0x442510}; + WEAK symbol Scr_GetEntityIdRef{0x372D50, 0x440D80}; + WEAK symbol Scr_GetEntityId{0x372CA0, 0x440CD0}; - WEAK symbol ScrPlace_GetViewPlacement{0x1401981F0, 0x140288550}; + WEAK symbol ScrPlace_GetViewPlacement{0x1981F0, 0x288550}; - WEAK symbol DB_GetXAssetTypeSize{0x14019A3B0, 0x14028BE70}; + WEAK symbol DB_GetXAssetTypeSize{0x19A3B0, 0x28BE70}; WEAK symbol LUI_OpenMenu{0x14039D5F0, 0x1404CD210}; + int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x39D5F0, 0x4CD210}; - WEAK symbol Menu_IsMenuOpenAndVisible{0x1404709C0, 0x1404C7320}; + WEAK symbol Menu_IsMenuOpenAndVisible{0x4709C0, 0x4C7320}; - WEAK symbol SL_FindString{0x14036D700, 0x14043B470}; - WEAK symbol SL_GetString{0x14036D9A0, 0x14043B840}; - WEAK symbol SL_ConvertToString{0x14036D420, 0x14043B170}; - WEAK symbol Scr_SetObjectField{0x1402B9F60, 0x140385330}; + WEAK symbol SL_FindString{0x36D700, 0x43B470}; + WEAK symbol SL_GetString{0x36D9A0, 0x43B840}; + WEAK symbol SL_ConvertToString{0x36D420, 0x43B170}; + WEAK symbol Scr_SetObjectField{0x2B9F60, 0x385330}; - WEAK symbol SV_DirectConnect{0, 0x140480860}; - WEAK symbol SV_Cmd_ArgvBuffer{0x1403446C0, 0x140404CA0}; - WEAK symbol SV_Cmd_TokenizeString{0x140344740, 0x140404D20}; - WEAK symbol SV_Cmd_EndTokenizedString{0x140344700, 0x140404CE0}; + WEAK symbol SV_DirectConnect{0, 0x480860}; + WEAK symbol SV_Cmd_ArgvBuffer{0x3446C0, 0x404CA0}; + WEAK symbol SV_Cmd_TokenizeString{0x344740, 0x404D20}; + WEAK symbol SV_Cmd_EndTokenizedString{0x344700, 0x404CE0}; - WEAK symbol SV_AddBot{0, 0x140480190}; - WEAK symbol SV_BotIsBot{0, 0x14046E6C0}; - WEAK symbol SV_BotGetRandomName{0, 0x14046DBA0}; - WEAK symbol SV_SpawnTestClient{0, 0x1404832A0}; + WEAK symbol SV_AddBot{0, 0x480190}; + WEAK symbol SV_BotIsBot{0, 0x46E6C0}; + WEAK symbol SV_BotGetRandomName{0, 0x46DBA0}; + WEAK symbol SV_SpawnTestClient{0, 0x4832A0}; - WEAK symbol SV_GetGuid{0, 0x140484B90}; - WEAK symbol SV_GetClientPing{0, 0x140484B70}; - WEAK symbol SV_GetPlayerstateForClientNum{0x1404426D0, 0x140484C10}; - WEAK symbol SV_SetConfigstring{0, 0x140486720}; - WEAK symbol SV_Loaded{0x140442F60, 0x1404864A0}; - WEAK symbol SV_KickClientNum{0, 0x14047ED00}; - WEAK symbol SV_MapExists{0, 0x14047ED60}; - WEAK symbol SV_ExecuteClientCommand{0, 0x140481870}; - WEAK symbol SV_FastRestart{0, 0x14047E990}; + WEAK symbol SV_GetGuid{0, 0x484B90}; + WEAK symbol SV_GetClientPing{0, 0x484B70}; + WEAK symbol SV_GetPlayerstateForClientNum{0x4426D0, 0x484C10}; + WEAK symbol SV_SetConfigstring{0, 0x486720}; + WEAK symbol SV_Loaded{0x442F60, 0x4864A0}; + WEAK symbol SV_KickClientNum{0, 0x47ED00}; + WEAK symbol SV_MapExists{0, 0x47ED60}; + WEAK symbol SV_ExecuteClientCommand{0, 0x481870}; + WEAK symbol SV_FastRestart{0, 0x47E990}; WEAK symbol SV_GameSendServerCommand{ - 0x1403F3A70, 0x140484AD0 + 0x3F3A70, 0x484AD0 }; - WEAK symbol Sys_ShowConsole{0x1403E3B90, 0x140514910}; - WEAK symbol Sys_Error{0x1403E0C40, 0x140511520}; + WEAK symbol Sys_ShowConsole{0x3E3B90, 0x514910}; + WEAK symbol Sys_Error{0x3E0C40, 0x511520}; WEAK symbol - Sys_BuildAbsPath{0x1403CFF90, 0x140507010}; - WEAK symbol Sys_Milliseconds{0x1403E2B10, 0x140513710}; - WEAK symbol Sys_IsDatabaseReady2{0x1403580B0, 0x14042B090}; - WEAK symbol Sys_SendPacket{0x1403E2820, 0x1405133B0}; - WEAK symbol Sys_FileExists{0x1403E0CE0, 0x1405115E0}; + Sys_BuildAbsPath{0x3CFF90, 0x507010}; + WEAK symbol Sys_Milliseconds{0x3E2B10, 0x513710}; + WEAK symbol Sys_IsDatabaseReady2{0x3580B0, 0x42B090}; + WEAK symbol Sys_SendPacket{0x3E2820, 0x5133B0}; + WEAK symbol Sys_FileExists{0x3E0CE0, 0x5115E0}; - WEAK symbol UI_GetMapDisplayName{0, 0x140408CC0}; - WEAK symbol UI_GetGameTypeDisplayName{0, 0x1404086A0}; - WEAK symbol UI_RunMenuScript{0x14039EFF0, 0x1404CFE60}; - WEAK symbol UI_TextWidth{0x1403A0F20, 0x1404D21A0}; + WEAK symbol UI_GetMapDisplayName{0, 0x408CC0}; + WEAK symbol UI_GetGameTypeDisplayName{0, 0x4086A0}; + WEAK symbol UI_RunMenuScript{0x39EFF0, 0x4CFE60}; + WEAK symbol UI_TextWidth{0x3A0F20, 0x4D21A0}; - WEAK symbol UI_SafeTranslateString{0x140350430, 0x14041C580}; + WEAK symbol UI_SafeTranslateString{0x350430, 0x41C580}; - WEAK symbol longjmp{0x140648FD4, 0x140779F64}; - WEAK symbol _setjmp{0x1406BFD30, 0x1407F5F90}; + WEAK symbol longjmp{0x648FD4, 0x779F64}; + WEAK symbol _setjmp{0x6BFD30, 0x7F5F90}; /*************************************************************** * Variables **************************************************************/ - WEAK symbol sv_cmd_args{0x14AD99A10, 0x14946BA20}; + WEAK symbol sv_cmd_args{0xAD99A10, 0x946BA20}; - WEAK symbol g_script_error_level{0x14A1917A8, 0x14A33C824}; - WEAK symbol g_script_error{0x14A1917B0, 0x14A33C940}; + WEAK symbol g_script_error_level{0xA1917A8, 0xA33C824}; + WEAK symbol g_script_error{0xA1917B0, 0xA33C940}; - WEAK symbol levelEntityId{0x149AF55B0, 0x149CA0730}; - WEAK symbol gameEntityId{0x149CA0734, 0x14B65E3B4}; + WEAK symbol levelEntityId{0x9AF55B0, 0x9CA0730}; + WEAK symbol gameEntityId{0x9CA0734, 0xB65E3B4}; - WEAK symbol command_whitelist{0x141079A60, 0x14120C360}; - WEAK symbol cmd_functions{0x14AD99AB8, 0x14946BAC8}; - WEAK symbol cmd_args{0x14AD99960, 0x14946B970}; + WEAK symbol command_whitelist{0x1079A60, 0x120C360}; + WEAK symbol cmd_functions{ 0xAD99AB8,0x344DF18 }; // H1MP(1.15) + WEAK symbol cmd_args{0xAD99960, 0x946B970}; - WEAK symbol g_poolSize{0, 0x140FEADF0}; - WEAK symbol g_classMap{0x14080A840, 0x1412106B0}; + WEAK symbol g_poolSize{0, 0xFEADF0}; + WEAK symbol g_classMap{0x80A840, 0x12106B0}; - WEAK symbol scr_VarGlob{0x14B686480, 0x149CC8800}; - WEAK symbol scr_VmPub{0x14A1938C0, 0x14A33EA40}; - WEAK symbol scr_function_stack{0x14BD06C40, 0x14A348FC0}; + WEAK symbol scr_VarGlob{0xB686480, 0x9CC8800}; + WEAK symbol scr_VmPub{0xA1938C0, 0xA33EA40}; + WEAK symbol scr_function_stack{0xBD06C40, 0xA348FC0}; - WEAK symbol gfxDrawMethod{0x14F05CE50, 0x14FD21180}; + WEAK symbol gfxDrawMethod{0xF05CE50, 0xFD21180}; - WEAK symbol dvarCount{0x14C217D10, 0x14D064CF4}; - WEAK symbol dvarPool{0x14C217D20, 0x14D064D00}; + WEAK symbol dvarCount{0xC217D10, 0xD064CF4}; + WEAK symbol dvarPool{0xC217D20, 0xD064D00}; - WEAK symbol DB_XAssetPool{0x140DE8C80, 0x140FEB5D0}; + WEAK symbol DB_XAssetPool{0xDE8C80, 0xFEB5D0}; - WEAK symbol keyCatchers{0x14243DAF0, 0x142D0BA9C}; - WEAK symbol playerKeys{0x1422A873C, 0x142C19AFC}; + WEAK symbol keyCatchers{0x243DAF0, 0x2D0BA9C}; + WEAK symbol playerKeys{0x22A873C, 0x2C19AFC}; - WEAK symbol query_socket{0, 0x14DDFBF98}; + WEAK symbol query_socket{0, 0xDDFBF98}; - WEAK symbol threadIds{0x14B19B880, 0x149810E00}; + WEAK symbol threadIds{0xB19B880, 0x9810E00}; namespace mp { - WEAK symbol g_entities{0, 0x14621E530}; - WEAK symbol svs_clients{0, 0x14B204A10}; - WEAK symbol svs_numclients{0, 0x14B204A0C}; - WEAK symbol gameTime{0, 0x14621BDBC}; + WEAK symbol g_entities{ 0, 0x71F19E0 }; // H1MP(1.15) + WEAK symbol svs_clients{0, 0xB204A10}; + WEAK symbol svs_numclients{0, 0xB204A0C}; + WEAK symbol gameTime{0, 0x621BDBC}; - WEAK symbol sv_serverId_value{0, 0x14A3E99B8}; + WEAK symbol sv_serverId_value{0, 0xA3E99B8}; - WEAK symbol virtualLobby_loaded{0, 0x142D077FD}; + WEAK symbol virtualLobby_loaded{0, 0x2D077FD}; } namespace sp { - WEAK symbol g_entities{0x14550DD90, 0}; + WEAK symbol g_entities{0x550DD90, 0}; } namespace hks { - WEAK symbol lua_state{0x141E2C2F8, 0x1426D3D08}; - WEAK symbol hksi_lua_pushlstring{0x14004DA90, 0x1400624F0}; - WEAK symbol hks_obj_getfield{0x14009C0A0, 0x14012C600}; - WEAK symbol hks_obj_settable{0x14009D240, 0x14012D820}; - WEAK symbol hks_obj_gettable{0x14009C580, 0x14012CAE0}; - WEAK symbol vm_call_internal{0x1400C87A0, 0x140159EB0}; - WEAK symbol Hashtable_Create{0x14008B3B0, 0x14011B320}; + WEAK symbol lua_state{0x1E2C2F8, 0x26D3D08}; + WEAK symbol hksi_lua_pushlstring{0x4DA90, 0x624F0}; + WEAK symbol hks_obj_getfield{0x9C0A0, 0x12C600}; + WEAK symbol hks_obj_settable{0x9D240, 0x12D820}; + WEAK symbol hks_obj_gettable{0x9C580, 0x12CAE0}; + WEAK symbol vm_call_internal{0xC87A0, 0x159EB0}; + WEAK symbol Hashtable_Create{0x8B3B0, 0x11B320}; WEAK symbol cclosure_Create{0x14008B5D0, 0x14011B540}; - WEAK symbol hksi_luaL_ref{0x1400A64D0, 0x140136D30}; - WEAK symbol hksi_luaL_unref{0x14009EF10, 0x14012F610}; + int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{0x8B5D0, 0x11B540}; + WEAK symbol hksi_luaL_ref{0xA64D0, 0x136D30}; + WEAK symbol hksi_luaL_unref{0x9EF10, 0x12F610}; } } From 7811e6aa3299d712722c08a2a9a6c3c365eb22ff Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:35:10 +0200 Subject: [PATCH 05/22] stuff --- src/client/component/arxan.cpp | 164 ++++ src/client/component/auth.cpp | 25 +- src/client/component/binding.cpp | 138 ---- src/client/component/bots.cpp | 103 --- src/client/component/branding.cpp | 65 -- src/client/component/colors.cpp | 182 ----- src/client/component/command.cpp | 648 ---------------- src/client/component/command.hpp | 50 -- src/client/component/console.cpp | 299 -------- src/client/component/console.hpp | 35 - src/client/component/dedicated.cpp | 333 -------- src/client/component/dedicated_info.cpp | 65 -- src/client/component/demonware.cpp | 604 --------------- src/client/component/demonware.hpp | 6 - src/client/component/discord.cpp | 148 ---- src/client/component/dvars.cpp | 443 ----------- src/client/component/dvars.hpp | 28 - src/client/component/exception.cpp | 261 ------- src/client/component/fastfiles.cpp | 49 -- src/client/component/fastfiles.hpp | 8 - src/client/component/filesystem.cpp | 94 --- src/client/component/filesystem.hpp | 19 - src/client/component/fps.cpp | 174 ----- src/client/component/game_console.cpp | 793 -------------------- src/client/component/game_console.hpp | 7 - src/client/component/game_module.cpp | 3 +- src/client/component/localized_strings.cpp | 52 -- src/client/component/localized_strings.hpp | 6 - src/client/component/logfile.cpp | 317 -------- src/client/component/logfile.hpp | 13 - src/client/component/lui.cpp | 58 -- src/client/component/map_rotation.cpp | 180 ----- src/client/component/network.cpp | 11 +- src/client/component/party.cpp | 630 ---------------- src/client/component/party.hpp | 17 - src/client/component/patches.cpp | 293 -------- src/client/component/renderer.cpp | 77 -- src/client/component/scheduler.cpp | 8 +- src/client/component/scripting.cpp | 141 ---- src/client/component/scripting.hpp | 8 - src/client/component/server_list.cpp | 443 ----------- src/client/component/server_list.hpp | 12 - src/client/component/shaders.cpp | 50 -- src/client/component/slowmotion.cpp | 53 -- src/client/component/splash.cpp | 141 ---- src/client/component/system_check.cpp | 25 +- src/client/component/thread_names.cpp | 60 -- src/client/component/ui_scripting.cpp | 180 ----- src/client/component/ui_scripting.hpp | 12 - src/client/component/updater.cpp | 474 ------------ src/client/component/updater.hpp | 26 - src/client/component/videos.cpp | 55 -- src/client/component/virtuallobby.cpp | 63 -- src/client/loader/loader.cpp | 7 +- src/client/loader/loader.hpp | 2 +- src/client/resources/ui_scripts/common.lua | 164 ---- src/client/resources/ui_scripts/updater.lua | 164 ---- 57 files changed, 200 insertions(+), 8286 deletions(-) create mode 100644 src/client/component/arxan.cpp delete mode 100644 src/client/component/binding.cpp delete mode 100644 src/client/component/bots.cpp delete mode 100644 src/client/component/branding.cpp delete mode 100644 src/client/component/colors.cpp delete mode 100644 src/client/component/command.cpp delete mode 100644 src/client/component/command.hpp delete mode 100644 src/client/component/console.cpp delete mode 100644 src/client/component/console.hpp delete mode 100644 src/client/component/dedicated.cpp delete mode 100644 src/client/component/dedicated_info.cpp delete mode 100644 src/client/component/demonware.cpp delete mode 100644 src/client/component/demonware.hpp delete mode 100644 src/client/component/discord.cpp delete mode 100644 src/client/component/dvars.cpp delete mode 100644 src/client/component/dvars.hpp delete mode 100644 src/client/component/exception.cpp delete mode 100644 src/client/component/fastfiles.cpp delete mode 100644 src/client/component/fastfiles.hpp delete mode 100644 src/client/component/filesystem.cpp delete mode 100644 src/client/component/filesystem.hpp delete mode 100644 src/client/component/fps.cpp delete mode 100644 src/client/component/game_console.cpp delete mode 100644 src/client/component/game_console.hpp delete mode 100644 src/client/component/localized_strings.cpp delete mode 100644 src/client/component/localized_strings.hpp delete mode 100644 src/client/component/logfile.cpp delete mode 100644 src/client/component/logfile.hpp delete mode 100644 src/client/component/lui.cpp delete mode 100644 src/client/component/map_rotation.cpp delete mode 100644 src/client/component/party.cpp delete mode 100644 src/client/component/party.hpp delete mode 100644 src/client/component/patches.cpp delete mode 100644 src/client/component/renderer.cpp delete mode 100644 src/client/component/scripting.cpp delete mode 100644 src/client/component/scripting.hpp delete mode 100644 src/client/component/server_list.cpp delete mode 100644 src/client/component/server_list.hpp delete mode 100644 src/client/component/shaders.cpp delete mode 100644 src/client/component/slowmotion.cpp delete mode 100644 src/client/component/splash.cpp delete mode 100644 src/client/component/thread_names.cpp delete mode 100644 src/client/component/ui_scripting.cpp delete mode 100644 src/client/component/ui_scripting.hpp delete mode 100644 src/client/component/updater.cpp delete mode 100644 src/client/component/updater.hpp delete mode 100644 src/client/component/videos.cpp delete mode 100644 src/client/component/virtuallobby.cpp delete mode 100644 src/client/resources/ui_scripts/common.lua delete mode 100644 src/client/resources/ui_scripts/updater.lua diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp new file mode 100644 index 00000000..adff7199 --- /dev/null +++ b/src/client/component/arxan.cpp @@ -0,0 +1,164 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" +#include "game/game.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 && size_t(handle) != 0x12345) + { + 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() == game::DW_LIVE_CONNECTED + && context->ContextFlags == CONTEXT_DEBUG_REGISTERS) + { + return TRUE; + } + + return SetThreadContext(thread, context); + } + } + + int just_return() + { + return 1; + } + + 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; + } + + if (function == "LoadStringA" || function == "LoadStringW") + { + return just_return; + } + + 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 + { + // cba to implement sp, not sure if it's even needed + if (game::environment::is_sp()) return; + + // some of arxan crashes + utils::hook::nop(0x14CDEFCAA, 6); + utils::hook::call(0x1405BCAD1, &just_return); + } + }; +} + +REGISTER_COMPONENT(arxan::component) \ No newline at end of file diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 346c8d80..c5aa8240 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -42,7 +42,7 @@ namespace auth std::string get_protected_data() { - std::string input = "X-Labs-H1Mod-Auth"; + std::string input = "X-Labs-H1STEAM-Auth"; DATA_BLOB data_in{}, data_out{}; data_in.pbData = reinterpret_cast(input.data()); @@ -177,21 +177,20 @@ namespace auth game::SV_DirectConnect(from); } - // CAN'T FIND //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.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.pushad64(); + // a.mov(rdx, rsi); + // a.call_aligned(direct_connect); + // a.popad64(); - // a.jmp(0x140488CE2); // H1MP64(1.4) - // }); + // a.jmp(0x140488CE2); // H1MP64(1.4) + // }); //} } @@ -225,8 +224,8 @@ namespace auth utils::hook::jump(0x1D7542_b, 0x1D7587_b); // STEAM MAYBE `1401D7553` ON FIRST utils::hook::jump(0x1D7A82_b, 0x1D7AC8_b); // STEAM - //utils::hook::jump(0x140488BC1, get_direct_connect_stub(), true); // H1(1.4) can't find - utils::hook::call(0x12D437_b, send_connect_data_stub); // H1(1.4) + //utils::hook::jump(0x1401CAE70, get_direct_connect_stub(), true); // STEAM + utils::hook::call(0x12D437_b, send_connect_data_stub); // STEAM // Skip checks for sending connect packet utils::hook::jump(0x1402508FC, 0x140250946); diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp deleted file mode 100644 index e40b7f42..00000000 --- a/src/client/component/binding.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#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 get_num_keys() - { - return SELECT_VALUE(102, 103); - } - - 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 < get_num_keys()) - { - 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 >= get_num_keys()) - { - value -= get_num_keys(); - 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 <= get_num_keys(); i++) - { - if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) - { - return i; - } - } - - // custom binds - return get_num_keys() + get_binding_for_custom_command(command); - } - - void cl_execute_key_stub(const int local_client_num, int key, const int down, const int time) - { - if (key >= get_num_keys()) - { - key -= get_num_keys(); - - 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(0x1401881DB, 0x14025032F), key_write_bindings_to_buffer_stub); // H1(1.4) - - // links a custom command to an index - utils::hook::jump(SELECT_VALUE(0x140343C00, 0x1404041E0), key_get_binding_for_cmd_stub); // H1(1.4) - - // execute custom binds - cl_execute_key_hook.create(SELECT_VALUE(0x140183C70, 0x14024ACF0), &cl_execute_key_stub); // H1(1.4) - } - }; -} - -REGISTER_COMPONENT(binding::component) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp deleted file mode 100644 index 81f74628..00000000 --- a/src/client/component/bots.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "command.hpp" -#include "scheduler.hpp" -#include "network.hpp" -#include "party.hpp" - -#include "game/game.hpp" -#include "game/scripting/execution.hpp" - -#include -#include -#include - -namespace bots -{ - namespace - { - bool can_add() - { - if (party::get_client_count() < *game::mp::svs_numclients) - { - return true; - } - return false; - } - - // TODO: when scripting comes, fix this to use better notifies - void bot_team_join(const int entity_num) - { - const game::scr_entref_t entref{static_cast(entity_num), 0}; - scheduler::once([entref]() - { - scripting::notify(entref, "luinotifyserver", {"team_select", 2}); - scheduler::once([entref]() - { - auto* _class = utils::string::va("class%d", utils::cryptography::random::get_integer() % 5); - scripting::notify(entref, "luinotifyserver", {"class_select", _class}); - }, scheduler::pipeline::server, 2s); - }, scheduler::pipeline::server, 2s); - } - - void spawn_bot(const int entity_num) - { - game::SV_SpawnTestClient(&game::mp::g_entities[entity_num]); - if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_CORE) - { - bot_team_join(entity_num); - } - } - - void add_bot() - { - if (!can_add()) - { - return; - } - - // SV_BotGetRandomName - const auto* const bot_name = game::SV_BotGetRandomName(); - auto* bot_ent = game::SV_AddBot(bot_name); - if (bot_ent) - { - spawn_bot(bot_ent->s.entityNum); - } - else if (can_add()) // workaround since first bot won't ever spawn - { - add_bot(); - } - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - command::add("spawnBot", [](const command::params& params) - { - if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) return; - - auto num_bots = 1; - if (params.size() == 2) - { - num_bots = atoi(params.get(1)); - } - - for (auto i = 0; i < (num_bots > *game::mp::svs_numclients ? *game::mp::svs_numclients : num_bots); i++) - { - scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i); - } - }); - } - }; -} - -REGISTER_COMPONENT(bots::component) \ No newline at end of file diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp deleted file mode 100644 index 2f74693b..00000000 --- a/src/client/component/branding.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "localized_strings.hpp" -#include "scheduler.hpp" -#include "command.hpp" -#include "version.hpp" - -#include "game/game.hpp" -#include "dvars.hpp" - -#include -#include - -// fonts/default.otf, fonts/defaultBold.otf, fonts/fira_mono_regular.ttf, fonts/fira_mono_bold.ttf - -namespace branding -{ - namespace - { - utils::hook::detour ui_get_formatted_build_number_hook; - - float color[4] = {0.666f, 0.666f, 0.666f, 0.666f}; - - 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; - } - - if (game::environment::is_mp()) - { - localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER\n"); - localized_strings::override("MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER"); - } - - dvars::override::set_string("version", utils::string::va("H1-Mod %s", VERSION)); - - ui_get_formatted_build_number_hook.create( - SELECT_VALUE(0x1403B1C40, 0x1404E74C0), ui_get_formatted_build_number_stub); - - scheduler::loop([]() - { - const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20); - - game::R_AddCmdDrawText("H1-Mod: " VERSION, 0x7FFFFFFF, font, 10.f, - 5.f + static_cast(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0); - }, scheduler::pipeline::renderer); - } - }; -} - -REGISTER_COMPONENT(branding::component) diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp deleted file mode 100644 index 75eff23a..00000000 --- a/src/client/component/colors.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" - -#include -#include - -namespace colors -{ - struct hsv_color - { - unsigned char h; - unsigned char s; - unsigned char v; - }; - - namespace - { - std::vector color_table; - - DWORD hsv_to_rgb(const hsv_color 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, static_cast(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 = utils::hook::invoke(0x14025BAA0, 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(0x14F142FF8, 0x14FE70634)); // H1(1.4) - } - else if (index == '9') - { - *color = *reinterpret_cast(SELECT_VALUE(0x14F142FFC, 0x14FE70638)); // H1(1.4) - } - else if (index == ':') - { - *color = hsv_to_rgb({static_cast((game::Sys_Milliseconds() / 100) % 256), 255, 255}); - } - else if (index == ';') - { - *color = *reinterpret_cast(SELECT_VALUE(0x14F143004, 0x14FE70640)); // H1(1.4) - } - else if (index == '<') - { - *color = 0xFFFCFF80; - } - 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(0x140503810, com_clean_name_stub); // H1(1.4) - - // don't apply colors to overhead names - utils::hook::call(0x1400AB416, get_client_name_stub); // H1(1.4) - - // patch I_CleanStr - utils::hook::jump(0x140503D00, i_clean_str_stub); // H1(1.4) - } - - // force new colors - utils::hook::jump(SELECT_VALUE(0x140524BD0, 0x1406206A0), rb_lookup_color_stub); // H1(1.4) - - // 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 deleted file mode 100644 index b5c1ad40..00000000 --- a/src/client/component/command.cpp +++ /dev/null @@ -1,648 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "command.hpp" -#include "console.hpp" -#include "game_console.hpp" - -#include "game/game.hpp" - -#include -#include -#include -#include "utils/io.hpp" -#include - -namespace command -{ - namespace - { - 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 (handlers.find(command) != handlers.end()) - { - handlers[command](params); - } - } - - void client_command(const int client_num, void* a2) - { - params_sv params = {}; - - const auto command = utils::string::to_lower(params[0]); - if (handlers_sv.find(command) != handlers_sv.end()) - { - handlers_sv[command](client_num, params); - } - - client_command_hook.invoke(client_num, a2); - } - - // 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(0x142623FB4); //H1(1.4) - auto* com_console_lines = reinterpret_cast(0x142623FC0); //H1(1.4) - - 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(); - utils::hook::invoke(0x1400D8210); - } - - game::dvar_t* dvar_command_stub() - { - const params args; - - if (args.size() <= 0) - { - return 0; - } - - const auto dvar = game::Dvar_FindVar(args[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\" default: \"%s\" hash: 0x%08lX", - args[0], current, reset, dvar->hash); - - 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(dvar->hash, "", command); - } - - return dvar; - } - - return 0; - } - } - - 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(0x142623FB4); //H1(1.4) - auto* com_console_lines = reinterpret_cast(0x142623FC0); //H1(1.4) - - for (int i = 0; i < com_num_console_lines; i++) - { - game::Cmd_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::generateHashValue(game::Cmd_Argv(1)), "", game::Cmd_Argv(2)); - } - - game::Cmd_EndTokenizeString(); - } - } - - params::params() - : nesting_(game::cmd_args->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) - { - } - - 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_test(const char* name, void (*callback)()) - { - static game::cmd_function_s cmd_test; - return game::Cmd_AddCommandInternal(name, callback, &cmd_test); - } - - void add(const char* name, const std::function& callback) - { - static game::cmd_function_s cmd_test; - - const auto command = utils::string::to_lower(name); - - if (handlers.find(command) == handlers.end()) - 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, 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.find(command) == handlers_sv.end()) - handlers_sv[command] = std::move(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_commands_sp(); - } - else - { - utils::hook::call(0x1400D728F, &parse_commandline_stub); // MWR TEST - utils::hook::jump(0x14041D750, dvar_command_stub); - - add_commands_mp(); - } - - add_commands_generic(); - } - - private: - static void add_commands_generic() - { - add("quit", game::Quit); - //add("quit_hard", utils::nt::raise_hard_exception); /* this command delivers you to a windows blue screen, its quit hard from windows xD */ - add("crash", []() - { - *reinterpret_cast(1) = 0; - }); - - /*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, 0)); - } - } - - console::info("Total %i matches\n", matches.size()); - });*/ - - add("commandDump", [](const params& argument) - { - console::info("================================ COMMAND DUMP =====================================\n"); - game::cmd_function_s* cmd = (*game::cmd_functions); - std::string filename; - if (argument.size() == 2) - { - filename = "h1-mod/"; - filename.append(argument[1]); - if (!filename.ends_with(".txt")) - { - filename.append(".txt"); - } - } - int 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("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]); - - const std::string filter = params.get(2); - enum_assets(type, [type, filter](const game::XAssetHeader header) - { - const auto asset = game::XAsset{type, header}; - const auto* const asset_name = game::DB_GetXAssetName(&asset); - //const auto entry = game::DB_FindXAssetEntry(type, asset_name); - //TODO: display which zone the asset is from - - if (!filter.empty() && !game_console::match_compare(filter, asset_name, false)) - { - return; - } - - console::info("%s\n", asset_name); - }, true); - } - }); - - 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->hash); - return; - } - - execute(dvar->current.string); - });*/ - } - - static void add_commands_sp() - { - add("god", []() - { - if (!game::SV_Loaded()) - { - return; - } - - game::sp::g_entities[0].flags ^= 1; - game::CG_GameMessage(0, utils::string::va("godmode %s", - game::sp::g_entities[0].flags & 1 - ? "^2on" - : "^1off")); - }); - - add("demigod", []() - { - if (!game::SV_Loaded()) - { - return; - } - - game::sp::g_entities[0].flags ^= 2; - game::CG_GameMessage(0, utils::string::va("demigod mode %s", - game::sp::g_entities[0].flags & 2 - ? "^2on" - : "^1off")); - }); - - add("notarget", []() - { - if (!game::SV_Loaded()) - { - return; - } - - game::sp::g_entities[0].flags ^= 4; - game::CG_GameMessage(0, utils::string::va("notarget %s", - game::sp::g_entities[0].flags & 4 - ? "^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")); - }); - } - - static void add_commands_mp() - { - //client_command_hook.create(0x1402E98F0, &client_command); - - /*add_sv("god", [](const int client_num, const params_sv&) - { - if (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - game::mp::g_entities[client_num].flags ^= 1; - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - utils::string::va("f \"godmode %s\"", - game::mp::g_entities[client_num].flags & 1 - ? "^2on" - : "^1off")); - }); - - add_sv("demigod", [](const int client_num, const params_sv&) - { - if (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - game::mp::g_entities[client_num].flags ^= 2; - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - utils::string::va("f \"demigod mode %s\"", - game::mp::g_entities[client_num].flags & 2 - ? "^2on" - : "^1off")); - }); - - add_sv("notarget", [](const int client_num, const params_sv&) - { - if (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - game::mp::g_entities[client_num].flags ^= 4; - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - utils::string::va("f \"notarget %s\"", - game::mp::g_entities[client_num].flags & 4 - ? "^2on" - : "^1off")); - }); - - add_sv("noclip", [](const int client_num, const params_sv&) - { - if (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - game::mp::g_entities[client_num].client->flags ^= 1; - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - 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 (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - game::mp::g_entities[client_num].client->flags ^= 2; - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - utils::string::va("f \"ufo %s\"", - game::mp::g_entities[client_num].client->flags & 2 - ? "^2on" - : "^1off")); - }); - - add_sv("give", [](const int client_num, const params_sv& params) - { - if (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - if (params.size() < 2) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"You did not specify a weapon name\""); - return; - } - - auto ps = game::SV_GetPlayerstateForClientNum(client_num); - const auto wp = game::G_GetWeaponForName(params.get(1)); - if (wp) - { - if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 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 (!game::Dvar_FindVar("sv_cheats")->current.enabled) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); - return; - } - - if (params.size() < 2) - { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - "f \"You did not specify a weapon name\""); - return; - } - - auto ps = game::SV_GetPlayerstateForClientNum(client_num); - const auto wp = game::G_GetWeaponForName(params.get(1)); - if (wp) - { - game::G_TakePlayerWeapon(ps, wp); - } - });*/ - } - }; -} - -REGISTER_COMPONENT(command::component) diff --git a/src/client/component/command.hpp b/src/client/component/command.hpp deleted file mode 100644 index bd70d0c6..00000000 --- a/src/client/component/command.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#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, std::function callback); - - void execute(std::string command, bool sync = false); -} \ No newline at end of file diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp deleted file mode 100644 index 174beaf8..00000000 --- a/src/client/component/console.cpp +++ /dev/null @@ -1,299 +0,0 @@ -#include -#include "console.hpp" -#include "loader/component_loader.hpp" -#include "game/game.hpp" -#include "command.hpp" - -#include -#include -#include -#include - -namespace game_console -{ - void print(int type, const std::string& data); -} - -namespace console -{ - namespace - { - using message_queue = std::queue; - utils::concurrency::container messages; - - bool native_console() - { - static const auto flag = utils::flags::has_flag("nativeconsole"); - return flag; - } - - void hide_console() - { - auto* const con_window = GetConsoleWindow(); - - DWORD process; - GetWindowThreadProcessId(con_window, &process); - - if (!native_console() && (process == GetCurrentProcessId() || IsDebuggerPresent())) - { - ShowWindow(con_window, SW_HIDE); - } - } - - std::string format(va_list* ap, const char* message) - { - static thread_local char buffer[0x1000]; - - const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); - - if (count < 0) return {}; - return {buffer, static_cast(count)}; - } - - void dispatch_message(const int type, const std::string& message) - { - if (native_console()) - { - printf("%s\n", message.data()); - return; - } - - game_console::print(type, message); - messages.access([&message](message_queue& msgs) - { - msgs.emplace(message); - }); - } - - void append_text(const char* text) - { - dispatch_message(con_type_info, text); - } - } - - class component final : public component_interface - { - public: - component() - { - hide_console(); - - if (native_console()) - { - setvbuf(stdout, nullptr, _IONBF, 0); - setvbuf(stderr, nullptr, _IONBF, 0); - } - else - { - (void)_pipe(this->handles_, 1024, _O_TEXT); - (void)_dup2(this->handles_[1], 1); - (void)_dup2(this->handles_[1], 2); - } - } - - void post_start() override - { - this->terminate_runner_ = false; - - this->console_runner_ = utils::thread::create_named_thread("Console IO", [this] - { - if (native_console()) - { - this->native_input(); - } - else - { - this->runner(); - } - }); - } - - void pre_destroy() override - { - this->terminate_runner_ = true; - - printf("\r\n"); - _flushall(); - - if (this->console_runner_.joinable()) - { - this->console_runner_.join(); - } - - if (this->console_thread_.joinable()) - { - this->console_thread_.join(); - } - -#ifndef NATIVE_CONSOLE - _close(this->handles_[0]); - _close(this->handles_[1]); -#endif - - messages.access([&](message_queue& msgs) - { - msgs = {}; - }); - } - - void post_unpack() override - { - // Redirect input (]command) - utils::hook::jump(SELECT_VALUE(0x1403E34C0, 0x1405141E0), append_text); // H1(1.4) - - this->initialize(); - } - - private: - volatile bool console_initialized_ = false; - volatile bool terminate_runner_ = false; - - std::thread console_runner_; - std::thread console_thread_; - - int handles_[2]{}; - - void initialize() - { - this->console_thread_ = utils::thread::create_named_thread("Console", [this]() - { - if (!native_console() && (game::environment::is_dedi() || !utils::flags::has_flag("noconsole"))) - { - game::Sys_ShowConsole(); - } - - if (!game::environment::is_dedi()) - { - // Hide that shit - ShowWindow(console::get_window(), SW_MINIMIZE); - } - - { - messages.access([&](message_queue&) - { - this->console_initialized_ = true; - }); - } - - MSG msg; - while (!this->terminate_runner_) - { - if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - command::execute("quit", false); - break; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - this->log_messages(); - std::this_thread::sleep_for(1ms); - } - } - }); - } - - void log_messages() - { - /*while*/ - if (this->console_initialized_ && !messages.get_raw().empty()) - { - std::queue message_queue_copy; - - { - messages.access([&](message_queue& msgs) - { - message_queue_copy = std::move(msgs); - msgs = {}; - }); - } - - while (!message_queue_copy.empty()) - { - log_message(message_queue_copy.front()); - message_queue_copy.pop(); - } - } - - fflush(stdout); - fflush(stderr); - } - - static void log_message(const std::string& message) - { - OutputDebugStringA(message.data()); - game::Conbuf_AppendText(message.data()); - } - - void runner() - { - char buffer[1024]; - - while (!this->terminate_runner_ && this->handles_[0]) - { - const auto len = _read(this->handles_[0], buffer, sizeof(buffer)); - if (len > 0) - { - dispatch_message(con_type_info, std::string(buffer, len)); - } - else - { - std::this_thread::sleep_for(1ms); - } - } - - std::this_thread::yield(); - } - - void native_input() - { - std::string cmd; - - while (!this->terminate_runner_) - { - std::getline(std::cin, cmd); - command::execute(cmd); - } - - std::this_thread::yield(); - } - }; - - HWND get_window() - { - return *reinterpret_cast((SELECT_VALUE(0x14CF56C00, 0x14DDFC2D0))); // H1(1.4) - } - - void set_title(std::string title) - { - SetWindowText(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(0x14CF56C10, 0x14DDFC2E0)); // H1(1.4) - 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 deleted file mode 100644 index 302951a8..00000000 --- a/src/client/component/console.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#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)...); - } -} \ No newline at end of file diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp deleted file mode 100644 index 8de5e9ac..00000000 --- a/src/client/component/dedicated.cpp +++ /dev/null @@ -1,333 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "scheduler.hpp" -#include "server_list.hpp" -#include "network.hpp" -#include "command.hpp" -#include "game/game.hpp" -#include "game/dvars.hpp" -#include "dvars.hpp" -#include "console.hpp" - -#include -#include - -namespace dedicated -{ - namespace - { - utils::hook::detour gscr_set_dynamic_dvar_hook; - utils::hook::detour com_quit_f_hook; - - void init_dedicated_server() - { - static bool initialized = false; - if (initialized) return; - initialized = true; - - // R_LoadGraphicsAssets - utils::hook::invoke(0x1405DF4B0); - } - - void send_heartbeat() - { - auto* const dvar = game::Dvar_FindVar("sv_lanOnly"); - if (dvar && dvar->current.enabled) - { - return; - } - - game::netadr_s target{}; - if (server_list::get_master_server(target)) - { - network::send(target, "heartbeat", "H1"); - } - } - - 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(const int client, const char* command) - { - if (game::Live_SyncOnlineDataFlags(0) == 0) - { - game::Cbuf_AddText(client, command); - game::Cbuf_AddText(client, "\n"); - } - 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) - { - game::Cbuf_AddText(0, command.data()); - game::Cbuf_AddText(0, "\n"); - } - } - - void sync_gpu_stub() - { - std::this_thread::sleep_for(1ms); - } - - game::dvar_t* gscr_set_dynamic_dvar() - { - /* - auto s = game::Scr_GetString(0); - auto* dvar = game::Dvar_FindVar(s); - - if (dvar && !strncmp("scr_", dvar->name, 4)) - { - return dvar; - } - */ - - return gscr_set_dynamic_dvar_hook.invoke(); - } - - void kill_server() - { - for (auto i = 0; i < *game::mp::svs_numclients; ++i) - { - if (game::mp::svs_clients[i].header.state >= 3) - { - game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE, - utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); - } - } - - com_quit_f_hook.invoke(); - } - - void sys_error_stub(const char* msg, ...) - { - char buffer[2048]; - - va_list ap; - va_start(ap, msg); - - vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap); - - va_end(ap); - - scheduler::once([]() - { - command::execute("map_rotate"); - }, scheduler::main, 3s); - - game::Com_Error(game::ERR_DROP, "%s", buffer); - } - } - - void initialize() - { - command::execute("exec default_xboxlive.cfg", true); - command::execute("onlinegame 1", true); - command::execute("xblive_privatematch 1", true); - } - - class component final : public component_interface - { - public: - void* load_import(const std::string& library, const std::string& function) override - { - return nullptr; - } - - void post_unpack() override - { - if (!game::environment::is_dedi()) - { - return; - } - -#ifdef DEBUG - printf("Starting dedicated server\n"); -#endif - - // Register dedicated dvar - dvars::register_bool("dedicated", true, game::DVAR_FLAG_READ); - - // Add lanonly mode - dvars::register_bool("sv_lanOnly", false, game::DVAR_FLAG_NONE); - - // Disable VirtualLobby - dvars::override::register_bool("virtualLobbyEnabled", false, game::DVAR_FLAG_READ); - - // Disable r_preloadShaders - dvars::override::register_bool("r_preloadShaders", false, game::DVAR_FLAG_READ); - - // Stop crashing from sys_errors - utils::hook::jump(0x140511520, sys_error_stub); - - // Hook R_SyncGpu - utils::hook::jump(0x1405E12F0, sync_gpu_stub); - - utils::hook::jump(0x140254800, init_dedicated_server); - - // delay startup commands until the initialization is done - utils::hook::call(0x1400D72D6, execute_startup_command); - - // delay console commands until the initialization is done - utils::hook::call(0x1400D808C, execute_console_command); - utils::hook::nop(0x1400D80A4, 5); - - // patch GScr_SetDynamicDvar to behave better - gscr_set_dynamic_dvar_hook.create(0x14036B600, &gscr_set_dynamic_dvar); - - utils::hook::nop(0x1404ED90E, 5); // don't load config file - utils::hook::nop(0x140403D92, 5); // ^ - utils::hook::set(0x1400DC1D0, 0xC3); // don't save config file - utils::hook::set(0x140274710, 0xC3); // disable self-registration - utils::hook::set(0x140515890, 0xC3); // init sound system (1) - utils::hook::set(0x1406574F0, 0xC3); // init sound system (2) - utils::hook::set(0x140620D10, 0xC3); // render thread - utils::hook::set(0x14025B850, 0xC3); // called from Com_Frame, seems to do renderer stuff - utils::hook::set(0x1402507B0, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly - utils::hook::set(0x1405D5178, 0x00); // r_loadForRenderer default to 0 - utils::hook::set(0x14050C2D0, 0xC3); // recommended settings check - TODO: Check hook - utils::hook::set(0x140514C00, 0xC3); // some mixer-related function called on shutdown - utils::hook::set(0x140409830, 0xC3); // dont load ui gametype stuff - - utils::hook::nop(0x140481B06, 6); // unknown check in SV_ExecuteClientMessage - utils::hook::nop(0x140480FAC, 4); // allow first slot to be occupied - utils::hook::nop(0x14025619B, 2); // properly shut down dedicated servers - utils::hook::nop(0x14025615E, 2); // ^ - utils::hook::nop(0x1402561C0, 5); // don't shutdown renderer - - utils::hook::set(0x140091840, 0xC3); // something to do with blendShapeVertsView - utils::hook::nop(0x140659A0D, 8); // sound thing - - // (COULD NOT FIND IN H1) - // utils::hook::set(0x1404D6960, 0xC3); // cpu detection stuff? - utils::hook::set(0x1405E97F0, 0xC3); // gfx stuff during fastfile loading - utils::hook::set(0x1405E9700, 0xC3); // ^ - utils::hook::set(0x1405E9790, 0xC3); // ^ - utils::hook::set(0x1402C1180, 0xC3); // ^ - utils::hook::set(0x1405E9750, 0xC3); // ^ - utils::hook::set(0x1405AD5B0, 0xC3); // directx stuff - utils::hook::set(0x1405DB150, 0xC3); // ^ - utils::hook::set(0x140625220, 0xC3); // ^ - mutex - utils::hook::set(0x1405DB650, 0xC3); // ^ - - utils::hook::set(0x14008B5F0, 0xC3); // rendering stuff - utils::hook::set(0x1405DB8B0, 0xC3); // ^ - utils::hook::set(0x1405DB9C0, 0xC3); // ^ - utils::hook::set(0x1405DC050, 0xC3); // ^ - utils::hook::set(0x1405DCBA0, 0xC3); // ^ - utils::hook::set(0x1405DD240, 0xC3); // ^ - - // shaders - utils::hook::set(0x1400916A0, 0xC3); // ^ - utils::hook::set(0x140091610, 0xC3); // ^ - utils::hook::set(0x14061ACC0, 0xC3); // ^ - mutex - - utils::hook::set(0x140516080, 0xC3); // idk - utils::hook::set(0x1405AE5F0, 0xC3); // ^ - - utils::hook::set(0x1405E0B30, 0xC3); // R_Shutdown - utils::hook::set(0x1405AE400, 0xC3); // shutdown stuff - utils::hook::set(0x1405E0C00, 0xC3); // ^ - utils::hook::set(0x1405DFE50, 0xC3); // ^ - - // utils::hook::set(0x1404B67E0, 0xC3); // sound crashes (H1 - questionable, function looks way different) - - utils::hook::set(0x14048B660, 0xC3); // disable host migration - - utils::hook::set(0x14042B2E0, 0xC3); // render synchronization lock - utils::hook::set(0x14042B210, 0xC3); // render synchronization unlock - - utils::hook::set(0x140176D2D, 0xEB); // LUI: Unable to start the LUI system due to errors in main.lua - - utils::hook::nop(0x140506ECE, 5); // Disable sound pak file loading - utils::hook::nop(0x140506ED6, 2); // ^ - utils::hook::set(0x1402C5910, 0xC3); // Disable image pak file loading - - // Reduce min required memory - utils::hook::set(0x14050C717, 0x80000000); - - utils::hook::set(0x1402BF7F0, 0xC3); // some loop - utils::hook::set(0x14007E150, 0xC3); // related to shader caching / techsets / fastfiles - - // initialize the game after onlinedataflags is 32 (workaround) - scheduler::schedule([=]() - { - if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2()) - { - scheduler::once([]() - { - command::execute("xstartprivateparty", true); - command::execute("disconnect", true); // 32 -> 0 - }, scheduler::pipeline::main, 1s); - return scheduler::cond_end; - } - - return scheduler::cond_continue; - }, scheduler::pipeline::main, 1s); - - scheduler::on_game_initialized([]() - { - initialize(); - - console::info("==================================\n"); - console::info("Server started!\n"); - console::info("==================================\n"); - - // remove disconnect command - game::Cmd_RemoveCommand("disconnect"); - - execute_startup_command_queue(); - execute_console_command_queue(); - - // Send heartbeat to dpmaster - scheduler::once(send_heartbeat, scheduler::pipeline::server); - scheduler::loop(send_heartbeat, scheduler::pipeline::server, 10min); - command::add("heartbeat", send_heartbeat); - }, scheduler::pipeline::main, 1s); - - command::add("killserver", kill_server); - com_quit_f_hook.create(0x1400DA640, &kill_server); - } - }; -} - -REGISTER_COMPONENT(dedicated::component) \ No newline at end of file diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp deleted file mode 100644 index 55973193..00000000 --- a/src/client/component/dedicated_info.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#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::loop([]() - { - auto* sv_running = game::Dvar_FindVar("sv_running"); - if (!sv_running || !sv_running->current.enabled) - { - console::set_title("H1-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 bot_count = 0; - auto client_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 >= 1 && self && self->client) - { - client_count++; - if (game::SV_BotIsBot(i)) - { - ++bot_count; - } - } - } - - std::string cleaned_hostname; - cleaned_hostname.resize(static_cast(strlen(sv_hostname->current.string) + 1)); - - utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(), - static_cast(strlen(sv_hostname->current.string)) + 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) \ No newline at end of file diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp deleted file mode 100644 index 4cb3362c..00000000 --- a/src/client/component/demonware.cpp +++ /dev/null @@ -1,604 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include -#include - -#include "game/game.hpp" -#include "game/demonware/servers/lobby_server.hpp" -#include "game/demonware/servers/auth3_server.hpp" -#include "game/demonware/servers/stun_server.hpp" -#include "game/demonware/servers/umbrella_server.hpp" -#include "game/demonware/server_registry.hpp" -#include - -#define TCP_BLOCKING true -#define UDP_BLOCKING false - -namespace demonware -{ - namespace - { - volatile bool exit_server; - std::thread server_thread; - utils::concurrency::container> blocking_sockets; - utils::concurrency::container> socket_map; - server_registry tcp_servers; - server_registry udp_servers; - - tcp_server* find_server(const SOCKET socket) - { - return socket_map.access([&](const std::unordered_map& map) -> tcp_server* - { - const auto entry = map.find(socket); - if (entry == map.end()) - { - return nullptr; - } - - return entry->second; - }); - } - - bool socket_link(const SOCKET socket, const uint32_t address) - { - auto* server = tcp_servers.find(address); - if (!server) - { - return false; - } - - socket_map.access([&](std::unordered_map& map) - { - map[socket] = server; - }); - - return true; - } - - void socket_unlink(const SOCKET socket) - { - socket_map.access([&](std::unordered_map& map) - { - const auto entry = map.find(socket); - if (entry != map.end()) - { - map.erase(entry); - } - }); - } - - bool is_socket_blocking(const SOCKET socket, const bool def) - { - return blocking_sockets.access([&](std::unordered_map& map) - { - const auto entry = map.find(socket); - if (entry == map.end()) - { - return def; - } - - return entry->second; - }); - } - - void remove_blocking_socket(const SOCKET socket) - { - blocking_sockets.access([&](std::unordered_map& map) - { - const auto entry = map.find(socket); - if (entry != map.end()) - { - map.erase(entry); - } - }); - } - - void add_blocking_socket(const SOCKET socket, const bool block) - { - blocking_sockets.access([&](std::unordered_map& map) - { - map[socket] = block; - }); - } - - void server_main() - { - exit_server = false; - - while (!exit_server) - { - tcp_servers.frame(); - udp_servers.frame(); - std::this_thread::sleep_for(50ms); - } - } - - namespace io - { - int getaddrinfo_stub(const char* name, const char* service, - const addrinfo* hints, addrinfo** res) - { -#ifdef DEBUG - printf("[ network ]: [getaddrinfo]: \"%s\" \"%s\"\n", name, service); -#endif - - base_server* server = tcp_servers.find(name); - if (!server) - { - server = udp_servers.find(name); - } - - if (!server) - { - return getaddrinfo(name, service, hints, res); - } - - const auto address = utils::memory::get_allocator()->allocate(); - const auto ai = utils::memory::get_allocator()->allocate(); - - auto in_addr = reinterpret_cast(address); - in_addr->sin_addr.s_addr = server->get_address(); - in_addr->sin_family = AF_INET; - - ai->ai_family = AF_INET; - ai->ai_socktype = SOCK_STREAM; - ai->ai_addr = address; - ai->ai_addrlen = sizeof(sockaddr); - ai->ai_next = nullptr; - ai->ai_flags = 0; - ai->ai_protocol = 0; - ai->ai_canonname = const_cast(name); - - *res = ai; - - return 0; - } - - void freeaddrinfo_stub(addrinfo* ai) - { - if (!utils::memory::get_allocator()->find(ai)) - { - return freeaddrinfo(ai); - } - - utils::memory::get_allocator()->free(ai->ai_addr); - utils::memory::get_allocator()->free(ai); - } - - int getpeername_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen) - { - auto* server = find_server(s); - - if (server) - { - auto in_addr = reinterpret_cast(addr); - in_addr->sin_addr.s_addr = server->get_address(); - in_addr->sin_family = AF_INET; - *addrlen = sizeof(sockaddr); - - return 0; - } - - return getpeername(s, addr, addrlen); - } - - int getsockname_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen) - { - auto* server = find_server(s); - - if (server) - { - auto in_addr = reinterpret_cast(addr); - in_addr->sin_addr.s_addr = server->get_address(); - in_addr->sin_family = AF_INET; - *addrlen = sizeof(sockaddr); - - return 0; - } - - return getsockname(s, addr, addrlen); - } - - hostent* gethostbyname_stub(const char* name) - { -#ifdef DEBUG - printf("[ network ]: [gethostbyname]: \"%s\"\n", name); -#endif - - base_server* server = tcp_servers.find(name); - if (!server) - { - server = udp_servers.find(name); - } - - if (!server) - { -#pragma warning(push) -#pragma warning(disable: 4996) - return gethostbyname(name); -#pragma warning(pop) - } - - static thread_local in_addr address{}; - address.s_addr = server->get_address(); - - static thread_local in_addr* addr_list[2]{}; - addr_list[0] = &address; - addr_list[1] = nullptr; - - static thread_local hostent host{}; - host.h_name = const_cast(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; - } - - int connect_stub(const SOCKET s, const struct sockaddr* addr, const int len) - { - if (len == sizeof(sockaddr_in)) - { - const auto* in_addr = reinterpret_cast(addr); - if (socket_link(s, in_addr->sin_addr.s_addr)) return 0; - } - - return connect(s, addr, len); - } - - int closesocket_stub(const SOCKET s) - { - remove_blocking_socket(s); - socket_unlink(s); - - return closesocket(s); - } - - int send_stub(const SOCKET s, const char* buf, const int len, const int flags) - { - auto* server = find_server(s); - - if (server) - { - server->handle_input(buf, len); - return len; - } - - return send(s, buf, len, flags); - } - - int recv_stub(const SOCKET s, char* buf, const int len, const int flags) - { - auto* server = find_server(s); - - if (server) - { - if (server->pending_data()) - { - return static_cast(server->handle_output(buf, len)); - } - else - { - WSASetLastError(WSAEWOULDBLOCK); - return -1; - } - } - - return recv(s, buf, len, flags); - } - - int sendto_stub(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to, - const int tolen) - { - const auto* in_addr = reinterpret_cast(to); - auto* server = udp_servers.find(in_addr->sin_addr.s_addr); - - if (server) - { - server->handle_input(buf, len, {s, to, tolen}); - return len; - } - - return sendto(s, buf, len, flags, to, tolen); - } - - int recvfrom_stub(const SOCKET s, char* buf, const int len, const int flags, struct sockaddr* from, - int* fromlen) - { - // Not supported yet - if (is_socket_blocking(s, UDP_BLOCKING)) - { - return recvfrom(s, buf, len, flags, from, fromlen); - } - - size_t result = 0; - udp_servers.for_each([&](udp_server& server) - { - if (server.pending_data(s)) - { - result = server.handle_output( - s, buf, static_cast(len), from, fromlen); - } - }); - - if (result) - { - return static_cast(result); - } - - return recvfrom(s, buf, len, flags, from, fromlen); - } - - int select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, - struct timeval* timeout) - { - if (exit_server) - { - return select(nfds, readfds, writefds, exceptfds, timeout); - } - - auto result = 0; - std::vector read_sockets; - std::vector write_sockets; - - socket_map.access([&](std::unordered_map& sockets) - { - for (auto& s : sockets) - { - if (readfds) - { - if (FD_ISSET(s.first, readfds)) - { - if (s.second->pending_data()) - { - read_sockets.push_back(s.first); - FD_CLR(s.first, readfds); - } - } - } - - if (writefds) - { - if (FD_ISSET(s.first, writefds)) - { - write_sockets.push_back(s.first); - FD_CLR(s.first, writefds); - } - } - - if (exceptfds) - { - if (FD_ISSET(s.first, exceptfds)) - { - FD_CLR(s.first, exceptfds); - } - } - } - }); - - if ((!readfds || readfds->fd_count == 0) && (!writefds || writefds->fd_count == 0)) - { - timeout->tv_sec = 0; - timeout->tv_usec = 0; - } - - result = select(nfds, readfds, writefds, exceptfds, timeout); - if (result < 0) result = 0; - - for (const auto& socket : read_sockets) - { - if (readfds) - { - FD_SET(socket, readfds); - result++; - } - } - - for (const auto& socket : write_sockets) - { - if (writefds) - { - FD_SET(socket, writefds); - result++; - } - } - - return result; - } - - int ioctlsocket_stub(const SOCKET s, const long cmd, u_long* argp) - { - if (static_cast(cmd) == (FIONBIO)) - { - add_blocking_socket(s, *argp == 0); - } - - return ioctlsocket(s, cmd, argp); - } - - BOOL internet_get_connected_state_stub(LPDWORD, DWORD) - { - // Allow offline play - return TRUE; - } - } - - void bd_logger_stub(char* a1, void* a2, void* a3, void* a4, const char* function, ...) - { - - } - -#ifdef DEBUG - void a(unsigned int n) - { - printf("bdAuth: Auth task failed with HTTP code [%u]\n", n); - } - - void b(unsigned int n) - { - printf("bdAuth: Decoded client ticket of unexpected size [%u]\n", n); - } - - void c(unsigned int n) - { - printf("bdAuth: Decoded server ticket of unexpected size [%u]\n", n); - } - - void d() - { - printf("bdAuth: Auth ticket magic number mismatch\n"); - } - - void e() - { - printf("bdAuth: Cross Authentication completed\n"); - } - - void f() - { - printf("bdAuth: Auth task reply contains invalid data / format\n"); - } - - void g(unsigned int n) - { - printf("bdAuth: Auth task returned with error code [%u]\n", n); - } - - void h(unsigned int n) - { - printf("bdAuth: Invalid or No Task ID [%u] in Auth reply\n", n); - } - - void i() - { - printf("bdAuth: Received reply from DemonWare Auth server\n"); - } - - void l() - { - printf("bdAuth: Unknown error\n"); - } -#endif - } - - class component final : public component_interface - { - public: - component() - { - udp_servers.create("phoenix.stun.us.demonware.net"); - udp_servers.create("phoenix.stun.eu.demonware.net"); - udp_servers.create("phoenix.stun.jp.demonware.net"); - udp_servers.create("phoenix.stun.au.demonware.net"); - - udp_servers.create("stun.us.demonware.net"); - udp_servers.create("stun.eu.demonware.net"); - udp_servers.create("stun.jp.demonware.net"); - udp_servers.create("stun.au.demonware.net"); - - tcp_servers.create("mwr-pc-steam-auth3.prod.demonware.net"); - tcp_servers.create("mwr-pc-steam-lobby.prod.demonware.net"); - tcp_servers.create("prod.umbrella.demonware.net"); - } - - void post_load() override - { - server_thread = utils::thread::create_named_thread("Demonware", server_main); - } - - void* load_import(const std::string& library, const std::string& function) override - { - if (library == "WS2_32.dll") - { - if (function == "#3") return io::closesocket_stub; - if (function == "#4") return io::connect_stub; - if (function == "#5") return io::getpeername_stub; - if (function == "#6") return io::getsockname_stub; - if (function == "#10") return io::ioctlsocket_stub; - if (function == "#16") return io::recv_stub; - if (function == "#17") return io::recvfrom_stub; - if (function == "#18") return io::select_stub; - if (function == "#19") return io::send_stub; - if (function == "#20") return io::sendto_stub; - if (function == "#52") return io::gethostbyname_stub; - if (function == "getaddrinfo") return io::getaddrinfo_stub; - if (function == "freeaddrinfo") return io::freeaddrinfo_stub; - } - - if (function == "InternetGetConnectedState") - { - return io::internet_get_connected_state_stub; - } - - return nullptr; - } - - void post_unpack() override - { - /* - mwr has upgraded some networking methods and the gethostbyname import from winsock library is no longer used - gethostbyname has been replaced with getaddrinfo - btw, still you can't get online.. - */ - utils::hook::jump(SELECT_VALUE(0x140610320, 0x1407400B0), bd_logger_stub); // H1MP64(1.4) - - if (game::environment::is_sp()) - { - utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) - utils::hook::set(0x140333A00, 0xC3); // dwNet H1(1.4) - return; - } - - utils::hook::set(0x140715039, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.4) - utils::hook::set(0x140715025, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.4) - utils::hook::set(0x14095433C, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] - - //HTTPS -> HTTP - utils::hook::inject(0x14006DDA9, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003852E] - utils::hook::inject(0x14006E11C, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003884F] - utils::hook::inject(0x14006E2FB, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x140038A07] - utils::hook::inject(0x14006E9A9, "http://prod.uno.demonware.net/v1.0/"); - utils::hook::inject(0x14006ED49, "http://prod.uno.demonware.net/v1.0/"); - utils::hook::inject(0x140728170, "http://%s:%d/auth/"); - - utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) - utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) - -#ifdef DEBUG - // yes - utils::hook::call(0x140727BEB, l); - utils::hook::call(0x140727AFC, i); - utils::hook::call(0x140727E49, h); - utils::hook::call(0x140727E30, g); - utils::hook::call(0x140727E37, f); - utils::hook::call(0x140727DF2, e); - utils::hook::call(0x140727DF9, d); - utils::hook::call(0x140727CFC, c); - utils::hook::call(0x140727C82, b); - utils::hook::call(0x140727E6A, a); -#endif - // Checks X-Signature header or something - utils::hook::set(0x140728380, 0xC301B0); - // Checks extended_data and extra_data in json object - utils::hook::set(0x140728E90, 0xC301B0); - // Update check - utils::hook::set(0x1403A5390, 0xC301B0); - - // Remove some while loop in demonware that freezes the rendering for a few secs at launch - utils::hook::nop(0x14057DBC5, 5); - } - - void pre_destroy() override - { - exit_server = true; - if (server_thread.joinable()) - { - server_thread.join(); - } - } - }; -} - -REGISTER_COMPONENT(demonware::component) diff --git a/src/client/component/demonware.hpp b/src/client/component/demonware.hpp deleted file mode 100644 index d26d1ccd..00000000 --- a/src/client/component/demonware.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace demonware -{ - -} \ No newline at end of file diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp deleted file mode 100644 index 5925a64a..00000000 --- a/src/client/component/discord.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "scheduler.hpp" -#include "game/game.hpp" - -#include "console.hpp" -#include "command.hpp" -#include "network.hpp" -#include "party.hpp" - -#include - -#include - -namespace discord -{ - namespace - { - DiscordRichPresence discord_presence; - - void update_discord() - { - Discord_RunCallbacks(); - - if (!game::CL_IsCgameInitialized() || game::VirtualLobby_Loaded()) - { - discord_presence.details = game::environment::is_sp() ? "Singleplayer" : "Multiplayer"; - discord_presence.state = "Main Menu"; - - auto firingRangeDvar = game::Dvar_FindVar("virtualLobbyInFiringRange"); - if (firingRangeDvar && firingRangeDvar->current.enabled == 1) - { - discord_presence.state = "Firing Range"; - } - - discord_presence.partySize = 0; - discord_presence.partyMax = 0; - discord_presence.startTimestamp = 0; - discord_presence.largeImageKey = game::environment::is_sp() ? "menu_singleplayer" : "menu_multiplayer"; - } - else - { - const auto map = game::Dvar_FindVar("mapname")->current.string; - const auto mapname = game::UI_SafeTranslateString(utils::string::va("PRESENCE_%s%s", (game::environment::is_sp() ? "SP_" : ""), map)); - - if (game::environment::is_mp()) - { - const auto gametype = game::UI_GetGameTypeDisplayName(game::Dvar_FindVar("g_gametype")->current.string); - - discord_presence.details = utils::string::va("%s on %s", gametype, mapname); - - char clean_hostname[0x100] = {0}; - utils::string::strip(game::Dvar_FindVar("sv_hostname")->current.string, - clean_hostname, sizeof(clean_hostname)); - auto max_clients = party::server_client_count(); - - // When true, we are in Private Match - if (game::SV_Loaded()) - { - strcpy_s(clean_hostname, "Private Match"); - max_clients = game::Dvar_FindVar("sv_maxclients")->current.integer; - } - - discord_presence.partySize = *reinterpret_cast(0x1429864C4); - discord_presence.partyMax = max_clients; - discord_presence.state = clean_hostname; - discord_presence.largeImageKey = map; - } - else if (game::environment::is_sp()) - { - discord_presence.state = ""; - discord_presence.largeImageKey = map; - discord_presence.details = mapname; - } - - if (!discord_presence.startTimestamp) - { - discord_presence.startTimestamp = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count(); - } - } - - 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 = nullptr; - handlers.spectateGame = nullptr; - handlers.joinRequest = nullptr; - - Discord_Initialize("947125042930667530", &handlers, 1, nullptr); - - scheduler::once([]() - { - scheduler::once(update_discord, scheduler::pipeline::async); - scheduler::loop(update_discord, scheduler::pipeline::async, 5s); - }, scheduler::pipeline::main); - - initialized_ = true; - } - - void pre_destroy() override - { - if (!initialized_ || game::environment::is_dedi()) - { - return; - } - - Discord_Shutdown(); - } - - private: - bool initialized_ = false; - - static void ready(const DiscordUser* /*request*/) - { - ZeroMemory(&discord_presence, sizeof(discord_presence)); - - discord_presence.instance = 1; - - console::info("Discord: Ready\n"); - - Discord_UpdatePresence(&discord_presence); - } - - static void errored(const int error_code, const char* message) - { - console::error("Discord: Error (%i): %s\n", error_code, message); - } - }; -} - -REGISTER_COMPONENT(discord::component) \ No newline at end of file diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp deleted file mode 100644 index d9c77fdf..00000000 --- a/src/client/component/dvars.cpp +++ /dev/null @@ -1,443 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "dvars.hpp" - -#include "game/game.hpp" - -#include - -namespace dvars -{ - struct dvar_base - { - unsigned int flags{}; - }; - - struct dvar_bool : dvar_base - { - bool value{}; - }; - - struct dvar_float : dvar_base - { - float value{}; - float min{}; - float max{}; - }; - - struct dvar_vector2 : dvar_base - { - float x{}; - float y{}; - float min{}; - float max{}; - }; - - struct dvar_vector3 : dvar_base - { - - float x{}; - float y{}; - float z{}; - float min{}; - float max{}; - }; - - struct dvar_int : dvar_base - { - int value{}; - int min{}; - int max{}; - }; - - struct dvar_string : dvar_base - { - std::string value{}; - }; - - namespace - { - 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; - } - - template - T* find_dvar(std::unordered_map& map, const int hash) - { - for (auto i = map.begin(); i != map.end(); ++i) - { - if (game::generateHashValue(i->first.data()) == hash) - { - return &i->second; - } - } - - return nullptr; - } - - bool find_dvar(std::unordered_set& set, const std::string& name) - { - return set.find(name) != set.end(); - } - - - bool find_dvar(std::unordered_set& set, const int hash) - { - for (auto i = set.begin(); i != set.end(); ++i) - { - if (game::generateHashValue(i->data()) == hash) - { - return true; - } - } - - return false; - } - } - - namespace disable - { - static std::unordered_set set_bool_disables; - static std::unordered_set set_float_disables; - static std::unordered_set set_int_disables; - static std::unordered_set set_string_disables; - - void set_bool(const std::string& name) - { - set_bool_disables.emplace(name); - } - - void set_float(const std::string& name) - { - set_float_disables.emplace(name); - } - - void set_int(const std::string& name) - { - set_int_disables.emplace(name); - } - - void set_string(const std::string& name) - { - set_string_disables.emplace(name); - } - } - - namespace override - { - static std::unordered_map register_bool_overrides; - static std::unordered_map register_float_overrides; - static std::unordered_map register_int_overrides; - static std::unordered_map register_string_overrides; - static std::unordered_map register_vector2_overrides; - static std::unordered_map register_vector3_overrides; - - static std::unordered_map set_bool_overrides; - static std::unordered_map set_float_overrides; - static std::unordered_map set_int_overrides; - static std::unordered_map set_string_overrides; - static std::unordered_map set_from_string_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] = std::move(values); - } - - void register_float(const std::string& name, const float value, const float min, const float max, - const unsigned int flags) - { - dvar_float values; - values.value = value; - values.min = min; - values.max = max; - values.flags = flags; - register_float_overrides[name] = std::move(values); - } - - void register_int(const std::string& name, const int value, const int min, const int max, - const unsigned int flags) - { - dvar_int values; - values.value = value; - values.min = min; - values.max = max; - values.flags = flags; - register_int_overrides[name] = std::move(values); - } - - void register_string(const std::string& name, const std::string& value, - const unsigned int flags) - { - dvar_string values; - values.value = value; - values.flags = flags; - register_string_overrides[name] = std::move(values); - } - - void register_vec2(const std::string& name, float x, float y, float min, float max, - const unsigned int flags) - { - dvar_vector2 values; - values.x = x; - values.y = y; - values.min = min; - values.max = max; - values.flags = flags; - register_vector2_overrides[name] = std::move(values); - } - - void register_vec3(const std::string& name, float x, float y, float z, float min, - float max, const unsigned int flags) - { - dvar_vector3 values; - values.x = x; - values.y = y; - values.z = z; - values.min = min; - values.max = max; - values.flags = flags; - register_vector3_overrides[name] = std::move(values); - } - - void set_bool(const std::string& name, const bool value) - { - set_bool_overrides[name] = value; - } - - void set_float(const std::string& name, const float value) - { - set_float_overrides[name] = value; - } - - void set_int(const std::string& name, const int value) - { - set_int_overrides[name] = value; - } - - void set_string(const std::string& name, const std::string& value) - { - set_string_overrides[name] = value; - } - - void set_from_string(const std::string& name, const std::string& value) - { - set_from_string_overrides[name] = value; - } - } - - utils::hook::detour dvar_register_bool_hook; - utils::hook::detour dvar_register_float_hook; - utils::hook::detour dvar_register_int_hook; - utils::hook::detour dvar_register_string_hook; - utils::hook::detour dvar_register_vector2_hook; - utils::hook::detour dvar_register_vector3_hook; - - utils::hook::detour dvar_set_bool_hook; - utils::hook::detour dvar_set_float_hook; - utils::hook::detour dvar_set_int_hook; - utils::hook::detour dvar_set_string_hook; - utils::hook::detour dvar_set_from_string_hook; - - game::dvar_t* dvar_register_bool(const int hash, const char* name, bool value, unsigned int flags) - { - auto* var = find_dvar(override::register_bool_overrides, hash); - if (var) - { - value = var->value; - flags = var->flags; - } - - return dvar_register_bool_hook.invoke(hash, name, value, flags); - } - - game::dvar_t* dvar_register_float(const int hash, const char* name, float value, float min, float max, unsigned int flags) - { - auto* var = find_dvar(override::register_float_overrides, hash); - if (var) - { - value = var->value; - min = var->min; - max = var->max; - flags = var->flags; - } - - return dvar_register_float_hook.invoke(hash, name, value, min, max, flags); - } - - game::dvar_t* dvar_register_int(const int hash, const char* name, int value, int min, int max, unsigned int flags) - { - auto* var = find_dvar(override::register_int_overrides, hash); - if (var) - { - value = var->value; - min = var->min; - max = var->max; - flags = var->flags; - } - - return dvar_register_int_hook.invoke(hash, name, value, min, max, flags); - } - - game::dvar_t* dvar_register_string(const int hash, const char* name, const char* value, unsigned int flags) - { - auto* var = find_dvar(override::register_string_overrides, hash); - if (var) - { - value = var->value.data(); - flags = var->flags; - } - - return dvar_register_string_hook.invoke(hash, name, value, flags); - } - - game::dvar_t* dvar_register_vector2(const int hash, const char* name, float x, float y, float min, float max, - unsigned int flags) - { - auto* var = find_dvar(override::register_vector2_overrides, hash); - if (var) - { - x = var->x; - y = var->y; - min = var->min; - max = var->max; - flags = var->flags; - } - - return dvar_register_vector2_hook.invoke(hash, name, x, y, min, max, flags); - } - - game::dvar_t* dvar_register_vector3(const int hash, const char* name, float x, float y, float z, float min, - float max, unsigned int flags) - { - auto* var = find_dvar(override::register_vector3_overrides, hash); - if (var) - { - x = var->x; - y = var->y; - z = var->z; - min = var->min; - max = var->max; - flags = var->flags; - } - - return dvar_register_vector3_hook.invoke(hash, name, x, y, z, min, max, flags); - } - - void dvar_set_bool(game::dvar_t* dvar, bool boolean) - { - const auto disabled = find_dvar(disable::set_bool_disables, dvar->hash); - if (disabled) - { - return; - } - - auto* var = find_dvar(override::set_bool_overrides, dvar->hash); - if (var) - { - boolean = *var; - } - - return dvar_set_bool_hook.invoke(dvar, boolean); - } - - void dvar_set_float(game::dvar_t* dvar, float fl) - { - const auto disabled = find_dvar(disable::set_float_disables, dvar->hash); - if (disabled) - { - return; - } - - auto* var = find_dvar(override::set_float_overrides, dvar->hash); - if (var) - { - fl = *var; - } - - return dvar_set_float_hook.invoke(dvar, fl); - } - - void dvar_set_int(game::dvar_t* dvar, int integer) - { - const auto disabled = find_dvar(disable::set_int_disables, dvar->hash); - if (disabled) - { - return; - } - - auto* var = find_dvar(override::set_int_overrides, dvar->hash); - if (var) - { - integer = *var; - } - - return dvar_set_int_hook.invoke(dvar, integer); - } - - void dvar_set_string(game::dvar_t* dvar, const char* string) - { - const auto disabled = find_dvar(disable::set_string_disables, dvar->hash); - if (disabled) - { - return; - } - - auto* var = find_dvar(override::set_string_overrides, dvar->hash); - if (var) - { - string = var->data(); - } - - return dvar_set_string_hook.invoke(dvar, string); - } - - void dvar_set_from_string(game::dvar_t* dvar, const char* string, game::DvarSetSource source) - { - const auto disabled = find_dvar(disable::set_string_disables, dvar->hash); - if (disabled) - { - return; - } - - auto* var = find_dvar(override::set_from_string_overrides, dvar->hash); - if (var) - { - string = var->data(); - } - - return dvar_set_from_string_hook.invoke(dvar, string, source); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - dvar_register_bool_hook.create(SELECT_VALUE(0x1403C47E0, 0x1404FA540), &dvar_register_bool); - dvar_register_float_hook.create(SELECT_VALUE(0x1403C4BB0, 0x1404FA910), &dvar_register_float); - dvar_register_int_hook.create(SELECT_VALUE(0x1403C4CC0, 0x1404FAA20), &dvar_register_int); - dvar_register_string_hook.create(SELECT_VALUE(0x1403C4DA0, 0x1404FAB00), &dvar_register_string); - dvar_register_vector2_hook.create(SELECT_VALUE(0x1403C4E80, 0x1404FABE0), &dvar_register_vector2); - dvar_register_vector3_hook.create(SELECT_VALUE(0x1403C4FC0, 0x1404FACE0), &dvar_register_vector3); - - dvar_set_bool_hook.create(SELECT_VALUE(0x1403C7020, 0x1404FCDF0), &dvar_set_bool); - dvar_set_float_hook.create(SELECT_VALUE(0x1403C7420, 0x1404FD360), &dvar_set_float); - dvar_set_int_hook.create(SELECT_VALUE(0x1403C76C0, 0x1404FD5E0), &dvar_set_int); - dvar_set_string_hook.create(SELECT_VALUE(0x1403C7900, 0x1404FD8D0), &dvar_set_string); - dvar_set_from_string_hook.create(SELECT_VALUE(0x1403C7620, 0x1404FD520), &dvar_set_from_string); - } - }; -} - -REGISTER_COMPONENT(dvars::component) diff --git a/src/client/component/dvars.hpp b/src/client/component/dvars.hpp deleted file mode 100644 index 66d6912d..00000000 --- a/src/client/component/dvars.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -namespace dvars -{ - namespace disable - { - void set_bool(const std::string& name); - void set_float(const std::string& name); - void set_int(const std::string& name); - void set_string(const std::string& name); - } - - namespace override - { - void register_bool(const std::string& name, bool value, const unsigned int flags); - void register_float(const std::string& name, float value, float min, float max, const unsigned int flags); - void register_int(const std::string& name, int value, int min, int max, const unsigned int flags); - void register_string(const std::string& name, const std::string& value, const unsigned int flags); - void register_vec2(const std::string& name, float x, float y, float min, float max, const unsigned int flags); - void register_vec3(const std::string& name, float x, float y, float z, float min, float max, const unsigned int flags); - - void set_bool(const std::string& name, bool boolean); - void set_float(const std::string& name, float fl); - void set_int(const std::string& name, int integer); - void set_string(const std::string& name, const std::string& string); - void set_from_string(const std::string& name, const std::string& value); - } -} diff --git a/src/client/component/exception.cpp b/src/client/component/exception.cpp deleted file mode 100644 index 028bb238..00000000 --- a/src/client/component/exception.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "system_check.hpp" -#include "scheduler.hpp" - -#include "game/game.hpp" - -#include -#include -#include -#include -#include - -#include - -#include - -#include "game/dvars.hpp" - -namespace exception -{ - namespace - { - thread_local struct - { - DWORD code = 0; - PVOID address = nullptr; - } exception_data; - - struct - { - std::chrono::time_point last_recovery{}; - std::atomic recovery_counts = {0}; - } recovery_data; - - bool is_game_thread() - { - static std::vector allowed_threads = - { - game::THREAD_CONTEXT_MAIN, - }; - - const auto self_id = GetCurrentThreadId(); - for (const auto& index : allowed_threads) - { - if (game::threadIds[index] == self_id) - { - return true; - } - } - - return false; - } - - bool is_exception_interval_too_short() - { - const auto delta = std::chrono::high_resolution_clock::now() - recovery_data.last_recovery; - return delta < 1min; - } - - bool too_many_exceptions_occured() - { - return recovery_data.recovery_counts >= 3; - } - - volatile bool& is_initialized() - { - static volatile bool initialized = false; - return initialized; - } - - bool is_recoverable() - { - return is_initialized() - && is_game_thread() - && !is_exception_interval_too_short() - && !too_many_exceptions_occured(); - } - - void show_mouse_cursor() - { - while (ShowCursor(TRUE) < 0); - } - - void display_error_dialog() - { - std::string error_str = utils::string::va("Fatal error (0x%08X) at 0x%p.\n" - "A minidump has been written.\n\n", - exception_data.code, exception_data.address); - - if (!system_check::is_valid()) - { - error_str += "Make sure to get supported game files to avoid such crashes!"; - } - else - { - error_str += "Make sure to update your graphics card drivers and install operating system updates!"; - } - - utils::thread::suspend_other_threads(); - show_mouse_cursor(); - - MessageBoxA(nullptr, error_str.data(), "H1-Mod ERROR", MB_ICONERROR); - TerminateProcess(GetCurrentProcess(), exception_data.code); - } - - void reset_state() - { - if (dvars::cg_legacyCrashHandling && dvars::cg_legacyCrashHandling->current.enabled) - { - display_error_dialog(); - } - - // TODO: Add a limit for dedi restarts - if (game::environment::is_dedi()) - { - utils::nt::relaunch_self(); - utils::nt::terminate(exception_data.code); - } - - if (is_recoverable()) - { - recovery_data.last_recovery = std::chrono::high_resolution_clock::now(); - ++recovery_data.recovery_counts; - - game::Com_Error(game::ERR_DROP, "Fatal error (0x%08X) at 0x%p.\nA minidump has been written.\n\n" - "H1-Mod has tried to recover your game, but it might not run stable anymore.\n\n" - "Make sure to update your graphics card drivers and install operating system updates!\n" - "Closing or restarting Steam might also help.", - exception_data.code, exception_data.address); - } - else - { - display_error_dialog(); - } - } - - size_t get_reset_state_stub() - { - static auto* stub = utils::hook::assemble([](utils::hook::assembler& a) - { - a.sub(rsp, 0x10); - a.or_(rsp, 0x8); - a.jmp(reset_state); - }); - - return reinterpret_cast(stub); - } - - std::string get_timestamp() - { - tm ltime{}; - char timestamp[MAX_PATH] = {0}; - const auto time = _time64(nullptr); - - _localtime64_s(<ime, &time); - strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d-%H-%M-%S", <ime); - - return timestamp; - } - - std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo) - { - std::string info{}; - const auto line = [&info](const std::string& text) - { - info.append(text); - info.append("\r\n"); - }; - - line("H1-Mod Crash Dump"); - line(""); - line("Version: "s + VERSION); - line("Environment: "s + game::environment::get_string()); - line("Timestamp: "s + get_timestamp()); - line("Clean game: "s + (system_check::is_valid() ? "Yes" : "No")); - line(utils::string::va("Exception: 0x%08X", exceptioninfo->ExceptionRecord->ExceptionCode)); - line(utils::string::va("Address: 0x%llX", exceptioninfo->ExceptionRecord->ExceptionAddress)); - -#pragma warning(push) -#pragma warning(disable: 4996) - OSVERSIONINFOEXA version_info; - ZeroMemory(&version_info, sizeof(version_info)); - version_info.dwOSVersionInfoSize = sizeof(version_info); - GetVersionExA(reinterpret_cast(&version_info)); -#pragma warning(pop) - - line(utils::string::va("OS Version: %u.%u", version_info.dwMajorVersion, version_info.dwMinorVersion)); - - return info; - } - - void write_minidump(const LPEXCEPTION_POINTERS exceptioninfo) - { - const std::string crash_name = utils::string::va("minidumps/h1-mod-crash-%d-%s.zip", - game::environment::get_real_mode(), - get_timestamp().data()); - - utils::compression::zip::archive zip_file{}; - zip_file.add("crash.dmp", create_minidump(exceptioninfo)); - zip_file.add("info.txt", generate_crash_info(exceptioninfo)); - zip_file.write(crash_name, "H1-Mod Crash Dump"); - } - - bool is_harmless_error(const LPEXCEPTION_POINTERS exceptioninfo) - { - const auto code = exceptioninfo->ExceptionRecord->ExceptionCode; - return code == STATUS_INTEGER_OVERFLOW || code == STATUS_FLOAT_OVERFLOW || code == STATUS_SINGLE_STEP; - } - - LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS exceptioninfo) - { - if (is_harmless_error(exceptioninfo)) - { - return EXCEPTION_CONTINUE_EXECUTION; - } - - write_minidump(exceptioninfo); - - exception_data.code = exceptioninfo->ExceptionRecord->ExceptionCode; - exception_data.address = exceptioninfo->ExceptionRecord->ExceptionAddress; - exceptioninfo->ContextRecord->Rip = get_reset_state_stub(); - - return EXCEPTION_CONTINUE_EXECUTION; - } - - LPTOP_LEVEL_EXCEPTION_FILTER WINAPI set_unhandled_exception_filter_stub(LPTOP_LEVEL_EXCEPTION_FILTER) - { - // Don't register anything here... - return &exception_filter; - } - } - - class component final : public component_interface - { - public: - component() - { - SetUnhandledExceptionFilter(exception_filter); - } - - void post_load() override - { - SetUnhandledExceptionFilter(exception_filter); - utils::hook::jump(SetUnhandledExceptionFilter, set_unhandled_exception_filter_stub, true); - - scheduler::on_game_initialized([]() - { - is_initialized() = true; - }); - } - - void post_unpack() override - { - dvars::cg_legacyCrashHandling = dvars::register_bool("cg_legacyCrashHandling", - false, game::DVAR_FLAG_SAVED, true); - } - }; -} - -REGISTER_COMPONENT(exception::component) diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp deleted file mode 100644 index d4eda37f..00000000 --- a/src/client/component/fastfiles.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "fastfiles.hpp" - -#include "command.hpp" -#include "console.hpp" - -#include -#include - -namespace fastfiles -{ - static utils::concurrency::container current_fastfile; - - namespace - { - utils::hook::detour db_try_load_x_file_internal_hook; - - void db_try_load_x_file_internal(const char* zone_name, const int flags) - { - printf("Loading fastfile %s\n", zone_name); - current_fastfile.access([&](std::string& fastfile) - { - fastfile = zone_name; - }); - db_try_load_x_file_internal_hook.invoke(zone_name, flags); - } - } - - std::string get_current_fastfile() - { - return current_fastfile.access([&](std::string& fastfile) - { - return fastfile; - }); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - db_try_load_x_file_internal_hook.create( - SELECT_VALUE(0x1401CDDD0, 0x1402BFFE0), &db_try_load_x_file_internal); - } - }; -} - -REGISTER_COMPONENT(fastfiles::component) diff --git a/src/client/component/fastfiles.hpp b/src/client/component/fastfiles.hpp deleted file mode 100644 index ac26d2ec..00000000 --- a/src/client/component/fastfiles.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "game/game.hpp" - -namespace fastfiles -{ - std::string get_current_fastfile(); -} diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp deleted file mode 100644 index da11d2e4..00000000 --- a/src/client/component/filesystem.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "filesystem.hpp" -#include "game_module.hpp" - -#include "game/game.hpp" -#include "dvars.hpp" - -#include -#include - -namespace filesystem -{ - namespace - { - bool custom_path_registered = false; - - 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) - { - custom_path_registered = false; - game::FS_Startup(gamename); - } - } - - 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_; - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - // Set fs_basegame - dvars::override::register_string("fs_basegame", "h1-mod", game::DVAR_FLAG_WRITE); - - utils::hook::call(SELECT_VALUE(0x1403B76E2, 0x1404ED3E2), fs_startup_stub); - if (game::environment::is_mp()) - { - utils::hook::call(0x1404ED823, fs_startup_stub); - } - - utils::hook::call(SELECT_VALUE(0x1403B8D31, 0x1404EE3D0), register_custom_path_stub); - utils::hook::call(SELECT_VALUE(0x1403B8D51, 0x1404EE3F0), register_custom_path_stub); - utils::hook::call(SELECT_VALUE(0x1403B8D90, 0x1404EE42F), register_custom_path_stub); - } - }; -} - -REGISTER_COMPONENT(filesystem::component) \ No newline at end of file diff --git a/src/client/component/filesystem.hpp b/src/client/component/filesystem.hpp deleted file mode 100644 index 6cec8c87..00000000 --- a/src/client/component/filesystem.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -namespace filesystem -{ - class file - { - public: - file(std::string name); - - bool exists() const; - const std::string& get_buffer() const; - const std::string& get_name() const; - - private: - bool valid_ = false; - std::string name_; - std::string buffer_; - }; -} \ No newline at end of file diff --git a/src/client/component/fps.cpp b/src/client/component/fps.cpp deleted file mode 100644 index db471119..00000000 --- a/src/client/component/fps.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include - -namespace fps -{ - namespace - { - game::dvar_t* cg_drawfps; - game::dvar_t* cg_drawping; - - float fps_color_good[4] = {0.6f, 1.0f, 0.0f, 1.0f}; - float fps_color_ok[4] = {1.0f, 0.7f, 0.3f, 1.0f}; - float fps_color_bad[4] = {1.0f, 0.3f, 0.3f, 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{}; - - void perf_calc_fps(cg_perf_data* data, const std::int32_t value) - { - data->history[data->index % 32] = value; - data->instant = value; - data->min = 0x7FFFFFFF; - 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(0x1405487A0, 0x1406575A0)); // H1(1.4) - } - - void cg_draw_fps() - { - if (cg_drawfps->current.integer > 0) - { - const auto fps = static_cast(static_cast(1000.0f / static_cast(cg_perf. - average)) - + 9.313225746154785e-10); - - const auto font = game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25); - const auto fps_string = utils::string::va("%i", fps); - - const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 15.0f) - game::R_TextWidth( - fps_string, 0x7FFFFFFF, font); - const auto y = font->pixelHeight + 10.f; - - const auto fps_color = fps >= 60 ? fps_color_good : (fps >= 30 ? fps_color_ok : fps_color_bad); - game::R_AddCmdDrawText(fps_string, 0x7FFFFFFF, font, x, y, 1.f, 1.f, 0.0f, fps_color, 6); - } - } - - void cg_draw_ping() - { - if (cg_drawping->current.integer > 0 && game::CL_IsCgameInitialized() && !game::VirtualLobby_Loaded()) - { - const auto ping = *reinterpret_cast(0x142D106F0); - - const auto font = game::R_RegisterFont("fonts/consolefont", 20); - const auto ping_string = utils::string::va("Ping: %i", ping); - - const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 375.0f) - game::R_TextWidth( - ping_string, 0x7FFFFFFF, font); - - const auto y = font->pixelHeight + 15.f; - game::R_AddCmdDrawText(ping_string, 0x7FFFFFFF, font, x, y, 1.f, 1.f, 0.0f, ping_color, 6); - } - } - - game::dvar_t* cg_draw_fps_register_stub(const char* name, const char** _enum, const int value, unsigned int /*flags*/, - const char* desc) - { - cg_drawfps = dvars::register_int("cg_drawFps", 0, 0, 2, game::DVAR_FLAG_SAVED, false); - 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(0x14018D261, 0x14025B747), &perf_update); - - // change cg_drawfps flags to saved - utils::hook::call(SELECT_VALUE(0x140139F48, 0x140222A46), &cg_draw_fps_register_stub); - - scheduler::loop(cg_draw_fps, scheduler::pipeline::renderer); - - if (game::environment::is_sp()) - { - cg_drawfps = dvars::register_int("cg_drawFps", 0, 0, 2, game::DVAR_FLAG_SAVED, false); - } - - if (game::environment::is_mp()) - { - // fix ping value - utils::hook::nop(0x14025AC41, 2); - - cg_drawping = dvars::register_int("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, true); - - 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 deleted file mode 100644 index cf7c3056..00000000 --- a/src/client/component/game_console.cpp +++ /dev/null @@ -1,793 +0,0 @@ -#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 "version.hpp" - -#define console_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 18) -#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_title[4] = {0.25f, 0.62f, 0.3f, 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.0f, - 1.0f, 0.0f, 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); - } - - 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 (const auto& dvar : dvars::dvar_list) - { - auto name = utils::string::to_lower(dvar); - if (game::Dvar_FindVar(name.data()) && match_compare(input, name, exact)) - { - suggestions.push_back(dvar); - } - - if (exact && suggestions.size() > 1) - { - return; - } - } - - if (suggestions.size() == 0 && game::Dvar_FindVar(input.data())) - { - suggestions.push_back(input.data()); - } - - 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; - } - } - - 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("H1-Mod: " VERSION ">", color_title); - - con.globals.left_x = con.globals.x; - con.globals.auto_complete_choice[0] = 0; - - game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, 18, con.globals.x, - con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0, 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) - { - auto* const 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(), 64); - 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++) - { - auto* const 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(), 64); - 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("H1-Mod 1.4", 0x7FFFFFFF, console_font, x, - ((height - 16.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_title, 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 local_client_num, const int key) - { - if (key == game::keyNum_t::K_GRAVE || - key == game::keyNum_t::K_TILDE || - key == '|' || - key == '\\') - { - return false; - } - - if (key > 127) - { - return true; - } - - if (*game::keyCatchers & 1) - { - if (key == game::keyNum_t::K_TAB) // tab (auto complete) - { - if (con.globals.may_auto_complete) - { - const auto first_char = con.buffer[0]; - - clear(); - - if (first_char == '\\' || first_char == '/') - { - con.buffer[0] = first_char; - 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 (size_t i = 0; i < clipboard.length(); i++) - { - console_char_event(local_client_num, 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 local_client_num, const int key, const int down) - { - if (key == game::keyNum_t::K_F10) - { - if (!game::Com_InFrontEnd()) - { - return false; - } - - game::Cmd_ExecuteSingleCommand(local_client_num, 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[local_client_num].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(), 0x100); - 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(), 0x100); - 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; - } - - - 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 - { - scheduler::loop(draw_console, scheduler::pipeline::renderer); - - - 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, "", 256); - - 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, "", 64); - - // 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 = dvars::register_vec4("con_inputBoxColor", 0.2f, 0.2f, 0.2f, 0.9f, 0.0f, 1.0f, - game::DVAR_FLAG_SAVED, - "color of console input box"); - dvars::con_inputHintBoxColor = dvars::register_vec4("con_inputHintBoxColor", 0.3f, 0.3f, 0.3f, 1.0f, - 0.0f, 1.0f, - game::DVAR_FLAG_SAVED, "color of console input hint box"); - dvars::con_outputBarColor = dvars::register_vec4("con_outputBarColor", 0.5f, 0.5f, 0.5f, 0.6f, 0.0f, - 1.0f, game::DVAR_FLAG_SAVED, - "color of console output bar"); - dvars::con_outputSliderColor = dvars::register_vec4("con_outputSliderColor", 1.0f, 0.8f, 0.0f, 1.0f, - 0.0f, 1.0f, - game::DVAR_FLAG_SAVED, "color of console output slider"); - dvars::con_outputWindowColor = dvars::register_vec4("con_outputWindowColor", 0.25f, 0.25f, 0.25f, 0.85f, - 0.0f, - 1.0f, game::DVAR_FLAG_SAVED, "color of console output window"); - dvars::con_inputDvarMatchColor = dvars::register_vec4("con_inputDvarMatchColor", 1.0f, 1.0f, 0.8f, 1.0f, - 0.0f, - 1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar"); - dvars::con_inputDvarValueColor = dvars::register_vec4("con_inputDvarValueColor", 1.0f, 1.0f, 0.8f, 1.0f, - 0.0f, - 1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar value"); - dvars::con_inputDvarInactiveValueColor = dvars::register_vec4( - "con_inputDvarInactiveValueColor", 0.8f, 0.8f, - 0.8f, 1.0f, 0.0f, 1.0f, game::DVAR_FLAG_SAVED, - "color of console inactive dvar value"); - dvars::con_inputCmdMatchColor = dvars::register_vec4("con_inputCmdMatchColor", 0.80f, 0.80f, 1.0f, 1.0f, - 0.0f, - 1.0f, game::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 deleted file mode 100644 index cdc001a7..00000000 --- a/src/client/component/game_console.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace game_console -{ - bool console_char_event(int local_client_num, int key); - bool console_key_event(int local_client_num, int key, int down); -} \ No newline at end of file diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp index bd984624..9bc79de0 100644 --- a/src/client/component/game_module.cpp +++ b/src/client/component/game_module.cpp @@ -1,6 +1,7 @@ #include #include "loader/component_loader.hpp" #include "game_module.hpp" +#include "game/game.hpp" #include @@ -90,7 +91,7 @@ namespace game_module utils::nt::library get_game_module() { - static utils::nt::library game{HMODULE(0x140000000)}; + static utils::nt::library game{HMODULE(game::base_address)}; return game; } diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp deleted file mode 100644 index 55b41d65..00000000 --- a/src/client/component/localized_strings.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "localized_strings.hpp" -#include -#include -#include -#include "game/game.hpp" - -namespace localized_strings -{ - namespace - { - utils::hook::detour seh_string_ed_get_string_hook; - - using localized_map = std::unordered_map; - utils::concurrency::container localized_overrides; - - const char* seh_string_ed_get_string(const char* reference) - { - return localized_overrides.access([&](const localized_map& map) - { - const auto entry = map.find(reference); - if (entry != map.end()) - { - return utils::string::va("%s", entry->second.data()); - } - - return seh_string_ed_get_string_hook.invoke(reference); - }); - } - } - - void override(const std::string& key, const std::string& value) - { - localized_overrides.access([&](localized_map& map) - { - map[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(0, 0x585DA0_b), &seh_string_ed_get_string); // H1-STEAM(1.15) - } - }; -} - -REGISTER_COMPONENT(localized_strings::component) diff --git a/src/client/component/localized_strings.hpp b/src/client/component/localized_strings.hpp deleted file mode 100644 index 01d15907..00000000 --- a/src/client/component/localized_strings.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace localized_strings -{ - void override(const std::string& key, const std::string& value); -} \ No newline at end of file diff --git a/src/client/component/logfile.cpp b/src/client/component/logfile.cpp deleted file mode 100644 index fc949d92..00000000 --- a/src/client/component/logfile.cpp +++ /dev/null @@ -1,317 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "scheduler.hpp" - -#include "game/scripting/entity.hpp" -#include "game/scripting/execution.hpp" -#include "game/scripting/lua/value_conversion.hpp" -#include "game/scripting/lua/error.hpp" - -#include - -#include "logfile.hpp" - -namespace logfile -{ - std::unordered_map vm_execute_hooks; - - namespace - { - utils::hook::detour scr_player_killed_hook; - utils::hook::detour scr_player_damage_hook; - - std::vector player_killed_callbacks; - std::vector player_damage_callbacks; - - utils::hook::detour vm_execute_hook; - char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END - bool hook_enabled = true; - - sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent) - { - if (!ent) - { - return {}; - } - - const scripting::entity player{game::Scr_GetEntityId(ent->s.entityNum, 0)}; - return scripting::lua::convert(state, player); - } - - std::string get_weapon_name(unsigned int weapon, bool isAlternate) - { - char output[1024] = {0}; - game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024); - return output; - } - - sol::lua_value convert_vector(lua_State* state, const float* vec) - { - if (!vec) - { - return {}; - } - - const auto vec_ = scripting::vector(vec); - return scripting::lua::convert(state, vec_); - } - - std::string convert_mod(const int meansOfDeath) - { - const auto value = reinterpret_cast(0x140FEC3F0)[meansOfDeath]; - const auto string = game::SL_ConvertToString(*value); - return string; - } - - void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, - game::mp::gentity_s* attacker, int damage, const int meansOfDeath, const unsigned int weapon, - const bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration) - { - { - const std::string hitloc = reinterpret_cast(0x140FEC4D0)[hitLoc]; - const auto mod_ = convert_mod(meansOfDeath); - - const auto weapon_ = get_weapon_name(weapon, isAlternate); - - for (const auto& callback : player_killed_callbacks) - { - const auto state = callback.lua_state(); - - const auto self_ = convert_entity(state, self); - const auto inflictor_ = convert_entity(state, inflictor); - const auto attacker_ = convert_entity(state, attacker); - - const auto dir = convert_vector(state, vDir); - - const auto result = callback(self_, inflictor_, attacker_, damage, - mod_, weapon_, dir, hitloc, psTimeOffset, deathAnimDuration); - - scripting::lua::handle_error(result); - - if (result.valid() && result.get_type() == sol::type::number) - { - damage = result.get(); - } - } - - if (damage == 0) - { - return; - } - } - - scr_player_killed_hook.invoke(self, inflictor, attacker, damage, meansOfDeath, - weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration); - } - - void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, - game::mp::gentity_s* attacker, int damage, int dflags, const int meansOfDeath, - const unsigned int weapon, const bool isAlternate, const float* vPoint, - const float* vDir, const unsigned int hitLoc, const int timeOffset) - { - { - const std::string hitloc = reinterpret_cast(0x140FEC4D0)[hitLoc]; - const auto mod_ = convert_mod(meansOfDeath); - - const auto weapon_ = get_weapon_name(weapon, isAlternate); - - for (const auto& callback : player_damage_callbacks) - { - const auto state = callback.lua_state(); - - const auto self_ = convert_entity(state, self); - const auto inflictor_ = convert_entity(state, inflictor); - const auto attacker_ = convert_entity(state, attacker); - - const auto point = convert_vector(state, vPoint); - const auto dir = convert_vector(state, vDir); - - const auto result = callback(self_, inflictor_, attacker_, - damage, dflags, mod_, weapon_, point, dir, hitloc); - - scripting::lua::handle_error(result); - - if (result.valid() && result.get_type() == sol::type::number) - { - damage = result.get(); - } - } - - if (damage == 0) - { - return; - } - } - - scr_player_damage_hook.invoke(self, inflictor, attacker, damage, dflags, - meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset); - } - - void client_command_stub(const int clientNum) - { - auto self = &game::mp::g_entities[clientNum]; - char cmd[1024] = {0}; - - game::SV_Cmd_ArgvBuffer(0, cmd, 1024); - - if (cmd == "say"s || cmd == "say_team"s) - { - auto hidden = false; - std::string message(game::ConcatArgs(1)); - - hidden = message[1] == '/'; - message.erase(0, hidden ? 2 : 1); - - scheduler::once([cmd, message, self]() - { - const scripting::entity level{*game::levelEntityId}; - const scripting::entity player{game::Scr_GetEntityId(self->s.entityNum, 0)}; - - scripting::notify(level, cmd, {player, message}); - scripting::notify(player, cmd, {message}); - }, scheduler::pipeline::server); - - if (hidden) - { - return; - } - } - - // ClientCommand - return utils::hook::invoke(0x140336000, clientNum); - } - - void g_shutdown_game_stub(const int freeScripts) - { - { - const scripting::entity level{*game::levelEntityId}; - scripting::notify(level, "shutdownGame_called", {1}); - } - - // G_ShutdownGame - return utils::hook::invoke(0x140345A60, freeScripts); - } - - unsigned int local_id_to_entity(unsigned int local_id) - { - const auto variable = game::scr_VarGlob->objectVariableValue[local_id]; - return variable.u.f.next; - } - - bool execute_vm_hook(const char* pos) - { - if (vm_execute_hooks.find(pos) == vm_execute_hooks.end()) - { - 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]; - const auto state = hook.lua_state(); - - const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId); - - std::vector args; - - const auto top = game::scr_function_stack->top; - - for (auto* value = top; value->type != game::SCRIPT_END; --value) - { - args.push_back(scripting::lua::convert(state, *value)); - } - - const auto result = hook(self, sol::as_args(args)); - scripting::lua::handle_error(result); - - 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.mov(dword_ptr(rbp, 0xA4), r15d); - - a.jmp(SELECT_VALUE(0x140376663, 0x140444653)); - - a.bind(replace); - - a.popad64(); - a.mov(r14, reinterpret_cast(empty_function)); - a.jmp(end); - } - } - - void add_player_damage_callback(const sol::protected_function& callback) - { - player_damage_callbacks.push_back(callback); - } - - void add_player_killed_callback(const sol::protected_function& callback) - { - player_killed_callbacks.push_back(callback); - } - - void clear_callbacks() - { - player_damage_callbacks.clear(); - player_killed_callbacks.clear(); - vm_execute_hooks.clear(); - } - - void enable_vm_execute_hook() - { - hook_enabled = true; - } - - void disable_vm_execute_hook() - { - hook_enabled = false; - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - utils::hook::call(0x14048191D, client_command_stub); - - scr_player_damage_hook.create(0x14037DC50, scr_player_damage_stub); - scr_player_killed_hook.create(0x14037DF30, scr_player_killed_stub); - - utils::hook::call(0x140484EC0, g_shutdown_game_stub); - utils::hook::call(0x1404853C1, g_shutdown_game_stub); - - utils::hook::jump(SELECT_VALUE(0x140376655, 0x140444645), utils::hook::assemble(vm_execute_stub), true); - } - }; -} - -REGISTER_COMPONENT(logfile::component) \ No newline at end of file diff --git a/src/client/component/logfile.hpp b/src/client/component/logfile.hpp deleted file mode 100644 index 77f699c8..00000000 --- a/src/client/component/logfile.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace logfile -{ - extern std::unordered_map vm_execute_hooks; - - void add_player_damage_callback(const sol::protected_function& callback); - void add_player_killed_callback(const sol::protected_function& callback); - void clear_callbacks(); - - void enable_vm_execute_hook(); - void disable_vm_execute_hook(); -} \ No newline at end of file diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp deleted file mode 100644 index d3a7edca..00000000 --- a/src/client/component/lui.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" - -#include "command.hpp" -#include "console.hpp" - -#include - -namespace lui -{ - class component final : public component_interface - { - public: - void post_unpack() override - { - // Don't show create cod account popup - //utils::hook::set(0x14017C957, 0); // H1(1.4) - -//#ifdef _DEBUG - // Enable development menus (causes issues in sp) - //utils::hook::set(SELECT_VALUE(0x1400B4ABC, 0x1401AB779), 1); -//#endif - - 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], 0, 0, 0); - }); - - command::add("lui_open_popup", [](const command::params& params) - { - if (params.size() <= 1) - { - console::info("usage: lui_open_popup \n"); - return; - } - - game::LUI_OpenMenu(0, params[1], 1, 0, 0); - }); - - command::add("runMenuScript", [](const command::params& params) - { - const auto args_str = params.join(1); - const auto* args = args_str.data(); - game::UI_RunMenuScript(0, &args); - }); - } - }; -} - -REGISTER_COMPONENT(lui::component) diff --git a/src/client/component/map_rotation.cpp b/src/client/component/map_rotation.cpp deleted file mode 100644 index 216cbfcd..00000000 --- a/src/client/component/map_rotation.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "command.hpp" -#include "scheduler.hpp" -#include -#include -#include "game/game.hpp" -#include - -namespace map_rotation -{ - DWORD previousPriority; - namespace - { - void set_dvar(const std::string& dvar, const std::string& value) - { - command::execute(utils::string::va("%s \"%s\"", dvar.data(), value.data()), true); - } - - void set_gametype(const std::string& gametype) - { - set_dvar("g_gametype", gametype); - } - - void launch_map(const std::string& mapname) - { - 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 && strlen(mapname->current.string) && mapname->current.string != - "mp_vlobby_room"s) - { - launch_map(mapname->current.string); - } - else - { - launch_map("mp_crash"); - } - } - - std::string load_current_map_rotation() - { - auto* rotation = game::Dvar_FindVar("sv_mapRotationCurrent"); - if (!strlen(rotation->current.string)) - { - rotation = game::Dvar_FindVar("sv_mapRotation"); - set_dvar("sv_mapRotationCurrent", rotation->current.string); - } - - return rotation->current.string; - } - - std::vector parse_current_map_rotation() - { - const auto rotation = load_current_map_rotation(); - return utils::string::split(rotation, ' '); - } - - void store_new_rotation(const std::vector& elements, const size_t index) - { - std::string value{}; - - for (auto i = index; i < elements.size(); ++i) - { - if (i != index) - { - value.push_back(' '); - } - - value.append(elements[i]); - } - - set_dvar("sv_mapRotationCurrent", value); - } - - void change_process_priority() - { - auto* const dvar = game::Dvar_FindVar("sv_autoPriority"); - if (dvar && dvar->current.enabled) - { - scheduler::on_game_initialized([]() - { - //printf("=======================setting OLD priority=======================\n"); - SetPriorityClass(GetCurrentProcess(), previousPriority); - }, scheduler::pipeline::main, 1s); - - previousPriority = GetPriorityClass(GetCurrentProcess()); - //printf("=======================setting NEW priority=======================\n"); - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - } - } - - void perform_map_rotation() - { - if (game::Live_SyncOnlineDataFlags(0) != 0) - { - scheduler::on_game_initialized(perform_map_rotation, scheduler::pipeline::main, 1s); - return; - } - - const auto rotation = parse_current_map_rotation(); - - for (size_t i = 0; !rotation.empty() && i < (rotation.size() - 1); i += 2) - { - const auto& key = rotation[i]; - const auto& value = rotation[i + 1]; - - if (key == "gametype") - { - set_gametype(value); - } - else if (key == "map") - { - store_new_rotation(rotation, i + 2); - change_process_priority(); - if (!game::SV_MapExists(value.data())) - { - printf("map_rotation: '%s' map doesn't exist!\n", value.data()); - launch_default_map(); - return; - } - launch_map(value); - return; - } - else - { - printf("Invalid map rotation key: %s\n", key.data()); - } - } - - launch_default_map(); - } - - 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); - } - - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_dedi()) - { - return; - } - - scheduler::once([]() - { - dvars::register_string("sv_mapRotation", "", game::DVAR_FLAG_NONE, true); - dvars::register_string("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, true); - dvars::register_string("sv_autoPriority", "", game::DVAR_FLAG_NONE, true); - }, scheduler::pipeline::main); - - command::add("map_rotate", &perform_map_rotation); - - // Hook GScr_ExitLevel - utils::hook::jump(0x140376630, &trigger_map_rotation); // not sure if working - - previousPriority = GetPriorityClass(GetCurrentProcess()); - } - }; -} - -REGISTER_COMPONENT(map_rotation::component) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index fb2a6f55..8069d61a 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -27,15 +27,8 @@ namespace network const auto cmd_string = utils::string::to_lower(command); auto& callbacks = get_callbacks(); const auto handler = callbacks.find(cmd_string); - - if (handler == callbacks.end()) - { - return false; - } - const auto offset = cmd_string.size() + 5; - - if (message->cursize <= offset) + if (message->cursize < offset || handler == callbacks.end()) { return false; } @@ -331,4 +324,4 @@ namespace network }; } -REGISTER_COMPONENT(network::component) +REGISTER_COMPONENT(network::component) \ No newline at end of file diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp deleted file mode 100644 index 0605afad..00000000 --- a/src/client/component/party.cpp +++ /dev/null @@ -1,630 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "party.hpp" -#include "console.hpp" -#include "command.hpp" -#include "network.hpp" -#include "scheduler.hpp" -#include "server_list.hpp" - -#include "steam/steam.hpp" - -#include -#include -#include -#include - -namespace party -{ - namespace - { - struct - { - game::netadr_s host{}; - std::string challenge{}; - bool hostDefined{false}; - } connect_state; - - std::string sv_motd; - int sv_maxclients; - - void perform_game_initialization() - { - command::execute("onlinegame 1", true); - command::execute("xstartprivateparty", true); - command::execute("xblive_privatematch 1", true); - command::execute("startentitlements", true); - } - - 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) != 0) - { - // initialize the game after onlinedataflags is 32 (workaround) - if (game::Live_SyncOnlineDataFlags(0) == 32) - { - scheduler::once([=]() - { - command::execute("xstartprivateparty", true); - command::execute("disconnect", true); // 32 -> 0 - - connect_to_party(target, mapname, gametype); - }, scheduler::pipeline::main, 1s); - return; - } - else - { - scheduler::once([=]() - { - connect_to_party(target, mapname, gametype); - }, scheduler::pipeline::main, 1s); - return; - } - } - - perform_game_initialization(); - - // exit from virtuallobby - utils::hook::invoke(0x140256D40, 1); - - // CL_ConnectFromParty - char session_info[0x100] = {}; - utils::hook::invoke(0x140251560, 0, session_info, &target, mapname.data(), gametype.data()); - } - - std::string get_dvar_string(const std::string& dvar) - { - auto* dvar_value = game::Dvar_FindVar(dvar.data()); - if (dvar_value && dvar_value->current.string) - { - return dvar_value->current.string; - } - - return {}; - } - - int get_dvar_int(const std::string& dvar) - { - auto* dvar_value = game::Dvar_FindVar(dvar.data()); - if (dvar_value && dvar_value->current.integer) - { - return dvar_value->current.integer; - } - - return -1; - } - - bool get_dvar_bool(const std::string& dvar) - { - auto* dvar_value = game::Dvar_FindVar(dvar.data()); - if (dvar_value && dvar_value->current.enabled) - { - return dvar_value->current.enabled; - } - - return false; - } - - void didyouknow_stub(const char* dvar_name, const char* string) - { - if (!party::sv_motd.empty()) - { - string = party::sv_motd.data(); - } - - // This function either does Dvar_SetString or Dvar_RegisterString for the given dvar - utils::hook::invoke(0x1404FB210, dvar_name, string); - } - - void disconnect_stub() - { - if (!game::VirtualLobby_Loaded()) - { - if (game::CL_IsCgameInitialized()) - { - // CL_ForwardCommandToServer - utils::hook::invoke(0x140253480, 0, "disconnect"); - // CL_WritePacket - utils::hook::invoke(0x14024DB10, 0); - } - // CL_Disconnect - utils::hook::invoke(0x140252060, 0); - } - } - - utils::hook::detour cldisconnect_hook; - - void cl_disconnect_stub(int a1) - { - party::sv_motd.clear(); - cldisconnect_hook.invoke(a1); - } - - const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a) - { - a.mov(rdx, rdi); - a.mov(ecx, 2); - a.jmp(0x140251F78); - }); - - void menu_error(const std::string& error) - { - utils::hook::invoke(0x1400DACC0, error.data(), "MENU_NOTICE"); - utils::hook::set(0x142C1DA98, 1); - } - } - - int get_client_num_by_name(const std::string& name) - { - for (auto i = 0; !name.empty() && i < *game::mp::svs_numclients; ++i) - { - if (game::mp::g_entities[i].client) - { - char client_name[16] = {0}; - strncpy_s(client_name, game::mp::g_entities[i].client->name, sizeof(client_name)); - game::I_CleanStr(client_name); - - if (client_name == name) - { - return i; - } - } - } - return -1; - } - - void reset_connect_state() - { - connect_state = {}; - } - - int get_client_count() - { - auto count = 0; - for (auto i = 0; i < *game::mp::svs_numclients; ++i) - { - if (game::mp::svs_clients[i].header.state >= 1) - { - ++count; - } - } - - return count; - } - - int get_bot_count() - { - auto count = 0; - for (auto i = 0; i < *game::mp::svs_numclients; ++i) - { - if (game::mp::svs_clients[i].header.state >= 1 && - game::SV_BotIsBot(i)) - { - ++count; - } - } - - return count; - } - - void connect(const game::netadr_s& target) - { - if (game::environment::is_sp()) - { - return; - } - - command::execute("lui_open_popup 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 start_map(const std::string& mapname) - { - if (game::Live_SyncOnlineDataFlags(0) > 32) - { - scheduler::once([=]() - { - command::execute("map " + mapname, false); - }, scheduler::pipeline::main, 1s); - } - else - { - if (!game::SV_MapExists(mapname.data())) - { - console::info("Map '%s' doesn't exist.\n", mapname.data()); - return; - } - - auto* current_mapname = game::Dvar_FindVar("mapname"); - if (current_mapname && utils::string::to_lower(current_mapname->current.string) == - utils::string::to_lower(mapname) && (game::SV_Loaded() && !game::VirtualLobby_Loaded())) - { - console::info("Restarting map: %s\n", mapname.data()); - command::execute("map_restart", false); - return; - } - - if (!game::environment::is_dedi()) - { - if (game::SV_Loaded()) - { - const auto* args = "Leave"; - game::UI_RunMenuScript(0, &args); - } - - perform_game_initialization(); - } - - console::info("Starting map: %s\n", mapname.data()); - - auto* gametype = game::Dvar_FindVar("g_gametype"); - if (gametype && gametype->current.string) - { - command::execute(utils::string::va("ui_gametype %s", gametype->current.string), true); - } - command::execute(utils::string::va("ui_mapname %s", mapname.data()), true); - - /*auto* maxclients = game::Dvar_FindVar("sv_maxclients"); - if (maxclients) - { - command::execute(utils::string::va("ui_maxclients %i", maxclients->current.integer), true); - command::execute(utils::string::va("party_maxplayers %i", maxclients->current.integer), true); - }*/ - - const auto* args = "StartServer"; - game::UI_RunMenuScript(0, &args); - } - } - - int server_client_count() - { - return party::sv_maxclients; - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - // hook disconnect command function - utils::hook::jump(0x1402521C7, disconnect_stub); - - // detour CL_Disconnect to clear motd - cldisconnect_hook.create(0x140252060, cl_disconnect_stub); - - if (game::environment::is_mp()) - { - // show custom drop reason - utils::hook::nop(0x140251EFB, 13); - utils::hook::jump(0x140251EFB, drop_reason_stub, true); - } - - // enable custom kick reason in GScr_KickPlayer - utils::hook::set(0x140376A1D, 0xEB); - - command::add("map", [](const command::params& argument) - { - if (argument.size() != 2) - { - return; - } - - start_map(argument[1]); - }); - - command::add("map_restart", []() - { - if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) - { - return; - } - *reinterpret_cast(0x14A3A91D0) = 1; // sv_map_restart - *reinterpret_cast(0x14A3A91D4) = 1; // sv_loadScripts - *reinterpret_cast(0x14A3A91D8) = 0; // sv_migrate - - utils::hook::invoke(0x14047E7F0); // SV_CheckLoadGame - }); - - command::add("fast_restart", []() - { - if (game::SV_Loaded() && !game::VirtualLobby_Loaded()) - { - game::SV_FastRestart(0); - } - }); - - command::add("reconnect", [](const command::params& argument) - { - 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& argument) - { - if (argument.size() != 2) - { - return; - } - - game::netadr_s target{}; - if (game::NET_StringToAdr(argument[1], &target)) - { - connect(target); - } - }); - - command::add("kickClient", [](const command::params& params) - { - if (params.size() < 2) - { - console::info("usage: kickClient , (optional)\n"); - return; - } - - if (!game::SV_Loaded() || game::VirtualLobby_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_numclients) - { - 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() || game::VirtualLobby_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_numclients; ++i) - { - scheduler::once([i, reason]() - { - game::SV_KickClientNum(i, reason.data()); - }, scheduler::pipeline::server); - } - return; - } - - const auto client_num = get_client_num_by_name(name); - if (client_num < 0 || client_num >= *game::mp::svs_numclients) - { - return; - } - - scheduler::once([client_num, reason]() - { - game::SV_KickClientNum(client_num, reason.data()); - }, scheduler::pipeline::server); - }); - - scheduler::once([]() - { - const auto hash = game::generateHashValue("sv_sayName"); - game::Dvar_RegisterString(hash, "sv_sayName", "console", game::DvarFlags::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, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s: %s\"", 84, name, message.data())); - printf("%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, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s\"", 84, message.data())); - printf("%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, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); - printf("%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, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s\"", 84, message.data())); - printf("%s\n", message.data()); - }); - - utils::hook::call(0x1404C6E8D, didyouknow_stub); // allow custom didyouknow based on sv_motd - - network::on("getInfo", [](const game::netadr_s& target, const std::string_view& data) - { - utils::info_string info{}; - info.set("challenge", std::string{data}); - info.set("gamename", "H1"); - info.set("hostname", get_dvar_string("sv_hostname")); - info.set("gametype", get_dvar_string("g_gametype")); - info.set("sv_motd", get_dvar_string("sv_motd")); - info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); - info.set("mapname", get_dvar_string("mapname")); - info.set("isPrivate", get_dvar_string("g_password").empty() ? "0" : "1"); - info.set("clients", utils::string::va("%i", get_client_count())); - info.set("bots", utils::string::va("%i", get_bot_count())); - info.set("sv_maxclients", utils::string::va("%i", *game::mp::svs_numclients)); - info.set("protocol", utils::string::va("%i", PROTOCOL)); - info.set("playmode", utils::string::va("%i", game::Com_GetCurrentCoDPlayMode())); - info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running") && !game::VirtualLobby_Loaded())); - info.set("dedicated", utils::string::va("%i", get_dvar_bool("dedicated"))); - - network::send(target, "infoResponse", info.build(), '\n'); - }); - - network::on("infoResponse", [](const game::netadr_s& target, const std::string_view& 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) - { - const auto str = "Invalid challenge."; - printf("%s\n", str); - menu_error(str); - return; - } - - const auto gamename = info.get("gamename"); - if (gamename != "H1"s) - { - const auto str = "Invalid gamename."; - printf("%s\n", str); - menu_error(str); - return; - } - - const auto playmode = info.get("playmode"); - if (game::CodPlayMode(std::atoi(playmode.data())) != game::Com_GetCurrentCoDPlayMode()) - { - const auto str = "Invalid playmode."; - printf("%s\n", str); - menu_error(str); - return; - } - - const auto sv_running = info.get("sv_running"); - if (!std::atoi(sv_running.data())) - { - const auto str = "Server not running."; - printf("%s\n", str); - menu_error(str); - return; - } - - const auto mapname = info.get("mapname"); - if (mapname.empty()) - { - const auto str = "Invalid map."; - printf("%s\n", str); - menu_error(str); - return; - } - - const auto gametype = info.get("gametype"); - if (gametype.empty()) - { - const auto str = "Invalid gametype."; - printf("%s\n", str); - menu_error(str); - return; - } - - party::sv_motd = info.get("sv_motd"); - party::sv_maxclients = std::stoi(info.get("sv_maxclients")); - - connect_to_party(target, mapname, gametype); - }); - } - }; -} - -REGISTER_COMPONENT(party::component) \ No newline at end of file diff --git a/src/client/component/party.hpp b/src/client/component/party.hpp deleted file mode 100644 index cd90ae9f..00000000 --- a/src/client/component/party.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace party -{ - void reset_connect_state(); - - void connect(const game::netadr_s& target); - void start_map(const std::string& mapname); - - int server_client_count(); - - int get_client_num_by_name(const std::string& name); - - int get_client_count(); - int get_bot_count(); -} \ No newline at end of file diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp deleted file mode 100644 index e9aaf21a..00000000 --- a/src/client/component/patches.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "dvars.hpp" -#include "version.h" -#include "command.hpp" -#include "console.hpp" -#include "network.hpp" -#include "scheduler.hpp" -#include "filesystem.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include - -namespace patches -{ - namespace - { - 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 client_num, 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(client_num, 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 - dvars::register_string("name", get_login_username().data(), game::DVAR_FLAG_SAVED, true); - - // Disable data validation error popup - dvars::register_int("data_validation_allow_drop", 0, 0, 0, game::DVAR_FLAG_NONE, true); - } - - return com_register_dvars_hook.invoke(); - } - - int is_item_unlocked() - { - return 0; // 0 == yes - } - - void set_client_dvar_from_server_stub(void* a1, void* a2, const char* dvar, const char* value) - { - if (dvar == "cg_fov"s) - { - return; - } - - // CG_SetClientDvarFromServer - utils::hook::invoke(0x140236120, a1, a2, dvar, value); - } - - const char* db_read_raw_file_stub(const char* filename, char* buf, const int size) - { - std::string file_name = filename; - if (file_name.find(".cfg") == std::string::npos) - { - file_name.append(".cfg"); - } - - const auto file = filesystem::file(file_name); - if (file.exists()) - { - snprintf(buf, size, "%s\n", file.get_buffer().data()); - return buf; - } - - // DB_ReadRawFile - return utils::hook::invoke(SELECT_VALUE(0x1401CD4F0, 0x1402BEF10), filename, buf, size); - } - - 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.entityNum]; - - // 22 => "end_game" - if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK) - { - return; - } - - cmd_lui_notify_server_hook.invoke(ent); - } - - void sv_execute_client_message_stub(game::mp::client_t* client, game::msg_t* msg) - { - if (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); - network::send(client->header.remoteAddress, "error", "EXE_LOSTRELIABLECOMMANDS", '\n'); - return; - } - - utils::hook::invoke(0x140481A00, client, msg); - } - - void aim_assist_add_to_target_list(void* a1, void* a2) - { - if (!dvars::aimassist_enabled->current.enabled) - return; - - game::AimAssist_AddToTargetList(a1, a2); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - // Register dvars - com_register_dvars_hook.create(SELECT_VALUE(0x140351B80, 0x1400D9320), &com_register_dvars_stub); // H1(1.4) - - // Unlock fps in main menu - utils::hook::set(SELECT_VALUE(0x14018D47B, 0x14025B86B), 0xEB); // H1(1.4) - - if (!game::environment::is_dedi()) - { - // Fix mouse lag - utils::hook::nop(SELECT_VALUE(0x1403E3C05, 0x1404DB1AF), 6); - scheduler::loop([]() - { - SetThreadExecutionState(ES_DISPLAY_REQUIRED); - }, scheduler::pipeline::main); - } - - // Make cg_fov and cg_fovscale saved dvars - dvars::override::register_float("cg_fov", 65.f, 40.f, 200.f, game::DvarFlags::DVAR_FLAG_SAVED); - dvars::override::register_float("cg_fovScale", 1.f, 0.1f, 2.f, game::DvarFlags::DVAR_FLAG_SAVED); - - // Allow kbam input when gamepad is enabled - utils::hook::nop(SELECT_VALUE(0x14018797E, 0x14024EF60), 2); - utils::hook::nop(SELECT_VALUE(0x1401856DC, 0x14024C6B0), 6); - - // Allow executing custom cfg files with the "exec" command - utils::hook::call(SELECT_VALUE(0x140343855, 0x140403E28), db_read_raw_file_stub); - - if (!game::environment::is_sp()) - { - patch_mp(); - } - } - - static void patch_mp() - { - // Use name dvar - utils::hook::jump(0x14050FF90, &live_get_local_client_name); // H1(1.4) - - // Patch SV_KickClientNum - sv_kick_client_num_hook.create(0x14047ED00, &sv_kick_client_num); // H1(1.4) - - // block changing name in-game - utils::hook::set(0x14047FC90, 0xC3); // H1(1.4) - - // patch "Couldn't find the bsp for this map." error to not be fatal in mp - utils::hook::call(0x1402BA26B, bsp_sys_error_stub); // H1(1.4) - - // client side aim assist dvar - dvars::aimassist_enabled = dvars::register_bool("aimassist_enabled", true, - game::DvarFlags::DVAR_FLAG_SAVED, - true); - utils::hook::call(0x14009EE9E, aim_assist_add_to_target_list); - - // unlock all items - utils::hook::jump(0x140413E60, is_item_unlocked); // LiveStorage_IsItemUnlockedFromTable_LocalClient H1(1.4) - utils::hook::jump(0x140413860, is_item_unlocked); // LiveStorage_IsItemUnlockedFromTable H1(1.4) - utils::hook::jump(0x140412B70, is_item_unlocked); // idk ( unlocks loot etc ) H1(1.4) - - // isProfanity - utils::hook::set(0x1402877D0, 0xC3C033); // MAY BE WRONG H1(1.4) - - // disable emblems - dvars::override::register_int("emblems_active", 0, 0, 0, game::DVAR_FLAG_NONE); - utils::hook::set(0x140479590, 0xC3); // don't register commands - - // disable elite_clan - dvars::override::register_int("elite_clan_active", 0, 0, 0, game::DVAR_FLAG_NONE); - utils::hook::set(0x140585680, 0xC3); // don't register commands H1(1.4) - - // disable codPointStore - dvars::override::register_int("codPointStore_enabled", 0, 0, 0, game::DVAR_FLAG_NONE); - - // don't register every replicated dvar as a network dvar - utils::hook::nop(0x14039E58E, 5); // dvar_foreach H1(1.4) - - // patch "Server is different version" to show the server client version - utils::hook::inject(0x140480952, VERSION); // H1(1.4) - - // prevent servers overriding our fov - utils::hook::call(0x14023279E, set_client_dvar_from_server_stub); - utils::hook::nop(0x1400DAF69, 5); - utils::hook::nop(0x140190C16, 5); - utils::hook::set(0x14021D22A, 0xEB); - - // unlock safeArea_* - utils::hook::jump(0x1402624F5, 0x140262503); // H1(1.4) - utils::hook::jump(0x14026251C, 0x140262547); // H1(1.4) - dvars::override::register_int("safeArea_adjusted_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED); - dvars::override::register_int("safeArea_adjusted_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED); - dvars::override::register_int("safeArea_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED); - dvars::override::register_int("safeArea_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED); - - // move chat position on the screen above menu splashes - dvars::override::register_vec2("cg_hudChatPosition", 5, 170, 0, 640, game::DVAR_FLAG_SAVED); - - // allow servers to check for new packages more often - dvars::override::register_int("sv_network_fps", 1000, 20, 1000, game::DVAR_FLAG_SAVED); - - // Massively increate timeouts - dvars::override::register_int("cl_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // Seems unused - dvars::override::register_int("sv_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // 30 - 0 - 1800 - dvars::override::register_int("cl_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // Seems unused - dvars::override::register_int("sv_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // 60 - 0 - 1800 - - dvars::register_int("scr_game_spectatetype", 1, 0, 99, game::DVAR_FLAG_REPLICATED); - - dvars::override::register_int("com_maxfps", 0, 10, 1000, game::DVAR_FLAG_SAVED); - - // Prevent clients from ending the game as non host by sending 'end_game' lui notification - // cmd_lui_notify_server_hook.create(0x140335A70, cmd_lui_notify_server_stub); // H1(1.4) - - // Prevent clients from sending invalid reliableAcknowledge - // utils::hook::call(0x1404899C6, sv_execute_client_message_stub); // H1(1.4) - - // "fix" for rare 'Out of memory error' error - if (utils::flags::has_flag("memoryfix")) - { - utils::hook::jump(0x140578BE0, malloc); - utils::hook::jump(0x140578B00, _aligned_malloc); - utils::hook::jump(0x140578C40, free); - utils::hook::jump(0x140578D30, realloc); - utils::hook::jump(0x140578B60, _aligned_realloc); - } - - // Change default hostname and make it replicated - dvars::override::register_string("sv_hostname", "^2H1-Mod^7 Default Server", game::DVAR_FLAG_REPLICATED); - } - }; -} - -REGISTER_COMPONENT(patches::component) diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp deleted file mode 100644 index b315be76..00000000 --- a/src/client/component/renderer.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include - -namespace renderer -{ - namespace - { - utils::hook::detour r_init_draw_method_hook; - utils::hook::detour r_update_front_end_dvar_options_hook; - - int get_fullbright_technique() - { - return game::TECHNIQUE_UNLIT; - } - - void gfxdrawmethod() - { - game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD; - - game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_LIT; - game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE; - game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : 242; - } - - void r_init_draw_method_stub() - { - gfxdrawmethod(); - } - - bool r_update_front_end_dvar_options_stub() - { - if (dvars::r_fullbright->modified) - { - //game::Dvar_ClearModified(dvars::r_fullbright); - game::R_SyncRenderThread(); - - gfxdrawmethod(); - } - - 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() || !game::environment::is_mp()) - { - return; - } - - dvars::r_fullbright = dvars::register_int("r_fullbright", 0, 0, 3, game::DVAR_FLAG_SAVED); - - r_init_draw_method_hook.create(SELECT_VALUE(0x1404BD140, 0x1405C46E0), &r_init_draw_method_stub); - r_update_front_end_dvar_options_hook.create(SELECT_VALUE(0x1404F8870, 0x1405FF9E0), &r_update_front_end_dvar_options_stub); - - // use "saved" flags for "r_normalMap" - utils::hook::set(SELECT_VALUE(0x1404CF5CA, 0x1405D460E), game::DVAR_FLAG_SAVED); - - // use "saved" flags for "r_specularMap" - utils::hook::set(SELECT_VALUE(0x1404CF5F5, 0x1405D4639), game::DVAR_FLAG_SAVED); - - // use "saved" flags for "r_specOccMap" - utils::hook::set(SELECT_VALUE(0x1404CF620, 0x1405D4664), game::DVAR_FLAG_SAVED); - } - }; -} - -#ifdef DEBUG -REGISTER_COMPONENT(renderer::component) -#endif \ No newline at end of file diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index ac837128..9a8911eb 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -180,9 +180,9 @@ namespace scheduler void post_unpack() override { - r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); // H1-STEAM(1.15) - g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); // H1(1.15) - //main_frame_hook.create(SELECT_VALUE(0x1401CE8D0, 0x1400D8310), scheduler::main_frame_stub); can't find + r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); + g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); + main_frame_hook.create(SELECT_VALUE(0, 0x1400D8310), scheduler::main_frame_stub); // I REPEAT, ARXAN IS PAIN } void pre_destroy() override @@ -196,4 +196,4 @@ namespace scheduler }; } -REGISTER_COMPONENT(scheduler::component) +REGISTER_COMPONENT(scheduler::component) \ No newline at end of file diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp deleted file mode 100644 index e3116122..00000000 --- a/src/client/component/scripting.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include - -#include "game/scripting/entity.hpp" -#include "game/scripting/functions.hpp" -#include "game/scripting/event.hpp" -#include "game/scripting/lua/engine.hpp" -#include "game/scripting/execution.hpp" - -#include "scheduler.hpp" -#include "scripting.hpp" - -namespace scripting -{ - std::unordered_map> fields_table; - std::unordered_map> script_function_table; - - namespace - { - utils::hook::detour vm_notify_hook; - utils::hook::detour scr_load_level_hook; - utils::hook::detour g_shutdown_game_hook; - - utils::hook::detour scr_add_class_field_hook; - - utils::hook::detour scr_set_thread_position_hook; - utils::hook::detour process_script_hook; - - std::string current_file; - - void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, - game::VariableValue* top) - { - if (!game::VirtualLobby_Loaded()) - { - const auto* string = game::SL_ConvertToString(string_value); - if (string) - { - event e; - e.name = string; - e.entity = notify_list_owner_id; - - for (auto* value = top; value->type != game::SCRIPT_END; --value) - { - e.arguments.emplace_back(*value); - } - - if (e.name == "entitydeleted") - { - scripting::clear_entity_fields(e.entity); - } - - lua::engine::notify(e); - } - } - - vm_notify_hook.invoke(notify_list_owner_id, string_value, top); - } - - void scr_load_level_stub() - { - scr_load_level_hook.invoke(); - if (!game::VirtualLobby_Loaded()) - { - lua::engine::start(); - } - } - - void g_shutdown_game_stub(const int free_scripts) - { - lua::engine::stop(); - return g_shutdown_game_hook.invoke(free_scripts); - } - - void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t _name, unsigned int canonicalString, unsigned int offset) - { - const auto name = game::SL_ConvertToString(_name); - - if (fields_table[classnum].find(name) == fields_table[classnum].end()) - { - fields_table[classnum][name] = offset; - } - - scr_add_class_field_hook.invoke(classnum, _name, canonicalString, offset); - } - - void process_script_stub(const char* filename) - { - const auto file_id = atoi(filename); - if (file_id) - { - current_file = scripting::find_token(file_id); - } - else - { - current_file = filename; - } - - process_script_hook.invoke(filename); - } - - void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) - { - const auto function_name = scripting::find_token(threadName); - script_function_table[current_file][function_name] = codePos; - scr_set_thread_position_hook.invoke(threadName, codePos); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - vm_notify_hook.create(SELECT_VALUE(0x140379A00, 0x1404479F0), vm_notify_stub); - - scr_add_class_field_hook.create(SELECT_VALUE(0x140370370, 0x14043E2C0), scr_add_class_field_stub); - - scr_set_thread_position_hook.create(SELECT_VALUE(0x14036A180, 0x140437D10), scr_set_thread_position_stub); - process_script_hook.create(SELECT_VALUE(0x1403737E0, 0x1404417E0), process_script_stub); - - scr_load_level_hook.create(SELECT_VALUE(0x1402A5BE0, 0x1403727C0), scr_load_level_stub); - g_shutdown_game_hook.create(SELECT_VALUE(0x140277D40, 0x140345A60), g_shutdown_game_stub); - - scheduler::loop([]() - { - lua::engine::run_frame(); - }, scheduler::pipeline::server); - } - }; -} - -REGISTER_COMPONENT(scripting::component) \ No newline at end of file diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp deleted file mode 100644 index 865ae858..00000000 --- a/src/client/component/scripting.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -namespace scripting -{ - extern std::unordered_map> fields_table; - extern std::unordered_map> script_function_table; -} \ No newline at end of file diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp deleted file mode 100644 index 1b7e759e..00000000 --- a/src/client/component/server_list.cpp +++ /dev/null @@ -1,443 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "server_list.hpp" -#include "localized_strings.hpp" -#include "network.hpp" -#include "scheduler.hpp" -#include "party.hpp" -#include "game/game.hpp" - -#include -#include -#include - -#include "console.hpp" -#include "command.hpp" - -namespace server_list -{ - namespace - { - const int server_limit = 18; - - struct server_info - { - // gotta add more to this - int clients; - int max_clients; - int bots; - int ping; - std::string host_name; - std::string map_name; - std::string game_type; - game::CodPlayMode play_mode; - char in_game; - game::netadr_s address; - }; - - struct - { - game::netadr_s address{}; - volatile bool requesting = false; - std::unordered_map queued_servers{}; - } master_state; - - std::mutex mutex; - std::vector servers; - - size_t server_list_page = 0; - volatile bool update_server_list = false; - std::chrono::high_resolution_clock::time_point last_scroll{}; - - size_t get_page_count() - { - const auto count = servers.size() / server_limit; - return count + (servers.size() % server_limit > 0); - } - - size_t get_page_base_index() - { - return server_list_page * server_limit; - } - - void refresh_server_list() - { - { - std::lock_guard _(mutex); - servers.clear(); - master_state.queued_servers.clear(); - server_list_page = 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("H1 %i full empty", PROTOCOL)); - } - } - - void join_server(int, int, const int index) - { - std::lock_guard _(mutex); - - const auto i = static_cast(index) + get_page_base_index(); - if (i < servers.size()) - { - static auto last_index = ~0ull; - 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; - } - - int ui_feeder_count() - { - std::lock_guard _(mutex); - if (update_server_list) - { - update_server_list = false; - return 0; - } - const auto count = static_cast(servers.size()); - const auto index = get_page_base_index(); - const auto diff = count - index; - return diff > server_limit ? server_limit : static_cast(diff); - } - - 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 = get_page_base_index() + index; - - if (i >= servers.size()) - { - return ""; - } - - if (column == 0) - { - return servers[i].host_name.empty() ? "" : utils::string::va("%s", servers[i].host_name.data()); - } - - if (column == 1) - { - return servers[i].map_name.empty() ? "Unknown" : utils::string::va("%s", servers[i].map_name.data()); - } - - if (column == 2) - { - return utils::string::va("%d/%d [%d]", servers[i].clients, servers[index].max_clients, - servers[i].bots); - } - - if (column == 3) - { - return servers[i].game_type.empty() ? "" : utils::string::va("%s", servers[i].game_type.data()); - } - - if (column == 4) - { - return servers[i].game_type.empty() ? "" : utils::string::va("%i", servers[i].ping); - } - - return ""; - } - - void sort_serverlist() - { - std::stable_sort(servers.begin(), servers.end(), [](const server_info& a, const server_info& b) - { - if (a.clients == b.clients) - { - return a.ping < b.ping; - } - - return a.clients > b.clients; - }); - } - - 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 is_scrolling_disabled() - { - return update_server_list || (std::chrono::high_resolution_clock::now() - last_scroll) < 500ms; - } - - bool scroll_down() - { - if (!is_server_list_open()) - { - return false; - } - - if (!is_scrolling_disabled() && server_list_page + 1 < get_page_count()) - { - last_scroll = std::chrono::high_resolution_clock::now(); - ++server_list_page; - trigger_refresh(); - } - - return true; - } - - bool scroll_up() - { - if (!is_server_list_open()) - { - return false; - } - - if (!is_scrolling_disabled() && server_list_page > 0) - { - last_scroll = std::chrono::high_resolution_clock::now(); - --server_list_page; - trigger_refresh(); - } - - return true; - } - - void resize_host_name(std::string& name) - { - name = utils::string::split(name, '\n').front(); - - game::Font_s* font = game::R_RegisterFont("fonts/default.otf", 18); - auto text_size = game::UI_TextWidth(name.data(), 32, font, 1.0f); - - while (text_size > 450) - { - text_size = game::UI_TextWidth(name.data(), 32, font, 1.0f); - name.pop_back(); - } - } - - utils::hook::detour lui_open_menu_hook; - - void lui_open_menu_stub(int controllerIndex, const char* menu, int a3, int a4, unsigned int a5) - { -#ifdef DEBUG - console::info("[LUI] %s\n", menu); -#endif - - if (!strcmp(menu, "menu_systemlink_join")) - { - refresh_server_list(); - } - - lui_open_menu_hook.invoke(controllerIndex, menu, a3, a4, a5); - } - } - - 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; - } - - bool get_master_server(game::netadr_s& address) - { - return game::NET_StringToAdr("135.148.53.121:20810", &address); - // return game::NET_StringToAdr("master.xlabs.dev:20810", &address); - } - - void handle_info_response(const game::netadr_s& address, const utils::info_string& info) - { - // Don't show servers that aren't dedicated! - const auto dedicated = std::atoi(info.get("dedicated").data()); - if (!dedicated) - { - return; - } - - // Don't show servers that aren't running! - const auto sv_running = std::atoi(info.get("sv_running").data()); - if (!sv_running) - { - return; - } - - // Only handle servers of the same playmode! - const auto playmode = game::CodPlayMode(std::atoi(info.get("playmode").data())); - if (game::Com_GetCurrentCoDPlayMode() != playmode) - { - return; - } - - 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); - } - - server_info server{}; - server.address = address; - server.host_name = info.get("hostname"); - server.map_name = game::UI_GetMapDisplayName(info.get("mapname").data()); - server.game_type = game::UI_GetGameTypeDisplayName(info.get("gametype").data()); - server.play_mode = playmode; - 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 = std::min(now - start_time, 999); - - server.in_game = 1; - - resize_host_name(server.host_name); - - insert_server(std::move(server)); - } - - 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"); - - // hook LUI_OpenMenu to refresh server list for system link menu - lui_open_menu_hook.create(game::LUI_OpenMenu, lui_open_menu_stub); - - // replace UI_RunMenuScript call in LUI_CoD_LuaCall_RefreshServerList to our refresh_servers - utils::hook::call(0x14018A0C9, &refresh_server_list); - utils::hook::call(0x14018A5DE, &join_server); - utils::hook::nop(0x14018A5FD, 5); - - // do feeder stuff - utils::hook::call(0x14018A199, &ui_feeder_count); - utils::hook::call(0x14018A3B1, &ui_feeder_item_text); - - scheduler::loop(do_frame_work, scheduler::pipeline::main); - - network::on("getServersResponse", [](const game::netadr_s& target, const std::string_view& data) - { - { - std::lock_guard _(mutex); - if (!master_state.requesting || master_state.address != target) - { - return; - } - - master_state.requesting = false; - - std::optional start{}; - for (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; - memcpy(&address.ip[0], data.data() + i + 0, 4); - 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 deleted file mode 100644 index d9974cfa..00000000 --- a/src/client/component/server_list.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "game/game.hpp" -#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); -} \ No newline at end of file diff --git a/src/client/component/shaders.cpp b/src/client/component/shaders.cpp deleted file mode 100644 index ec632115..00000000 --- a/src/client/component/shaders.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" -#include "dvars.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include - -namespace shaders -{ - namespace - { - game::dvar_t* disable_shader_caching = nullptr; - - bool shader_should_show_dialog_stub() - { - return !disable_shader_caching->current.enabled; - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_mp()) - { - return; - } - - const auto has_flag = utils::flags::has_flag("noshadercaching"); - - disable_shader_caching = dvars::register_bool("disable_shader_caching", has_flag, game::DVAR_FLAG_SAVED, true); - if (has_flag) - { - dvars::override::set_bool("disable_shader_caching", 1); - dvars::override::set_from_string("disable_shader_caching", "1"); - } - - utils::hook::jump(0x14007E710, shader_should_show_dialog_stub); - } - }; -} - -REGISTER_COMPONENT(shaders::component) diff --git a/src/client/component/slowmotion.cpp b/src/client/component/slowmotion.cpp deleted file mode 100644 index 71f66dbf..00000000 --- a/src/client/component/slowmotion.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "game/game.hpp" - -#include -#include - -namespace slowmotion -{ - namespace - { - 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(1u); - } - - if (game::Scr_GetNumParam() >= 3) - { - duration = static_cast(game::Scr_GetFloat(2u) * 1000.0f); - } - - game::SV_SetConfigstring(10, utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end)); - game::Com_SetSlowMotion(start, end, duration); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_dedi()) - { - return; - } - - utils::hook::jump(0x140365480, scr_cmd_set_slow_motion); // H1(1.4) - } - }; -} - -REGISTER_COMPONENT(slowmotion::component) diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp deleted file mode 100644 index 3dfd6541..00000000 --- a/src/client/component/splash.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#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(0x1403E192E, 0x1405123E2), 5); // winmain doesn't even exist in 1.15? lmao - utils::hook::jump(SELECT_VALUE(0, 0x5BE1D0_b), destroy_stub); // H1-STEAM(1.15) - utils::hook::jump(SELECT_VALUE(0, 0x5BE210_b), destroy_stub); // H1-STEAM(1.15) - } - - 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("H1 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 = "H1 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, "H1 Splash Screen", "H1", - 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/system_check.cpp b/src/client/component/system_check.cpp index 9c88bd5c..e3631248 100644 --- a/src/client/component/system_check.cpp +++ b/src/client/component/system_check.cpp @@ -51,27 +51,28 @@ namespace system_check { static std::unordered_map mp_zone_hashes = { - {"patch_common_mp.ff", "3F44B0CFB0B8E0FBD9687C2942204AB7F11E66E6E15C73B8B4A5EB5920115A31"}, + {"patch_common_mp.ff", "E45EF5F29D12A5A47F405F89FBBEE479C0A90D02141ABF852D481689514134A1"}, }; static std::unordered_map sp_zone_hashes = { // Steam doesn't necessarily deliver this file :( - {"patch_common.ff", "BB0617DD94AF2F511571E7184BBEDE76E64D97E5D0DAFDB457F00717F035EBF0"}, + {"patch_common.ff", "1D32A9770F90ED022AA76F4859B4AB178E194A703383E61AC2CE83B1E828B18F"}, }; 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 != 0xFFB8006D && value != 0xFFB80080) - { - throw std::runtime_error("Unsupported Call of Duty: Modern Warfare Remastered version(1.4)"); - } - } + //void verify_binary_version() + //{ + // if (*(int*)(uint64_t(GetModuleHandle(NULL)) + 0x4CCD3D) != 1251288) + // { + // MessageBoxA(0, "UNSUPPORTED VERSION MWR(1.15)", "H1MP-STEAM", MB_ICONWARNING); + + // return; + // } + //} } bool is_valid() @@ -85,12 +86,12 @@ namespace system_check public: void post_load() override { - verify_binary_version(); + //verify_binary_version(); if (!is_valid()) { MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n" - "Please get the latest officially supported Call of Duty: Modern Warfare Remastered 1.4 files, or you will get random crashes and issues.", + "Please get the latest officially supported Call of Duty: Modern Warfare Remastered 1.15 STEAM files, or you will get random crashes and issues.", "Invalid game files!", MB_ICONINFORMATION); } } diff --git a/src/client/component/thread_names.cpp b/src/client/component/thread_names.cpp deleted file mode 100644 index 84b5fa70..00000000 --- a/src/client/component/thread_names.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" - -#include "game/game.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 deleted file mode 100644 index 941dda10..00000000 --- a/src/client/component/ui_scripting.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include "scheduler.hpp" -#include "command.hpp" - -#include "ui_scripting.hpp" - -#include "game/ui_scripting/lua/engine.hpp" -#include "game/ui_scripting/execution.hpp" -#include "game/ui_scripting/lua/error.hpp" - -#include -#include - -namespace ui_scripting -{ - namespace - { - std::unordered_map converted_functions; - - utils::hook::detour hksi_lual_error_hook; - utils::hook::detour hksi_lual_error_hook2; - utils::hook::detour hks_start_hook; - utils::hook::detour hks_shutdown_hook; - utils::hook::detour hks_allocator_hook; - utils::hook::detour hks_frame_hook; - - bool error_hook_enabled = false; - - void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...) - { - char va_buffer[2048] = {0}; - - va_list ap; - va_start(ap, fmt); - vsprintf_s(va_buffer, fmt, ap); - va_end(ap); - - const auto formatted = std::string(va_buffer); - - if (!error_hook_enabled) - { - return hksi_lual_error_hook.invoke(s, formatted.data()); - } - else - { - throw std::runtime_error(formatted); - } - } - - void* hks_start_stub(char a1) - { - const auto _1 = gsl::finally([]() - { - ui_scripting::lua::engine::start(); - }); - - return hks_start_hook.invoke(a1); - } - - void hks_shutdown_stub() - { - ui_scripting::lua::engine::stop(); - hks_shutdown_hook.invoke(); - } - - void* hks_allocator_stub(void* userData, void* oldMemory, unsigned __int64 oldSize, unsigned __int64 newSize) - { - const auto closure = reinterpret_cast(oldMemory); - if (converted_functions.find(closure) != converted_functions.end()) - { - converted_functions.erase(closure); - } - - return hks_allocator_hook.invoke(userData, oldMemory, oldSize, newSize); - } - - void hks_frame_stub() - { - const auto state = *game::hks::lua_state; - if (state) - { - ui_scripting::lua::engine::run_frame(); - } - } - } - - int main_function_handler(game::hks::lua_State* state) - { - const auto value = state->m_apistack.base[-1]; - if (value.t != game::hks::TCFUNCTION) - { - return 0; - } - - const auto closure = reinterpret_cast(value.v.cClosure); - if (converted_functions.find(closure) == converted_functions.end()) - { - return 0; - } - - const auto function = converted_functions[closure]; - const auto count = static_cast(state->m_apistack.top - state->m_apistack.base); - const auto arguments = get_return_values(count); - const auto s = function.lua_state(); - - std::vector converted_args; - - for (const auto& argument : arguments) - { - converted_args.push_back(lua::convert(s, argument)); - } - - const auto results = function(sol::as_args(converted_args)); - lua::handle_error(results); - - for (const auto& result : results) - { - push_value(lua::convert({s, result})); - } - - return results.return_count(); - } - - void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function) - { - converted_functions[closure] = function; - } - - void clear_converted_functions() - { - converted_functions.clear(); - } - - void enable_error_hook() - { - error_hook_enabled = true; - } - - void disable_error_hook() - { - error_hook_enabled = false; - } - - class component final : public component_interface - { - public: - - void post_unpack() override - { - if (game::environment::is_dedi()) - { - return; - } - - hks_start_hook.create(SELECT_VALUE(0x1400E4B40, 0x140176A40), hks_start_stub); - hks_shutdown_hook.create(SELECT_VALUE(0x1400DD3D0, 0x14016CA80), hks_shutdown_stub); - hksi_lual_error_hook.create(SELECT_VALUE(0x1400A5EA0, 0x14012F300), hksi_lual_error_stub); - hks_allocator_hook.create(SELECT_VALUE(0x14009B570, 0x14012BAC0), hks_allocator_stub); - hks_frame_hook.create(SELECT_VALUE(0x1400E37F0, 0x1401755B0), hks_frame_stub); - - if (game::environment::is_mp()) - { - hksi_lual_error_hook2.create(0x1401366B0, hksi_lual_error_stub); - } - - command::add("lui_restart", []() - { - utils::hook::invoke(SELECT_VALUE(0x1400DD3D0, 0x14016CA80)); - utils::hook::invoke(SELECT_VALUE(0x1400E6170, 0x1401780D0)); - }); - } - }; -} - -REGISTER_COMPONENT(ui_scripting::component) \ No newline at end of file diff --git a/src/client/component/ui_scripting.hpp b/src/client/component/ui_scripting.hpp deleted file mode 100644 index 2a48f6ec..00000000 --- a/src/client/component/ui_scripting.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "game/ui_scripting/lua/value_conversion.hpp" - -namespace ui_scripting -{ - int main_function_handler(game::hks::lua_State* state); - void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function); - void clear_converted_functions(); - - void enable_error_hook(); - void disable_error_hook(); -} \ No newline at end of file diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp deleted file mode 100644 index 939dbd1c..00000000 --- a/src/client/component/updater.cpp +++ /dev/null @@ -1,474 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" -#include "dvars.hpp" -#include "updater.hpp" - -#include "version.h" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include -#include -#include -#include - -#define MASTER "https://master.fed0001.xyz/h1-mod/" - -#define FILES_PATH "files.json" -#define FILES_PATH_DEV "files-dev.json" - -#define DATA_PATH "data/" -#define DATA_PATH_DEV "data-dev/" - -#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates" -#define ERR_DOWNLOAD_FAIL "Failed to download file " -#define ERR_WRITE_FAIL "Failed to write file " - -#define BINARY_NAME "h1-mod.exe" - -namespace updater -{ - namespace - { - game::dvar_t* cl_auto_update; - bool has_tried_update = false; - - struct status - { - bool done; - bool success; - }; - - struct file_data - { - std::string name; - std::string data; - }; - - struct update_data_t - { - bool restart_required{}; - bool cancelled{}; - status check{}; - status download{}; - std::string error{}; - std::string current_file{}; - std::vector required_files{}; - }; - - utils::concurrency::container update_data; - - std::string get_branch() - { - return GIT_BRANCH; - } - - std::string select(const std::string& main, const std::string& develop) - { - if (get_branch() == "develop") - { - return develop; - } - - return main; - } - - std::string get_data_path() - { - if (get_branch() == "develop") - { - return DATA_PATH_DEV; - } - - return DATA_PATH; - } - - void set_update_check_status(bool done, bool success, const std::string& error = {}) - { - update_data.access([done, success, error](update_data_t& data_) - { - data_.check.done = done; - data_.check.success = success; - data_.error = error; - }); - } - - void set_update_download_status(bool done, bool success, const std::string& error = {}) - { - update_data.access([done, success, error](update_data_t& data_) - { - data_.download.done = done; - data_.download.success = success; - data_.error = error; - }); - } - - bool check_file(const std::string& name, const std::string& sha) - { - std::string data; - if (!utils::io::read_file(name, &data)) - { - return false; - } - - if (utils::cryptography::sha1::compute(data, true) != sha) - { - return false; - } - - return true; - } - - std::string load_binary_name() - { - // utils::nt::library self; - // return self.get_name(); - // returns the game's name and not the client's - - return BINARY_NAME; - } - - std::string get_binary_name() - { - static const auto name = load_binary_name(); - return name; - } - - std::string get_time_str() - { - return utils::string::va("%i", uint32_t(time(nullptr))); - } - - std::optional download_file(const std::string& name) - { - return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str()); - } - - bool is_update_cancelled() - { - return update_data.access([](update_data_t& data_) - { - return data_.cancelled; - }); - } - - bool write_file(const std::string& name, const std::string& data) - { - if (get_binary_name() == name && - utils::io::file_exists(name) && - !utils::io::move_file(name, name + ".old")) - { - return false; - } - -#ifdef DEBUG - return utils::io::write_file("update_test/" + name, data); -#else - return utils::io::write_file(name, data); -#endif - } - - void delete_old_file() - { - utils::io::remove_file(get_binary_name() + ".old"); - } - - void reset_data() - { - update_data.access([](update_data_t& data_) - { - data_ = {}; - }); - } - - std::string get_mode_flag() - { - if (game::environment::is_mp()) - { - return "-multiplayer"; - } - - if (game::environment::is_sp()) - { - return "-singleplayer"; - } - - return {}; - } - } - - // workaround - void relaunch() - { - if (!utils::io::file_exists(BINARY_NAME)) - { - utils::nt::terminate(0); - return; - } - - 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); - - char buf[1024] = {0}; - const auto command_line = utils::string::va("%s %s", GetCommandLineA(), get_mode_flag().data()); - strcpy_s(buf, 1024, command_line); - - CreateProcess(BINARY_NAME, buf, 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); - - utils::nt::terminate(0); - } - - void set_has_tried_update(bool tried) - { - has_tried_update = tried; - } - - bool get_has_tried_update() - { - return has_tried_update; - } - - bool auto_updates_enabled() - { - return cl_auto_update->current.enabled; - } - - bool is_update_check_done() - { - return update_data.access([](update_data_t& data_) - { - return data_.check.done; - }); - } - - bool is_update_download_done() - { - return update_data.access([](update_data_t& data_) - { - return data_.download.done; - }); - } - - bool get_update_check_status() - { - return update_data.access([](update_data_t& data_) - { - return data_.check.success; - }); - } - - bool get_update_download_status() - { - return update_data.access([](update_data_t& data_) - { - return data_.download.success; - }); - } - - bool is_update_available() - { - return update_data.access([](update_data_t& data_) - { - return data_.required_files.size() > 0; - }); - } - - bool is_restart_required() - { - return update_data.access([](update_data_t& data_) - { - return data_.restart_required; - }); - } - - std::string get_last_error() - { - return update_data.access([](update_data_t& data_) - { - return data_.error; - }); - } - - std::string get_current_file() - { - return update_data.access([](update_data_t& data_) - { - return data_.current_file; - }); - } - - void cancel_update() - { -#ifdef DEBUG - printf("[Updater] Cancelling update\n"); -#endif - - return update_data.access([](update_data_t& data_) - { - data_.cancelled = true; - }); - } - - void start_update_check() - { - cancel_update(); - reset_data(); - -#ifdef DEBUG - printf("[Updater] starting update check\n"); -#endif - - scheduler::once([]() - { - const auto files_data = utils::http::get_data(MASTER + select(FILES_PATH, FILES_PATH_DEV) + "?" + get_time_str()); - - if (is_update_cancelled()) - { - reset_data(); - return; - } - - if (!files_data.has_value()) - { - set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); - return; - } - - rapidjson::Document j; - j.Parse(files_data.value().data()); - - if (!j.IsArray()) - { - set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); - return; - } - - std::vector required_files; - - const auto files = j.GetArray(); - for (const auto& file : files) - { - if (!file.IsArray() || file.Size() != 3 || !file[0].IsString() || !file[2].IsString()) - { - continue; - } - - const auto name = file[0].GetString(); - const auto sha = file[2].GetString(); - - if (!check_file(name, sha)) - { - if (get_binary_name() == name) - { - update_data.access([](update_data_t& data_) - { - data_.restart_required = true; - }); - } - -#ifdef DEBUG - printf("[Updater] need file %s\n", name); -#endif - - required_files.push_back(name); - } - } - - update_data.access([&required_files](update_data_t& data_) - { - data_.check.done = true; - data_.check.success = true; - data_.required_files = required_files; - }); - }, scheduler::pipeline::async); - } - - void start_update_download() - { -#ifdef DEBUG - printf("[Updater] starting update download\n"); -#endif - - if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled()) - { - return; - } - - scheduler::once([]() - { - const auto required_files = update_data.access>([](update_data_t& data_) - { - return data_.required_files; - }); - - std::vector downloads; - - for (const auto& file : required_files) - { - update_data.access([file](update_data_t& data_) - { - data_.current_file = file; - }); - -#ifdef DEBUG - printf("[Updater] downloading file %s\n", file.data()); -#endif - - const auto data = download_file(file); - - if (is_update_cancelled()) - { - reset_data(); - return; - } - - if (!data.has_value()) - { - set_update_download_status(true, false, ERR_DOWNLOAD_FAIL + file); - return; - } - - downloads.push_back({file, data.value()}); - } - - for (const auto& download : downloads) - { - if (!write_file(download.name, download.data)) - { - set_update_download_status(true, false, ERR_WRITE_FAIL + download.name); - return; - } - } - - set_update_download_status(true, true); - }, scheduler::pipeline::async); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - delete_old_file(); - cl_auto_update = dvars::register_bool("cg_auto_update", true, game::DVAR_FLAG_SAVED, true); - } - }; -} - -REGISTER_COMPONENT(updater::component) diff --git a/src/client/component/updater.hpp b/src/client/component/updater.hpp deleted file mode 100644 index 9a3dd45e..00000000 --- a/src/client/component/updater.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -namespace updater -{ - void relaunch(); - - void set_has_tried_update(bool tried); - bool get_has_tried_update(); - bool auto_updates_enabled(); - - bool is_update_available(); - bool is_update_check_done(); - bool get_update_check_status(); - - bool is_update_download_done(); - bool get_update_download_status(); - - bool is_restart_required(); - - std::string get_last_error(); - std::string get_current_file(); - - void start_update_check(); - void start_update_download(); - void cancel_update(); -} \ No newline at end of file diff --git a/src/client/component/videos.cpp b/src/client/component/videos.cpp deleted file mode 100644 index a602cc8a..00000000 --- a/src/client/component/videos.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" - -#include - -namespace videos -{ - namespace - { - utils::hook::detour playvid_hook; - std::unordered_map video_replaces; - - void playvid(const char* name, const int a2, const int a3) - { - const auto vid = video_replaces.find(name); - if (vid != video_replaces.end()) - { - char path[256]; - game::Sys_BuildAbsPath(path, sizeof(path), game::SF_VIDEO, vid->second.data(), ".bik"); - - if (game::Sys_FileExists(path)) - { - name = vid->second.data(); - } - } - - return playvid_hook.invoke(name, a2, a3); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - playvid_hook.create(SELECT_VALUE(0x1404A9D00, 0x1405B0AF0), &playvid); // H1(1.4) - - if (game::environment::is_mp()) - { - video_replaces["menus_bg_comp2"] = "menus_bg_h1mod"; - video_replaces["mp_menus_bg_options"] = "menus_bg_h1mod_blur"; - } - else if (game::environment::is_sp()) - { - video_replaces["sp_menus_bg_main_menu"] = "menus_bg_h1mod_sp"; - video_replaces["sp_menus_bg_campaign"] = "menus_bg_h1mod_sp"; - video_replaces["sp_menus_bg_options"] = "menus_bg_h1mod_sp"; - } - } - }; -} - -REGISTER_COMPONENT(videos::component) diff --git a/src/client/component/virtuallobby.cpp b/src/client/component/virtuallobby.cpp deleted file mode 100644 index eb6295f7..00000000 --- a/src/client/component/virtuallobby.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include - -namespace virtuallobby -{ - namespace - { - game::dvar_t* virtualLobby_fovscale; - - const auto get_fovscale_stub = utils::hook::assemble([](utils::hook::assembler& a) - { - const auto ret = a.newLabel(); - const auto original = a.newLabel(); - - a.pushad64(); - a.mov(rax, qword_ptr(0x1425F7210)); // virtualLobbyInFiringRange - a.cmp(byte_ptr(rax, 0x10), 1); - a.je(original); - a.call_aligned(game::VirtualLobby_Loaded); - a.cmp(al, 0); - a.je(original); - - // virtuallobby - a.popad64(); - a.mov(rax, ptr(reinterpret_cast(&virtualLobby_fovscale))); - a.jmp(ret); - - // original - a.bind(original); - a.popad64(); - a.mov(rax, qword_ptr(0x1413A8580)); - a.jmp(ret); - - a.bind(ret); - a.mov(rcx, 0x142935000); - a.jmp(0x1400B556A); - }); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_mp()) - { - return; - } - - virtualLobby_fovscale = dvars::register_float("virtualLobby_fovScale", 0.7f, 0.0f, 2.0f, game::DVAR_FLAG_SAVED); - - utils::hook::nop(0x1400B555C, 14); - utils::hook::jump(0x1400B555C, get_fovscale_stub, true); - } - }; -} - -REGISTER_COMPONENT(virtuallobby::component) diff --git a/src/client/loader/loader.cpp b/src/client/loader/loader.cpp index 1bc7b41c..4ec12c7c 100644 --- a/src/client/loader/loader.cpp +++ b/src/client/loader/loader.cpp @@ -31,7 +31,7 @@ FARPROC loader::load(const utils::nt::library& library, const std::string& buffe return FARPROC(library.get_ptr() + source.get_relative_entry_point()); } -FARPROC loader::load_library(const std::string& filename) const +FARPROC loader::load_library(const std::string& filename, uint64_t* base_address) const { const auto target = utils::nt::library::load(filename); if (!target) @@ -40,10 +40,7 @@ FARPROC loader::load_library(const std::string& filename) const } const auto base = size_t(target.get_ptr()); - if(base != 0x140000000) - { - throw std::runtime_error{utils::string::va("Binary was mapped at 0x%llX (instead of 0x%llX). Something is severely broken :(", base, 0x140000000)}; - } + *base_address = base; this->load_imports(target, target); this->load_tls(target, target); diff --git a/src/client/loader/loader.hpp b/src/client/loader/loader.hpp index 2c5d86f9..0c0b5a12 100644 --- a/src/client/loader/loader.hpp +++ b/src/client/loader/loader.hpp @@ -5,7 +5,7 @@ class loader final { public: FARPROC load(const utils::nt::library& library, const std::string& buffer) const; - FARPROC load_library(const std::string& filename) const; + FARPROC load_library(const std::string& filename, uint64_t* base_address) const; void set_import_resolver(const std::function& resolver); diff --git a/src/client/resources/ui_scripts/common.lua b/src/client/resources/ui_scripts/common.lua deleted file mode 100644 index 8f68e96d..00000000 --- a/src/client/resources/ui_scripts/common.lua +++ /dev/null @@ -1,164 +0,0 @@ -menucallbacks = {} -originalmenus = {} -stack = {} - -LUI.MenuBuilder.m_types_build["generic_waiting_popup_"] = function (menu, event) - local oncancel = stack.oncancel - local popup = LUI.MenuBuilder.BuildRegisteredType("waiting_popup", { - message_text = stack.text, - isLiveWithCancel = true, - cancel_func = function(...) - local args = {...} - oncancel() - LUI.FlowManager.RequestLeaveMenu(args[1]) - end - }) - - local listchildren = popup:getChildById("LUIHorizontalList"):getchildren() - local children = listchildren[2]:getchildren() - popup.text = children[2] - - stack = { - ret = popup - } - - return popup -end - -LUI.MenuBuilder.m_types_build["generic_yes_no_popup_"] = function() - local callback = stack.callback - local popup = LUI.MenuBuilder.BuildRegisteredType("generic_yesno_popup", { - popup_title = stack.title, - message_text = stack.text, - yes_action = function() - callback(true) - end, - no_action = function() - callback(false) - end - }) - - stack = { - ret = popup - } - - return popup -end - -LUI.MenuBuilder.m_types_build["generic_confirmation_popup_"] = function() - local popup = LUI.MenuBuilder.BuildRegisteredType( "generic_confirmation_popup", { - cancel_will_close = false, - popup_title = stack.title, - message_text = stack.text, - button_text = stack.buttontext, - confirmation_action = stack.callback - }) - - stack = { - ret = popup - } - - return stack.ret -end - -LUI.onmenuopen = function(name, callback) - if (not LUI.MenuBuilder.m_types_build[name]) then - return - end - - if (not menucallbacks[name]) then - menucallbacks[name] = {} - end - - table.insert(menucallbacks[name], callback) - - if (not originalmenus[name]) then - originalmenus[name] = LUI.MenuBuilder.m_types_build[name] - LUI.MenuBuilder.m_types_build[name] = function(...) - local args = {...} - local menu = originalmenus[name](table.unpack(args)) - - for k, v in luiglobals.next, menucallbacks[name] do - v(menu, table.unpack(args)) - end - - return menu - end - end -end - -local addoptionstextinfo = LUI.Options.AddOptionTextInfo -LUI.Options.AddOptionTextInfo = function(menu) - local result = addoptionstextinfo(menu) - menu.optionTextInfo = result - return result -end - -LUI.addmenubutton = function(name, data) - LUI.onmenuopen(name, function(menu) - if (not menu.list) then - return - end - - local button = menu:AddButton(data.text, data.callback, nil, true, nil, { - desc_text = data.description - }) - - local buttonlist = menu:getChildById(menu.type .. "_list") - - if (data.id) then - button.id = data.id - end - - if (data.index) then - buttonlist:removeElement(button) - buttonlist:insertElement(button, data.index) - end - - local hintbox = menu.optionTextInfo - menu:removeElement(hintbox) - - LUI.Options.InitScrollingList(menu.list, nil) - menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu) - end) -end - -LUI.openmenu = function(menu, args) - stack = args - LUI.FlowManager.RequestAddMenu(nil, menu) - return stack.ret -end - -LUI.openpopupmenu = function(menu, args) - stack = args - LUI.FlowManager.RequestPopupMenu(nil, menu) - return stack.ret -end - -LUI.yesnopopup = function(data) - for k, v in luiglobals.next, data do - stack[k] = v - end - LUI.FlowManager.RequestPopupMenu(nil, "generic_yes_no_popup_") - return stack.ret -end - -LUI.confirmationpopup = function(data) - for k, v in luiglobals.next, data do - stack[k] = v - end - LUI.FlowManager.RequestPopupMenu(nil, "generic_confirmation_popup_") - return stack.ret -end - -function userdata_:getchildren() - local children = {} - local first = self:getFirstChild() - - while (first) do - table.insert(children, first) - first = first:getNextSibling() - end - - return children -end diff --git a/src/client/resources/ui_scripts/updater.lua b/src/client/resources/ui_scripts/updater.lua deleted file mode 100644 index 01d77360..00000000 --- a/src/client/resources/ui_scripts/updater.lua +++ /dev/null @@ -1,164 +0,0 @@ -updatecancelled = false -taskinterval = 100 - -updater.cancelupdate() - -function startupdatecheck(popup, autoclose) - updatecancelled = false - - local callback = function() - if (not updater.getupdatecheckstatus()) then - if (autoclose) then - LUI.FlowManager.RequestLeaveMenu(popup) - return - end - - popup.text:setText("Error: " .. updater.getlasterror()) - return - end - - if (not updater.isupdateavailable()) then - if (autoclose) then - LUI.FlowManager.RequestLeaveMenu(popup) - return - end - - popup.text:setText("No updates available") - return - end - - LUI.yesnopopup({ - title = "NOTICE", - text = "An update is available, proceed with installation?", - callback = function(result) - if (result) then - startupdatedownload(popup, autoclose) - else - LUI.FlowManager.RequestLeaveMenu(popup) - end - end - }) - end - - updater.startupdatecheck() - createtask({ - done = updater.isupdatecheckdone, - cancelled = isupdatecancelled, - callback = callback, - interval = taskinterval - }) -end - -function startupdatedownload(popup, autoclose) - updater.startupdatedownload() - - local textupdate = nil - local previousfile = nil - textupdate = game:oninterval(function() - local file = updater.getcurrentfile() - if (file == previousfile) then - return - end - - file = previousfile - popup.text:setText("Downloading file " .. updater.getcurrentfile() .. "...") - end, 10) - - local callback = function() - textupdate:clear() - - if (not updater.getupdatedownloadstatus()) then - if (autoclose) then - LUI.FlowManager.RequestLeaveMenu(popup) - return - end - - popup.text:setText("Error: " .. updater.getlasterror()) - return - end - - popup.text:setText("Update successful") - - if (updater.isrestartrequired()) then - LUI.confirmationpopup({ - title = "RESTART REQUIRED", - text = "Update requires restart", - buttontext = "RESTART", - callback = function() - updater.relaunch() - end - }) - else - if (LUI.mp_menus) then - Engine.Exec("lui_restart; lui_open mp_main_menu") - else - Engine.Exec("lui_restart") - end - end - - if (autoclose) then - LUI.FlowManager.RequestLeaveMenu(popup) - end - end - - createtask({ - done = updater.isupdatedownloaddone, - cancelled = isupdatecancelled, - callback = callback, - interval = taskinterval - }) -end - -function updaterpopup(oncancel) - return LUI.openpopupmenu("generic_waiting_popup_", { - oncancel = oncancel, - withcancel = true, - text = "Checking for updates..." - }) -end - -function createtask(data) - local interval = nil - interval = game:oninterval(function() - if (data.cancelled()) then - interval:clear() - return - end - - if (data.done()) then - interval:clear() - data.callback() - end - end, data.interval) - return interval -end - -function isupdatecancelled() - return updatecancelled -end - -function tryupdate(autoclose) - updatecancelled = false - local popup = updaterpopup(function() - updater.cancelupdate() - updatecancelled = true - end) - - startupdatecheck(popup, autoclose) -end - -function tryautoupdate() - if (not updater.autoupdatesenabled()) then - return - end - - if (not updater.gethastriedupdate()) then - game:ontimeout(function() - updater.sethastriedupdate(true) - tryupdate(true) - end, 100) - end -end - -LUI.onmenuopen("mp_main_menu", tryautoupdate) -LUI.onmenuopen("main_lockout", tryautoupdate) \ No newline at end of file From 29d5c1deb4d20c40ca0ca10075516d41e7dd70be Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:45:35 +0200 Subject: [PATCH 06/22] remove submodules --- .gitmodules | 18 +----------------- deps/libtomcrypt | 1 - deps/libtommath | 1 - deps/protobuf | 1 - deps/zlib | 1 - 5 files changed, 1 insertion(+), 21 deletions(-) delete mode 160000 deps/libtomcrypt delete mode 160000 deps/libtommath delete mode 160000 deps/protobuf delete mode 160000 deps/zlib diff --git a/.gitmodules b/.gitmodules index 7230acd8..39bd5688 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,20 +27,4 @@ url = https://github.com/lua/lua.git [submodule "deps/stb"] path = deps/stb - url = https://github.com/nothings/stb.git -[submodule "deps/libtomcrypt"] - path = deps/libtomcrypt - url = git://github.com/libtom/libtomcrypt.git - branch = develop -[submodule "deps/zlib"] - path = deps/zlib - url = git://github.com/madler/zlib.git - branch = develop -[submodule "deps/libtommath"] - path = deps/libtommath - url = git://github.com/libtom/libtommath.git - branch = develop -[submodule "deps/protobuf"] - path = deps/protobuf - url = git://github.com/protocolbuffers/protobuf.git - branch = 3.17.x + url = https://github.com/nothings/stb.git \ No newline at end of file diff --git a/deps/libtomcrypt b/deps/libtomcrypt deleted file mode 160000 index 673f5ce2..00000000 --- a/deps/libtomcrypt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 673f5ce29015a9bba3c96792920a10601b5b0718 diff --git a/deps/libtommath b/deps/libtommath deleted file mode 160000 index 04e9d1e7..00000000 --- a/deps/libtommath +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 04e9d1e7a0493910b2eb5e757d623870692ada04 diff --git a/deps/protobuf b/deps/protobuf deleted file mode 160000 index 5500c72c..00000000 --- a/deps/protobuf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5500c72c5b616da9f0125bcfab513987a1226e2b diff --git a/deps/zlib b/deps/zlib deleted file mode 160000 index 2014a993..00000000 --- a/deps/zlib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2014a993addbc8f1b9785d97f55fd189792c2f78 From e0eb721364818ee3bb018f0205b80032a810db20 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Thu, 17 Mar 2022 03:15:30 +0200 Subject: [PATCH 07/22] readd submodules --- .gitmodules | 18 +++++++++++++++++- deps/libtomcrypt | 1 + deps/libtommath | 1 + deps/protobuf | 1 + deps/zlib | 1 + 5 files changed, 21 insertions(+), 1 deletion(-) create mode 160000 deps/libtomcrypt create mode 160000 deps/libtommath create mode 160000 deps/protobuf create mode 160000 deps/zlib diff --git a/.gitmodules b/.gitmodules index 39bd5688..bc131f93 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,4 +27,20 @@ url = https://github.com/lua/lua.git [submodule "deps/stb"] path = deps/stb - url = https://github.com/nothings/stb.git \ No newline at end of file + url = https://github.com/nothings/stb.git +[submodule "deps/libtomcrypt"] + path = deps/libtomcrypt + url = https://github.com/libtom/libtomcrypt.git + branch = develop +[submodule "deps/libtommath"] + path = deps/libtommath + url = https://github.com/libtom/libtommath.git + branch = develop +[submodule "deps/protobuf"] + path = deps/protobuf + url = https://github.com/protocolbuffers/protobuf.git + branch = 3.17.x +[submodule "deps/zlib"] + path = deps/zlib + url = https://github.com/madler/zlib.git + branch = develop diff --git a/deps/libtomcrypt b/deps/libtomcrypt new file mode 160000 index 00000000..06a81aeb --- /dev/null +++ b/deps/libtomcrypt @@ -0,0 +1 @@ +Subproject commit 06a81aeb227424182125363f7554fad5146d6d2a diff --git a/deps/libtommath b/deps/libtommath new file mode 160000 index 00000000..66de8642 --- /dev/null +++ b/deps/libtommath @@ -0,0 +1 @@ +Subproject commit 66de86426e9cdb88526974c765108f01554af2b0 diff --git a/deps/protobuf b/deps/protobuf new file mode 160000 index 00000000..5500c72c --- /dev/null +++ b/deps/protobuf @@ -0,0 +1 @@ +Subproject commit 5500c72c5b616da9f0125bcfab513987a1226e2b diff --git a/deps/zlib b/deps/zlib new file mode 160000 index 00000000..2014a993 --- /dev/null +++ b/deps/zlib @@ -0,0 +1 @@ +Subproject commit 2014a993addbc8f1b9785d97f55fd189792c2f78 From 1ed4f717f62315046b2c4b641124874b707d6009 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Fri, 18 Mar 2022 02:40:50 +0200 Subject: [PATCH 08/22] Revert "stuff" This reverts commit 2a9ff724269dea40b1f6c3e080db6c40cf3cd4d9. --- src/client/component/arxan.cpp | 164 ---- src/client/component/auth.cpp | 25 +- src/client/component/binding.cpp | 138 ++++ src/client/component/bots.cpp | 103 +++ src/client/component/branding.cpp | 65 ++ src/client/component/colors.cpp | 182 +++++ src/client/component/command.cpp | 648 ++++++++++++++++ src/client/component/command.hpp | 50 ++ src/client/component/console.cpp | 299 ++++++++ src/client/component/console.hpp | 35 + src/client/component/dedicated.cpp | 333 ++++++++ src/client/component/dedicated_info.cpp | 65 ++ src/client/component/demonware.cpp | 604 +++++++++++++++ src/client/component/demonware.hpp | 6 + src/client/component/discord.cpp | 148 ++++ src/client/component/dvars.cpp | 443 +++++++++++ src/client/component/dvars.hpp | 28 + src/client/component/exception.cpp | 261 +++++++ src/client/component/fastfiles.cpp | 49 ++ src/client/component/fastfiles.hpp | 8 + src/client/component/filesystem.cpp | 94 +++ src/client/component/filesystem.hpp | 19 + src/client/component/fps.cpp | 174 +++++ src/client/component/game_console.cpp | 793 ++++++++++++++++++++ src/client/component/game_console.hpp | 7 + src/client/component/game_module.cpp | 3 +- src/client/component/localized_strings.cpp | 52 ++ src/client/component/localized_strings.hpp | 6 + src/client/component/logfile.cpp | 317 ++++++++ src/client/component/logfile.hpp | 13 + src/client/component/lui.cpp | 58 ++ src/client/component/map_rotation.cpp | 180 +++++ src/client/component/network.cpp | 11 +- src/client/component/party.cpp | 630 ++++++++++++++++ src/client/component/party.hpp | 17 + src/client/component/patches.cpp | 293 ++++++++ src/client/component/renderer.cpp | 77 ++ src/client/component/scheduler.cpp | 8 +- src/client/component/scripting.cpp | 141 ++++ src/client/component/scripting.hpp | 8 + src/client/component/server_list.cpp | 443 +++++++++++ src/client/component/server_list.hpp | 12 + src/client/component/shaders.cpp | 50 ++ src/client/component/slowmotion.cpp | 53 ++ src/client/component/splash.cpp | 141 ++++ src/client/component/system_check.cpp | 25 +- src/client/component/thread_names.cpp | 60 ++ src/client/component/ui_scripting.cpp | 180 +++++ src/client/component/ui_scripting.hpp | 12 + src/client/component/updater.cpp | 474 ++++++++++++ src/client/component/updater.hpp | 26 + src/client/component/videos.cpp | 55 ++ src/client/component/virtuallobby.cpp | 63 ++ src/client/loader/loader.cpp | 7 +- src/client/loader/loader.hpp | 2 +- src/client/resources/ui_scripts/common.lua | 164 ++++ src/client/resources/ui_scripts/updater.lua | 164 ++++ 57 files changed, 8286 insertions(+), 200 deletions(-) delete mode 100644 src/client/component/arxan.cpp 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/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/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/dvars.cpp create mode 100644 src/client/component/dvars.hpp create mode 100644 src/client/component/exception.cpp 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/localized_strings.cpp create mode 100644 src/client/component/localized_strings.hpp create mode 100644 src/client/component/logfile.cpp create mode 100644 src/client/component/logfile.hpp create mode 100644 src/client/component/lui.cpp create mode 100644 src/client/component/map_rotation.cpp 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/renderer.cpp create mode 100644 src/client/component/scripting.cpp create mode 100644 src/client/component/scripting.hpp create mode 100644 src/client/component/server_list.cpp create mode 100644 src/client/component/server_list.hpp create mode 100644 src/client/component/shaders.cpp create mode 100644 src/client/component/slowmotion.cpp create mode 100644 src/client/component/splash.cpp 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/updater.cpp create mode 100644 src/client/component/updater.hpp create mode 100644 src/client/component/videos.cpp create mode 100644 src/client/component/virtuallobby.cpp create mode 100644 src/client/resources/ui_scripts/common.lua create mode 100644 src/client/resources/ui_scripts/updater.lua diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp deleted file mode 100644 index adff7199..00000000 --- a/src/client/component/arxan.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "scheduler.hpp" -#include "game/game.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 && size_t(handle) != 0x12345) - { - 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() == game::DW_LIVE_CONNECTED - && context->ContextFlags == CONTEXT_DEBUG_REGISTERS) - { - return TRUE; - } - - return SetThreadContext(thread, context); - } - } - - int just_return() - { - return 1; - } - - 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; - } - - if (function == "LoadStringA" || function == "LoadStringW") - { - return just_return; - } - - 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 - { - // cba to implement sp, not sure if it's even needed - if (game::environment::is_sp()) return; - - // some of arxan crashes - utils::hook::nop(0x14CDEFCAA, 6); - utils::hook::call(0x1405BCAD1, &just_return); - } - }; -} - -REGISTER_COMPONENT(arxan::component) \ No newline at end of file diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index c5aa8240..346c8d80 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -42,7 +42,7 @@ namespace auth std::string get_protected_data() { - std::string input = "X-Labs-H1STEAM-Auth"; + std::string input = "X-Labs-H1Mod-Auth"; DATA_BLOB data_in{}, data_out{}; data_in.pbData = reinterpret_cast(input.data()); @@ -177,20 +177,21 @@ namespace auth game::SV_DirectConnect(from); } + // CAN'T FIND //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.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.pushad64(); + // a.mov(rdx, rsi); + // a.call_aligned(direct_connect); + // a.popad64(); - // a.jmp(0x140488CE2); // H1MP64(1.4) - // }); + // a.jmp(0x140488CE2); // H1MP64(1.4) + // }); //} } @@ -224,8 +225,8 @@ namespace auth utils::hook::jump(0x1D7542_b, 0x1D7587_b); // STEAM MAYBE `1401D7553` ON FIRST utils::hook::jump(0x1D7A82_b, 0x1D7AC8_b); // STEAM - //utils::hook::jump(0x1401CAE70, get_direct_connect_stub(), true); // STEAM - utils::hook::call(0x12D437_b, send_connect_data_stub); // STEAM + //utils::hook::jump(0x140488BC1, get_direct_connect_stub(), true); // H1(1.4) can't find + utils::hook::call(0x12D437_b, send_connect_data_stub); // H1(1.4) // Skip checks for sending connect packet utils::hook::jump(0x1402508FC, 0x140250946); diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp new file mode 100644 index 00000000..e40b7f42 --- /dev/null +++ b/src/client/component/binding.cpp @@ -0,0 +1,138 @@ +#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 get_num_keys() + { + return SELECT_VALUE(102, 103); + } + + 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 < get_num_keys()) + { + 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 >= get_num_keys()) + { + value -= get_num_keys(); + 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 <= get_num_keys(); i++) + { + if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) + { + return i; + } + } + + // custom binds + return get_num_keys() + get_binding_for_custom_command(command); + } + + void cl_execute_key_stub(const int local_client_num, int key, const int down, const int time) + { + if (key >= get_num_keys()) + { + key -= get_num_keys(); + + 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(0x1401881DB, 0x14025032F), key_write_bindings_to_buffer_stub); // H1(1.4) + + // links a custom command to an index + utils::hook::jump(SELECT_VALUE(0x140343C00, 0x1404041E0), key_get_binding_for_cmd_stub); // H1(1.4) + + // execute custom binds + cl_execute_key_hook.create(SELECT_VALUE(0x140183C70, 0x14024ACF0), &cl_execute_key_stub); // H1(1.4) + } + }; +} + +REGISTER_COMPONENT(binding::component) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp new file mode 100644 index 00000000..81f74628 --- /dev/null +++ b/src/client/component/bots.cpp @@ -0,0 +1,103 @@ +#include +#include "loader/component_loader.hpp" + +#include "command.hpp" +#include "scheduler.hpp" +#include "network.hpp" +#include "party.hpp" + +#include "game/game.hpp" +#include "game/scripting/execution.hpp" + +#include +#include +#include + +namespace bots +{ + namespace + { + bool can_add() + { + if (party::get_client_count() < *game::mp::svs_numclients) + { + return true; + } + return false; + } + + // TODO: when scripting comes, fix this to use better notifies + void bot_team_join(const int entity_num) + { + const game::scr_entref_t entref{static_cast(entity_num), 0}; + scheduler::once([entref]() + { + scripting::notify(entref, "luinotifyserver", {"team_select", 2}); + scheduler::once([entref]() + { + auto* _class = utils::string::va("class%d", utils::cryptography::random::get_integer() % 5); + scripting::notify(entref, "luinotifyserver", {"class_select", _class}); + }, scheduler::pipeline::server, 2s); + }, scheduler::pipeline::server, 2s); + } + + void spawn_bot(const int entity_num) + { + game::SV_SpawnTestClient(&game::mp::g_entities[entity_num]); + if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_CORE) + { + bot_team_join(entity_num); + } + } + + void add_bot() + { + if (!can_add()) + { + return; + } + + // SV_BotGetRandomName + const auto* const bot_name = game::SV_BotGetRandomName(); + auto* bot_ent = game::SV_AddBot(bot_name); + if (bot_ent) + { + spawn_bot(bot_ent->s.entityNum); + } + else if (can_add()) // workaround since first bot won't ever spawn + { + add_bot(); + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + command::add("spawnBot", [](const command::params& params) + { + if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) return; + + auto num_bots = 1; + if (params.size() == 2) + { + num_bots = atoi(params.get(1)); + } + + for (auto i = 0; i < (num_bots > *game::mp::svs_numclients ? *game::mp::svs_numclients : num_bots); i++) + { + scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i); + } + }); + } + }; +} + +REGISTER_COMPONENT(bots::component) \ No newline at end of file diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp new file mode 100644 index 00000000..2f74693b --- /dev/null +++ b/src/client/component/branding.cpp @@ -0,0 +1,65 @@ +#include +#include "loader/component_loader.hpp" + +#include "localized_strings.hpp" +#include "scheduler.hpp" +#include "command.hpp" +#include "version.hpp" + +#include "game/game.hpp" +#include "dvars.hpp" + +#include +#include + +// fonts/default.otf, fonts/defaultBold.otf, fonts/fira_mono_regular.ttf, fonts/fira_mono_bold.ttf + +namespace branding +{ + namespace + { + utils::hook::detour ui_get_formatted_build_number_hook; + + float color[4] = {0.666f, 0.666f, 0.666f, 0.666f}; + + 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; + } + + if (game::environment::is_mp()) + { + localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER\n"); + localized_strings::override("MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER"); + } + + dvars::override::set_string("version", utils::string::va("H1-Mod %s", VERSION)); + + ui_get_formatted_build_number_hook.create( + SELECT_VALUE(0x1403B1C40, 0x1404E74C0), ui_get_formatted_build_number_stub); + + scheduler::loop([]() + { + const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20); + + game::R_AddCmdDrawText("H1-Mod: " VERSION, 0x7FFFFFFF, font, 10.f, + 5.f + static_cast(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0); + }, scheduler::pipeline::renderer); + } + }; +} + +REGISTER_COMPONENT(branding::component) diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp new file mode 100644 index 00000000..75eff23a --- /dev/null +++ b/src/client/component/colors.cpp @@ -0,0 +1,182 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include +#include + +namespace colors +{ + struct hsv_color + { + unsigned char h; + unsigned char s; + unsigned char v; + }; + + namespace + { + std::vector color_table; + + DWORD hsv_to_rgb(const hsv_color 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, static_cast(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 = utils::hook::invoke(0x14025BAA0, 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(0x14F142FF8, 0x14FE70634)); // H1(1.4) + } + else if (index == '9') + { + *color = *reinterpret_cast(SELECT_VALUE(0x14F142FFC, 0x14FE70638)); // H1(1.4) + } + else if (index == ':') + { + *color = hsv_to_rgb({static_cast((game::Sys_Milliseconds() / 100) % 256), 255, 255}); + } + else if (index == ';') + { + *color = *reinterpret_cast(SELECT_VALUE(0x14F143004, 0x14FE70640)); // H1(1.4) + } + else if (index == '<') + { + *color = 0xFFFCFF80; + } + 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(0x140503810, com_clean_name_stub); // H1(1.4) + + // don't apply colors to overhead names + utils::hook::call(0x1400AB416, get_client_name_stub); // H1(1.4) + + // patch I_CleanStr + utils::hook::jump(0x140503D00, i_clean_str_stub); // H1(1.4) + } + + // force new colors + utils::hook::jump(SELECT_VALUE(0x140524BD0, 0x1406206A0), rb_lookup_color_stub); // H1(1.4) + + // 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 00000000..b5c1ad40 --- /dev/null +++ b/src/client/component/command.cpp @@ -0,0 +1,648 @@ +#include +#include "loader/component_loader.hpp" +#include "command.hpp" +#include "console.hpp" +#include "game_console.hpp" + +#include "game/game.hpp" + +#include +#include +#include +#include "utils/io.hpp" +#include + +namespace command +{ + namespace + { + 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 (handlers.find(command) != handlers.end()) + { + handlers[command](params); + } + } + + void client_command(const int client_num, void* a2) + { + params_sv params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (handlers_sv.find(command) != handlers_sv.end()) + { + handlers_sv[command](client_num, params); + } + + client_command_hook.invoke(client_num, a2); + } + + // 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(0x142623FB4); //H1(1.4) + auto* com_console_lines = reinterpret_cast(0x142623FC0); //H1(1.4) + + 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(); + utils::hook::invoke(0x1400D8210); + } + + game::dvar_t* dvar_command_stub() + { + const params args; + + if (args.size() <= 0) + { + return 0; + } + + const auto dvar = game::Dvar_FindVar(args[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\" default: \"%s\" hash: 0x%08lX", + args[0], current, reset, dvar->hash); + + 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(dvar->hash, "", command); + } + + return dvar; + } + + return 0; + } + } + + 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(0x142623FB4); //H1(1.4) + auto* com_console_lines = reinterpret_cast(0x142623FC0); //H1(1.4) + + for (int i = 0; i < com_num_console_lines; i++) + { + game::Cmd_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::generateHashValue(game::Cmd_Argv(1)), "", game::Cmd_Argv(2)); + } + + game::Cmd_EndTokenizeString(); + } + } + + params::params() + : nesting_(game::cmd_args->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) + { + } + + 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_test(const char* name, void (*callback)()) + { + static game::cmd_function_s cmd_test; + return game::Cmd_AddCommandInternal(name, callback, &cmd_test); + } + + void add(const char* name, const std::function& callback) + { + static game::cmd_function_s cmd_test; + + const auto command = utils::string::to_lower(name); + + if (handlers.find(command) == handlers.end()) + 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, 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.find(command) == handlers_sv.end()) + handlers_sv[command] = std::move(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_commands_sp(); + } + else + { + utils::hook::call(0x1400D728F, &parse_commandline_stub); // MWR TEST + utils::hook::jump(0x14041D750, dvar_command_stub); + + add_commands_mp(); + } + + add_commands_generic(); + } + + private: + static void add_commands_generic() + { + add("quit", game::Quit); + //add("quit_hard", utils::nt::raise_hard_exception); /* this command delivers you to a windows blue screen, its quit hard from windows xD */ + add("crash", []() + { + *reinterpret_cast(1) = 0; + }); + + /*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, 0)); + } + } + + console::info("Total %i matches\n", matches.size()); + });*/ + + add("commandDump", [](const params& argument) + { + console::info("================================ COMMAND DUMP =====================================\n"); + game::cmd_function_s* cmd = (*game::cmd_functions); + std::string filename; + if (argument.size() == 2) + { + filename = "h1-mod/"; + filename.append(argument[1]); + if (!filename.ends_with(".txt")) + { + filename.append(".txt"); + } + } + int 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("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]); + + const std::string filter = params.get(2); + enum_assets(type, [type, filter](const game::XAssetHeader header) + { + const auto asset = game::XAsset{type, header}; + const auto* const asset_name = game::DB_GetXAssetName(&asset); + //const auto entry = game::DB_FindXAssetEntry(type, asset_name); + //TODO: display which zone the asset is from + + if (!filter.empty() && !game_console::match_compare(filter, asset_name, false)) + { + return; + } + + console::info("%s\n", asset_name); + }, true); + } + }); + + 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->hash); + return; + } + + execute(dvar->current.string); + });*/ + } + + static void add_commands_sp() + { + add("god", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= 1; + game::CG_GameMessage(0, utils::string::va("godmode %s", + game::sp::g_entities[0].flags & 1 + ? "^2on" + : "^1off")); + }); + + add("demigod", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= 2; + game::CG_GameMessage(0, utils::string::va("demigod mode %s", + game::sp::g_entities[0].flags & 2 + ? "^2on" + : "^1off")); + }); + + add("notarget", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= 4; + game::CG_GameMessage(0, utils::string::va("notarget %s", + game::sp::g_entities[0].flags & 4 + ? "^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")); + }); + } + + static void add_commands_mp() + { + //client_command_hook.create(0x1402E98F0, &client_command); + + /*add_sv("god", [](const int client_num, const params_sv&) + { + if (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].flags ^= 1; + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + utils::string::va("f \"godmode %s\"", + game::mp::g_entities[client_num].flags & 1 + ? "^2on" + : "^1off")); + }); + + add_sv("demigod", [](const int client_num, const params_sv&) + { + if (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].flags ^= 2; + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + utils::string::va("f \"demigod mode %s\"", + game::mp::g_entities[client_num].flags & 2 + ? "^2on" + : "^1off")); + }); + + add_sv("notarget", [](const int client_num, const params_sv&) + { + if (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].flags ^= 4; + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + utils::string::va("f \"notarget %s\"", + game::mp::g_entities[client_num].flags & 4 + ? "^2on" + : "^1off")); + }); + + add_sv("noclip", [](const int client_num, const params_sv&) + { + if (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].client->flags ^= 1; + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + 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 (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].client->flags ^= 2; + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + utils::string::va("f \"ufo %s\"", + game::mp::g_entities[client_num].client->flags & 2 + ? "^2on" + : "^1off")); + }); + + add_sv("give", [](const int client_num, const params_sv& params) + { + if (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + if (params.size() < 2) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"You did not specify a weapon name\""); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(client_num); + const auto wp = game::G_GetWeaponForName(params.get(1)); + if (wp) + { + if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 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 (!game::Dvar_FindVar("sv_cheats")->current.enabled) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"Cheats are not enabled on this server\""); + return; + } + + if (params.size() < 2) + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + "f \"You did not specify a weapon name\""); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(client_num); + const auto wp = game::G_GetWeaponForName(params.get(1)); + if (wp) + { + 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 00000000..bd70d0c6 --- /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, std::function callback); + + void execute(std::string command, bool sync = false); +} \ No newline at end of file diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp new file mode 100644 index 00000000..174beaf8 --- /dev/null +++ b/src/client/component/console.cpp @@ -0,0 +1,299 @@ +#include +#include "console.hpp" +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "command.hpp" + +#include +#include +#include +#include + +namespace game_console +{ + void print(int type, const std::string& data); +} + +namespace console +{ + namespace + { + using message_queue = std::queue; + utils::concurrency::container messages; + + bool native_console() + { + static const auto flag = utils::flags::has_flag("nativeconsole"); + return flag; + } + + void hide_console() + { + auto* const con_window = GetConsoleWindow(); + + DWORD process; + GetWindowThreadProcessId(con_window, &process); + + if (!native_console() && (process == GetCurrentProcessId() || IsDebuggerPresent())) + { + ShowWindow(con_window, SW_HIDE); + } + } + + std::string format(va_list* ap, const char* message) + { + static thread_local char buffer[0x1000]; + + const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); + + if (count < 0) return {}; + return {buffer, static_cast(count)}; + } + + void dispatch_message(const int type, const std::string& message) + { + if (native_console()) + { + printf("%s\n", message.data()); + return; + } + + game_console::print(type, message); + messages.access([&message](message_queue& msgs) + { + msgs.emplace(message); + }); + } + + void append_text(const char* text) + { + dispatch_message(con_type_info, text); + } + } + + class component final : public component_interface + { + public: + component() + { + hide_console(); + + if (native_console()) + { + setvbuf(stdout, nullptr, _IONBF, 0); + setvbuf(stderr, nullptr, _IONBF, 0); + } + else + { + (void)_pipe(this->handles_, 1024, _O_TEXT); + (void)_dup2(this->handles_[1], 1); + (void)_dup2(this->handles_[1], 2); + } + } + + void post_start() override + { + this->terminate_runner_ = false; + + this->console_runner_ = utils::thread::create_named_thread("Console IO", [this] + { + if (native_console()) + { + this->native_input(); + } + else + { + this->runner(); + } + }); + } + + void pre_destroy() override + { + this->terminate_runner_ = true; + + printf("\r\n"); + _flushall(); + + if (this->console_runner_.joinable()) + { + this->console_runner_.join(); + } + + if (this->console_thread_.joinable()) + { + this->console_thread_.join(); + } + +#ifndef NATIVE_CONSOLE + _close(this->handles_[0]); + _close(this->handles_[1]); +#endif + + messages.access([&](message_queue& msgs) + { + msgs = {}; + }); + } + + void post_unpack() override + { + // Redirect input (]command) + utils::hook::jump(SELECT_VALUE(0x1403E34C0, 0x1405141E0), append_text); // H1(1.4) + + this->initialize(); + } + + private: + volatile bool console_initialized_ = false; + volatile bool terminate_runner_ = false; + + std::thread console_runner_; + std::thread console_thread_; + + int handles_[2]{}; + + void initialize() + { + this->console_thread_ = utils::thread::create_named_thread("Console", [this]() + { + if (!native_console() && (game::environment::is_dedi() || !utils::flags::has_flag("noconsole"))) + { + game::Sys_ShowConsole(); + } + + if (!game::environment::is_dedi()) + { + // Hide that shit + ShowWindow(console::get_window(), SW_MINIMIZE); + } + + { + messages.access([&](message_queue&) + { + this->console_initialized_ = true; + }); + } + + MSG msg; + while (!this->terminate_runner_) + { + if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + command::execute("quit", false); + break; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + this->log_messages(); + std::this_thread::sleep_for(1ms); + } + } + }); + } + + void log_messages() + { + /*while*/ + if (this->console_initialized_ && !messages.get_raw().empty()) + { + std::queue message_queue_copy; + + { + messages.access([&](message_queue& msgs) + { + message_queue_copy = std::move(msgs); + msgs = {}; + }); + } + + while (!message_queue_copy.empty()) + { + log_message(message_queue_copy.front()); + message_queue_copy.pop(); + } + } + + fflush(stdout); + fflush(stderr); + } + + static void log_message(const std::string& message) + { + OutputDebugStringA(message.data()); + game::Conbuf_AppendText(message.data()); + } + + void runner() + { + char buffer[1024]; + + while (!this->terminate_runner_ && this->handles_[0]) + { + const auto len = _read(this->handles_[0], buffer, sizeof(buffer)); + if (len > 0) + { + dispatch_message(con_type_info, std::string(buffer, len)); + } + else + { + std::this_thread::sleep_for(1ms); + } + } + + std::this_thread::yield(); + } + + void native_input() + { + std::string cmd; + + while (!this->terminate_runner_) + { + std::getline(std::cin, cmd); + command::execute(cmd); + } + + std::this_thread::yield(); + } + }; + + HWND get_window() + { + return *reinterpret_cast((SELECT_VALUE(0x14CF56C00, 0x14DDFC2D0))); // H1(1.4) + } + + void set_title(std::string title) + { + SetWindowText(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(0x14CF56C10, 0x14DDFC2E0)); // H1(1.4) + 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 00000000..302951a8 --- /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)...); + } +} \ No newline at end of file diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp new file mode 100644 index 00000000..8de5e9ac --- /dev/null +++ b/src/client/component/dedicated.cpp @@ -0,0 +1,333 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" +#include "network.hpp" +#include "command.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" +#include "dvars.hpp" +#include "console.hpp" + +#include +#include + +namespace dedicated +{ + namespace + { + utils::hook::detour gscr_set_dynamic_dvar_hook; + utils::hook::detour com_quit_f_hook; + + void init_dedicated_server() + { + static bool initialized = false; + if (initialized) return; + initialized = true; + + // R_LoadGraphicsAssets + utils::hook::invoke(0x1405DF4B0); + } + + void send_heartbeat() + { + auto* const dvar = game::Dvar_FindVar("sv_lanOnly"); + if (dvar && dvar->current.enabled) + { + return; + } + + game::netadr_s target{}; + if (server_list::get_master_server(target)) + { + network::send(target, "heartbeat", "H1"); + } + } + + 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(const int client, const char* command) + { + if (game::Live_SyncOnlineDataFlags(0) == 0) + { + game::Cbuf_AddText(client, command); + game::Cbuf_AddText(client, "\n"); + } + 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) + { + game::Cbuf_AddText(0, command.data()); + game::Cbuf_AddText(0, "\n"); + } + } + + void sync_gpu_stub() + { + std::this_thread::sleep_for(1ms); + } + + game::dvar_t* gscr_set_dynamic_dvar() + { + /* + auto s = game::Scr_GetString(0); + auto* dvar = game::Dvar_FindVar(s); + + if (dvar && !strncmp("scr_", dvar->name, 4)) + { + return dvar; + } + */ + + return gscr_set_dynamic_dvar_hook.invoke(); + } + + void kill_server() + { + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + if (game::mp::svs_clients[i].header.state >= 3) + { + game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE, + utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); + } + } + + com_quit_f_hook.invoke(); + } + + void sys_error_stub(const char* msg, ...) + { + char buffer[2048]; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap); + + va_end(ap); + + scheduler::once([]() + { + command::execute("map_rotate"); + }, scheduler::main, 3s); + + game::Com_Error(game::ERR_DROP, "%s", buffer); + } + } + + void initialize() + { + command::execute("exec default_xboxlive.cfg", true); + command::execute("onlinegame 1", true); + command::execute("xblive_privatematch 1", true); + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + return nullptr; + } + + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + +#ifdef DEBUG + printf("Starting dedicated server\n"); +#endif + + // Register dedicated dvar + dvars::register_bool("dedicated", true, game::DVAR_FLAG_READ); + + // Add lanonly mode + dvars::register_bool("sv_lanOnly", false, game::DVAR_FLAG_NONE); + + // Disable VirtualLobby + dvars::override::register_bool("virtualLobbyEnabled", false, game::DVAR_FLAG_READ); + + // Disable r_preloadShaders + dvars::override::register_bool("r_preloadShaders", false, game::DVAR_FLAG_READ); + + // Stop crashing from sys_errors + utils::hook::jump(0x140511520, sys_error_stub); + + // Hook R_SyncGpu + utils::hook::jump(0x1405E12F0, sync_gpu_stub); + + utils::hook::jump(0x140254800, init_dedicated_server); + + // delay startup commands until the initialization is done + utils::hook::call(0x1400D72D6, execute_startup_command); + + // delay console commands until the initialization is done + utils::hook::call(0x1400D808C, execute_console_command); + utils::hook::nop(0x1400D80A4, 5); + + // patch GScr_SetDynamicDvar to behave better + gscr_set_dynamic_dvar_hook.create(0x14036B600, &gscr_set_dynamic_dvar); + + utils::hook::nop(0x1404ED90E, 5); // don't load config file + utils::hook::nop(0x140403D92, 5); // ^ + utils::hook::set(0x1400DC1D0, 0xC3); // don't save config file + utils::hook::set(0x140274710, 0xC3); // disable self-registration + utils::hook::set(0x140515890, 0xC3); // init sound system (1) + utils::hook::set(0x1406574F0, 0xC3); // init sound system (2) + utils::hook::set(0x140620D10, 0xC3); // render thread + utils::hook::set(0x14025B850, 0xC3); // called from Com_Frame, seems to do renderer stuff + utils::hook::set(0x1402507B0, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly + utils::hook::set(0x1405D5178, 0x00); // r_loadForRenderer default to 0 + utils::hook::set(0x14050C2D0, 0xC3); // recommended settings check - TODO: Check hook + utils::hook::set(0x140514C00, 0xC3); // some mixer-related function called on shutdown + utils::hook::set(0x140409830, 0xC3); // dont load ui gametype stuff + + utils::hook::nop(0x140481B06, 6); // unknown check in SV_ExecuteClientMessage + utils::hook::nop(0x140480FAC, 4); // allow first slot to be occupied + utils::hook::nop(0x14025619B, 2); // properly shut down dedicated servers + utils::hook::nop(0x14025615E, 2); // ^ + utils::hook::nop(0x1402561C0, 5); // don't shutdown renderer + + utils::hook::set(0x140091840, 0xC3); // something to do with blendShapeVertsView + utils::hook::nop(0x140659A0D, 8); // sound thing + + // (COULD NOT FIND IN H1) + // utils::hook::set(0x1404D6960, 0xC3); // cpu detection stuff? + utils::hook::set(0x1405E97F0, 0xC3); // gfx stuff during fastfile loading + utils::hook::set(0x1405E9700, 0xC3); // ^ + utils::hook::set(0x1405E9790, 0xC3); // ^ + utils::hook::set(0x1402C1180, 0xC3); // ^ + utils::hook::set(0x1405E9750, 0xC3); // ^ + utils::hook::set(0x1405AD5B0, 0xC3); // directx stuff + utils::hook::set(0x1405DB150, 0xC3); // ^ + utils::hook::set(0x140625220, 0xC3); // ^ - mutex + utils::hook::set(0x1405DB650, 0xC3); // ^ + + utils::hook::set(0x14008B5F0, 0xC3); // rendering stuff + utils::hook::set(0x1405DB8B0, 0xC3); // ^ + utils::hook::set(0x1405DB9C0, 0xC3); // ^ + utils::hook::set(0x1405DC050, 0xC3); // ^ + utils::hook::set(0x1405DCBA0, 0xC3); // ^ + utils::hook::set(0x1405DD240, 0xC3); // ^ + + // shaders + utils::hook::set(0x1400916A0, 0xC3); // ^ + utils::hook::set(0x140091610, 0xC3); // ^ + utils::hook::set(0x14061ACC0, 0xC3); // ^ - mutex + + utils::hook::set(0x140516080, 0xC3); // idk + utils::hook::set(0x1405AE5F0, 0xC3); // ^ + + utils::hook::set(0x1405E0B30, 0xC3); // R_Shutdown + utils::hook::set(0x1405AE400, 0xC3); // shutdown stuff + utils::hook::set(0x1405E0C00, 0xC3); // ^ + utils::hook::set(0x1405DFE50, 0xC3); // ^ + + // utils::hook::set(0x1404B67E0, 0xC3); // sound crashes (H1 - questionable, function looks way different) + + utils::hook::set(0x14048B660, 0xC3); // disable host migration + + utils::hook::set(0x14042B2E0, 0xC3); // render synchronization lock + utils::hook::set(0x14042B210, 0xC3); // render synchronization unlock + + utils::hook::set(0x140176D2D, 0xEB); // LUI: Unable to start the LUI system due to errors in main.lua + + utils::hook::nop(0x140506ECE, 5); // Disable sound pak file loading + utils::hook::nop(0x140506ED6, 2); // ^ + utils::hook::set(0x1402C5910, 0xC3); // Disable image pak file loading + + // Reduce min required memory + utils::hook::set(0x14050C717, 0x80000000); + + utils::hook::set(0x1402BF7F0, 0xC3); // some loop + utils::hook::set(0x14007E150, 0xC3); // related to shader caching / techsets / fastfiles + + // initialize the game after onlinedataflags is 32 (workaround) + scheduler::schedule([=]() + { + if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2()) + { + scheduler::once([]() + { + command::execute("xstartprivateparty", true); + command::execute("disconnect", true); // 32 -> 0 + }, scheduler::pipeline::main, 1s); + return scheduler::cond_end; + } + + return scheduler::cond_continue; + }, scheduler::pipeline::main, 1s); + + scheduler::on_game_initialized([]() + { + initialize(); + + console::info("==================================\n"); + console::info("Server started!\n"); + console::info("==================================\n"); + + // remove disconnect command + game::Cmd_RemoveCommand("disconnect"); + + execute_startup_command_queue(); + execute_console_command_queue(); + + // Send heartbeat to dpmaster + scheduler::once(send_heartbeat, scheduler::pipeline::server); + scheduler::loop(send_heartbeat, scheduler::pipeline::server, 10min); + command::add("heartbeat", send_heartbeat); + }, scheduler::pipeline::main, 1s); + + command::add("killserver", kill_server); + com_quit_f_hook.create(0x1400DA640, &kill_server); + } + }; +} + +REGISTER_COMPONENT(dedicated::component) \ No newline at end of file diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp new file mode 100644 index 00000000..55973193 --- /dev/null +++ b/src/client/component/dedicated_info.cpp @@ -0,0 +1,65 @@ +#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::loop([]() + { + auto* sv_running = game::Dvar_FindVar("sv_running"); + if (!sv_running || !sv_running->current.enabled) + { + console::set_title("H1-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 bot_count = 0; + auto client_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 >= 1 && self && self->client) + { + client_count++; + if (game::SV_BotIsBot(i)) + { + ++bot_count; + } + } + } + + std::string cleaned_hostname; + cleaned_hostname.resize(static_cast(strlen(sv_hostname->current.string) + 1)); + + utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(), + static_cast(strlen(sv_hostname->current.string)) + 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) \ No newline at end of file diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp new file mode 100644 index 00000000..4cb3362c --- /dev/null +++ b/src/client/component/demonware.cpp @@ -0,0 +1,604 @@ +#include +#include "loader/component_loader.hpp" + +#include +#include + +#include "game/game.hpp" +#include "game/demonware/servers/lobby_server.hpp" +#include "game/demonware/servers/auth3_server.hpp" +#include "game/demonware/servers/stun_server.hpp" +#include "game/demonware/servers/umbrella_server.hpp" +#include "game/demonware/server_registry.hpp" +#include + +#define TCP_BLOCKING true +#define UDP_BLOCKING false + +namespace demonware +{ + namespace + { + volatile bool exit_server; + std::thread server_thread; + utils::concurrency::container> blocking_sockets; + utils::concurrency::container> socket_map; + server_registry tcp_servers; + server_registry udp_servers; + + tcp_server* find_server(const SOCKET socket) + { + return socket_map.access([&](const std::unordered_map& map) -> tcp_server* + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return nullptr; + } + + return entry->second; + }); + } + + bool socket_link(const SOCKET socket, const uint32_t address) + { + auto* server = tcp_servers.find(address); + if (!server) + { + return false; + } + + socket_map.access([&](std::unordered_map& map) + { + map[socket] = server; + }); + + return true; + } + + void socket_unlink(const SOCKET socket) + { + socket_map.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry != map.end()) + { + map.erase(entry); + } + }); + } + + bool is_socket_blocking(const SOCKET socket, const bool def) + { + return blocking_sockets.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry == map.end()) + { + return def; + } + + return entry->second; + }); + } + + void remove_blocking_socket(const SOCKET socket) + { + blocking_sockets.access([&](std::unordered_map& map) + { + const auto entry = map.find(socket); + if (entry != map.end()) + { + map.erase(entry); + } + }); + } + + void add_blocking_socket(const SOCKET socket, const bool block) + { + blocking_sockets.access([&](std::unordered_map& map) + { + map[socket] = block; + }); + } + + void server_main() + { + exit_server = false; + + while (!exit_server) + { + tcp_servers.frame(); + udp_servers.frame(); + std::this_thread::sleep_for(50ms); + } + } + + namespace io + { + int getaddrinfo_stub(const char* name, const char* service, + const addrinfo* hints, addrinfo** res) + { +#ifdef DEBUG + printf("[ network ]: [getaddrinfo]: \"%s\" \"%s\"\n", name, service); +#endif + + base_server* server = tcp_servers.find(name); + if (!server) + { + server = udp_servers.find(name); + } + + if (!server) + { + return getaddrinfo(name, service, hints, res); + } + + const auto address = utils::memory::get_allocator()->allocate(); + const auto ai = utils::memory::get_allocator()->allocate(); + + auto in_addr = reinterpret_cast(address); + in_addr->sin_addr.s_addr = server->get_address(); + in_addr->sin_family = AF_INET; + + ai->ai_family = AF_INET; + ai->ai_socktype = SOCK_STREAM; + ai->ai_addr = address; + ai->ai_addrlen = sizeof(sockaddr); + ai->ai_next = nullptr; + ai->ai_flags = 0; + ai->ai_protocol = 0; + ai->ai_canonname = const_cast(name); + + *res = ai; + + return 0; + } + + void freeaddrinfo_stub(addrinfo* ai) + { + if (!utils::memory::get_allocator()->find(ai)) + { + return freeaddrinfo(ai); + } + + utils::memory::get_allocator()->free(ai->ai_addr); + utils::memory::get_allocator()->free(ai); + } + + int getpeername_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen) + { + auto* server = find_server(s); + + if (server) + { + auto in_addr = reinterpret_cast(addr); + in_addr->sin_addr.s_addr = server->get_address(); + in_addr->sin_family = AF_INET; + *addrlen = sizeof(sockaddr); + + return 0; + } + + return getpeername(s, addr, addrlen); + } + + int getsockname_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen) + { + auto* server = find_server(s); + + if (server) + { + auto in_addr = reinterpret_cast(addr); + in_addr->sin_addr.s_addr = server->get_address(); + in_addr->sin_family = AF_INET; + *addrlen = sizeof(sockaddr); + + return 0; + } + + return getsockname(s, addr, addrlen); + } + + hostent* gethostbyname_stub(const char* name) + { +#ifdef DEBUG + printf("[ network ]: [gethostbyname]: \"%s\"\n", name); +#endif + + base_server* server = tcp_servers.find(name); + if (!server) + { + server = udp_servers.find(name); + } + + if (!server) + { +#pragma warning(push) +#pragma warning(disable: 4996) + return gethostbyname(name); +#pragma warning(pop) + } + + static thread_local in_addr address{}; + address.s_addr = server->get_address(); + + static thread_local in_addr* addr_list[2]{}; + addr_list[0] = &address; + addr_list[1] = nullptr; + + static thread_local hostent host{}; + host.h_name = const_cast(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; + } + + int connect_stub(const SOCKET s, const struct sockaddr* addr, const int len) + { + if (len == sizeof(sockaddr_in)) + { + const auto* in_addr = reinterpret_cast(addr); + if (socket_link(s, in_addr->sin_addr.s_addr)) return 0; + } + + return connect(s, addr, len); + } + + int closesocket_stub(const SOCKET s) + { + remove_blocking_socket(s); + socket_unlink(s); + + return closesocket(s); + } + + int send_stub(const SOCKET s, const char* buf, const int len, const int flags) + { + auto* server = find_server(s); + + if (server) + { + server->handle_input(buf, len); + return len; + } + + return send(s, buf, len, flags); + } + + int recv_stub(const SOCKET s, char* buf, const int len, const int flags) + { + auto* server = find_server(s); + + if (server) + { + if (server->pending_data()) + { + return static_cast(server->handle_output(buf, len)); + } + else + { + WSASetLastError(WSAEWOULDBLOCK); + return -1; + } + } + + return recv(s, buf, len, flags); + } + + int sendto_stub(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to, + const int tolen) + { + const auto* in_addr = reinterpret_cast(to); + auto* server = udp_servers.find(in_addr->sin_addr.s_addr); + + if (server) + { + server->handle_input(buf, len, {s, to, tolen}); + return len; + } + + return sendto(s, buf, len, flags, to, tolen); + } + + int recvfrom_stub(const SOCKET s, char* buf, const int len, const int flags, struct sockaddr* from, + int* fromlen) + { + // Not supported yet + if (is_socket_blocking(s, UDP_BLOCKING)) + { + return recvfrom(s, buf, len, flags, from, fromlen); + } + + size_t result = 0; + udp_servers.for_each([&](udp_server& server) + { + if (server.pending_data(s)) + { + result = server.handle_output( + s, buf, static_cast(len), from, fromlen); + } + }); + + if (result) + { + return static_cast(result); + } + + return recvfrom(s, buf, len, flags, from, fromlen); + } + + int select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, + struct timeval* timeout) + { + if (exit_server) + { + return select(nfds, readfds, writefds, exceptfds, timeout); + } + + auto result = 0; + std::vector read_sockets; + std::vector write_sockets; + + socket_map.access([&](std::unordered_map& sockets) + { + for (auto& s : sockets) + { + if (readfds) + { + if (FD_ISSET(s.first, readfds)) + { + if (s.second->pending_data()) + { + read_sockets.push_back(s.first); + FD_CLR(s.first, readfds); + } + } + } + + if (writefds) + { + if (FD_ISSET(s.first, writefds)) + { + write_sockets.push_back(s.first); + FD_CLR(s.first, writefds); + } + } + + if (exceptfds) + { + if (FD_ISSET(s.first, exceptfds)) + { + FD_CLR(s.first, exceptfds); + } + } + } + }); + + if ((!readfds || readfds->fd_count == 0) && (!writefds || writefds->fd_count == 0)) + { + timeout->tv_sec = 0; + timeout->tv_usec = 0; + } + + result = select(nfds, readfds, writefds, exceptfds, timeout); + if (result < 0) result = 0; + + for (const auto& socket : read_sockets) + { + if (readfds) + { + FD_SET(socket, readfds); + result++; + } + } + + for (const auto& socket : write_sockets) + { + if (writefds) + { + FD_SET(socket, writefds); + result++; + } + } + + return result; + } + + int ioctlsocket_stub(const SOCKET s, const long cmd, u_long* argp) + { + if (static_cast(cmd) == (FIONBIO)) + { + add_blocking_socket(s, *argp == 0); + } + + return ioctlsocket(s, cmd, argp); + } + + BOOL internet_get_connected_state_stub(LPDWORD, DWORD) + { + // Allow offline play + return TRUE; + } + } + + void bd_logger_stub(char* a1, void* a2, void* a3, void* a4, const char* function, ...) + { + + } + +#ifdef DEBUG + void a(unsigned int n) + { + printf("bdAuth: Auth task failed with HTTP code [%u]\n", n); + } + + void b(unsigned int n) + { + printf("bdAuth: Decoded client ticket of unexpected size [%u]\n", n); + } + + void c(unsigned int n) + { + printf("bdAuth: Decoded server ticket of unexpected size [%u]\n", n); + } + + void d() + { + printf("bdAuth: Auth ticket magic number mismatch\n"); + } + + void e() + { + printf("bdAuth: Cross Authentication completed\n"); + } + + void f() + { + printf("bdAuth: Auth task reply contains invalid data / format\n"); + } + + void g(unsigned int n) + { + printf("bdAuth: Auth task returned with error code [%u]\n", n); + } + + void h(unsigned int n) + { + printf("bdAuth: Invalid or No Task ID [%u] in Auth reply\n", n); + } + + void i() + { + printf("bdAuth: Received reply from DemonWare Auth server\n"); + } + + void l() + { + printf("bdAuth: Unknown error\n"); + } +#endif + } + + class component final : public component_interface + { + public: + component() + { + udp_servers.create("phoenix.stun.us.demonware.net"); + udp_servers.create("phoenix.stun.eu.demonware.net"); + udp_servers.create("phoenix.stun.jp.demonware.net"); + udp_servers.create("phoenix.stun.au.demonware.net"); + + udp_servers.create("stun.us.demonware.net"); + udp_servers.create("stun.eu.demonware.net"); + udp_servers.create("stun.jp.demonware.net"); + udp_servers.create("stun.au.demonware.net"); + + tcp_servers.create("mwr-pc-steam-auth3.prod.demonware.net"); + tcp_servers.create("mwr-pc-steam-lobby.prod.demonware.net"); + tcp_servers.create("prod.umbrella.demonware.net"); + } + + void post_load() override + { + server_thread = utils::thread::create_named_thread("Demonware", server_main); + } + + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "WS2_32.dll") + { + if (function == "#3") return io::closesocket_stub; + if (function == "#4") return io::connect_stub; + if (function == "#5") return io::getpeername_stub; + if (function == "#6") return io::getsockname_stub; + if (function == "#10") return io::ioctlsocket_stub; + if (function == "#16") return io::recv_stub; + if (function == "#17") return io::recvfrom_stub; + if (function == "#18") return io::select_stub; + if (function == "#19") return io::send_stub; + if (function == "#20") return io::sendto_stub; + if (function == "#52") return io::gethostbyname_stub; + if (function == "getaddrinfo") return io::getaddrinfo_stub; + if (function == "freeaddrinfo") return io::freeaddrinfo_stub; + } + + if (function == "InternetGetConnectedState") + { + return io::internet_get_connected_state_stub; + } + + return nullptr; + } + + void post_unpack() override + { + /* + mwr has upgraded some networking methods and the gethostbyname import from winsock library is no longer used + gethostbyname has been replaced with getaddrinfo + btw, still you can't get online.. + */ + utils::hook::jump(SELECT_VALUE(0x140610320, 0x1407400B0), bd_logger_stub); // H1MP64(1.4) + + if (game::environment::is_sp()) + { + utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) + utils::hook::set(0x140333A00, 0xC3); // dwNet H1(1.4) + return; + } + + utils::hook::set(0x140715039, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.4) + utils::hook::set(0x140715025, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.4) + utils::hook::set(0x14095433C, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] + + //HTTPS -> HTTP + utils::hook::inject(0x14006DDA9, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003852E] + utils::hook::inject(0x14006E11C, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003884F] + utils::hook::inject(0x14006E2FB, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x140038A07] + utils::hook::inject(0x14006E9A9, "http://prod.uno.demonware.net/v1.0/"); + utils::hook::inject(0x14006ED49, "http://prod.uno.demonware.net/v1.0/"); + utils::hook::inject(0x140728170, "http://%s:%d/auth/"); + + utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) + utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) + +#ifdef DEBUG + // yes + utils::hook::call(0x140727BEB, l); + utils::hook::call(0x140727AFC, i); + utils::hook::call(0x140727E49, h); + utils::hook::call(0x140727E30, g); + utils::hook::call(0x140727E37, f); + utils::hook::call(0x140727DF2, e); + utils::hook::call(0x140727DF9, d); + utils::hook::call(0x140727CFC, c); + utils::hook::call(0x140727C82, b); + utils::hook::call(0x140727E6A, a); +#endif + // Checks X-Signature header or something + utils::hook::set(0x140728380, 0xC301B0); + // Checks extended_data and extra_data in json object + utils::hook::set(0x140728E90, 0xC301B0); + // Update check + utils::hook::set(0x1403A5390, 0xC301B0); + + // Remove some while loop in demonware that freezes the rendering for a few secs at launch + utils::hook::nop(0x14057DBC5, 5); + } + + void pre_destroy() override + { + exit_server = true; + if (server_thread.joinable()) + { + server_thread.join(); + } + } + }; +} + +REGISTER_COMPONENT(demonware::component) diff --git a/src/client/component/demonware.hpp b/src/client/component/demonware.hpp new file mode 100644 index 00000000..d26d1ccd --- /dev/null +++ b/src/client/component/demonware.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace demonware +{ + +} \ No newline at end of file diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp new file mode 100644 index 00000000..5925a64a --- /dev/null +++ b/src/client/component/discord.cpp @@ -0,0 +1,148 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" +#include "game/game.hpp" + +#include "console.hpp" +#include "command.hpp" +#include "network.hpp" +#include "party.hpp" + +#include + +#include + +namespace discord +{ + namespace + { + DiscordRichPresence discord_presence; + + void update_discord() + { + Discord_RunCallbacks(); + + if (!game::CL_IsCgameInitialized() || game::VirtualLobby_Loaded()) + { + discord_presence.details = game::environment::is_sp() ? "Singleplayer" : "Multiplayer"; + discord_presence.state = "Main Menu"; + + auto firingRangeDvar = game::Dvar_FindVar("virtualLobbyInFiringRange"); + if (firingRangeDvar && firingRangeDvar->current.enabled == 1) + { + discord_presence.state = "Firing Range"; + } + + discord_presence.partySize = 0; + discord_presence.partyMax = 0; + discord_presence.startTimestamp = 0; + discord_presence.largeImageKey = game::environment::is_sp() ? "menu_singleplayer" : "menu_multiplayer"; + } + else + { + const auto map = game::Dvar_FindVar("mapname")->current.string; + const auto mapname = game::UI_SafeTranslateString(utils::string::va("PRESENCE_%s%s", (game::environment::is_sp() ? "SP_" : ""), map)); + + if (game::environment::is_mp()) + { + const auto gametype = game::UI_GetGameTypeDisplayName(game::Dvar_FindVar("g_gametype")->current.string); + + discord_presence.details = utils::string::va("%s on %s", gametype, mapname); + + char clean_hostname[0x100] = {0}; + utils::string::strip(game::Dvar_FindVar("sv_hostname")->current.string, + clean_hostname, sizeof(clean_hostname)); + auto max_clients = party::server_client_count(); + + // When true, we are in Private Match + if (game::SV_Loaded()) + { + strcpy_s(clean_hostname, "Private Match"); + max_clients = game::Dvar_FindVar("sv_maxclients")->current.integer; + } + + discord_presence.partySize = *reinterpret_cast(0x1429864C4); + discord_presence.partyMax = max_clients; + discord_presence.state = clean_hostname; + discord_presence.largeImageKey = map; + } + else if (game::environment::is_sp()) + { + discord_presence.state = ""; + discord_presence.largeImageKey = map; + discord_presence.details = mapname; + } + + if (!discord_presence.startTimestamp) + { + discord_presence.startTimestamp = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); + } + } + + 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 = nullptr; + handlers.spectateGame = nullptr; + handlers.joinRequest = nullptr; + + Discord_Initialize("947125042930667530", &handlers, 1, nullptr); + + scheduler::once([]() + { + scheduler::once(update_discord, scheduler::pipeline::async); + scheduler::loop(update_discord, scheduler::pipeline::async, 5s); + }, scheduler::pipeline::main); + + initialized_ = true; + } + + void pre_destroy() override + { + if (!initialized_ || game::environment::is_dedi()) + { + return; + } + + Discord_Shutdown(); + } + + private: + bool initialized_ = false; + + static void ready(const DiscordUser* /*request*/) + { + ZeroMemory(&discord_presence, sizeof(discord_presence)); + + discord_presence.instance = 1; + + console::info("Discord: Ready\n"); + + Discord_UpdatePresence(&discord_presence); + } + + static void errored(const int error_code, const char* message) + { + console::error("Discord: Error (%i): %s\n", error_code, message); + } + }; +} + +REGISTER_COMPONENT(discord::component) \ No newline at end of file diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp new file mode 100644 index 00000000..d9c77fdf --- /dev/null +++ b/src/client/component/dvars.cpp @@ -0,0 +1,443 @@ +#include +#include "loader/component_loader.hpp" +#include "dvars.hpp" + +#include "game/game.hpp" + +#include + +namespace dvars +{ + struct dvar_base + { + unsigned int flags{}; + }; + + struct dvar_bool : dvar_base + { + bool value{}; + }; + + struct dvar_float : dvar_base + { + float value{}; + float min{}; + float max{}; + }; + + struct dvar_vector2 : dvar_base + { + float x{}; + float y{}; + float min{}; + float max{}; + }; + + struct dvar_vector3 : dvar_base + { + + float x{}; + float y{}; + float z{}; + float min{}; + float max{}; + }; + + struct dvar_int : dvar_base + { + int value{}; + int min{}; + int max{}; + }; + + struct dvar_string : dvar_base + { + std::string value{}; + }; + + namespace + { + 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; + } + + template + T* find_dvar(std::unordered_map& map, const int hash) + { + for (auto i = map.begin(); i != map.end(); ++i) + { + if (game::generateHashValue(i->first.data()) == hash) + { + return &i->second; + } + } + + return nullptr; + } + + bool find_dvar(std::unordered_set& set, const std::string& name) + { + return set.find(name) != set.end(); + } + + + bool find_dvar(std::unordered_set& set, const int hash) + { + for (auto i = set.begin(); i != set.end(); ++i) + { + if (game::generateHashValue(i->data()) == hash) + { + return true; + } + } + + return false; + } + } + + namespace disable + { + static std::unordered_set set_bool_disables; + static std::unordered_set set_float_disables; + static std::unordered_set set_int_disables; + static std::unordered_set set_string_disables; + + void set_bool(const std::string& name) + { + set_bool_disables.emplace(name); + } + + void set_float(const std::string& name) + { + set_float_disables.emplace(name); + } + + void set_int(const std::string& name) + { + set_int_disables.emplace(name); + } + + void set_string(const std::string& name) + { + set_string_disables.emplace(name); + } + } + + namespace override + { + static std::unordered_map register_bool_overrides; + static std::unordered_map register_float_overrides; + static std::unordered_map register_int_overrides; + static std::unordered_map register_string_overrides; + static std::unordered_map register_vector2_overrides; + static std::unordered_map register_vector3_overrides; + + static std::unordered_map set_bool_overrides; + static std::unordered_map set_float_overrides; + static std::unordered_map set_int_overrides; + static std::unordered_map set_string_overrides; + static std::unordered_map set_from_string_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] = std::move(values); + } + + void register_float(const std::string& name, const float value, const float min, const float max, + const unsigned int flags) + { + dvar_float values; + values.value = value; + values.min = min; + values.max = max; + values.flags = flags; + register_float_overrides[name] = std::move(values); + } + + void register_int(const std::string& name, const int value, const int min, const int max, + const unsigned int flags) + { + dvar_int values; + values.value = value; + values.min = min; + values.max = max; + values.flags = flags; + register_int_overrides[name] = std::move(values); + } + + void register_string(const std::string& name, const std::string& value, + const unsigned int flags) + { + dvar_string values; + values.value = value; + values.flags = flags; + register_string_overrides[name] = std::move(values); + } + + void register_vec2(const std::string& name, float x, float y, float min, float max, + const unsigned int flags) + { + dvar_vector2 values; + values.x = x; + values.y = y; + values.min = min; + values.max = max; + values.flags = flags; + register_vector2_overrides[name] = std::move(values); + } + + void register_vec3(const std::string& name, float x, float y, float z, float min, + float max, const unsigned int flags) + { + dvar_vector3 values; + values.x = x; + values.y = y; + values.z = z; + values.min = min; + values.max = max; + values.flags = flags; + register_vector3_overrides[name] = std::move(values); + } + + void set_bool(const std::string& name, const bool value) + { + set_bool_overrides[name] = value; + } + + void set_float(const std::string& name, const float value) + { + set_float_overrides[name] = value; + } + + void set_int(const std::string& name, const int value) + { + set_int_overrides[name] = value; + } + + void set_string(const std::string& name, const std::string& value) + { + set_string_overrides[name] = value; + } + + void set_from_string(const std::string& name, const std::string& value) + { + set_from_string_overrides[name] = value; + } + } + + utils::hook::detour dvar_register_bool_hook; + utils::hook::detour dvar_register_float_hook; + utils::hook::detour dvar_register_int_hook; + utils::hook::detour dvar_register_string_hook; + utils::hook::detour dvar_register_vector2_hook; + utils::hook::detour dvar_register_vector3_hook; + + utils::hook::detour dvar_set_bool_hook; + utils::hook::detour dvar_set_float_hook; + utils::hook::detour dvar_set_int_hook; + utils::hook::detour dvar_set_string_hook; + utils::hook::detour dvar_set_from_string_hook; + + game::dvar_t* dvar_register_bool(const int hash, const char* name, bool value, unsigned int flags) + { + auto* var = find_dvar(override::register_bool_overrides, hash); + if (var) + { + value = var->value; + flags = var->flags; + } + + return dvar_register_bool_hook.invoke(hash, name, value, flags); + } + + game::dvar_t* dvar_register_float(const int hash, const char* name, float value, float min, float max, unsigned int flags) + { + auto* var = find_dvar(override::register_float_overrides, hash); + if (var) + { + value = var->value; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_float_hook.invoke(hash, name, value, min, max, flags); + } + + game::dvar_t* dvar_register_int(const int hash, const char* name, int value, int min, int max, unsigned int flags) + { + auto* var = find_dvar(override::register_int_overrides, hash); + if (var) + { + value = var->value; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_int_hook.invoke(hash, name, value, min, max, flags); + } + + game::dvar_t* dvar_register_string(const int hash, const char* name, const char* value, unsigned int flags) + { + auto* var = find_dvar(override::register_string_overrides, hash); + if (var) + { + value = var->value.data(); + flags = var->flags; + } + + return dvar_register_string_hook.invoke(hash, name, value, flags); + } + + game::dvar_t* dvar_register_vector2(const int hash, const char* name, float x, float y, float min, float max, + unsigned int flags) + { + auto* var = find_dvar(override::register_vector2_overrides, hash); + if (var) + { + x = var->x; + y = var->y; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_vector2_hook.invoke(hash, name, x, y, min, max, flags); + } + + game::dvar_t* dvar_register_vector3(const int hash, const char* name, float x, float y, float z, float min, + float max, unsigned int flags) + { + auto* var = find_dvar(override::register_vector3_overrides, hash); + if (var) + { + x = var->x; + y = var->y; + z = var->z; + min = var->min; + max = var->max; + flags = var->flags; + } + + return dvar_register_vector3_hook.invoke(hash, name, x, y, z, min, max, flags); + } + + void dvar_set_bool(game::dvar_t* dvar, bool boolean) + { + const auto disabled = find_dvar(disable::set_bool_disables, dvar->hash); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_bool_overrides, dvar->hash); + if (var) + { + boolean = *var; + } + + return dvar_set_bool_hook.invoke(dvar, boolean); + } + + void dvar_set_float(game::dvar_t* dvar, float fl) + { + const auto disabled = find_dvar(disable::set_float_disables, dvar->hash); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_float_overrides, dvar->hash); + if (var) + { + fl = *var; + } + + return dvar_set_float_hook.invoke(dvar, fl); + } + + void dvar_set_int(game::dvar_t* dvar, int integer) + { + const auto disabled = find_dvar(disable::set_int_disables, dvar->hash); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_int_overrides, dvar->hash); + if (var) + { + integer = *var; + } + + return dvar_set_int_hook.invoke(dvar, integer); + } + + void dvar_set_string(game::dvar_t* dvar, const char* string) + { + const auto disabled = find_dvar(disable::set_string_disables, dvar->hash); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_string_overrides, dvar->hash); + if (var) + { + string = var->data(); + } + + return dvar_set_string_hook.invoke(dvar, string); + } + + void dvar_set_from_string(game::dvar_t* dvar, const char* string, game::DvarSetSource source) + { + const auto disabled = find_dvar(disable::set_string_disables, dvar->hash); + if (disabled) + { + return; + } + + auto* var = find_dvar(override::set_from_string_overrides, dvar->hash); + if (var) + { + string = var->data(); + } + + return dvar_set_from_string_hook.invoke(dvar, string, source); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + dvar_register_bool_hook.create(SELECT_VALUE(0x1403C47E0, 0x1404FA540), &dvar_register_bool); + dvar_register_float_hook.create(SELECT_VALUE(0x1403C4BB0, 0x1404FA910), &dvar_register_float); + dvar_register_int_hook.create(SELECT_VALUE(0x1403C4CC0, 0x1404FAA20), &dvar_register_int); + dvar_register_string_hook.create(SELECT_VALUE(0x1403C4DA0, 0x1404FAB00), &dvar_register_string); + dvar_register_vector2_hook.create(SELECT_VALUE(0x1403C4E80, 0x1404FABE0), &dvar_register_vector2); + dvar_register_vector3_hook.create(SELECT_VALUE(0x1403C4FC0, 0x1404FACE0), &dvar_register_vector3); + + dvar_set_bool_hook.create(SELECT_VALUE(0x1403C7020, 0x1404FCDF0), &dvar_set_bool); + dvar_set_float_hook.create(SELECT_VALUE(0x1403C7420, 0x1404FD360), &dvar_set_float); + dvar_set_int_hook.create(SELECT_VALUE(0x1403C76C0, 0x1404FD5E0), &dvar_set_int); + dvar_set_string_hook.create(SELECT_VALUE(0x1403C7900, 0x1404FD8D0), &dvar_set_string); + dvar_set_from_string_hook.create(SELECT_VALUE(0x1403C7620, 0x1404FD520), &dvar_set_from_string); + } + }; +} + +REGISTER_COMPONENT(dvars::component) diff --git a/src/client/component/dvars.hpp b/src/client/component/dvars.hpp new file mode 100644 index 00000000..66d6912d --- /dev/null +++ b/src/client/component/dvars.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace dvars +{ + namespace disable + { + void set_bool(const std::string& name); + void set_float(const std::string& name); + void set_int(const std::string& name); + void set_string(const std::string& name); + } + + namespace override + { + void register_bool(const std::string& name, bool value, const unsigned int flags); + void register_float(const std::string& name, float value, float min, float max, const unsigned int flags); + void register_int(const std::string& name, int value, int min, int max, const unsigned int flags); + void register_string(const std::string& name, const std::string& value, const unsigned int flags); + void register_vec2(const std::string& name, float x, float y, float min, float max, const unsigned int flags); + void register_vec3(const std::string& name, float x, float y, float z, float min, float max, const unsigned int flags); + + void set_bool(const std::string& name, bool boolean); + void set_float(const std::string& name, float fl); + void set_int(const std::string& name, int integer); + void set_string(const std::string& name, const std::string& string); + void set_from_string(const std::string& name, const std::string& value); + } +} diff --git a/src/client/component/exception.cpp b/src/client/component/exception.cpp new file mode 100644 index 00000000..028bb238 --- /dev/null +++ b/src/client/component/exception.cpp @@ -0,0 +1,261 @@ +#include +#include "loader/component_loader.hpp" +#include "system_check.hpp" +#include "scheduler.hpp" + +#include "game/game.hpp" + +#include +#include +#include +#include +#include + +#include + +#include + +#include "game/dvars.hpp" + +namespace exception +{ + namespace + { + thread_local struct + { + DWORD code = 0; + PVOID address = nullptr; + } exception_data; + + struct + { + std::chrono::time_point last_recovery{}; + std::atomic recovery_counts = {0}; + } recovery_data; + + bool is_game_thread() + { + static std::vector allowed_threads = + { + game::THREAD_CONTEXT_MAIN, + }; + + const auto self_id = GetCurrentThreadId(); + for (const auto& index : allowed_threads) + { + if (game::threadIds[index] == self_id) + { + return true; + } + } + + return false; + } + + bool is_exception_interval_too_short() + { + const auto delta = std::chrono::high_resolution_clock::now() - recovery_data.last_recovery; + return delta < 1min; + } + + bool too_many_exceptions_occured() + { + return recovery_data.recovery_counts >= 3; + } + + volatile bool& is_initialized() + { + static volatile bool initialized = false; + return initialized; + } + + bool is_recoverable() + { + return is_initialized() + && is_game_thread() + && !is_exception_interval_too_short() + && !too_many_exceptions_occured(); + } + + void show_mouse_cursor() + { + while (ShowCursor(TRUE) < 0); + } + + void display_error_dialog() + { + std::string error_str = utils::string::va("Fatal error (0x%08X) at 0x%p.\n" + "A minidump has been written.\n\n", + exception_data.code, exception_data.address); + + if (!system_check::is_valid()) + { + error_str += "Make sure to get supported game files to avoid such crashes!"; + } + else + { + error_str += "Make sure to update your graphics card drivers and install operating system updates!"; + } + + utils::thread::suspend_other_threads(); + show_mouse_cursor(); + + MessageBoxA(nullptr, error_str.data(), "H1-Mod ERROR", MB_ICONERROR); + TerminateProcess(GetCurrentProcess(), exception_data.code); + } + + void reset_state() + { + if (dvars::cg_legacyCrashHandling && dvars::cg_legacyCrashHandling->current.enabled) + { + display_error_dialog(); + } + + // TODO: Add a limit for dedi restarts + if (game::environment::is_dedi()) + { + utils::nt::relaunch_self(); + utils::nt::terminate(exception_data.code); + } + + if (is_recoverable()) + { + recovery_data.last_recovery = std::chrono::high_resolution_clock::now(); + ++recovery_data.recovery_counts; + + game::Com_Error(game::ERR_DROP, "Fatal error (0x%08X) at 0x%p.\nA minidump has been written.\n\n" + "H1-Mod has tried to recover your game, but it might not run stable anymore.\n\n" + "Make sure to update your graphics card drivers and install operating system updates!\n" + "Closing or restarting Steam might also help.", + exception_data.code, exception_data.address); + } + else + { + display_error_dialog(); + } + } + + size_t get_reset_state_stub() + { + static auto* stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.sub(rsp, 0x10); + a.or_(rsp, 0x8); + a.jmp(reset_state); + }); + + return reinterpret_cast(stub); + } + + std::string get_timestamp() + { + tm ltime{}; + char timestamp[MAX_PATH] = {0}; + const auto time = _time64(nullptr); + + _localtime64_s(<ime, &time); + strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d-%H-%M-%S", <ime); + + return timestamp; + } + + std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo) + { + std::string info{}; + const auto line = [&info](const std::string& text) + { + info.append(text); + info.append("\r\n"); + }; + + line("H1-Mod Crash Dump"); + line(""); + line("Version: "s + VERSION); + line("Environment: "s + game::environment::get_string()); + line("Timestamp: "s + get_timestamp()); + line("Clean game: "s + (system_check::is_valid() ? "Yes" : "No")); + line(utils::string::va("Exception: 0x%08X", exceptioninfo->ExceptionRecord->ExceptionCode)); + line(utils::string::va("Address: 0x%llX", exceptioninfo->ExceptionRecord->ExceptionAddress)); + +#pragma warning(push) +#pragma warning(disable: 4996) + OSVERSIONINFOEXA version_info; + ZeroMemory(&version_info, sizeof(version_info)); + version_info.dwOSVersionInfoSize = sizeof(version_info); + GetVersionExA(reinterpret_cast(&version_info)); +#pragma warning(pop) + + line(utils::string::va("OS Version: %u.%u", version_info.dwMajorVersion, version_info.dwMinorVersion)); + + return info; + } + + void write_minidump(const LPEXCEPTION_POINTERS exceptioninfo) + { + const std::string crash_name = utils::string::va("minidumps/h1-mod-crash-%d-%s.zip", + game::environment::get_real_mode(), + get_timestamp().data()); + + utils::compression::zip::archive zip_file{}; + zip_file.add("crash.dmp", create_minidump(exceptioninfo)); + zip_file.add("info.txt", generate_crash_info(exceptioninfo)); + zip_file.write(crash_name, "H1-Mod Crash Dump"); + } + + bool is_harmless_error(const LPEXCEPTION_POINTERS exceptioninfo) + { + const auto code = exceptioninfo->ExceptionRecord->ExceptionCode; + return code == STATUS_INTEGER_OVERFLOW || code == STATUS_FLOAT_OVERFLOW || code == STATUS_SINGLE_STEP; + } + + LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS exceptioninfo) + { + if (is_harmless_error(exceptioninfo)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + + write_minidump(exceptioninfo); + + exception_data.code = exceptioninfo->ExceptionRecord->ExceptionCode; + exception_data.address = exceptioninfo->ExceptionRecord->ExceptionAddress; + exceptioninfo->ContextRecord->Rip = get_reset_state_stub(); + + return EXCEPTION_CONTINUE_EXECUTION; + } + + LPTOP_LEVEL_EXCEPTION_FILTER WINAPI set_unhandled_exception_filter_stub(LPTOP_LEVEL_EXCEPTION_FILTER) + { + // Don't register anything here... + return &exception_filter; + } + } + + class component final : public component_interface + { + public: + component() + { + SetUnhandledExceptionFilter(exception_filter); + } + + void post_load() override + { + SetUnhandledExceptionFilter(exception_filter); + utils::hook::jump(SetUnhandledExceptionFilter, set_unhandled_exception_filter_stub, true); + + scheduler::on_game_initialized([]() + { + is_initialized() = true; + }); + } + + void post_unpack() override + { + dvars::cg_legacyCrashHandling = dvars::register_bool("cg_legacyCrashHandling", + false, game::DVAR_FLAG_SAVED, true); + } + }; +} + +REGISTER_COMPONENT(exception::component) diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp new file mode 100644 index 00000000..d4eda37f --- /dev/null +++ b/src/client/component/fastfiles.cpp @@ -0,0 +1,49 @@ +#include +#include "loader/component_loader.hpp" +#include "fastfiles.hpp" + +#include "command.hpp" +#include "console.hpp" + +#include +#include + +namespace fastfiles +{ + static utils::concurrency::container current_fastfile; + + namespace + { + utils::hook::detour db_try_load_x_file_internal_hook; + + void db_try_load_x_file_internal(const char* zone_name, const int flags) + { + printf("Loading fastfile %s\n", zone_name); + current_fastfile.access([&](std::string& fastfile) + { + fastfile = zone_name; + }); + db_try_load_x_file_internal_hook.invoke(zone_name, flags); + } + } + + std::string get_current_fastfile() + { + return current_fastfile.access([&](std::string& fastfile) + { + return fastfile; + }); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + db_try_load_x_file_internal_hook.create( + SELECT_VALUE(0x1401CDDD0, 0x1402BFFE0), &db_try_load_x_file_internal); + } + }; +} + +REGISTER_COMPONENT(fastfiles::component) diff --git a/src/client/component/fastfiles.hpp b/src/client/component/fastfiles.hpp new file mode 100644 index 00000000..ac26d2ec --- /dev/null +++ b/src/client/component/fastfiles.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "game/game.hpp" + +namespace fastfiles +{ + std::string get_current_fastfile(); +} diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp new file mode 100644 index 00000000..da11d2e4 --- /dev/null +++ b/src/client/component/filesystem.cpp @@ -0,0 +1,94 @@ +#include +#include "loader/component_loader.hpp" +#include "filesystem.hpp" +#include "game_module.hpp" + +#include "game/game.hpp" +#include "dvars.hpp" + +#include +#include + +namespace filesystem +{ + namespace + { + bool custom_path_registered = false; + + 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) + { + custom_path_registered = false; + game::FS_Startup(gamename); + } + } + + 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_; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Set fs_basegame + dvars::override::register_string("fs_basegame", "h1-mod", game::DVAR_FLAG_WRITE); + + utils::hook::call(SELECT_VALUE(0x1403B76E2, 0x1404ED3E2), fs_startup_stub); + if (game::environment::is_mp()) + { + utils::hook::call(0x1404ED823, fs_startup_stub); + } + + utils::hook::call(SELECT_VALUE(0x1403B8D31, 0x1404EE3D0), register_custom_path_stub); + utils::hook::call(SELECT_VALUE(0x1403B8D51, 0x1404EE3F0), register_custom_path_stub); + utils::hook::call(SELECT_VALUE(0x1403B8D90, 0x1404EE42F), register_custom_path_stub); + } + }; +} + +REGISTER_COMPONENT(filesystem::component) \ No newline at end of file diff --git a/src/client/component/filesystem.hpp b/src/client/component/filesystem.hpp new file mode 100644 index 00000000..6cec8c87 --- /dev/null +++ b/src/client/component/filesystem.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace filesystem +{ + class file + { + public: + file(std::string name); + + bool exists() const; + const std::string& get_buffer() const; + const std::string& get_name() const; + + private: + bool valid_ = false; + std::string name_; + std::string buffer_; + }; +} \ No newline at end of file diff --git a/src/client/component/fps.cpp b/src/client/component/fps.cpp new file mode 100644 index 00000000..db471119 --- /dev/null +++ b/src/client/component/fps.cpp @@ -0,0 +1,174 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include + +namespace fps +{ + namespace + { + game::dvar_t* cg_drawfps; + game::dvar_t* cg_drawping; + + float fps_color_good[4] = {0.6f, 1.0f, 0.0f, 1.0f}; + float fps_color_ok[4] = {1.0f, 0.7f, 0.3f, 1.0f}; + float fps_color_bad[4] = {1.0f, 0.3f, 0.3f, 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{}; + + void perf_calc_fps(cg_perf_data* data, const std::int32_t value) + { + data->history[data->index % 32] = value; + data->instant = value; + data->min = 0x7FFFFFFF; + 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(0x1405487A0, 0x1406575A0)); // H1(1.4) + } + + void cg_draw_fps() + { + if (cg_drawfps->current.integer > 0) + { + const auto fps = static_cast(static_cast(1000.0f / static_cast(cg_perf. + average)) + + 9.313225746154785e-10); + + const auto font = game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25); + const auto fps_string = utils::string::va("%i", fps); + + const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 15.0f) - game::R_TextWidth( + fps_string, 0x7FFFFFFF, font); + const auto y = font->pixelHeight + 10.f; + + const auto fps_color = fps >= 60 ? fps_color_good : (fps >= 30 ? fps_color_ok : fps_color_bad); + game::R_AddCmdDrawText(fps_string, 0x7FFFFFFF, font, x, y, 1.f, 1.f, 0.0f, fps_color, 6); + } + } + + void cg_draw_ping() + { + if (cg_drawping->current.integer > 0 && game::CL_IsCgameInitialized() && !game::VirtualLobby_Loaded()) + { + const auto ping = *reinterpret_cast(0x142D106F0); + + const auto font = game::R_RegisterFont("fonts/consolefont", 20); + const auto ping_string = utils::string::va("Ping: %i", ping); + + const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 375.0f) - game::R_TextWidth( + ping_string, 0x7FFFFFFF, font); + + const auto y = font->pixelHeight + 15.f; + game::R_AddCmdDrawText(ping_string, 0x7FFFFFFF, font, x, y, 1.f, 1.f, 0.0f, ping_color, 6); + } + } + + game::dvar_t* cg_draw_fps_register_stub(const char* name, const char** _enum, const int value, unsigned int /*flags*/, + const char* desc) + { + cg_drawfps = dvars::register_int("cg_drawFps", 0, 0, 2, game::DVAR_FLAG_SAVED, false); + 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(0x14018D261, 0x14025B747), &perf_update); + + // change cg_drawfps flags to saved + utils::hook::call(SELECT_VALUE(0x140139F48, 0x140222A46), &cg_draw_fps_register_stub); + + scheduler::loop(cg_draw_fps, scheduler::pipeline::renderer); + + if (game::environment::is_sp()) + { + cg_drawfps = dvars::register_int("cg_drawFps", 0, 0, 2, game::DVAR_FLAG_SAVED, false); + } + + if (game::environment::is_mp()) + { + // fix ping value + utils::hook::nop(0x14025AC41, 2); + + cg_drawping = dvars::register_int("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, true); + + 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 00000000..cf7c3056 --- /dev/null +++ b/src/client/component/game_console.cpp @@ -0,0 +1,793 @@ +#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 "version.hpp" + +#define console_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 18) +#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_title[4] = {0.25f, 0.62f, 0.3f, 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.0f, + 1.0f, 0.0f, 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); + } + + 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 (const auto& dvar : dvars::dvar_list) + { + auto name = utils::string::to_lower(dvar); + if (game::Dvar_FindVar(name.data()) && match_compare(input, name, exact)) + { + suggestions.push_back(dvar); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + + if (suggestions.size() == 0 && game::Dvar_FindVar(input.data())) + { + suggestions.push_back(input.data()); + } + + 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; + } + } + + 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("H1-Mod: " VERSION ">", color_title); + + con.globals.left_x = con.globals.x; + con.globals.auto_complete_choice[0] = 0; + + game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, 18, con.globals.x, + con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0, 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) + { + auto* const 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(), 64); + 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++) + { + auto* const 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(), 64); + 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("H1-Mod 1.4", 0x7FFFFFFF, console_font, x, + ((height - 16.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_title, 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 local_client_num, const int key) + { + if (key == game::keyNum_t::K_GRAVE || + key == game::keyNum_t::K_TILDE || + key == '|' || + key == '\\') + { + return false; + } + + if (key > 127) + { + return true; + } + + if (*game::keyCatchers & 1) + { + if (key == game::keyNum_t::K_TAB) // tab (auto complete) + { + if (con.globals.may_auto_complete) + { + const auto first_char = con.buffer[0]; + + clear(); + + if (first_char == '\\' || first_char == '/') + { + con.buffer[0] = first_char; + 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 (size_t i = 0; i < clipboard.length(); i++) + { + console_char_event(local_client_num, 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 local_client_num, const int key, const int down) + { + if (key == game::keyNum_t::K_F10) + { + if (!game::Com_InFrontEnd()) + { + return false; + } + + game::Cmd_ExecuteSingleCommand(local_client_num, 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[local_client_num].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(), 0x100); + 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(), 0x100); + 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; + } + + + 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 + { + scheduler::loop(draw_console, scheduler::pipeline::renderer); + + + 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, "", 256); + + 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, "", 64); + + // 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 = dvars::register_vec4("con_inputBoxColor", 0.2f, 0.2f, 0.2f, 0.9f, 0.0f, 1.0f, + game::DVAR_FLAG_SAVED, + "color of console input box"); + dvars::con_inputHintBoxColor = dvars::register_vec4("con_inputHintBoxColor", 0.3f, 0.3f, 0.3f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED, "color of console input hint box"); + dvars::con_outputBarColor = dvars::register_vec4("con_outputBarColor", 0.5f, 0.5f, 0.5f, 0.6f, 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, + "color of console output bar"); + dvars::con_outputSliderColor = dvars::register_vec4("con_outputSliderColor", 1.0f, 0.8f, 0.0f, 1.0f, + 0.0f, 1.0f, + game::DVAR_FLAG_SAVED, "color of console output slider"); + dvars::con_outputWindowColor = dvars::register_vec4("con_outputWindowColor", 0.25f, 0.25f, 0.25f, 0.85f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console output window"); + dvars::con_inputDvarMatchColor = dvars::register_vec4("con_inputDvarMatchColor", 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar"); + dvars::con_inputDvarValueColor = dvars::register_vec4("con_inputDvarValueColor", 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, + 1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar value"); + dvars::con_inputDvarInactiveValueColor = dvars::register_vec4( + "con_inputDvarInactiveValueColor", 0.8f, 0.8f, + 0.8f, 1.0f, 0.0f, 1.0f, game::DVAR_FLAG_SAVED, + "color of console inactive dvar value"); + dvars::con_inputCmdMatchColor = dvars::register_vec4("con_inputCmdMatchColor", 0.80f, 0.80f, 1.0f, 1.0f, + 0.0f, + 1.0f, game::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 00000000..cdc001a7 --- /dev/null +++ b/src/client/component/game_console.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace game_console +{ + bool console_char_event(int local_client_num, int key); + bool console_key_event(int local_client_num, int key, int down); +} \ No newline at end of file diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp index 9bc79de0..bd984624 100644 --- a/src/client/component/game_module.cpp +++ b/src/client/component/game_module.cpp @@ -1,7 +1,6 @@ #include #include "loader/component_loader.hpp" #include "game_module.hpp" -#include "game/game.hpp" #include @@ -91,7 +90,7 @@ namespace game_module utils::nt::library get_game_module() { - static utils::nt::library game{HMODULE(game::base_address)}; + static utils::nt::library game{HMODULE(0x140000000)}; return game; } diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp new file mode 100644 index 00000000..55b41d65 --- /dev/null +++ b/src/client/component/localized_strings.cpp @@ -0,0 +1,52 @@ +#include +#include "loader/component_loader.hpp" +#include "localized_strings.hpp" +#include +#include +#include +#include "game/game.hpp" + +namespace localized_strings +{ + namespace + { + utils::hook::detour seh_string_ed_get_string_hook; + + using localized_map = std::unordered_map; + utils::concurrency::container localized_overrides; + + const char* seh_string_ed_get_string(const char* reference) + { + return localized_overrides.access([&](const localized_map& map) + { + const auto entry = map.find(reference); + if (entry != map.end()) + { + return utils::string::va("%s", entry->second.data()); + } + + return seh_string_ed_get_string_hook.invoke(reference); + }); + } + } + + void override(const std::string& key, const std::string& value) + { + localized_overrides.access([&](localized_map& map) + { + map[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(0, 0x585DA0_b), &seh_string_ed_get_string); // H1-STEAM(1.15) + } + }; +} + +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 00000000..01d15907 --- /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); +} \ No newline at end of file diff --git a/src/client/component/logfile.cpp b/src/client/component/logfile.cpp new file mode 100644 index 00000000..fc949d92 --- /dev/null +++ b/src/client/component/logfile.cpp @@ -0,0 +1,317 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" + +#include "game/scripting/entity.hpp" +#include "game/scripting/execution.hpp" +#include "game/scripting/lua/value_conversion.hpp" +#include "game/scripting/lua/error.hpp" + +#include + +#include "logfile.hpp" + +namespace logfile +{ + std::unordered_map vm_execute_hooks; + + namespace + { + utils::hook::detour scr_player_killed_hook; + utils::hook::detour scr_player_damage_hook; + + std::vector player_killed_callbacks; + std::vector player_damage_callbacks; + + utils::hook::detour vm_execute_hook; + char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END + bool hook_enabled = true; + + sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent) + { + if (!ent) + { + return {}; + } + + const scripting::entity player{game::Scr_GetEntityId(ent->s.entityNum, 0)}; + return scripting::lua::convert(state, player); + } + + std::string get_weapon_name(unsigned int weapon, bool isAlternate) + { + char output[1024] = {0}; + game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024); + return output; + } + + sol::lua_value convert_vector(lua_State* state, const float* vec) + { + if (!vec) + { + return {}; + } + + const auto vec_ = scripting::vector(vec); + return scripting::lua::convert(state, vec_); + } + + std::string convert_mod(const int meansOfDeath) + { + const auto value = reinterpret_cast(0x140FEC3F0)[meansOfDeath]; + const auto string = game::SL_ConvertToString(*value); + return string; + } + + void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, + game::mp::gentity_s* attacker, int damage, const int meansOfDeath, const unsigned int weapon, + const bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration) + { + { + const std::string hitloc = reinterpret_cast(0x140FEC4D0)[hitLoc]; + const auto mod_ = convert_mod(meansOfDeath); + + const auto weapon_ = get_weapon_name(weapon, isAlternate); + + for (const auto& callback : player_killed_callbacks) + { + const auto state = callback.lua_state(); + + const auto self_ = convert_entity(state, self); + const auto inflictor_ = convert_entity(state, inflictor); + const auto attacker_ = convert_entity(state, attacker); + + const auto dir = convert_vector(state, vDir); + + const auto result = callback(self_, inflictor_, attacker_, damage, + mod_, weapon_, dir, hitloc, psTimeOffset, deathAnimDuration); + + scripting::lua::handle_error(result); + + if (result.valid() && result.get_type() == sol::type::number) + { + damage = result.get(); + } + } + + if (damage == 0) + { + return; + } + } + + scr_player_killed_hook.invoke(self, inflictor, attacker, damage, meansOfDeath, + weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration); + } + + void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, + game::mp::gentity_s* attacker, int damage, int dflags, const int meansOfDeath, + const unsigned int weapon, const bool isAlternate, const float* vPoint, + const float* vDir, const unsigned int hitLoc, const int timeOffset) + { + { + const std::string hitloc = reinterpret_cast(0x140FEC4D0)[hitLoc]; + const auto mod_ = convert_mod(meansOfDeath); + + const auto weapon_ = get_weapon_name(weapon, isAlternate); + + for (const auto& callback : player_damage_callbacks) + { + const auto state = callback.lua_state(); + + const auto self_ = convert_entity(state, self); + const auto inflictor_ = convert_entity(state, inflictor); + const auto attacker_ = convert_entity(state, attacker); + + const auto point = convert_vector(state, vPoint); + const auto dir = convert_vector(state, vDir); + + const auto result = callback(self_, inflictor_, attacker_, + damage, dflags, mod_, weapon_, point, dir, hitloc); + + scripting::lua::handle_error(result); + + if (result.valid() && result.get_type() == sol::type::number) + { + damage = result.get(); + } + } + + if (damage == 0) + { + return; + } + } + + scr_player_damage_hook.invoke(self, inflictor, attacker, damage, dflags, + meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset); + } + + void client_command_stub(const int clientNum) + { + auto self = &game::mp::g_entities[clientNum]; + char cmd[1024] = {0}; + + game::SV_Cmd_ArgvBuffer(0, cmd, 1024); + + if (cmd == "say"s || cmd == "say_team"s) + { + auto hidden = false; + std::string message(game::ConcatArgs(1)); + + hidden = message[1] == '/'; + message.erase(0, hidden ? 2 : 1); + + scheduler::once([cmd, message, self]() + { + const scripting::entity level{*game::levelEntityId}; + const scripting::entity player{game::Scr_GetEntityId(self->s.entityNum, 0)}; + + scripting::notify(level, cmd, {player, message}); + scripting::notify(player, cmd, {message}); + }, scheduler::pipeline::server); + + if (hidden) + { + return; + } + } + + // ClientCommand + return utils::hook::invoke(0x140336000, clientNum); + } + + void g_shutdown_game_stub(const int freeScripts) + { + { + const scripting::entity level{*game::levelEntityId}; + scripting::notify(level, "shutdownGame_called", {1}); + } + + // G_ShutdownGame + return utils::hook::invoke(0x140345A60, freeScripts); + } + + unsigned int local_id_to_entity(unsigned int local_id) + { + const auto variable = game::scr_VarGlob->objectVariableValue[local_id]; + return variable.u.f.next; + } + + bool execute_vm_hook(const char* pos) + { + if (vm_execute_hooks.find(pos) == vm_execute_hooks.end()) + { + 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]; + const auto state = hook.lua_state(); + + const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId); + + std::vector args; + + const auto top = game::scr_function_stack->top; + + for (auto* value = top; value->type != game::SCRIPT_END; --value) + { + args.push_back(scripting::lua::convert(state, *value)); + } + + const auto result = hook(self, sol::as_args(args)); + scripting::lua::handle_error(result); + + 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.mov(dword_ptr(rbp, 0xA4), r15d); + + a.jmp(SELECT_VALUE(0x140376663, 0x140444653)); + + a.bind(replace); + + a.popad64(); + a.mov(r14, reinterpret_cast(empty_function)); + a.jmp(end); + } + } + + void add_player_damage_callback(const sol::protected_function& callback) + { + player_damage_callbacks.push_back(callback); + } + + void add_player_killed_callback(const sol::protected_function& callback) + { + player_killed_callbacks.push_back(callback); + } + + void clear_callbacks() + { + player_damage_callbacks.clear(); + player_killed_callbacks.clear(); + vm_execute_hooks.clear(); + } + + void enable_vm_execute_hook() + { + hook_enabled = true; + } + + void disable_vm_execute_hook() + { + hook_enabled = false; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + utils::hook::call(0x14048191D, client_command_stub); + + scr_player_damage_hook.create(0x14037DC50, scr_player_damage_stub); + scr_player_killed_hook.create(0x14037DF30, scr_player_killed_stub); + + utils::hook::call(0x140484EC0, g_shutdown_game_stub); + utils::hook::call(0x1404853C1, g_shutdown_game_stub); + + utils::hook::jump(SELECT_VALUE(0x140376655, 0x140444645), utils::hook::assemble(vm_execute_stub), true); + } + }; +} + +REGISTER_COMPONENT(logfile::component) \ No newline at end of file diff --git a/src/client/component/logfile.hpp b/src/client/component/logfile.hpp new file mode 100644 index 00000000..77f699c8 --- /dev/null +++ b/src/client/component/logfile.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace logfile +{ + extern std::unordered_map vm_execute_hooks; + + void add_player_damage_callback(const sol::protected_function& callback); + void add_player_killed_callback(const sol::protected_function& callback); + void clear_callbacks(); + + void enable_vm_execute_hook(); + void disable_vm_execute_hook(); +} \ No newline at end of file diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp new file mode 100644 index 00000000..d3a7edca --- /dev/null +++ b/src/client/component/lui.cpp @@ -0,0 +1,58 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" + +#include + +namespace lui +{ + class component final : public component_interface + { + public: + void post_unpack() override + { + // Don't show create cod account popup + //utils::hook::set(0x14017C957, 0); // H1(1.4) + +//#ifdef _DEBUG + // Enable development menus (causes issues in sp) + //utils::hook::set(SELECT_VALUE(0x1400B4ABC, 0x1401AB779), 1); +//#endif + + 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], 0, 0, 0); + }); + + command::add("lui_open_popup", [](const command::params& params) + { + if (params.size() <= 1) + { + console::info("usage: lui_open_popup \n"); + return; + } + + game::LUI_OpenMenu(0, params[1], 1, 0, 0); + }); + + command::add("runMenuScript", [](const command::params& params) + { + const auto args_str = params.join(1); + const auto* args = args_str.data(); + game::UI_RunMenuScript(0, &args); + }); + } + }; +} + +REGISTER_COMPONENT(lui::component) diff --git a/src/client/component/map_rotation.cpp b/src/client/component/map_rotation.cpp new file mode 100644 index 00000000..216cbfcd --- /dev/null +++ b/src/client/component/map_rotation.cpp @@ -0,0 +1,180 @@ +#include +#include "loader/component_loader.hpp" +#include "command.hpp" +#include "scheduler.hpp" +#include +#include +#include "game/game.hpp" +#include + +namespace map_rotation +{ + DWORD previousPriority; + namespace + { + void set_dvar(const std::string& dvar, const std::string& value) + { + command::execute(utils::string::va("%s \"%s\"", dvar.data(), value.data()), true); + } + + void set_gametype(const std::string& gametype) + { + set_dvar("g_gametype", gametype); + } + + void launch_map(const std::string& mapname) + { + 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 && strlen(mapname->current.string) && mapname->current.string != + "mp_vlobby_room"s) + { + launch_map(mapname->current.string); + } + else + { + launch_map("mp_crash"); + } + } + + std::string load_current_map_rotation() + { + auto* rotation = game::Dvar_FindVar("sv_mapRotationCurrent"); + if (!strlen(rotation->current.string)) + { + rotation = game::Dvar_FindVar("sv_mapRotation"); + set_dvar("sv_mapRotationCurrent", rotation->current.string); + } + + return rotation->current.string; + } + + std::vector parse_current_map_rotation() + { + const auto rotation = load_current_map_rotation(); + return utils::string::split(rotation, ' '); + } + + void store_new_rotation(const std::vector& elements, const size_t index) + { + std::string value{}; + + for (auto i = index; i < elements.size(); ++i) + { + if (i != index) + { + value.push_back(' '); + } + + value.append(elements[i]); + } + + set_dvar("sv_mapRotationCurrent", value); + } + + void change_process_priority() + { + auto* const dvar = game::Dvar_FindVar("sv_autoPriority"); + if (dvar && dvar->current.enabled) + { + scheduler::on_game_initialized([]() + { + //printf("=======================setting OLD priority=======================\n"); + SetPriorityClass(GetCurrentProcess(), previousPriority); + }, scheduler::pipeline::main, 1s); + + previousPriority = GetPriorityClass(GetCurrentProcess()); + //printf("=======================setting NEW priority=======================\n"); + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + } + } + + void perform_map_rotation() + { + if (game::Live_SyncOnlineDataFlags(0) != 0) + { + scheduler::on_game_initialized(perform_map_rotation, scheduler::pipeline::main, 1s); + return; + } + + const auto rotation = parse_current_map_rotation(); + + for (size_t i = 0; !rotation.empty() && i < (rotation.size() - 1); i += 2) + { + const auto& key = rotation[i]; + const auto& value = rotation[i + 1]; + + if (key == "gametype") + { + set_gametype(value); + } + else if (key == "map") + { + store_new_rotation(rotation, i + 2); + change_process_priority(); + if (!game::SV_MapExists(value.data())) + { + printf("map_rotation: '%s' map doesn't exist!\n", value.data()); + launch_default_map(); + return; + } + launch_map(value); + return; + } + else + { + printf("Invalid map rotation key: %s\n", key.data()); + } + } + + launch_default_map(); + } + + 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); + } + + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + scheduler::once([]() + { + dvars::register_string("sv_mapRotation", "", game::DVAR_FLAG_NONE, true); + dvars::register_string("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, true); + dvars::register_string("sv_autoPriority", "", game::DVAR_FLAG_NONE, true); + }, scheduler::pipeline::main); + + command::add("map_rotate", &perform_map_rotation); + + // Hook GScr_ExitLevel + utils::hook::jump(0x140376630, &trigger_map_rotation); // not sure if working + + previousPriority = GetPriorityClass(GetCurrentProcess()); + } + }; +} + +REGISTER_COMPONENT(map_rotation::component) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 8069d61a..fb2a6f55 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -27,8 +27,15 @@ namespace network const auto cmd_string = utils::string::to_lower(command); auto& callbacks = get_callbacks(); const auto handler = callbacks.find(cmd_string); + + if (handler == callbacks.end()) + { + return false; + } + const auto offset = cmd_string.size() + 5; - if (message->cursize < offset || handler == callbacks.end()) + + if (message->cursize <= offset) { return false; } @@ -324,4 +331,4 @@ namespace network }; } -REGISTER_COMPONENT(network::component) \ No newline at end of file +REGISTER_COMPONENT(network::component) diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp new file mode 100644 index 00000000..0605afad --- /dev/null +++ b/src/client/component/party.cpp @@ -0,0 +1,630 @@ +#include +#include "loader/component_loader.hpp" + +#include "party.hpp" +#include "console.hpp" +#include "command.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" + +#include "steam/steam.hpp" + +#include +#include +#include +#include + +namespace party +{ + namespace + { + struct + { + game::netadr_s host{}; + std::string challenge{}; + bool hostDefined{false}; + } connect_state; + + std::string sv_motd; + int sv_maxclients; + + void perform_game_initialization() + { + command::execute("onlinegame 1", true); + command::execute("xstartprivateparty", true); + command::execute("xblive_privatematch 1", true); + command::execute("startentitlements", true); + } + + 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) != 0) + { + // initialize the game after onlinedataflags is 32 (workaround) + if (game::Live_SyncOnlineDataFlags(0) == 32) + { + scheduler::once([=]() + { + command::execute("xstartprivateparty", true); + command::execute("disconnect", true); // 32 -> 0 + + connect_to_party(target, mapname, gametype); + }, scheduler::pipeline::main, 1s); + return; + } + else + { + scheduler::once([=]() + { + connect_to_party(target, mapname, gametype); + }, scheduler::pipeline::main, 1s); + return; + } + } + + perform_game_initialization(); + + // exit from virtuallobby + utils::hook::invoke(0x140256D40, 1); + + // CL_ConnectFromParty + char session_info[0x100] = {}; + utils::hook::invoke(0x140251560, 0, session_info, &target, mapname.data(), gametype.data()); + } + + std::string get_dvar_string(const std::string& dvar) + { + auto* dvar_value = game::Dvar_FindVar(dvar.data()); + if (dvar_value && dvar_value->current.string) + { + return dvar_value->current.string; + } + + return {}; + } + + int get_dvar_int(const std::string& dvar) + { + auto* dvar_value = game::Dvar_FindVar(dvar.data()); + if (dvar_value && dvar_value->current.integer) + { + return dvar_value->current.integer; + } + + return -1; + } + + bool get_dvar_bool(const std::string& dvar) + { + auto* dvar_value = game::Dvar_FindVar(dvar.data()); + if (dvar_value && dvar_value->current.enabled) + { + return dvar_value->current.enabled; + } + + return false; + } + + void didyouknow_stub(const char* dvar_name, const char* string) + { + if (!party::sv_motd.empty()) + { + string = party::sv_motd.data(); + } + + // This function either does Dvar_SetString or Dvar_RegisterString for the given dvar + utils::hook::invoke(0x1404FB210, dvar_name, string); + } + + void disconnect_stub() + { + if (!game::VirtualLobby_Loaded()) + { + if (game::CL_IsCgameInitialized()) + { + // CL_ForwardCommandToServer + utils::hook::invoke(0x140253480, 0, "disconnect"); + // CL_WritePacket + utils::hook::invoke(0x14024DB10, 0); + } + // CL_Disconnect + utils::hook::invoke(0x140252060, 0); + } + } + + utils::hook::detour cldisconnect_hook; + + void cl_disconnect_stub(int a1) + { + party::sv_motd.clear(); + cldisconnect_hook.invoke(a1); + } + + const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.mov(rdx, rdi); + a.mov(ecx, 2); + a.jmp(0x140251F78); + }); + + void menu_error(const std::string& error) + { + utils::hook::invoke(0x1400DACC0, error.data(), "MENU_NOTICE"); + utils::hook::set(0x142C1DA98, 1); + } + } + + int get_client_num_by_name(const std::string& name) + { + for (auto i = 0; !name.empty() && i < *game::mp::svs_numclients; ++i) + { + if (game::mp::g_entities[i].client) + { + char client_name[16] = {0}; + strncpy_s(client_name, game::mp::g_entities[i].client->name, sizeof(client_name)); + game::I_CleanStr(client_name); + + if (client_name == name) + { + return i; + } + } + } + return -1; + } + + void reset_connect_state() + { + connect_state = {}; + } + + int get_client_count() + { + auto count = 0; + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + if (game::mp::svs_clients[i].header.state >= 1) + { + ++count; + } + } + + return count; + } + + int get_bot_count() + { + auto count = 0; + for (auto i = 0; i < *game::mp::svs_numclients; ++i) + { + if (game::mp::svs_clients[i].header.state >= 1 && + game::SV_BotIsBot(i)) + { + ++count; + } + } + + return count; + } + + void connect(const game::netadr_s& target) + { + if (game::environment::is_sp()) + { + return; + } + + command::execute("lui_open_popup 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 start_map(const std::string& mapname) + { + if (game::Live_SyncOnlineDataFlags(0) > 32) + { + scheduler::once([=]() + { + command::execute("map " + mapname, false); + }, scheduler::pipeline::main, 1s); + } + else + { + if (!game::SV_MapExists(mapname.data())) + { + console::info("Map '%s' doesn't exist.\n", mapname.data()); + return; + } + + auto* current_mapname = game::Dvar_FindVar("mapname"); + if (current_mapname && utils::string::to_lower(current_mapname->current.string) == + utils::string::to_lower(mapname) && (game::SV_Loaded() && !game::VirtualLobby_Loaded())) + { + console::info("Restarting map: %s\n", mapname.data()); + command::execute("map_restart", false); + return; + } + + if (!game::environment::is_dedi()) + { + if (game::SV_Loaded()) + { + const auto* args = "Leave"; + game::UI_RunMenuScript(0, &args); + } + + perform_game_initialization(); + } + + console::info("Starting map: %s\n", mapname.data()); + + auto* gametype = game::Dvar_FindVar("g_gametype"); + if (gametype && gametype->current.string) + { + command::execute(utils::string::va("ui_gametype %s", gametype->current.string), true); + } + command::execute(utils::string::va("ui_mapname %s", mapname.data()), true); + + /*auto* maxclients = game::Dvar_FindVar("sv_maxclients"); + if (maxclients) + { + command::execute(utils::string::va("ui_maxclients %i", maxclients->current.integer), true); + command::execute(utils::string::va("party_maxplayers %i", maxclients->current.integer), true); + }*/ + + const auto* args = "StartServer"; + game::UI_RunMenuScript(0, &args); + } + } + + int server_client_count() + { + return party::sv_maxclients; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + // hook disconnect command function + utils::hook::jump(0x1402521C7, disconnect_stub); + + // detour CL_Disconnect to clear motd + cldisconnect_hook.create(0x140252060, cl_disconnect_stub); + + if (game::environment::is_mp()) + { + // show custom drop reason + utils::hook::nop(0x140251EFB, 13); + utils::hook::jump(0x140251EFB, drop_reason_stub, true); + } + + // enable custom kick reason in GScr_KickPlayer + utils::hook::set(0x140376A1D, 0xEB); + + command::add("map", [](const command::params& argument) + { + if (argument.size() != 2) + { + return; + } + + start_map(argument[1]); + }); + + command::add("map_restart", []() + { + if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) + { + return; + } + *reinterpret_cast(0x14A3A91D0) = 1; // sv_map_restart + *reinterpret_cast(0x14A3A91D4) = 1; // sv_loadScripts + *reinterpret_cast(0x14A3A91D8) = 0; // sv_migrate + + utils::hook::invoke(0x14047E7F0); // SV_CheckLoadGame + }); + + command::add("fast_restart", []() + { + if (game::SV_Loaded() && !game::VirtualLobby_Loaded()) + { + game::SV_FastRestart(0); + } + }); + + command::add("reconnect", [](const command::params& argument) + { + 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& argument) + { + if (argument.size() != 2) + { + return; + } + + game::netadr_s target{}; + if (game::NET_StringToAdr(argument[1], &target)) + { + connect(target); + } + }); + + command::add("kickClient", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: kickClient , (optional)\n"); + return; + } + + if (!game::SV_Loaded() || game::VirtualLobby_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_numclients) + { + 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() || game::VirtualLobby_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_numclients; ++i) + { + scheduler::once([i, reason]() + { + game::SV_KickClientNum(i, reason.data()); + }, scheduler::pipeline::server); + } + return; + } + + const auto client_num = get_client_num_by_name(name); + if (client_num < 0 || client_num >= *game::mp::svs_numclients) + { + return; + } + + scheduler::once([client_num, reason]() + { + game::SV_KickClientNum(client_num, reason.data()); + }, scheduler::pipeline::server); + }); + + scheduler::once([]() + { + const auto hash = game::generateHashValue("sv_sayName"); + game::Dvar_RegisterString(hash, "sv_sayName", "console", game::DvarFlags::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, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s: %s\"", 84, name, message.data())); + printf("%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, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s\"", 84, message.data())); + printf("%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, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); + printf("%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, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s\"", 84, message.data())); + printf("%s\n", message.data()); + }); + + utils::hook::call(0x1404C6E8D, didyouknow_stub); // allow custom didyouknow based on sv_motd + + network::on("getInfo", [](const game::netadr_s& target, const std::string_view& data) + { + utils::info_string info{}; + info.set("challenge", std::string{data}); + info.set("gamename", "H1"); + info.set("hostname", get_dvar_string("sv_hostname")); + info.set("gametype", get_dvar_string("g_gametype")); + info.set("sv_motd", get_dvar_string("sv_motd")); + info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); + info.set("mapname", get_dvar_string("mapname")); + info.set("isPrivate", get_dvar_string("g_password").empty() ? "0" : "1"); + info.set("clients", utils::string::va("%i", get_client_count())); + info.set("bots", utils::string::va("%i", get_bot_count())); + info.set("sv_maxclients", utils::string::va("%i", *game::mp::svs_numclients)); + info.set("protocol", utils::string::va("%i", PROTOCOL)); + info.set("playmode", utils::string::va("%i", game::Com_GetCurrentCoDPlayMode())); + info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running") && !game::VirtualLobby_Loaded())); + info.set("dedicated", utils::string::va("%i", get_dvar_bool("dedicated"))); + + network::send(target, "infoResponse", info.build(), '\n'); + }); + + network::on("infoResponse", [](const game::netadr_s& target, const std::string_view& 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) + { + const auto str = "Invalid challenge."; + printf("%s\n", str); + menu_error(str); + return; + } + + const auto gamename = info.get("gamename"); + if (gamename != "H1"s) + { + const auto str = "Invalid gamename."; + printf("%s\n", str); + menu_error(str); + return; + } + + const auto playmode = info.get("playmode"); + if (game::CodPlayMode(std::atoi(playmode.data())) != game::Com_GetCurrentCoDPlayMode()) + { + const auto str = "Invalid playmode."; + printf("%s\n", str); + menu_error(str); + return; + } + + const auto sv_running = info.get("sv_running"); + if (!std::atoi(sv_running.data())) + { + const auto str = "Server not running."; + printf("%s\n", str); + menu_error(str); + return; + } + + const auto mapname = info.get("mapname"); + if (mapname.empty()) + { + const auto str = "Invalid map."; + printf("%s\n", str); + menu_error(str); + return; + } + + const auto gametype = info.get("gametype"); + if (gametype.empty()) + { + const auto str = "Invalid gametype."; + printf("%s\n", str); + menu_error(str); + return; + } + + party::sv_motd = info.get("sv_motd"); + party::sv_maxclients = std::stoi(info.get("sv_maxclients")); + + connect_to_party(target, mapname, gametype); + }); + } + }; +} + +REGISTER_COMPONENT(party::component) \ No newline at end of file diff --git a/src/client/component/party.hpp b/src/client/component/party.hpp new file mode 100644 index 00000000..cd90ae9f --- /dev/null +++ b/src/client/component/party.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "game/game.hpp" + +namespace party +{ + void reset_connect_state(); + + void connect(const game::netadr_s& target); + void start_map(const std::string& mapname); + + int server_client_count(); + + int get_client_num_by_name(const std::string& name); + + int get_client_count(); + int get_bot_count(); +} \ No newline at end of file diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp new file mode 100644 index 00000000..e9aaf21a --- /dev/null +++ b/src/client/component/patches.cpp @@ -0,0 +1,293 @@ +#include +#include "loader/component_loader.hpp" + +#include "dvars.hpp" +#include "version.h" +#include "command.hpp" +#include "console.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "filesystem.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include + +namespace patches +{ + namespace + { + 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 client_num, 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(client_num, 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 + dvars::register_string("name", get_login_username().data(), game::DVAR_FLAG_SAVED, true); + + // Disable data validation error popup + dvars::register_int("data_validation_allow_drop", 0, 0, 0, game::DVAR_FLAG_NONE, true); + } + + return com_register_dvars_hook.invoke(); + } + + int is_item_unlocked() + { + return 0; // 0 == yes + } + + void set_client_dvar_from_server_stub(void* a1, void* a2, const char* dvar, const char* value) + { + if (dvar == "cg_fov"s) + { + return; + } + + // CG_SetClientDvarFromServer + utils::hook::invoke(0x140236120, a1, a2, dvar, value); + } + + const char* db_read_raw_file_stub(const char* filename, char* buf, const int size) + { + std::string file_name = filename; + if (file_name.find(".cfg") == std::string::npos) + { + file_name.append(".cfg"); + } + + const auto file = filesystem::file(file_name); + if (file.exists()) + { + snprintf(buf, size, "%s\n", file.get_buffer().data()); + return buf; + } + + // DB_ReadRawFile + return utils::hook::invoke(SELECT_VALUE(0x1401CD4F0, 0x1402BEF10), filename, buf, size); + } + + 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.entityNum]; + + // 22 => "end_game" + if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK) + { + return; + } + + cmd_lui_notify_server_hook.invoke(ent); + } + + void sv_execute_client_message_stub(game::mp::client_t* client, game::msg_t* msg) + { + if (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); + network::send(client->header.remoteAddress, "error", "EXE_LOSTRELIABLECOMMANDS", '\n'); + return; + } + + utils::hook::invoke(0x140481A00, client, msg); + } + + void aim_assist_add_to_target_list(void* a1, void* a2) + { + if (!dvars::aimassist_enabled->current.enabled) + return; + + game::AimAssist_AddToTargetList(a1, a2); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Register dvars + com_register_dvars_hook.create(SELECT_VALUE(0x140351B80, 0x1400D9320), &com_register_dvars_stub); // H1(1.4) + + // Unlock fps in main menu + utils::hook::set(SELECT_VALUE(0x14018D47B, 0x14025B86B), 0xEB); // H1(1.4) + + if (!game::environment::is_dedi()) + { + // Fix mouse lag + utils::hook::nop(SELECT_VALUE(0x1403E3C05, 0x1404DB1AF), 6); + scheduler::loop([]() + { + SetThreadExecutionState(ES_DISPLAY_REQUIRED); + }, scheduler::pipeline::main); + } + + // Make cg_fov and cg_fovscale saved dvars + dvars::override::register_float("cg_fov", 65.f, 40.f, 200.f, game::DvarFlags::DVAR_FLAG_SAVED); + dvars::override::register_float("cg_fovScale", 1.f, 0.1f, 2.f, game::DvarFlags::DVAR_FLAG_SAVED); + + // Allow kbam input when gamepad is enabled + utils::hook::nop(SELECT_VALUE(0x14018797E, 0x14024EF60), 2); + utils::hook::nop(SELECT_VALUE(0x1401856DC, 0x14024C6B0), 6); + + // Allow executing custom cfg files with the "exec" command + utils::hook::call(SELECT_VALUE(0x140343855, 0x140403E28), db_read_raw_file_stub); + + if (!game::environment::is_sp()) + { + patch_mp(); + } + } + + static void patch_mp() + { + // Use name dvar + utils::hook::jump(0x14050FF90, &live_get_local_client_name); // H1(1.4) + + // Patch SV_KickClientNum + sv_kick_client_num_hook.create(0x14047ED00, &sv_kick_client_num); // H1(1.4) + + // block changing name in-game + utils::hook::set(0x14047FC90, 0xC3); // H1(1.4) + + // patch "Couldn't find the bsp for this map." error to not be fatal in mp + utils::hook::call(0x1402BA26B, bsp_sys_error_stub); // H1(1.4) + + // client side aim assist dvar + dvars::aimassist_enabled = dvars::register_bool("aimassist_enabled", true, + game::DvarFlags::DVAR_FLAG_SAVED, + true); + utils::hook::call(0x14009EE9E, aim_assist_add_to_target_list); + + // unlock all items + utils::hook::jump(0x140413E60, is_item_unlocked); // LiveStorage_IsItemUnlockedFromTable_LocalClient H1(1.4) + utils::hook::jump(0x140413860, is_item_unlocked); // LiveStorage_IsItemUnlockedFromTable H1(1.4) + utils::hook::jump(0x140412B70, is_item_unlocked); // idk ( unlocks loot etc ) H1(1.4) + + // isProfanity + utils::hook::set(0x1402877D0, 0xC3C033); // MAY BE WRONG H1(1.4) + + // disable emblems + dvars::override::register_int("emblems_active", 0, 0, 0, game::DVAR_FLAG_NONE); + utils::hook::set(0x140479590, 0xC3); // don't register commands + + // disable elite_clan + dvars::override::register_int("elite_clan_active", 0, 0, 0, game::DVAR_FLAG_NONE); + utils::hook::set(0x140585680, 0xC3); // don't register commands H1(1.4) + + // disable codPointStore + dvars::override::register_int("codPointStore_enabled", 0, 0, 0, game::DVAR_FLAG_NONE); + + // don't register every replicated dvar as a network dvar + utils::hook::nop(0x14039E58E, 5); // dvar_foreach H1(1.4) + + // patch "Server is different version" to show the server client version + utils::hook::inject(0x140480952, VERSION); // H1(1.4) + + // prevent servers overriding our fov + utils::hook::call(0x14023279E, set_client_dvar_from_server_stub); + utils::hook::nop(0x1400DAF69, 5); + utils::hook::nop(0x140190C16, 5); + utils::hook::set(0x14021D22A, 0xEB); + + // unlock safeArea_* + utils::hook::jump(0x1402624F5, 0x140262503); // H1(1.4) + utils::hook::jump(0x14026251C, 0x140262547); // H1(1.4) + dvars::override::register_int("safeArea_adjusted_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED); + dvars::override::register_int("safeArea_adjusted_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED); + dvars::override::register_int("safeArea_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED); + dvars::override::register_int("safeArea_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED); + + // move chat position on the screen above menu splashes + dvars::override::register_vec2("cg_hudChatPosition", 5, 170, 0, 640, game::DVAR_FLAG_SAVED); + + // allow servers to check for new packages more often + dvars::override::register_int("sv_network_fps", 1000, 20, 1000, game::DVAR_FLAG_SAVED); + + // Massively increate timeouts + dvars::override::register_int("cl_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // Seems unused + dvars::override::register_int("sv_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // 30 - 0 - 1800 + dvars::override::register_int("cl_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // Seems unused + dvars::override::register_int("sv_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // 60 - 0 - 1800 + + dvars::register_int("scr_game_spectatetype", 1, 0, 99, game::DVAR_FLAG_REPLICATED); + + dvars::override::register_int("com_maxfps", 0, 10, 1000, game::DVAR_FLAG_SAVED); + + // Prevent clients from ending the game as non host by sending 'end_game' lui notification + // cmd_lui_notify_server_hook.create(0x140335A70, cmd_lui_notify_server_stub); // H1(1.4) + + // Prevent clients from sending invalid reliableAcknowledge + // utils::hook::call(0x1404899C6, sv_execute_client_message_stub); // H1(1.4) + + // "fix" for rare 'Out of memory error' error + if (utils::flags::has_flag("memoryfix")) + { + utils::hook::jump(0x140578BE0, malloc); + utils::hook::jump(0x140578B00, _aligned_malloc); + utils::hook::jump(0x140578C40, free); + utils::hook::jump(0x140578D30, realloc); + utils::hook::jump(0x140578B60, _aligned_realloc); + } + + // Change default hostname and make it replicated + dvars::override::register_string("sv_hostname", "^2H1-Mod^7 Default Server", game::DVAR_FLAG_REPLICATED); + } + }; +} + +REGISTER_COMPONENT(patches::component) diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp new file mode 100644 index 00000000..b315be76 --- /dev/null +++ b/src/client/component/renderer.cpp @@ -0,0 +1,77 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace renderer +{ + namespace + { + utils::hook::detour r_init_draw_method_hook; + utils::hook::detour r_update_front_end_dvar_options_hook; + + int get_fullbright_technique() + { + return game::TECHNIQUE_UNLIT; + } + + void gfxdrawmethod() + { + game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD; + + game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_LIT; + game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE; + game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : 242; + } + + void r_init_draw_method_stub() + { + gfxdrawmethod(); + } + + bool r_update_front_end_dvar_options_stub() + { + if (dvars::r_fullbright->modified) + { + //game::Dvar_ClearModified(dvars::r_fullbright); + game::R_SyncRenderThread(); + + gfxdrawmethod(); + } + + 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() || !game::environment::is_mp()) + { + return; + } + + dvars::r_fullbright = dvars::register_int("r_fullbright", 0, 0, 3, game::DVAR_FLAG_SAVED); + + r_init_draw_method_hook.create(SELECT_VALUE(0x1404BD140, 0x1405C46E0), &r_init_draw_method_stub); + r_update_front_end_dvar_options_hook.create(SELECT_VALUE(0x1404F8870, 0x1405FF9E0), &r_update_front_end_dvar_options_stub); + + // use "saved" flags for "r_normalMap" + utils::hook::set(SELECT_VALUE(0x1404CF5CA, 0x1405D460E), game::DVAR_FLAG_SAVED); + + // use "saved" flags for "r_specularMap" + utils::hook::set(SELECT_VALUE(0x1404CF5F5, 0x1405D4639), game::DVAR_FLAG_SAVED); + + // use "saved" flags for "r_specOccMap" + utils::hook::set(SELECT_VALUE(0x1404CF620, 0x1405D4664), game::DVAR_FLAG_SAVED); + } + }; +} + +#ifdef DEBUG +REGISTER_COMPONENT(renderer::component) +#endif \ No newline at end of file diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index 9a8911eb..ac837128 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -180,9 +180,9 @@ namespace scheduler void post_unpack() override { - r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); - g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); - main_frame_hook.create(SELECT_VALUE(0, 0x1400D8310), scheduler::main_frame_stub); // I REPEAT, ARXAN IS PAIN + r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); // H1-STEAM(1.15) + g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); // H1(1.15) + //main_frame_hook.create(SELECT_VALUE(0x1401CE8D0, 0x1400D8310), scheduler::main_frame_stub); can't find } void pre_destroy() override @@ -196,4 +196,4 @@ namespace scheduler }; } -REGISTER_COMPONENT(scheduler::component) \ No newline at end of file +REGISTER_COMPONENT(scheduler::component) diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp new file mode 100644 index 00000000..e3116122 --- /dev/null +++ b/src/client/component/scripting.cpp @@ -0,0 +1,141 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include + +#include "game/scripting/entity.hpp" +#include "game/scripting/functions.hpp" +#include "game/scripting/event.hpp" +#include "game/scripting/lua/engine.hpp" +#include "game/scripting/execution.hpp" + +#include "scheduler.hpp" +#include "scripting.hpp" + +namespace scripting +{ + std::unordered_map> fields_table; + std::unordered_map> script_function_table; + + namespace + { + utils::hook::detour vm_notify_hook; + utils::hook::detour scr_load_level_hook; + utils::hook::detour g_shutdown_game_hook; + + utils::hook::detour scr_add_class_field_hook; + + utils::hook::detour scr_set_thread_position_hook; + utils::hook::detour process_script_hook; + + std::string current_file; + + void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, + game::VariableValue* top) + { + if (!game::VirtualLobby_Loaded()) + { + const auto* string = game::SL_ConvertToString(string_value); + if (string) + { + event e; + e.name = string; + e.entity = notify_list_owner_id; + + for (auto* value = top; value->type != game::SCRIPT_END; --value) + { + e.arguments.emplace_back(*value); + } + + if (e.name == "entitydeleted") + { + scripting::clear_entity_fields(e.entity); + } + + lua::engine::notify(e); + } + } + + vm_notify_hook.invoke(notify_list_owner_id, string_value, top); + } + + void scr_load_level_stub() + { + scr_load_level_hook.invoke(); + if (!game::VirtualLobby_Loaded()) + { + lua::engine::start(); + } + } + + void g_shutdown_game_stub(const int free_scripts) + { + lua::engine::stop(); + return g_shutdown_game_hook.invoke(free_scripts); + } + + void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t _name, unsigned int canonicalString, unsigned int offset) + { + const auto name = game::SL_ConvertToString(_name); + + if (fields_table[classnum].find(name) == fields_table[classnum].end()) + { + fields_table[classnum][name] = offset; + } + + scr_add_class_field_hook.invoke(classnum, _name, canonicalString, offset); + } + + void process_script_stub(const char* filename) + { + const auto file_id = atoi(filename); + if (file_id) + { + current_file = scripting::find_token(file_id); + } + else + { + current_file = filename; + } + + process_script_hook.invoke(filename); + } + + void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) + { + const auto function_name = scripting::find_token(threadName); + script_function_table[current_file][function_name] = codePos; + scr_set_thread_position_hook.invoke(threadName, codePos); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + vm_notify_hook.create(SELECT_VALUE(0x140379A00, 0x1404479F0), vm_notify_stub); + + scr_add_class_field_hook.create(SELECT_VALUE(0x140370370, 0x14043E2C0), scr_add_class_field_stub); + + scr_set_thread_position_hook.create(SELECT_VALUE(0x14036A180, 0x140437D10), scr_set_thread_position_stub); + process_script_hook.create(SELECT_VALUE(0x1403737E0, 0x1404417E0), process_script_stub); + + scr_load_level_hook.create(SELECT_VALUE(0x1402A5BE0, 0x1403727C0), scr_load_level_stub); + g_shutdown_game_hook.create(SELECT_VALUE(0x140277D40, 0x140345A60), g_shutdown_game_stub); + + scheduler::loop([]() + { + lua::engine::run_frame(); + }, scheduler::pipeline::server); + } + }; +} + +REGISTER_COMPONENT(scripting::component) \ No newline at end of file diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp new file mode 100644 index 00000000..865ae858 --- /dev/null +++ b/src/client/component/scripting.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +namespace scripting +{ + extern std::unordered_map> fields_table; + extern std::unordered_map> script_function_table; +} \ No newline at end of file diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp new file mode 100644 index 00000000..1b7e759e --- /dev/null +++ b/src/client/component/server_list.cpp @@ -0,0 +1,443 @@ +#include +#include "loader/component_loader.hpp" +#include "server_list.hpp" +#include "localized_strings.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "party.hpp" +#include "game/game.hpp" + +#include +#include +#include + +#include "console.hpp" +#include "command.hpp" + +namespace server_list +{ + namespace + { + const int server_limit = 18; + + struct server_info + { + // gotta add more to this + int clients; + int max_clients; + int bots; + int ping; + std::string host_name; + std::string map_name; + std::string game_type; + game::CodPlayMode play_mode; + char in_game; + game::netadr_s address; + }; + + struct + { + game::netadr_s address{}; + volatile bool requesting = false; + std::unordered_map queued_servers{}; + } master_state; + + std::mutex mutex; + std::vector servers; + + size_t server_list_page = 0; + volatile bool update_server_list = false; + std::chrono::high_resolution_clock::time_point last_scroll{}; + + size_t get_page_count() + { + const auto count = servers.size() / server_limit; + return count + (servers.size() % server_limit > 0); + } + + size_t get_page_base_index() + { + return server_list_page * server_limit; + } + + void refresh_server_list() + { + { + std::lock_guard _(mutex); + servers.clear(); + master_state.queued_servers.clear(); + server_list_page = 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("H1 %i full empty", PROTOCOL)); + } + } + + void join_server(int, int, const int index) + { + std::lock_guard _(mutex); + + const auto i = static_cast(index) + get_page_base_index(); + if (i < servers.size()) + { + static auto last_index = ~0ull; + 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; + } + + int ui_feeder_count() + { + std::lock_guard _(mutex); + if (update_server_list) + { + update_server_list = false; + return 0; + } + const auto count = static_cast(servers.size()); + const auto index = get_page_base_index(); + const auto diff = count - index; + return diff > server_limit ? server_limit : static_cast(diff); + } + + 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 = get_page_base_index() + index; + + if (i >= servers.size()) + { + return ""; + } + + if (column == 0) + { + return servers[i].host_name.empty() ? "" : utils::string::va("%s", servers[i].host_name.data()); + } + + if (column == 1) + { + return servers[i].map_name.empty() ? "Unknown" : utils::string::va("%s", servers[i].map_name.data()); + } + + if (column == 2) + { + return utils::string::va("%d/%d [%d]", servers[i].clients, servers[index].max_clients, + servers[i].bots); + } + + if (column == 3) + { + return servers[i].game_type.empty() ? "" : utils::string::va("%s", servers[i].game_type.data()); + } + + if (column == 4) + { + return servers[i].game_type.empty() ? "" : utils::string::va("%i", servers[i].ping); + } + + return ""; + } + + void sort_serverlist() + { + std::stable_sort(servers.begin(), servers.end(), [](const server_info& a, const server_info& b) + { + if (a.clients == b.clients) + { + return a.ping < b.ping; + } + + return a.clients > b.clients; + }); + } + + 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 is_scrolling_disabled() + { + return update_server_list || (std::chrono::high_resolution_clock::now() - last_scroll) < 500ms; + } + + bool scroll_down() + { + if (!is_server_list_open()) + { + return false; + } + + if (!is_scrolling_disabled() && server_list_page + 1 < get_page_count()) + { + last_scroll = std::chrono::high_resolution_clock::now(); + ++server_list_page; + trigger_refresh(); + } + + return true; + } + + bool scroll_up() + { + if (!is_server_list_open()) + { + return false; + } + + if (!is_scrolling_disabled() && server_list_page > 0) + { + last_scroll = std::chrono::high_resolution_clock::now(); + --server_list_page; + trigger_refresh(); + } + + return true; + } + + void resize_host_name(std::string& name) + { + name = utils::string::split(name, '\n').front(); + + game::Font_s* font = game::R_RegisterFont("fonts/default.otf", 18); + auto text_size = game::UI_TextWidth(name.data(), 32, font, 1.0f); + + while (text_size > 450) + { + text_size = game::UI_TextWidth(name.data(), 32, font, 1.0f); + name.pop_back(); + } + } + + utils::hook::detour lui_open_menu_hook; + + void lui_open_menu_stub(int controllerIndex, const char* menu, int a3, int a4, unsigned int a5) + { +#ifdef DEBUG + console::info("[LUI] %s\n", menu); +#endif + + if (!strcmp(menu, "menu_systemlink_join")) + { + refresh_server_list(); + } + + lui_open_menu_hook.invoke(controllerIndex, menu, a3, a4, a5); + } + } + + 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; + } + + bool get_master_server(game::netadr_s& address) + { + return game::NET_StringToAdr("135.148.53.121:20810", &address); + // return game::NET_StringToAdr("master.xlabs.dev:20810", &address); + } + + void handle_info_response(const game::netadr_s& address, const utils::info_string& info) + { + // Don't show servers that aren't dedicated! + const auto dedicated = std::atoi(info.get("dedicated").data()); + if (!dedicated) + { + return; + } + + // Don't show servers that aren't running! + const auto sv_running = std::atoi(info.get("sv_running").data()); + if (!sv_running) + { + return; + } + + // Only handle servers of the same playmode! + const auto playmode = game::CodPlayMode(std::atoi(info.get("playmode").data())); + if (game::Com_GetCurrentCoDPlayMode() != playmode) + { + return; + } + + 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); + } + + server_info server{}; + server.address = address; + server.host_name = info.get("hostname"); + server.map_name = game::UI_GetMapDisplayName(info.get("mapname").data()); + server.game_type = game::UI_GetGameTypeDisplayName(info.get("gametype").data()); + server.play_mode = playmode; + 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 = std::min(now - start_time, 999); + + server.in_game = 1; + + resize_host_name(server.host_name); + + insert_server(std::move(server)); + } + + 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"); + + // hook LUI_OpenMenu to refresh server list for system link menu + lui_open_menu_hook.create(game::LUI_OpenMenu, lui_open_menu_stub); + + // replace UI_RunMenuScript call in LUI_CoD_LuaCall_RefreshServerList to our refresh_servers + utils::hook::call(0x14018A0C9, &refresh_server_list); + utils::hook::call(0x14018A5DE, &join_server); + utils::hook::nop(0x14018A5FD, 5); + + // do feeder stuff + utils::hook::call(0x14018A199, &ui_feeder_count); + utils::hook::call(0x14018A3B1, &ui_feeder_item_text); + + scheduler::loop(do_frame_work, scheduler::pipeline::main); + + network::on("getServersResponse", [](const game::netadr_s& target, const std::string_view& data) + { + { + std::lock_guard _(mutex); + if (!master_state.requesting || master_state.address != target) + { + return; + } + + master_state.requesting = false; + + std::optional start{}; + for (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; + memcpy(&address.ip[0], data.data() + i + 0, 4); + 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 00000000..d9974cfa --- /dev/null +++ b/src/client/component/server_list.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "game/game.hpp" +#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); +} \ No newline at end of file diff --git a/src/client/component/shaders.cpp b/src/client/component/shaders.cpp new file mode 100644 index 00000000..ec632115 --- /dev/null +++ b/src/client/component/shaders.cpp @@ -0,0 +1,50 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" +#include "dvars.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include + +namespace shaders +{ + namespace + { + game::dvar_t* disable_shader_caching = nullptr; + + bool shader_should_show_dialog_stub() + { + return !disable_shader_caching->current.enabled; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) + { + return; + } + + const auto has_flag = utils::flags::has_flag("noshadercaching"); + + disable_shader_caching = dvars::register_bool("disable_shader_caching", has_flag, game::DVAR_FLAG_SAVED, true); + if (has_flag) + { + dvars::override::set_bool("disable_shader_caching", 1); + dvars::override::set_from_string("disable_shader_caching", "1"); + } + + utils::hook::jump(0x14007E710, shader_should_show_dialog_stub); + } + }; +} + +REGISTER_COMPONENT(shaders::component) diff --git a/src/client/component/slowmotion.cpp b/src/client/component/slowmotion.cpp new file mode 100644 index 00000000..71f66dbf --- /dev/null +++ b/src/client/component/slowmotion.cpp @@ -0,0 +1,53 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include + +namespace slowmotion +{ + namespace + { + 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(1u); + } + + if (game::Scr_GetNumParam() >= 3) + { + duration = static_cast(game::Scr_GetFloat(2u) * 1000.0f); + } + + game::SV_SetConfigstring(10, utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end)); + game::Com_SetSlowMotion(start, end, duration); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + utils::hook::jump(0x140365480, scr_cmd_set_slow_motion); // H1(1.4) + } + }; +} + +REGISTER_COMPONENT(slowmotion::component) diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp new file mode 100644 index 00000000..3dfd6541 --- /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(0x1403E192E, 0x1405123E2), 5); // winmain doesn't even exist in 1.15? lmao + utils::hook::jump(SELECT_VALUE(0, 0x5BE1D0_b), destroy_stub); // H1-STEAM(1.15) + utils::hook::jump(SELECT_VALUE(0, 0x5BE210_b), destroy_stub); // H1-STEAM(1.15) + } + + 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("H1 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 = "H1 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, "H1 Splash Screen", "H1", + 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/system_check.cpp b/src/client/component/system_check.cpp index e3631248..9c88bd5c 100644 --- a/src/client/component/system_check.cpp +++ b/src/client/component/system_check.cpp @@ -51,28 +51,27 @@ namespace system_check { static std::unordered_map mp_zone_hashes = { - {"patch_common_mp.ff", "E45EF5F29D12A5A47F405F89FBBEE479C0A90D02141ABF852D481689514134A1"}, + {"patch_common_mp.ff", "3F44B0CFB0B8E0FBD9687C2942204AB7F11E66E6E15C73B8B4A5EB5920115A31"}, }; static std::unordered_map sp_zone_hashes = { // Steam doesn't necessarily deliver this file :( - {"patch_common.ff", "1D32A9770F90ED022AA76F4859B4AB178E194A703383E61AC2CE83B1E828B18F"}, + {"patch_common.ff", "BB0617DD94AF2F511571E7184BBEDE76E64D97E5D0DAFDB457F00717F035EBF0"}, }; return verify_hashes(mp_zone_hashes) && (game::environment::is_dedi() || verify_hashes(sp_zone_hashes)); } - //void verify_binary_version() - //{ - // if (*(int*)(uint64_t(GetModuleHandle(NULL)) + 0x4CCD3D) != 1251288) - // { - // MessageBoxA(0, "UNSUPPORTED VERSION MWR(1.15)", "H1MP-STEAM", MB_ICONWARNING); - - // return; - // } - //} + void verify_binary_version() + { + const auto value = *reinterpret_cast(0x140001337); + if (value != 0xFFB8006D && value != 0xFFB80080) + { + throw std::runtime_error("Unsupported Call of Duty: Modern Warfare Remastered version(1.4)"); + } + } } bool is_valid() @@ -86,12 +85,12 @@ namespace system_check public: void post_load() override { - //verify_binary_version(); + verify_binary_version(); if (!is_valid()) { MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n" - "Please get the latest officially supported Call of Duty: Modern Warfare Remastered 1.15 STEAM files, or you will get random crashes and issues.", + "Please get the latest officially supported Call of Duty: Modern Warfare Remastered 1.4 files, or you will get random crashes and issues.", "Invalid game files!", MB_ICONINFORMATION); } } diff --git a/src/client/component/thread_names.cpp b/src/client/component/thread_names.cpp new file mode 100644 index 00000000..84b5fa70 --- /dev/null +++ b/src/client/component/thread_names.cpp @@ -0,0 +1,60 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" + +#include "game/game.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 00000000..941dda10 --- /dev/null +++ b/src/client/component/ui_scripting.cpp @@ -0,0 +1,180 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "scheduler.hpp" +#include "command.hpp" + +#include "ui_scripting.hpp" + +#include "game/ui_scripting/lua/engine.hpp" +#include "game/ui_scripting/execution.hpp" +#include "game/ui_scripting/lua/error.hpp" + +#include +#include + +namespace ui_scripting +{ + namespace + { + std::unordered_map converted_functions; + + utils::hook::detour hksi_lual_error_hook; + utils::hook::detour hksi_lual_error_hook2; + utils::hook::detour hks_start_hook; + utils::hook::detour hks_shutdown_hook; + utils::hook::detour hks_allocator_hook; + utils::hook::detour hks_frame_hook; + + bool error_hook_enabled = false; + + void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...) + { + char va_buffer[2048] = {0}; + + va_list ap; + va_start(ap, fmt); + vsprintf_s(va_buffer, fmt, ap); + va_end(ap); + + const auto formatted = std::string(va_buffer); + + if (!error_hook_enabled) + { + return hksi_lual_error_hook.invoke(s, formatted.data()); + } + else + { + throw std::runtime_error(formatted); + } + } + + void* hks_start_stub(char a1) + { + const auto _1 = gsl::finally([]() + { + ui_scripting::lua::engine::start(); + }); + + return hks_start_hook.invoke(a1); + } + + void hks_shutdown_stub() + { + ui_scripting::lua::engine::stop(); + hks_shutdown_hook.invoke(); + } + + void* hks_allocator_stub(void* userData, void* oldMemory, unsigned __int64 oldSize, unsigned __int64 newSize) + { + const auto closure = reinterpret_cast(oldMemory); + if (converted_functions.find(closure) != converted_functions.end()) + { + converted_functions.erase(closure); + } + + return hks_allocator_hook.invoke(userData, oldMemory, oldSize, newSize); + } + + void hks_frame_stub() + { + const auto state = *game::hks::lua_state; + if (state) + { + ui_scripting::lua::engine::run_frame(); + } + } + } + + int main_function_handler(game::hks::lua_State* state) + { + const auto value = state->m_apistack.base[-1]; + if (value.t != game::hks::TCFUNCTION) + { + return 0; + } + + const auto closure = reinterpret_cast(value.v.cClosure); + if (converted_functions.find(closure) == converted_functions.end()) + { + return 0; + } + + const auto function = converted_functions[closure]; + const auto count = static_cast(state->m_apistack.top - state->m_apistack.base); + const auto arguments = get_return_values(count); + const auto s = function.lua_state(); + + std::vector converted_args; + + for (const auto& argument : arguments) + { + converted_args.push_back(lua::convert(s, argument)); + } + + const auto results = function(sol::as_args(converted_args)); + lua::handle_error(results); + + for (const auto& result : results) + { + push_value(lua::convert({s, result})); + } + + return results.return_count(); + } + + void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function) + { + converted_functions[closure] = function; + } + + void clear_converted_functions() + { + converted_functions.clear(); + } + + void enable_error_hook() + { + error_hook_enabled = true; + } + + void disable_error_hook() + { + error_hook_enabled = false; + } + + class component final : public component_interface + { + public: + + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + hks_start_hook.create(SELECT_VALUE(0x1400E4B40, 0x140176A40), hks_start_stub); + hks_shutdown_hook.create(SELECT_VALUE(0x1400DD3D0, 0x14016CA80), hks_shutdown_stub); + hksi_lual_error_hook.create(SELECT_VALUE(0x1400A5EA0, 0x14012F300), hksi_lual_error_stub); + hks_allocator_hook.create(SELECT_VALUE(0x14009B570, 0x14012BAC0), hks_allocator_stub); + hks_frame_hook.create(SELECT_VALUE(0x1400E37F0, 0x1401755B0), hks_frame_stub); + + if (game::environment::is_mp()) + { + hksi_lual_error_hook2.create(0x1401366B0, hksi_lual_error_stub); + } + + command::add("lui_restart", []() + { + utils::hook::invoke(SELECT_VALUE(0x1400DD3D0, 0x14016CA80)); + utils::hook::invoke(SELECT_VALUE(0x1400E6170, 0x1401780D0)); + }); + } + }; +} + +REGISTER_COMPONENT(ui_scripting::component) \ No newline at end of file diff --git a/src/client/component/ui_scripting.hpp b/src/client/component/ui_scripting.hpp new file mode 100644 index 00000000..2a48f6ec --- /dev/null +++ b/src/client/component/ui_scripting.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "game/ui_scripting/lua/value_conversion.hpp" + +namespace ui_scripting +{ + int main_function_handler(game::hks::lua_State* state); + void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function); + void clear_converted_functions(); + + void enable_error_hook(); + void disable_error_hook(); +} \ No newline at end of file diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp new file mode 100644 index 00000000..939dbd1c --- /dev/null +++ b/src/client/component/updater.cpp @@ -0,0 +1,474 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" +#include "dvars.hpp" +#include "updater.hpp" + +#include "version.h" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include +#include +#include +#include + +#define MASTER "https://master.fed0001.xyz/h1-mod/" + +#define FILES_PATH "files.json" +#define FILES_PATH_DEV "files-dev.json" + +#define DATA_PATH "data/" +#define DATA_PATH_DEV "data-dev/" + +#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates" +#define ERR_DOWNLOAD_FAIL "Failed to download file " +#define ERR_WRITE_FAIL "Failed to write file " + +#define BINARY_NAME "h1-mod.exe" + +namespace updater +{ + namespace + { + game::dvar_t* cl_auto_update; + bool has_tried_update = false; + + struct status + { + bool done; + bool success; + }; + + struct file_data + { + std::string name; + std::string data; + }; + + struct update_data_t + { + bool restart_required{}; + bool cancelled{}; + status check{}; + status download{}; + std::string error{}; + std::string current_file{}; + std::vector required_files{}; + }; + + utils::concurrency::container update_data; + + std::string get_branch() + { + return GIT_BRANCH; + } + + std::string select(const std::string& main, const std::string& develop) + { + if (get_branch() == "develop") + { + return develop; + } + + return main; + } + + std::string get_data_path() + { + if (get_branch() == "develop") + { + return DATA_PATH_DEV; + } + + return DATA_PATH; + } + + void set_update_check_status(bool done, bool success, const std::string& error = {}) + { + update_data.access([done, success, error](update_data_t& data_) + { + data_.check.done = done; + data_.check.success = success; + data_.error = error; + }); + } + + void set_update_download_status(bool done, bool success, const std::string& error = {}) + { + update_data.access([done, success, error](update_data_t& data_) + { + data_.download.done = done; + data_.download.success = success; + data_.error = error; + }); + } + + bool check_file(const std::string& name, const std::string& sha) + { + std::string data; + if (!utils::io::read_file(name, &data)) + { + return false; + } + + if (utils::cryptography::sha1::compute(data, true) != sha) + { + return false; + } + + return true; + } + + std::string load_binary_name() + { + // utils::nt::library self; + // return self.get_name(); + // returns the game's name and not the client's + + return BINARY_NAME; + } + + std::string get_binary_name() + { + static const auto name = load_binary_name(); + return name; + } + + std::string get_time_str() + { + return utils::string::va("%i", uint32_t(time(nullptr))); + } + + std::optional download_file(const std::string& name) + { + return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str()); + } + + bool is_update_cancelled() + { + return update_data.access([](update_data_t& data_) + { + return data_.cancelled; + }); + } + + bool write_file(const std::string& name, const std::string& data) + { + if (get_binary_name() == name && + utils::io::file_exists(name) && + !utils::io::move_file(name, name + ".old")) + { + return false; + } + +#ifdef DEBUG + return utils::io::write_file("update_test/" + name, data); +#else + return utils::io::write_file(name, data); +#endif + } + + void delete_old_file() + { + utils::io::remove_file(get_binary_name() + ".old"); + } + + void reset_data() + { + update_data.access([](update_data_t& data_) + { + data_ = {}; + }); + } + + std::string get_mode_flag() + { + if (game::environment::is_mp()) + { + return "-multiplayer"; + } + + if (game::environment::is_sp()) + { + return "-singleplayer"; + } + + return {}; + } + } + + // workaround + void relaunch() + { + if (!utils::io::file_exists(BINARY_NAME)) + { + utils::nt::terminate(0); + return; + } + + 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); + + char buf[1024] = {0}; + const auto command_line = utils::string::va("%s %s", GetCommandLineA(), get_mode_flag().data()); + strcpy_s(buf, 1024, command_line); + + CreateProcess(BINARY_NAME, buf, 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); + + utils::nt::terminate(0); + } + + void set_has_tried_update(bool tried) + { + has_tried_update = tried; + } + + bool get_has_tried_update() + { + return has_tried_update; + } + + bool auto_updates_enabled() + { + return cl_auto_update->current.enabled; + } + + bool is_update_check_done() + { + return update_data.access([](update_data_t& data_) + { + return data_.check.done; + }); + } + + bool is_update_download_done() + { + return update_data.access([](update_data_t& data_) + { + return data_.download.done; + }); + } + + bool get_update_check_status() + { + return update_data.access([](update_data_t& data_) + { + return data_.check.success; + }); + } + + bool get_update_download_status() + { + return update_data.access([](update_data_t& data_) + { + return data_.download.success; + }); + } + + bool is_update_available() + { + return update_data.access([](update_data_t& data_) + { + return data_.required_files.size() > 0; + }); + } + + bool is_restart_required() + { + return update_data.access([](update_data_t& data_) + { + return data_.restart_required; + }); + } + + std::string get_last_error() + { + return update_data.access([](update_data_t& data_) + { + return data_.error; + }); + } + + std::string get_current_file() + { + return update_data.access([](update_data_t& data_) + { + return data_.current_file; + }); + } + + void cancel_update() + { +#ifdef DEBUG + printf("[Updater] Cancelling update\n"); +#endif + + return update_data.access([](update_data_t& data_) + { + data_.cancelled = true; + }); + } + + void start_update_check() + { + cancel_update(); + reset_data(); + +#ifdef DEBUG + printf("[Updater] starting update check\n"); +#endif + + scheduler::once([]() + { + const auto files_data = utils::http::get_data(MASTER + select(FILES_PATH, FILES_PATH_DEV) + "?" + get_time_str()); + + if (is_update_cancelled()) + { + reset_data(); + return; + } + + if (!files_data.has_value()) + { + set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); + return; + } + + rapidjson::Document j; + j.Parse(files_data.value().data()); + + if (!j.IsArray()) + { + set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); + return; + } + + std::vector required_files; + + const auto files = j.GetArray(); + for (const auto& file : files) + { + if (!file.IsArray() || file.Size() != 3 || !file[0].IsString() || !file[2].IsString()) + { + continue; + } + + const auto name = file[0].GetString(); + const auto sha = file[2].GetString(); + + if (!check_file(name, sha)) + { + if (get_binary_name() == name) + { + update_data.access([](update_data_t& data_) + { + data_.restart_required = true; + }); + } + +#ifdef DEBUG + printf("[Updater] need file %s\n", name); +#endif + + required_files.push_back(name); + } + } + + update_data.access([&required_files](update_data_t& data_) + { + data_.check.done = true; + data_.check.success = true; + data_.required_files = required_files; + }); + }, scheduler::pipeline::async); + } + + void start_update_download() + { +#ifdef DEBUG + printf("[Updater] starting update download\n"); +#endif + + if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled()) + { + return; + } + + scheduler::once([]() + { + const auto required_files = update_data.access>([](update_data_t& data_) + { + return data_.required_files; + }); + + std::vector downloads; + + for (const auto& file : required_files) + { + update_data.access([file](update_data_t& data_) + { + data_.current_file = file; + }); + +#ifdef DEBUG + printf("[Updater] downloading file %s\n", file.data()); +#endif + + const auto data = download_file(file); + + if (is_update_cancelled()) + { + reset_data(); + return; + } + + if (!data.has_value()) + { + set_update_download_status(true, false, ERR_DOWNLOAD_FAIL + file); + return; + } + + downloads.push_back({file, data.value()}); + } + + for (const auto& download : downloads) + { + if (!write_file(download.name, download.data)) + { + set_update_download_status(true, false, ERR_WRITE_FAIL + download.name); + return; + } + } + + set_update_download_status(true, true); + }, scheduler::pipeline::async); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + delete_old_file(); + cl_auto_update = dvars::register_bool("cg_auto_update", true, game::DVAR_FLAG_SAVED, true); + } + }; +} + +REGISTER_COMPONENT(updater::component) diff --git a/src/client/component/updater.hpp b/src/client/component/updater.hpp new file mode 100644 index 00000000..9a3dd45e --- /dev/null +++ b/src/client/component/updater.hpp @@ -0,0 +1,26 @@ +#pragma once + +namespace updater +{ + void relaunch(); + + void set_has_tried_update(bool tried); + bool get_has_tried_update(); + bool auto_updates_enabled(); + + bool is_update_available(); + bool is_update_check_done(); + bool get_update_check_status(); + + bool is_update_download_done(); + bool get_update_download_status(); + + bool is_restart_required(); + + std::string get_last_error(); + std::string get_current_file(); + + void start_update_check(); + void start_update_download(); + void cancel_update(); +} \ No newline at end of file diff --git a/src/client/component/videos.cpp b/src/client/component/videos.cpp new file mode 100644 index 00000000..a602cc8a --- /dev/null +++ b/src/client/component/videos.cpp @@ -0,0 +1,55 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include + +namespace videos +{ + namespace + { + utils::hook::detour playvid_hook; + std::unordered_map video_replaces; + + void playvid(const char* name, const int a2, const int a3) + { + const auto vid = video_replaces.find(name); + if (vid != video_replaces.end()) + { + char path[256]; + game::Sys_BuildAbsPath(path, sizeof(path), game::SF_VIDEO, vid->second.data(), ".bik"); + + if (game::Sys_FileExists(path)) + { + name = vid->second.data(); + } + } + + return playvid_hook.invoke(name, a2, a3); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + playvid_hook.create(SELECT_VALUE(0x1404A9D00, 0x1405B0AF0), &playvid); // H1(1.4) + + if (game::environment::is_mp()) + { + video_replaces["menus_bg_comp2"] = "menus_bg_h1mod"; + video_replaces["mp_menus_bg_options"] = "menus_bg_h1mod_blur"; + } + else if (game::environment::is_sp()) + { + video_replaces["sp_menus_bg_main_menu"] = "menus_bg_h1mod_sp"; + video_replaces["sp_menus_bg_campaign"] = "menus_bg_h1mod_sp"; + video_replaces["sp_menus_bg_options"] = "menus_bg_h1mod_sp"; + } + } + }; +} + +REGISTER_COMPONENT(videos::component) diff --git a/src/client/component/virtuallobby.cpp b/src/client/component/virtuallobby.cpp new file mode 100644 index 00000000..eb6295f7 --- /dev/null +++ b/src/client/component/virtuallobby.cpp @@ -0,0 +1,63 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace virtuallobby +{ + namespace + { + game::dvar_t* virtualLobby_fovscale; + + const auto get_fovscale_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto ret = a.newLabel(); + const auto original = a.newLabel(); + + a.pushad64(); + a.mov(rax, qword_ptr(0x1425F7210)); // virtualLobbyInFiringRange + a.cmp(byte_ptr(rax, 0x10), 1); + a.je(original); + a.call_aligned(game::VirtualLobby_Loaded); + a.cmp(al, 0); + a.je(original); + + // virtuallobby + a.popad64(); + a.mov(rax, ptr(reinterpret_cast(&virtualLobby_fovscale))); + a.jmp(ret); + + // original + a.bind(original); + a.popad64(); + a.mov(rax, qword_ptr(0x1413A8580)); + a.jmp(ret); + + a.bind(ret); + a.mov(rcx, 0x142935000); + a.jmp(0x1400B556A); + }); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) + { + return; + } + + virtualLobby_fovscale = dvars::register_float("virtualLobby_fovScale", 0.7f, 0.0f, 2.0f, game::DVAR_FLAG_SAVED); + + utils::hook::nop(0x1400B555C, 14); + utils::hook::jump(0x1400B555C, get_fovscale_stub, true); + } + }; +} + +REGISTER_COMPONENT(virtuallobby::component) diff --git a/src/client/loader/loader.cpp b/src/client/loader/loader.cpp index 4ec12c7c..1bc7b41c 100644 --- a/src/client/loader/loader.cpp +++ b/src/client/loader/loader.cpp @@ -31,7 +31,7 @@ FARPROC loader::load(const utils::nt::library& library, const std::string& buffe return FARPROC(library.get_ptr() + source.get_relative_entry_point()); } -FARPROC loader::load_library(const std::string& filename, uint64_t* base_address) const +FARPROC loader::load_library(const std::string& filename) const { const auto target = utils::nt::library::load(filename); if (!target) @@ -40,7 +40,10 @@ FARPROC loader::load_library(const std::string& filename, uint64_t* base_address } const auto base = size_t(target.get_ptr()); - *base_address = base; + if(base != 0x140000000) + { + throw std::runtime_error{utils::string::va("Binary was mapped at 0x%llX (instead of 0x%llX). Something is severely broken :(", base, 0x140000000)}; + } this->load_imports(target, target); this->load_tls(target, target); diff --git a/src/client/loader/loader.hpp b/src/client/loader/loader.hpp index 0c0b5a12..2c5d86f9 100644 --- a/src/client/loader/loader.hpp +++ b/src/client/loader/loader.hpp @@ -5,7 +5,7 @@ class loader final { public: FARPROC load(const utils::nt::library& library, const std::string& buffer) const; - FARPROC load_library(const std::string& filename, uint64_t* base_address) const; + FARPROC load_library(const std::string& filename) const; void set_import_resolver(const std::function& resolver); diff --git a/src/client/resources/ui_scripts/common.lua b/src/client/resources/ui_scripts/common.lua new file mode 100644 index 00000000..8f68e96d --- /dev/null +++ b/src/client/resources/ui_scripts/common.lua @@ -0,0 +1,164 @@ +menucallbacks = {} +originalmenus = {} +stack = {} + +LUI.MenuBuilder.m_types_build["generic_waiting_popup_"] = function (menu, event) + local oncancel = stack.oncancel + local popup = LUI.MenuBuilder.BuildRegisteredType("waiting_popup", { + message_text = stack.text, + isLiveWithCancel = true, + cancel_func = function(...) + local args = {...} + oncancel() + LUI.FlowManager.RequestLeaveMenu(args[1]) + end + }) + + local listchildren = popup:getChildById("LUIHorizontalList"):getchildren() + local children = listchildren[2]:getchildren() + popup.text = children[2] + + stack = { + ret = popup + } + + return popup +end + +LUI.MenuBuilder.m_types_build["generic_yes_no_popup_"] = function() + local callback = stack.callback + local popup = LUI.MenuBuilder.BuildRegisteredType("generic_yesno_popup", { + popup_title = stack.title, + message_text = stack.text, + yes_action = function() + callback(true) + end, + no_action = function() + callback(false) + end + }) + + stack = { + ret = popup + } + + return popup +end + +LUI.MenuBuilder.m_types_build["generic_confirmation_popup_"] = function() + local popup = LUI.MenuBuilder.BuildRegisteredType( "generic_confirmation_popup", { + cancel_will_close = false, + popup_title = stack.title, + message_text = stack.text, + button_text = stack.buttontext, + confirmation_action = stack.callback + }) + + stack = { + ret = popup + } + + return stack.ret +end + +LUI.onmenuopen = function(name, callback) + if (not LUI.MenuBuilder.m_types_build[name]) then + return + end + + if (not menucallbacks[name]) then + menucallbacks[name] = {} + end + + table.insert(menucallbacks[name], callback) + + if (not originalmenus[name]) then + originalmenus[name] = LUI.MenuBuilder.m_types_build[name] + LUI.MenuBuilder.m_types_build[name] = function(...) + local args = {...} + local menu = originalmenus[name](table.unpack(args)) + + for k, v in luiglobals.next, menucallbacks[name] do + v(menu, table.unpack(args)) + end + + return menu + end + end +end + +local addoptionstextinfo = LUI.Options.AddOptionTextInfo +LUI.Options.AddOptionTextInfo = function(menu) + local result = addoptionstextinfo(menu) + menu.optionTextInfo = result + return result +end + +LUI.addmenubutton = function(name, data) + LUI.onmenuopen(name, function(menu) + if (not menu.list) then + return + end + + local button = menu:AddButton(data.text, data.callback, nil, true, nil, { + desc_text = data.description + }) + + local buttonlist = menu:getChildById(menu.type .. "_list") + + if (data.id) then + button.id = data.id + end + + if (data.index) then + buttonlist:removeElement(button) + buttonlist:insertElement(button, data.index) + end + + local hintbox = menu.optionTextInfo + menu:removeElement(hintbox) + + LUI.Options.InitScrollingList(menu.list, nil) + menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu) + end) +end + +LUI.openmenu = function(menu, args) + stack = args + LUI.FlowManager.RequestAddMenu(nil, menu) + return stack.ret +end + +LUI.openpopupmenu = function(menu, args) + stack = args + LUI.FlowManager.RequestPopupMenu(nil, menu) + return stack.ret +end + +LUI.yesnopopup = function(data) + for k, v in luiglobals.next, data do + stack[k] = v + end + LUI.FlowManager.RequestPopupMenu(nil, "generic_yes_no_popup_") + return stack.ret +end + +LUI.confirmationpopup = function(data) + for k, v in luiglobals.next, data do + stack[k] = v + end + LUI.FlowManager.RequestPopupMenu(nil, "generic_confirmation_popup_") + return stack.ret +end + +function userdata_:getchildren() + local children = {} + local first = self:getFirstChild() + + while (first) do + table.insert(children, first) + first = first:getNextSibling() + end + + return children +end diff --git a/src/client/resources/ui_scripts/updater.lua b/src/client/resources/ui_scripts/updater.lua new file mode 100644 index 00000000..01d77360 --- /dev/null +++ b/src/client/resources/ui_scripts/updater.lua @@ -0,0 +1,164 @@ +updatecancelled = false +taskinterval = 100 + +updater.cancelupdate() + +function startupdatecheck(popup, autoclose) + updatecancelled = false + + local callback = function() + if (not updater.getupdatecheckstatus()) then + if (autoclose) then + LUI.FlowManager.RequestLeaveMenu(popup) + return + end + + popup.text:setText("Error: " .. updater.getlasterror()) + return + end + + if (not updater.isupdateavailable()) then + if (autoclose) then + LUI.FlowManager.RequestLeaveMenu(popup) + return + end + + popup.text:setText("No updates available") + return + end + + LUI.yesnopopup({ + title = "NOTICE", + text = "An update is available, proceed with installation?", + callback = function(result) + if (result) then + startupdatedownload(popup, autoclose) + else + LUI.FlowManager.RequestLeaveMenu(popup) + end + end + }) + end + + updater.startupdatecheck() + createtask({ + done = updater.isupdatecheckdone, + cancelled = isupdatecancelled, + callback = callback, + interval = taskinterval + }) +end + +function startupdatedownload(popup, autoclose) + updater.startupdatedownload() + + local textupdate = nil + local previousfile = nil + textupdate = game:oninterval(function() + local file = updater.getcurrentfile() + if (file == previousfile) then + return + end + + file = previousfile + popup.text:setText("Downloading file " .. updater.getcurrentfile() .. "...") + end, 10) + + local callback = function() + textupdate:clear() + + if (not updater.getupdatedownloadstatus()) then + if (autoclose) then + LUI.FlowManager.RequestLeaveMenu(popup) + return + end + + popup.text:setText("Error: " .. updater.getlasterror()) + return + end + + popup.text:setText("Update successful") + + if (updater.isrestartrequired()) then + LUI.confirmationpopup({ + title = "RESTART REQUIRED", + text = "Update requires restart", + buttontext = "RESTART", + callback = function() + updater.relaunch() + end + }) + else + if (LUI.mp_menus) then + Engine.Exec("lui_restart; lui_open mp_main_menu") + else + Engine.Exec("lui_restart") + end + end + + if (autoclose) then + LUI.FlowManager.RequestLeaveMenu(popup) + end + end + + createtask({ + done = updater.isupdatedownloaddone, + cancelled = isupdatecancelled, + callback = callback, + interval = taskinterval + }) +end + +function updaterpopup(oncancel) + return LUI.openpopupmenu("generic_waiting_popup_", { + oncancel = oncancel, + withcancel = true, + text = "Checking for updates..." + }) +end + +function createtask(data) + local interval = nil + interval = game:oninterval(function() + if (data.cancelled()) then + interval:clear() + return + end + + if (data.done()) then + interval:clear() + data.callback() + end + end, data.interval) + return interval +end + +function isupdatecancelled() + return updatecancelled +end + +function tryupdate(autoclose) + updatecancelled = false + local popup = updaterpopup(function() + updater.cancelupdate() + updatecancelled = true + end) + + startupdatecheck(popup, autoclose) +end + +function tryautoupdate() + if (not updater.autoupdatesenabled()) then + return + end + + if (not updater.gethastriedupdate()) then + game:ontimeout(function() + updater.sethastriedupdate(true) + tryupdate(true) + end, 100) + end +end + +LUI.onmenuopen("mp_main_menu", tryautoupdate) +LUI.onmenuopen("main_lockout", tryautoupdate) \ No newline at end of file From 34b2fcd4cc0c62e1346f3296b7c2f9ddcbd9d635 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Fri, 18 Mar 2022 02:54:50 +0200 Subject: [PATCH 09/22] loader [skip ci] --- src/client/loader/loader.cpp | 7 ++----- src/client/loader/loader.hpp | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/client/loader/loader.cpp b/src/client/loader/loader.cpp index 1bc7b41c..4ec12c7c 100644 --- a/src/client/loader/loader.cpp +++ b/src/client/loader/loader.cpp @@ -31,7 +31,7 @@ FARPROC loader::load(const utils::nt::library& library, const std::string& buffe return FARPROC(library.get_ptr() + source.get_relative_entry_point()); } -FARPROC loader::load_library(const std::string& filename) const +FARPROC loader::load_library(const std::string& filename, uint64_t* base_address) const { const auto target = utils::nt::library::load(filename); if (!target) @@ -40,10 +40,7 @@ FARPROC loader::load_library(const std::string& filename) const } const auto base = size_t(target.get_ptr()); - if(base != 0x140000000) - { - throw std::runtime_error{utils::string::va("Binary was mapped at 0x%llX (instead of 0x%llX). Something is severely broken :(", base, 0x140000000)}; - } + *base_address = base; this->load_imports(target, target); this->load_tls(target, target); diff --git a/src/client/loader/loader.hpp b/src/client/loader/loader.hpp index 2c5d86f9..0c0b5a12 100644 --- a/src/client/loader/loader.hpp +++ b/src/client/loader/loader.hpp @@ -5,7 +5,7 @@ class loader final { public: FARPROC load(const utils::nt::library& library, const std::string& buffer) const; - FARPROC load_library(const std::string& filename) const; + FARPROC load_library(const std::string& filename, uint64_t* base_address) const; void set_import_resolver(const std::function& resolver); From a59bcbf442da2ffc4d9059bf40b7350c8db2d1b9 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Fri, 18 Mar 2022 02:58:43 +0200 Subject: [PATCH 10/22] arxan class [skip ci] --- src/client/component/arxan.cpp | 164 +++++++++++++++++++++++++++++++++ src/client/main.cpp | 50 ++++++---- 2 files changed, 195 insertions(+), 19 deletions(-) create mode 100644 src/client/component/arxan.cpp diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp new file mode 100644 index 00000000..adff7199 --- /dev/null +++ b/src/client/component/arxan.cpp @@ -0,0 +1,164 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" +#include "game/game.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 && size_t(handle) != 0x12345) + { + 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() == game::DW_LIVE_CONNECTED + && context->ContextFlags == CONTEXT_DEBUG_REGISTERS) + { + return TRUE; + } + + return SetThreadContext(thread, context); + } + } + + int just_return() + { + return 1; + } + + 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; + } + + if (function == "LoadStringA" || function == "LoadStringW") + { + return just_return; + } + + 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 + { + // cba to implement sp, not sure if it's even needed + if (game::environment::is_sp()) return; + + // some of arxan crashes + utils::hook::nop(0x14CDEFCAA, 6); + utils::hook::call(0x1405BCAD1, &just_return); + } + }; +} + +REGISTER_COMPONENT(arxan::component) \ No newline at end of file diff --git a/src/client/main.cpp b/src/client/main.cpp index 519756b2..71979cbf 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -51,7 +51,7 @@ launcher::mode detect_mode_from_arguments() } -FARPROC load_binary(const launcher::mode mode) +FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) { loader loader; utils::nt::library self; @@ -97,11 +97,11 @@ FARPROC load_binary(const launcher::mode mode) if (!utils::io::read_file(binary, &data)) { throw std::runtime_error(utils::string::va( - "Failed to read game binary (%s)!\nPlease copy the h1-mod.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there.", + "Failed to read game binary (%s)!\nPlease copy the h1x.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there.", binary.data())); } - return loader.load_library(binary); + return loader.load_library(binary, base_address); } void remove_crash_file() @@ -111,10 +111,10 @@ void remove_crash_file() void enable_dpi_awareness() { - const utils::nt::library user32{"user32.dll"}; + const utils::nt::library user32{ "user32.dll" }; const auto set_dpi = user32 - ? user32.get_proc("SetProcessDpiAwarenessContext") - : nullptr; + ? user32.get_proc("SetProcessDpiAwarenessContext") + : nullptr; if (set_dpi) { set_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); @@ -149,48 +149,60 @@ void limit_parallel_dll_loading() int main() { + ShowWindow(GetConsoleWindow(), SW_HIDE); + FARPROC entry_point; enable_dpi_awareness(); - // This requires admin privilege, but I suppose many - // people will start with admin rights if it crashes. limit_parallel_dll_loading(); srand(uint32_t(time(nullptr))); + remove_crash_file(); { auto premature_shutdown = true; const auto _ = gsl::finally([&premature_shutdown]() - { - if (premature_shutdown) { - component_loader::pre_destroy(); - } - }); + if (premature_shutdown) + { + component_loader::pre_destroy(); + } + }); try { - remove_crash_file(); - - if (!component_loader::post_start()) return 0; + if (!component_loader::post_start()) + { + return 0; + } auto mode = detect_mode_from_arguments(); if (mode == launcher::mode::none) { const launcher launcher; mode = launcher.run(); - if (mode == launcher::mode::none) return 0; + if (mode == launcher::mode::none) + { + return 0; + } } game::environment::set_mode(mode); - entry_point = load_binary(mode); + uint64_t base_address{}; + entry_point = load_binary(mode, &base_address); if (!entry_point) { throw std::runtime_error("Unable to load binary into memory"); } - if (!component_loader::post_load()) return 0; + game::base_address = base_address; + //verify_version(); + + if (!component_loader::post_load()) + { + return 0; + } premature_shutdown = false; } From a7bbcb355fae461c5bd8f3f87ec7a4c283073d01 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:19:50 +0200 Subject: [PATCH 11/22] small clean up [skip ci] also no compiler err's --- src/client/component/bots.cpp | 103 - src/client/component/logfile.cpp | 317 -- src/client/component/logfile.hpp | 13 - src/client/component/lui.cpp | 58 - src/client/component/scripting.cpp | 141 - src/client/component/scripting.hpp | 8 - src/client/component/shaders.cpp | 50 - src/client/component/slowmotion.cpp | 53 - src/client/component/thread_names.cpp | 60 - src/client/component/ui_scripting.cpp | 180 - src/client/component/ui_scripting.hpp | 12 - src/client/component/updater.cpp | 474 --- src/client/component/updater.hpp | 26 - src/client/component/videos.cpp | 55 - src/client/component/virtuallobby.cpp | 63 - src/client/game/scripting/entity.cpp | 120 - src/client/game/scripting/entity.hpp | 50 - src/client/game/scripting/event.hpp | 13 - src/client/game/scripting/execution.cpp | 240 -- src/client/game/scripting/execution.hpp | 36 - src/client/game/scripting/function_tables.cpp | 3480 ----------------- src/client/game/scripting/functions.cpp | 106 - src/client/game/scripting/functions.hpp | 16 - src/client/game/scripting/lua/context.cpp | 542 --- src/client/game/scripting/lua/context.hpp | 45 - src/client/game/scripting/lua/engine.cpp | 75 - src/client/game/scripting/lua/engine.hpp | 11 - src/client/game/scripting/lua/error.cpp | 37 - src/client/game/scripting/lua/error.hpp | 8 - .../game/scripting/lua/event_handler.cpp | 174 - .../game/scripting/lua/event_handler.hpp | 58 - src/client/game/scripting/lua/scheduler.cpp | 171 - src/client/game/scripting/lua/scheduler.hpp | 54 - .../game/scripting/lua/value_conversion.cpp | 319 -- .../game/scripting/lua/value_conversion.hpp | 11 - src/client/game/scripting/safe_execution.cpp | 72 - src/client/game/scripting/safe_execution.hpp | 10 - src/client/game/scripting/script_value.cpp | 278 -- src/client/game/scripting/script_value.hpp | 52 - src/client/game/scripting/stack_isolation.cpp | 27 - src/client/game/scripting/stack_isolation.hpp | 25 - src/client/game/scripting/variable_value.cpp | 68 - src/client/game/scripting/variable_value.hpp | 27 - src/client/game/scripting/vector.cpp | 85 - src/client/game/scripting/vector.hpp | 31 - src/client/game/symbols.hpp | 2 + src/client/game/ui_scripting/execution.cpp | 161 - src/client/game/ui_scripting/execution.hpp | 18 - src/client/game/ui_scripting/lua/context.cpp | 239 -- src/client/game/ui_scripting/lua/context.hpp | 42 - src/client/game/ui_scripting/lua/engine.cpp | 73 - src/client/game/ui_scripting/lua/engine.hpp | 8 - src/client/game/ui_scripting/lua/error.cpp | 18 - src/client/game/ui_scripting/lua/error.hpp | 8 - .../game/ui_scripting/lua/scheduler.cpp | 122 - .../game/ui_scripting/lua/scheduler.hpp | 50 - .../ui_scripting/lua/value_conversion.cpp | 144 - .../ui_scripting/lua/value_conversion.hpp | 9 - src/client/game/ui_scripting/script_value.cpp | 274 -- src/client/game/ui_scripting/script_value.hpp | 56 - src/client/game/ui_scripting/types.cpp | 276 -- src/client/game/ui_scripting/types.hpp | 89 - src/client/main.cpp | 2 +- 63 files changed, 3 insertions(+), 9442 deletions(-) delete mode 100644 src/client/component/bots.cpp delete mode 100644 src/client/component/logfile.cpp delete mode 100644 src/client/component/logfile.hpp delete mode 100644 src/client/component/lui.cpp delete mode 100644 src/client/component/scripting.cpp delete mode 100644 src/client/component/scripting.hpp delete mode 100644 src/client/component/shaders.cpp delete mode 100644 src/client/component/slowmotion.cpp delete mode 100644 src/client/component/thread_names.cpp delete mode 100644 src/client/component/ui_scripting.cpp delete mode 100644 src/client/component/ui_scripting.hpp delete mode 100644 src/client/component/updater.cpp delete mode 100644 src/client/component/updater.hpp delete mode 100644 src/client/component/videos.cpp delete mode 100644 src/client/component/virtuallobby.cpp delete mode 100644 src/client/game/scripting/entity.cpp delete mode 100644 src/client/game/scripting/entity.hpp delete mode 100644 src/client/game/scripting/event.hpp delete mode 100644 src/client/game/scripting/execution.cpp delete mode 100644 src/client/game/scripting/execution.hpp delete mode 100644 src/client/game/scripting/function_tables.cpp delete mode 100644 src/client/game/scripting/functions.cpp delete mode 100644 src/client/game/scripting/functions.hpp delete mode 100644 src/client/game/scripting/lua/context.cpp delete mode 100644 src/client/game/scripting/lua/context.hpp delete mode 100644 src/client/game/scripting/lua/engine.cpp delete mode 100644 src/client/game/scripting/lua/engine.hpp delete mode 100644 src/client/game/scripting/lua/error.cpp delete mode 100644 src/client/game/scripting/lua/error.hpp delete mode 100644 src/client/game/scripting/lua/event_handler.cpp delete mode 100644 src/client/game/scripting/lua/event_handler.hpp delete mode 100644 src/client/game/scripting/lua/scheduler.cpp delete mode 100644 src/client/game/scripting/lua/scheduler.hpp delete mode 100644 src/client/game/scripting/lua/value_conversion.cpp delete mode 100644 src/client/game/scripting/lua/value_conversion.hpp delete mode 100644 src/client/game/scripting/safe_execution.cpp delete mode 100644 src/client/game/scripting/safe_execution.hpp delete mode 100644 src/client/game/scripting/script_value.cpp delete mode 100644 src/client/game/scripting/script_value.hpp delete mode 100644 src/client/game/scripting/stack_isolation.cpp delete mode 100644 src/client/game/scripting/stack_isolation.hpp delete mode 100644 src/client/game/scripting/variable_value.cpp delete mode 100644 src/client/game/scripting/variable_value.hpp delete mode 100644 src/client/game/scripting/vector.cpp delete mode 100644 src/client/game/scripting/vector.hpp delete mode 100644 src/client/game/ui_scripting/execution.cpp delete mode 100644 src/client/game/ui_scripting/execution.hpp delete mode 100644 src/client/game/ui_scripting/lua/context.cpp delete mode 100644 src/client/game/ui_scripting/lua/context.hpp delete mode 100644 src/client/game/ui_scripting/lua/engine.cpp delete mode 100644 src/client/game/ui_scripting/lua/engine.hpp delete mode 100644 src/client/game/ui_scripting/lua/error.cpp delete mode 100644 src/client/game/ui_scripting/lua/error.hpp delete mode 100644 src/client/game/ui_scripting/lua/scheduler.cpp delete mode 100644 src/client/game/ui_scripting/lua/scheduler.hpp delete mode 100644 src/client/game/ui_scripting/lua/value_conversion.cpp delete mode 100644 src/client/game/ui_scripting/lua/value_conversion.hpp delete mode 100644 src/client/game/ui_scripting/script_value.cpp delete mode 100644 src/client/game/ui_scripting/script_value.hpp delete mode 100644 src/client/game/ui_scripting/types.cpp delete mode 100644 src/client/game/ui_scripting/types.hpp diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp deleted file mode 100644 index 81f74628..00000000 --- a/src/client/component/bots.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "command.hpp" -#include "scheduler.hpp" -#include "network.hpp" -#include "party.hpp" - -#include "game/game.hpp" -#include "game/scripting/execution.hpp" - -#include -#include -#include - -namespace bots -{ - namespace - { - bool can_add() - { - if (party::get_client_count() < *game::mp::svs_numclients) - { - return true; - } - return false; - } - - // TODO: when scripting comes, fix this to use better notifies - void bot_team_join(const int entity_num) - { - const game::scr_entref_t entref{static_cast(entity_num), 0}; - scheduler::once([entref]() - { - scripting::notify(entref, "luinotifyserver", {"team_select", 2}); - scheduler::once([entref]() - { - auto* _class = utils::string::va("class%d", utils::cryptography::random::get_integer() % 5); - scripting::notify(entref, "luinotifyserver", {"class_select", _class}); - }, scheduler::pipeline::server, 2s); - }, scheduler::pipeline::server, 2s); - } - - void spawn_bot(const int entity_num) - { - game::SV_SpawnTestClient(&game::mp::g_entities[entity_num]); - if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_CORE) - { - bot_team_join(entity_num); - } - } - - void add_bot() - { - if (!can_add()) - { - return; - } - - // SV_BotGetRandomName - const auto* const bot_name = game::SV_BotGetRandomName(); - auto* bot_ent = game::SV_AddBot(bot_name); - if (bot_ent) - { - spawn_bot(bot_ent->s.entityNum); - } - else if (can_add()) // workaround since first bot won't ever spawn - { - add_bot(); - } - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - command::add("spawnBot", [](const command::params& params) - { - if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) return; - - auto num_bots = 1; - if (params.size() == 2) - { - num_bots = atoi(params.get(1)); - } - - for (auto i = 0; i < (num_bots > *game::mp::svs_numclients ? *game::mp::svs_numclients : num_bots); i++) - { - scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i); - } - }); - } - }; -} - -REGISTER_COMPONENT(bots::component) \ No newline at end of file diff --git a/src/client/component/logfile.cpp b/src/client/component/logfile.cpp deleted file mode 100644 index fc949d92..00000000 --- a/src/client/component/logfile.cpp +++ /dev/null @@ -1,317 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "scheduler.hpp" - -#include "game/scripting/entity.hpp" -#include "game/scripting/execution.hpp" -#include "game/scripting/lua/value_conversion.hpp" -#include "game/scripting/lua/error.hpp" - -#include - -#include "logfile.hpp" - -namespace logfile -{ - std::unordered_map vm_execute_hooks; - - namespace - { - utils::hook::detour scr_player_killed_hook; - utils::hook::detour scr_player_damage_hook; - - std::vector player_killed_callbacks; - std::vector player_damage_callbacks; - - utils::hook::detour vm_execute_hook; - char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END - bool hook_enabled = true; - - sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent) - { - if (!ent) - { - return {}; - } - - const scripting::entity player{game::Scr_GetEntityId(ent->s.entityNum, 0)}; - return scripting::lua::convert(state, player); - } - - std::string get_weapon_name(unsigned int weapon, bool isAlternate) - { - char output[1024] = {0}; - game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024); - return output; - } - - sol::lua_value convert_vector(lua_State* state, const float* vec) - { - if (!vec) - { - return {}; - } - - const auto vec_ = scripting::vector(vec); - return scripting::lua::convert(state, vec_); - } - - std::string convert_mod(const int meansOfDeath) - { - const auto value = reinterpret_cast(0x140FEC3F0)[meansOfDeath]; - const auto string = game::SL_ConvertToString(*value); - return string; - } - - void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, - game::mp::gentity_s* attacker, int damage, const int meansOfDeath, const unsigned int weapon, - const bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration) - { - { - const std::string hitloc = reinterpret_cast(0x140FEC4D0)[hitLoc]; - const auto mod_ = convert_mod(meansOfDeath); - - const auto weapon_ = get_weapon_name(weapon, isAlternate); - - for (const auto& callback : player_killed_callbacks) - { - const auto state = callback.lua_state(); - - const auto self_ = convert_entity(state, self); - const auto inflictor_ = convert_entity(state, inflictor); - const auto attacker_ = convert_entity(state, attacker); - - const auto dir = convert_vector(state, vDir); - - const auto result = callback(self_, inflictor_, attacker_, damage, - mod_, weapon_, dir, hitloc, psTimeOffset, deathAnimDuration); - - scripting::lua::handle_error(result); - - if (result.valid() && result.get_type() == sol::type::number) - { - damage = result.get(); - } - } - - if (damage == 0) - { - return; - } - } - - scr_player_killed_hook.invoke(self, inflictor, attacker, damage, meansOfDeath, - weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration); - } - - void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, - game::mp::gentity_s* attacker, int damage, int dflags, const int meansOfDeath, - const unsigned int weapon, const bool isAlternate, const float* vPoint, - const float* vDir, const unsigned int hitLoc, const int timeOffset) - { - { - const std::string hitloc = reinterpret_cast(0x140FEC4D0)[hitLoc]; - const auto mod_ = convert_mod(meansOfDeath); - - const auto weapon_ = get_weapon_name(weapon, isAlternate); - - for (const auto& callback : player_damage_callbacks) - { - const auto state = callback.lua_state(); - - const auto self_ = convert_entity(state, self); - const auto inflictor_ = convert_entity(state, inflictor); - const auto attacker_ = convert_entity(state, attacker); - - const auto point = convert_vector(state, vPoint); - const auto dir = convert_vector(state, vDir); - - const auto result = callback(self_, inflictor_, attacker_, - damage, dflags, mod_, weapon_, point, dir, hitloc); - - scripting::lua::handle_error(result); - - if (result.valid() && result.get_type() == sol::type::number) - { - damage = result.get(); - } - } - - if (damage == 0) - { - return; - } - } - - scr_player_damage_hook.invoke(self, inflictor, attacker, damage, dflags, - meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset); - } - - void client_command_stub(const int clientNum) - { - auto self = &game::mp::g_entities[clientNum]; - char cmd[1024] = {0}; - - game::SV_Cmd_ArgvBuffer(0, cmd, 1024); - - if (cmd == "say"s || cmd == "say_team"s) - { - auto hidden = false; - std::string message(game::ConcatArgs(1)); - - hidden = message[1] == '/'; - message.erase(0, hidden ? 2 : 1); - - scheduler::once([cmd, message, self]() - { - const scripting::entity level{*game::levelEntityId}; - const scripting::entity player{game::Scr_GetEntityId(self->s.entityNum, 0)}; - - scripting::notify(level, cmd, {player, message}); - scripting::notify(player, cmd, {message}); - }, scheduler::pipeline::server); - - if (hidden) - { - return; - } - } - - // ClientCommand - return utils::hook::invoke(0x140336000, clientNum); - } - - void g_shutdown_game_stub(const int freeScripts) - { - { - const scripting::entity level{*game::levelEntityId}; - scripting::notify(level, "shutdownGame_called", {1}); - } - - // G_ShutdownGame - return utils::hook::invoke(0x140345A60, freeScripts); - } - - unsigned int local_id_to_entity(unsigned int local_id) - { - const auto variable = game::scr_VarGlob->objectVariableValue[local_id]; - return variable.u.f.next; - } - - bool execute_vm_hook(const char* pos) - { - if (vm_execute_hooks.find(pos) == vm_execute_hooks.end()) - { - 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]; - const auto state = hook.lua_state(); - - const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId); - - std::vector args; - - const auto top = game::scr_function_stack->top; - - for (auto* value = top; value->type != game::SCRIPT_END; --value) - { - args.push_back(scripting::lua::convert(state, *value)); - } - - const auto result = hook(self, sol::as_args(args)); - scripting::lua::handle_error(result); - - 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.mov(dword_ptr(rbp, 0xA4), r15d); - - a.jmp(SELECT_VALUE(0x140376663, 0x140444653)); - - a.bind(replace); - - a.popad64(); - a.mov(r14, reinterpret_cast(empty_function)); - a.jmp(end); - } - } - - void add_player_damage_callback(const sol::protected_function& callback) - { - player_damage_callbacks.push_back(callback); - } - - void add_player_killed_callback(const sol::protected_function& callback) - { - player_killed_callbacks.push_back(callback); - } - - void clear_callbacks() - { - player_damage_callbacks.clear(); - player_killed_callbacks.clear(); - vm_execute_hooks.clear(); - } - - void enable_vm_execute_hook() - { - hook_enabled = true; - } - - void disable_vm_execute_hook() - { - hook_enabled = false; - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - utils::hook::call(0x14048191D, client_command_stub); - - scr_player_damage_hook.create(0x14037DC50, scr_player_damage_stub); - scr_player_killed_hook.create(0x14037DF30, scr_player_killed_stub); - - utils::hook::call(0x140484EC0, g_shutdown_game_stub); - utils::hook::call(0x1404853C1, g_shutdown_game_stub); - - utils::hook::jump(SELECT_VALUE(0x140376655, 0x140444645), utils::hook::assemble(vm_execute_stub), true); - } - }; -} - -REGISTER_COMPONENT(logfile::component) \ No newline at end of file diff --git a/src/client/component/logfile.hpp b/src/client/component/logfile.hpp deleted file mode 100644 index 77f699c8..00000000 --- a/src/client/component/logfile.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace logfile -{ - extern std::unordered_map vm_execute_hooks; - - void add_player_damage_callback(const sol::protected_function& callback); - void add_player_killed_callback(const sol::protected_function& callback); - void clear_callbacks(); - - void enable_vm_execute_hook(); - void disable_vm_execute_hook(); -} \ No newline at end of file diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp deleted file mode 100644 index d3a7edca..00000000 --- a/src/client/component/lui.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" - -#include "command.hpp" -#include "console.hpp" - -#include - -namespace lui -{ - class component final : public component_interface - { - public: - void post_unpack() override - { - // Don't show create cod account popup - //utils::hook::set(0x14017C957, 0); // H1(1.4) - -//#ifdef _DEBUG - // Enable development menus (causes issues in sp) - //utils::hook::set(SELECT_VALUE(0x1400B4ABC, 0x1401AB779), 1); -//#endif - - 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], 0, 0, 0); - }); - - command::add("lui_open_popup", [](const command::params& params) - { - if (params.size() <= 1) - { - console::info("usage: lui_open_popup \n"); - return; - } - - game::LUI_OpenMenu(0, params[1], 1, 0, 0); - }); - - command::add("runMenuScript", [](const command::params& params) - { - const auto args_str = params.join(1); - const auto* args = args_str.data(); - game::UI_RunMenuScript(0, &args); - }); - } - }; -} - -REGISTER_COMPONENT(lui::component) diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp deleted file mode 100644 index e3116122..00000000 --- a/src/client/component/scripting.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include - -#include "game/scripting/entity.hpp" -#include "game/scripting/functions.hpp" -#include "game/scripting/event.hpp" -#include "game/scripting/lua/engine.hpp" -#include "game/scripting/execution.hpp" - -#include "scheduler.hpp" -#include "scripting.hpp" - -namespace scripting -{ - std::unordered_map> fields_table; - std::unordered_map> script_function_table; - - namespace - { - utils::hook::detour vm_notify_hook; - utils::hook::detour scr_load_level_hook; - utils::hook::detour g_shutdown_game_hook; - - utils::hook::detour scr_add_class_field_hook; - - utils::hook::detour scr_set_thread_position_hook; - utils::hook::detour process_script_hook; - - std::string current_file; - - void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, - game::VariableValue* top) - { - if (!game::VirtualLobby_Loaded()) - { - const auto* string = game::SL_ConvertToString(string_value); - if (string) - { - event e; - e.name = string; - e.entity = notify_list_owner_id; - - for (auto* value = top; value->type != game::SCRIPT_END; --value) - { - e.arguments.emplace_back(*value); - } - - if (e.name == "entitydeleted") - { - scripting::clear_entity_fields(e.entity); - } - - lua::engine::notify(e); - } - } - - vm_notify_hook.invoke(notify_list_owner_id, string_value, top); - } - - void scr_load_level_stub() - { - scr_load_level_hook.invoke(); - if (!game::VirtualLobby_Loaded()) - { - lua::engine::start(); - } - } - - void g_shutdown_game_stub(const int free_scripts) - { - lua::engine::stop(); - return g_shutdown_game_hook.invoke(free_scripts); - } - - void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t _name, unsigned int canonicalString, unsigned int offset) - { - const auto name = game::SL_ConvertToString(_name); - - if (fields_table[classnum].find(name) == fields_table[classnum].end()) - { - fields_table[classnum][name] = offset; - } - - scr_add_class_field_hook.invoke(classnum, _name, canonicalString, offset); - } - - void process_script_stub(const char* filename) - { - const auto file_id = atoi(filename); - if (file_id) - { - current_file = scripting::find_token(file_id); - } - else - { - current_file = filename; - } - - process_script_hook.invoke(filename); - } - - void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) - { - const auto function_name = scripting::find_token(threadName); - script_function_table[current_file][function_name] = codePos; - scr_set_thread_position_hook.invoke(threadName, codePos); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::environment::is_sp()) - { - return; - } - - vm_notify_hook.create(SELECT_VALUE(0x140379A00, 0x1404479F0), vm_notify_stub); - - scr_add_class_field_hook.create(SELECT_VALUE(0x140370370, 0x14043E2C0), scr_add_class_field_stub); - - scr_set_thread_position_hook.create(SELECT_VALUE(0x14036A180, 0x140437D10), scr_set_thread_position_stub); - process_script_hook.create(SELECT_VALUE(0x1403737E0, 0x1404417E0), process_script_stub); - - scr_load_level_hook.create(SELECT_VALUE(0x1402A5BE0, 0x1403727C0), scr_load_level_stub); - g_shutdown_game_hook.create(SELECT_VALUE(0x140277D40, 0x140345A60), g_shutdown_game_stub); - - scheduler::loop([]() - { - lua::engine::run_frame(); - }, scheduler::pipeline::server); - } - }; -} - -REGISTER_COMPONENT(scripting::component) \ No newline at end of file diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp deleted file mode 100644 index 865ae858..00000000 --- a/src/client/component/scripting.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -namespace scripting -{ - extern std::unordered_map> fields_table; - extern std::unordered_map> script_function_table; -} \ No newline at end of file diff --git a/src/client/component/shaders.cpp b/src/client/component/shaders.cpp deleted file mode 100644 index ec632115..00000000 --- a/src/client/component/shaders.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" -#include "dvars.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include - -namespace shaders -{ - namespace - { - game::dvar_t* disable_shader_caching = nullptr; - - bool shader_should_show_dialog_stub() - { - return !disable_shader_caching->current.enabled; - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_mp()) - { - return; - } - - const auto has_flag = utils::flags::has_flag("noshadercaching"); - - disable_shader_caching = dvars::register_bool("disable_shader_caching", has_flag, game::DVAR_FLAG_SAVED, true); - if (has_flag) - { - dvars::override::set_bool("disable_shader_caching", 1); - dvars::override::set_from_string("disable_shader_caching", "1"); - } - - utils::hook::jump(0x14007E710, shader_should_show_dialog_stub); - } - }; -} - -REGISTER_COMPONENT(shaders::component) diff --git a/src/client/component/slowmotion.cpp b/src/client/component/slowmotion.cpp deleted file mode 100644 index 71f66dbf..00000000 --- a/src/client/component/slowmotion.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include "loader/component_loader.hpp" -#include "game/game.hpp" - -#include -#include - -namespace slowmotion -{ - namespace - { - 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(1u); - } - - if (game::Scr_GetNumParam() >= 3) - { - duration = static_cast(game::Scr_GetFloat(2u) * 1000.0f); - } - - game::SV_SetConfigstring(10, utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end)); - game::Com_SetSlowMotion(start, end, duration); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_dedi()) - { - return; - } - - utils::hook::jump(0x140365480, scr_cmd_set_slow_motion); // H1(1.4) - } - }; -} - -REGISTER_COMPONENT(slowmotion::component) diff --git a/src/client/component/thread_names.cpp b/src/client/component/thread_names.cpp deleted file mode 100644 index 84b5fa70..00000000 --- a/src/client/component/thread_names.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" - -#include "game/game.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 deleted file mode 100644 index 941dda10..00000000 --- a/src/client/component/ui_scripting.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include "scheduler.hpp" -#include "command.hpp" - -#include "ui_scripting.hpp" - -#include "game/ui_scripting/lua/engine.hpp" -#include "game/ui_scripting/execution.hpp" -#include "game/ui_scripting/lua/error.hpp" - -#include -#include - -namespace ui_scripting -{ - namespace - { - std::unordered_map converted_functions; - - utils::hook::detour hksi_lual_error_hook; - utils::hook::detour hksi_lual_error_hook2; - utils::hook::detour hks_start_hook; - utils::hook::detour hks_shutdown_hook; - utils::hook::detour hks_allocator_hook; - utils::hook::detour hks_frame_hook; - - bool error_hook_enabled = false; - - void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...) - { - char va_buffer[2048] = {0}; - - va_list ap; - va_start(ap, fmt); - vsprintf_s(va_buffer, fmt, ap); - va_end(ap); - - const auto formatted = std::string(va_buffer); - - if (!error_hook_enabled) - { - return hksi_lual_error_hook.invoke(s, formatted.data()); - } - else - { - throw std::runtime_error(formatted); - } - } - - void* hks_start_stub(char a1) - { - const auto _1 = gsl::finally([]() - { - ui_scripting::lua::engine::start(); - }); - - return hks_start_hook.invoke(a1); - } - - void hks_shutdown_stub() - { - ui_scripting::lua::engine::stop(); - hks_shutdown_hook.invoke(); - } - - void* hks_allocator_stub(void* userData, void* oldMemory, unsigned __int64 oldSize, unsigned __int64 newSize) - { - const auto closure = reinterpret_cast(oldMemory); - if (converted_functions.find(closure) != converted_functions.end()) - { - converted_functions.erase(closure); - } - - return hks_allocator_hook.invoke(userData, oldMemory, oldSize, newSize); - } - - void hks_frame_stub() - { - const auto state = *game::hks::lua_state; - if (state) - { - ui_scripting::lua::engine::run_frame(); - } - } - } - - int main_function_handler(game::hks::lua_State* state) - { - const auto value = state->m_apistack.base[-1]; - if (value.t != game::hks::TCFUNCTION) - { - return 0; - } - - const auto closure = reinterpret_cast(value.v.cClosure); - if (converted_functions.find(closure) == converted_functions.end()) - { - return 0; - } - - const auto function = converted_functions[closure]; - const auto count = static_cast(state->m_apistack.top - state->m_apistack.base); - const auto arguments = get_return_values(count); - const auto s = function.lua_state(); - - std::vector converted_args; - - for (const auto& argument : arguments) - { - converted_args.push_back(lua::convert(s, argument)); - } - - const auto results = function(sol::as_args(converted_args)); - lua::handle_error(results); - - for (const auto& result : results) - { - push_value(lua::convert({s, result})); - } - - return results.return_count(); - } - - void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function) - { - converted_functions[closure] = function; - } - - void clear_converted_functions() - { - converted_functions.clear(); - } - - void enable_error_hook() - { - error_hook_enabled = true; - } - - void disable_error_hook() - { - error_hook_enabled = false; - } - - class component final : public component_interface - { - public: - - void post_unpack() override - { - if (game::environment::is_dedi()) - { - return; - } - - hks_start_hook.create(SELECT_VALUE(0x1400E4B40, 0x140176A40), hks_start_stub); - hks_shutdown_hook.create(SELECT_VALUE(0x1400DD3D0, 0x14016CA80), hks_shutdown_stub); - hksi_lual_error_hook.create(SELECT_VALUE(0x1400A5EA0, 0x14012F300), hksi_lual_error_stub); - hks_allocator_hook.create(SELECT_VALUE(0x14009B570, 0x14012BAC0), hks_allocator_stub); - hks_frame_hook.create(SELECT_VALUE(0x1400E37F0, 0x1401755B0), hks_frame_stub); - - if (game::environment::is_mp()) - { - hksi_lual_error_hook2.create(0x1401366B0, hksi_lual_error_stub); - } - - command::add("lui_restart", []() - { - utils::hook::invoke(SELECT_VALUE(0x1400DD3D0, 0x14016CA80)); - utils::hook::invoke(SELECT_VALUE(0x1400E6170, 0x1401780D0)); - }); - } - }; -} - -REGISTER_COMPONENT(ui_scripting::component) \ No newline at end of file diff --git a/src/client/component/ui_scripting.hpp b/src/client/component/ui_scripting.hpp deleted file mode 100644 index 2a48f6ec..00000000 --- a/src/client/component/ui_scripting.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "game/ui_scripting/lua/value_conversion.hpp" - -namespace ui_scripting -{ - int main_function_handler(game::hks::lua_State* state); - void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function); - void clear_converted_functions(); - - void enable_error_hook(); - void disable_error_hook(); -} \ No newline at end of file diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp deleted file mode 100644 index 939dbd1c..00000000 --- a/src/client/component/updater.cpp +++ /dev/null @@ -1,474 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" -#include "dvars.hpp" -#include "updater.hpp" - -#include "version.h" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include -#include -#include -#include - -#define MASTER "https://master.fed0001.xyz/h1-mod/" - -#define FILES_PATH "files.json" -#define FILES_PATH_DEV "files-dev.json" - -#define DATA_PATH "data/" -#define DATA_PATH_DEV "data-dev/" - -#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates" -#define ERR_DOWNLOAD_FAIL "Failed to download file " -#define ERR_WRITE_FAIL "Failed to write file " - -#define BINARY_NAME "h1-mod.exe" - -namespace updater -{ - namespace - { - game::dvar_t* cl_auto_update; - bool has_tried_update = false; - - struct status - { - bool done; - bool success; - }; - - struct file_data - { - std::string name; - std::string data; - }; - - struct update_data_t - { - bool restart_required{}; - bool cancelled{}; - status check{}; - status download{}; - std::string error{}; - std::string current_file{}; - std::vector required_files{}; - }; - - utils::concurrency::container update_data; - - std::string get_branch() - { - return GIT_BRANCH; - } - - std::string select(const std::string& main, const std::string& develop) - { - if (get_branch() == "develop") - { - return develop; - } - - return main; - } - - std::string get_data_path() - { - if (get_branch() == "develop") - { - return DATA_PATH_DEV; - } - - return DATA_PATH; - } - - void set_update_check_status(bool done, bool success, const std::string& error = {}) - { - update_data.access([done, success, error](update_data_t& data_) - { - data_.check.done = done; - data_.check.success = success; - data_.error = error; - }); - } - - void set_update_download_status(bool done, bool success, const std::string& error = {}) - { - update_data.access([done, success, error](update_data_t& data_) - { - data_.download.done = done; - data_.download.success = success; - data_.error = error; - }); - } - - bool check_file(const std::string& name, const std::string& sha) - { - std::string data; - if (!utils::io::read_file(name, &data)) - { - return false; - } - - if (utils::cryptography::sha1::compute(data, true) != sha) - { - return false; - } - - return true; - } - - std::string load_binary_name() - { - // utils::nt::library self; - // return self.get_name(); - // returns the game's name and not the client's - - return BINARY_NAME; - } - - std::string get_binary_name() - { - static const auto name = load_binary_name(); - return name; - } - - std::string get_time_str() - { - return utils::string::va("%i", uint32_t(time(nullptr))); - } - - std::optional download_file(const std::string& name) - { - return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str()); - } - - bool is_update_cancelled() - { - return update_data.access([](update_data_t& data_) - { - return data_.cancelled; - }); - } - - bool write_file(const std::string& name, const std::string& data) - { - if (get_binary_name() == name && - utils::io::file_exists(name) && - !utils::io::move_file(name, name + ".old")) - { - return false; - } - -#ifdef DEBUG - return utils::io::write_file("update_test/" + name, data); -#else - return utils::io::write_file(name, data); -#endif - } - - void delete_old_file() - { - utils::io::remove_file(get_binary_name() + ".old"); - } - - void reset_data() - { - update_data.access([](update_data_t& data_) - { - data_ = {}; - }); - } - - std::string get_mode_flag() - { - if (game::environment::is_mp()) - { - return "-multiplayer"; - } - - if (game::environment::is_sp()) - { - return "-singleplayer"; - } - - return {}; - } - } - - // workaround - void relaunch() - { - if (!utils::io::file_exists(BINARY_NAME)) - { - utils::nt::terminate(0); - return; - } - - 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); - - char buf[1024] = {0}; - const auto command_line = utils::string::va("%s %s", GetCommandLineA(), get_mode_flag().data()); - strcpy_s(buf, 1024, command_line); - - CreateProcess(BINARY_NAME, buf, 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); - - utils::nt::terminate(0); - } - - void set_has_tried_update(bool tried) - { - has_tried_update = tried; - } - - bool get_has_tried_update() - { - return has_tried_update; - } - - bool auto_updates_enabled() - { - return cl_auto_update->current.enabled; - } - - bool is_update_check_done() - { - return update_data.access([](update_data_t& data_) - { - return data_.check.done; - }); - } - - bool is_update_download_done() - { - return update_data.access([](update_data_t& data_) - { - return data_.download.done; - }); - } - - bool get_update_check_status() - { - return update_data.access([](update_data_t& data_) - { - return data_.check.success; - }); - } - - bool get_update_download_status() - { - return update_data.access([](update_data_t& data_) - { - return data_.download.success; - }); - } - - bool is_update_available() - { - return update_data.access([](update_data_t& data_) - { - return data_.required_files.size() > 0; - }); - } - - bool is_restart_required() - { - return update_data.access([](update_data_t& data_) - { - return data_.restart_required; - }); - } - - std::string get_last_error() - { - return update_data.access([](update_data_t& data_) - { - return data_.error; - }); - } - - std::string get_current_file() - { - return update_data.access([](update_data_t& data_) - { - return data_.current_file; - }); - } - - void cancel_update() - { -#ifdef DEBUG - printf("[Updater] Cancelling update\n"); -#endif - - return update_data.access([](update_data_t& data_) - { - data_.cancelled = true; - }); - } - - void start_update_check() - { - cancel_update(); - reset_data(); - -#ifdef DEBUG - printf("[Updater] starting update check\n"); -#endif - - scheduler::once([]() - { - const auto files_data = utils::http::get_data(MASTER + select(FILES_PATH, FILES_PATH_DEV) + "?" + get_time_str()); - - if (is_update_cancelled()) - { - reset_data(); - return; - } - - if (!files_data.has_value()) - { - set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); - return; - } - - rapidjson::Document j; - j.Parse(files_data.value().data()); - - if (!j.IsArray()) - { - set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); - return; - } - - std::vector required_files; - - const auto files = j.GetArray(); - for (const auto& file : files) - { - if (!file.IsArray() || file.Size() != 3 || !file[0].IsString() || !file[2].IsString()) - { - continue; - } - - const auto name = file[0].GetString(); - const auto sha = file[2].GetString(); - - if (!check_file(name, sha)) - { - if (get_binary_name() == name) - { - update_data.access([](update_data_t& data_) - { - data_.restart_required = true; - }); - } - -#ifdef DEBUG - printf("[Updater] need file %s\n", name); -#endif - - required_files.push_back(name); - } - } - - update_data.access([&required_files](update_data_t& data_) - { - data_.check.done = true; - data_.check.success = true; - data_.required_files = required_files; - }); - }, scheduler::pipeline::async); - } - - void start_update_download() - { -#ifdef DEBUG - printf("[Updater] starting update download\n"); -#endif - - if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled()) - { - return; - } - - scheduler::once([]() - { - const auto required_files = update_data.access>([](update_data_t& data_) - { - return data_.required_files; - }); - - std::vector downloads; - - for (const auto& file : required_files) - { - update_data.access([file](update_data_t& data_) - { - data_.current_file = file; - }); - -#ifdef DEBUG - printf("[Updater] downloading file %s\n", file.data()); -#endif - - const auto data = download_file(file); - - if (is_update_cancelled()) - { - reset_data(); - return; - } - - if (!data.has_value()) - { - set_update_download_status(true, false, ERR_DOWNLOAD_FAIL + file); - return; - } - - downloads.push_back({file, data.value()}); - } - - for (const auto& download : downloads) - { - if (!write_file(download.name, download.data)) - { - set_update_download_status(true, false, ERR_WRITE_FAIL + download.name); - return; - } - } - - set_update_download_status(true, true); - }, scheduler::pipeline::async); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - delete_old_file(); - cl_auto_update = dvars::register_bool("cg_auto_update", true, game::DVAR_FLAG_SAVED, true); - } - }; -} - -REGISTER_COMPONENT(updater::component) diff --git a/src/client/component/updater.hpp b/src/client/component/updater.hpp deleted file mode 100644 index 9a3dd45e..00000000 --- a/src/client/component/updater.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -namespace updater -{ - void relaunch(); - - void set_has_tried_update(bool tried); - bool get_has_tried_update(); - bool auto_updates_enabled(); - - bool is_update_available(); - bool is_update_check_done(); - bool get_update_check_status(); - - bool is_update_download_done(); - bool get_update_download_status(); - - bool is_restart_required(); - - std::string get_last_error(); - std::string get_current_file(); - - void start_update_check(); - void start_update_download(); - void cancel_update(); -} \ No newline at end of file diff --git a/src/client/component/videos.cpp b/src/client/component/videos.cpp deleted file mode 100644 index a602cc8a..00000000 --- a/src/client/component/videos.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" - -#include - -namespace videos -{ - namespace - { - utils::hook::detour playvid_hook; - std::unordered_map video_replaces; - - void playvid(const char* name, const int a2, const int a3) - { - const auto vid = video_replaces.find(name); - if (vid != video_replaces.end()) - { - char path[256]; - game::Sys_BuildAbsPath(path, sizeof(path), game::SF_VIDEO, vid->second.data(), ".bik"); - - if (game::Sys_FileExists(path)) - { - name = vid->second.data(); - } - } - - return playvid_hook.invoke(name, a2, a3); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - playvid_hook.create(SELECT_VALUE(0x1404A9D00, 0x1405B0AF0), &playvid); // H1(1.4) - - if (game::environment::is_mp()) - { - video_replaces["menus_bg_comp2"] = "menus_bg_h1mod"; - video_replaces["mp_menus_bg_options"] = "menus_bg_h1mod_blur"; - } - else if (game::environment::is_sp()) - { - video_replaces["sp_menus_bg_main_menu"] = "menus_bg_h1mod_sp"; - video_replaces["sp_menus_bg_campaign"] = "menus_bg_h1mod_sp"; - video_replaces["sp_menus_bg_options"] = "menus_bg_h1mod_sp"; - } - } - }; -} - -REGISTER_COMPONENT(videos::component) diff --git a/src/client/component/virtuallobby.cpp b/src/client/component/virtuallobby.cpp deleted file mode 100644 index eb6295f7..00000000 --- a/src/client/component/virtuallobby.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include - -namespace virtuallobby -{ - namespace - { - game::dvar_t* virtualLobby_fovscale; - - const auto get_fovscale_stub = utils::hook::assemble([](utils::hook::assembler& a) - { - const auto ret = a.newLabel(); - const auto original = a.newLabel(); - - a.pushad64(); - a.mov(rax, qword_ptr(0x1425F7210)); // virtualLobbyInFiringRange - a.cmp(byte_ptr(rax, 0x10), 1); - a.je(original); - a.call_aligned(game::VirtualLobby_Loaded); - a.cmp(al, 0); - a.je(original); - - // virtuallobby - a.popad64(); - a.mov(rax, ptr(reinterpret_cast(&virtualLobby_fovscale))); - a.jmp(ret); - - // original - a.bind(original); - a.popad64(); - a.mov(rax, qword_ptr(0x1413A8580)); - a.jmp(ret); - - a.bind(ret); - a.mov(rcx, 0x142935000); - a.jmp(0x1400B556A); - }); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (!game::environment::is_mp()) - { - return; - } - - virtualLobby_fovscale = dvars::register_float("virtualLobby_fovScale", 0.7f, 0.0f, 2.0f, game::DVAR_FLAG_SAVED); - - utils::hook::nop(0x1400B555C, 14); - utils::hook::jump(0x1400B555C, get_fovscale_stub, true); - } - }; -} - -REGISTER_COMPONENT(virtuallobby::component) diff --git a/src/client/game/scripting/entity.cpp b/src/client/game/scripting/entity.cpp deleted file mode 100644 index b81dea1b..00000000 --- a/src/client/game/scripting/entity.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include "entity.hpp" -#include "script_value.hpp" -#include "execution.hpp" - -namespace scripting -{ - entity::entity() - : entity(0) - { - } - - entity::entity(const entity& other) : entity(other.entity_id_) - { - } - - entity::entity(entity&& other) noexcept - { - this->entity_id_ = other.entity_id_; - other.entity_id_ = 0; - } - - entity::entity(const unsigned int entity_id) - : entity_id_(entity_id) - { - this->add(); - } - - entity::entity(game::scr_entref_t entref) - : entity(game::FindEntityId(entref.entnum, entref.classnum)) - { - } - - entity::~entity() - { - this->release(); - } - - entity& entity::operator=(const entity& other) - { - if (&other != this) - { - this->release(); - this->entity_id_ = other.entity_id_; - this->add(); - } - - return *this; - } - - entity& entity::operator=(entity&& other) noexcept - { - if (&other != this) - { - this->release(); - this->entity_id_ = other.entity_id_; - other.entity_id_ = 0; - } - - return *this; - } - - unsigned int entity::get_entity_id() const - { - return this->entity_id_; - } - - game::scr_entref_t entity::get_entity_reference() const - { - if (!this->entity_id_) - { - const auto not_null = static_cast(~0ui16); - return game::scr_entref_t{not_null, not_null}; - } - - return game::Scr_GetEntityIdRef(this->get_entity_id()); - } - - bool entity::operator==(const entity& other) const noexcept - { - return this->get_entity_id() == other.get_entity_id(); - } - - bool entity::operator!=(const entity& other) const noexcept - { - return !this->operator==(other); - } - - void entity::add() const - { - if (this->entity_id_) - { - game::AddRefToValue(game::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); - } - } - - void entity::release() const - { - if (this->entity_id_) - { - game::RemoveRefToValue(game::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); - } - } - - void entity::set(const std::string& field, const script_value& value) const - { - set_entity_field(*this, field, value); - } - - template <> - script_value entity::get(const std::string& field) const - { - return get_entity_field(*this, field); - } - - script_value entity::call(const std::string& name, const std::vector& arguments) const - { - return call_function(name, *this, arguments); - } -} diff --git a/src/client/game/scripting/entity.hpp b/src/client/game/scripting/entity.hpp deleted file mode 100644 index b1702379..00000000 --- a/src/client/game/scripting/entity.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include "game/game.hpp" -#include "script_value.hpp" - -namespace scripting -{ - class entity final - { - public: - entity(); - entity(unsigned int entity_id); - entity(game::scr_entref_t entref); - - entity(const entity& other); - entity(entity&& other) noexcept; - - ~entity(); - - entity& operator=(const entity& other); - entity& operator=(entity&& other) noexcept; - - void set(const std::string& field, const script_value& value) const; - - template - T get(const std::string& field) const; - - script_value call(const std::string& name, const std::vector& arguments = {}) const; - - unsigned int get_entity_id() const; - game::scr_entref_t get_entity_reference() const; - - bool operator ==(const entity& other) const noexcept; - bool operator !=(const entity& other) const noexcept; - - private: - unsigned int entity_id_; - - void add() const; - void release() const; - }; - - template <> - script_value entity::get(const std::string& field) const; - - template - T entity::get(const std::string& field) const - { - return this->get(field).as(); - } -} diff --git a/src/client/game/scripting/event.hpp b/src/client/game/scripting/event.hpp deleted file mode 100644 index bc1d53e0..00000000 --- a/src/client/game/scripting/event.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "script_value.hpp" -#include "entity.hpp" - -namespace scripting -{ - struct event - { - std::string name; - entity entity{}; - std::vector arguments; - }; -} diff --git a/src/client/game/scripting/execution.cpp b/src/client/game/scripting/execution.cpp deleted file mode 100644 index 29faaad4..00000000 --- a/src/client/game/scripting/execution.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include "execution.hpp" -#include "safe_execution.hpp" -#include "stack_isolation.hpp" - -#include "component/scripting.hpp" - -namespace scripting -{ - namespace - { - game::VariableValue* allocate_argument() - { - game::VariableValue* value_ptr = ++game::scr_VmPub->top; - ++game::scr_VmPub->inparamcount; - return value_ptr; - } - - void push_value(const script_value& value) - { - auto* value_ptr = allocate_argument(); - *value_ptr = value.get_raw(); - - game::AddRefToValue(value_ptr->type, value_ptr->u); - } - - int get_field_id(const int classnum, const std::string& field) - { - if (scripting::fields_table[classnum].find(field) != scripting::fields_table[classnum].end()) - { - return scripting::fields_table[classnum][field]; - } - - return -1; - } - - script_value get_return_value() - { - if (game::scr_VmPub->inparamcount == 0) - { - return {}; - } - - game::Scr_ClearOutParams(); - game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; - game::scr_VmPub->inparamcount = 0; - - return script_value(game::scr_VmPub->top[1 - game::scr_VmPub->outparamcount]); - } - } - - void notify(const entity& entity, const std::string& event, const std::vector& arguments) - { - stack_isolation _; - for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) - { - push_value(*i); - } - - const auto event_id = game::SL_GetString(event.data(), 0); - game::Scr_NotifyId(entity.get_entity_id(), event_id, game::scr_VmPub->inparamcount); - } - - script_value call_function(const std::string& name, const entity& entity, - const std::vector& arguments) - { - const auto entref = entity.get_entity_reference(); - - const auto is_method_call = *reinterpret_cast(&entref) != -1; - const auto function = find_function(name, !is_method_call); - if (function == nullptr) - { - throw std::runtime_error("Unknown "s + (is_method_call ? "method" : "function") + " '" + name + "'"); - } - - stack_isolation _; - - for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) - { - push_value(*i); - } - - game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; - game::scr_VmPub->inparamcount = 0; - - if (!safe_execution::call(function, entref)) - { - throw std::runtime_error( - "Error executing "s + (is_method_call ? "method" : "function") + " '" + name + "'"); - } - - return get_return_value(); - } - - script_value call_function(const std::string& name, const std::vector& arguments) - { - return call_function(name, entity(), arguments); - } - - template <> - script_value call(const std::string& name, const std::vector& arguments) - { - return call_function(name, arguments); - } - - script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector& arguments) - { - const auto id = entity.get_entity_id(); - - stack_isolation _; - for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) - { - scripting::push_value(*i); - } - - game::AddRefToObject(id); - - const auto local_id = game::AllocThread(id); - const auto result = game::VM_Execute(local_id, pos, (unsigned int)arguments.size()); - game::RemoveRefToObject(result); - - return get_return_value(); - } - - const char* get_function_pos(const std::string& filename, const std::string& function) - { - if (scripting::script_function_table.find(filename) == scripting::script_function_table.end()) - { - throw std::runtime_error("File '" + filename + "' not found"); - }; - - const auto functions = scripting::script_function_table[filename]; - if (functions.find(function) == functions.end()) - { - throw std::runtime_error("Function '" + function + "' in file '" + filename + "' not found"); - } - - return functions.at(function); - } - - script_value call_script_function(const entity& entity, const std::string& filename, - const std::string& function, const std::vector& arguments) - { - const auto pos = get_function_pos(filename, function); - return exec_ent_thread(entity, pos, arguments); - } - - static std::unordered_map> custom_fields; - - script_value get_custom_field(const entity& entity, const std::string& field) - { - auto& fields = custom_fields[entity.get_entity_id()]; - const auto _field = fields.find(field); - if (_field != fields.end()) - { - return _field->second; - } - return {}; - } - - void set_custom_field(const entity& entity, const std::string& field, const script_value& value) - { - const auto id = entity.get_entity_id(); - - if (custom_fields[id].find(field) != custom_fields[id].end()) - { - custom_fields[id][field] = value; - return; - } - - custom_fields[id].insert(std::make_pair(field, value)); - } - - void clear_entity_fields(const entity& entity) - { - const auto id = entity.get_entity_id(); - - if (custom_fields.find(id) != custom_fields.end()) - { - custom_fields[id].clear(); - } - } - - void clear_custom_fields() - { - custom_fields.clear(); - } - - void set_entity_field(const entity& entity, const std::string& field, const script_value& value) - { - const auto entref = entity.get_entity_reference(); - const int id = get_field_id(entref.classnum, field); - - if (id != -1) - { - stack_isolation _; - push_value(value); - - game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; - game::scr_VmPub->inparamcount = 0; - - if (!safe_execution::set_entity_field(entref, id)) - { - throw std::runtime_error("Failed to set value for field '" + field + "'"); - } - } - else - { - // Read custom fields - set_custom_field(entity, field, value); - } - } - - script_value get_entity_field(const entity& entity, const std::string& field) - { - const auto entref = entity.get_entity_reference(); - const auto id = get_field_id(entref.classnum, field); - - if (id != -1) - { - stack_isolation _; - - game::VariableValue value{}; - if (!safe_execution::get_entity_field(entref, id, &value)) - { - throw std::runtime_error("Failed to get value for field '" + field + "'"); - } - - const auto __ = gsl::finally([value]() - { - game::RemoveRefToValue(value.type, value.u); - }); - - return value; - } - - // Add custom fields - return get_custom_field(entity, field); - } -} diff --git a/src/client/game/scripting/execution.hpp b/src/client/game/scripting/execution.hpp deleted file mode 100644 index 7fff1840..00000000 --- a/src/client/game/scripting/execution.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "game/game.hpp" -#include "entity.hpp" -#include "script_value.hpp" - -namespace scripting -{ - script_value call_function(const std::string& name, const std::vector& arguments); - script_value call_function(const std::string& name, const entity& entity, - const std::vector& arguments); - - template - T call(const std::string& name, const std::vector& arguments = {}); - - template <> - script_value call(const std::string& name, const std::vector& arguments); - - template - T call(const std::string& name, const std::vector& arguments) - { - return call(name, arguments).as(); - } - - script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector& arguments); - const char* get_function_pos(const std::string& filename, const std::string& function); - script_value call_script_function(const entity& entity, const std::string& filename, - const std::string& function, const std::vector& arguments); - - void clear_entity_fields(const entity& entity); - void clear_custom_fields(); - - void set_entity_field(const entity& entity, const std::string& field, const script_value& value); - script_value get_entity_field(const entity& entity, const std::string& field); - - void notify(const entity& entity, const std::string& event, const std::vector& arguments); -} diff --git a/src/client/game/scripting/function_tables.cpp b/src/client/game/scripting/function_tables.cpp deleted file mode 100644 index 9a70a9dd..00000000 --- a/src/client/game/scripting/function_tables.cpp +++ /dev/null @@ -1,3480 +0,0 @@ -#include - -// This file has been generated. -// Do not touch! - -// https://github.com/xensik/gsc-tool/blob/dev/src/h1/xsk/resolver.cpp :) - -namespace scripting -{ - std::unordered_map function_map = - { - {"_func_001", 0x001}, // SP 0x14029D940 MP 0x140368EA0 - {"getweaponarray", 0x002}, // SP 0x14028F750 MP 0x140357B80 - {"_func_003", 0x003}, // SP 0x1405D92F0 MP 0x1403668A0 - {"_func_004", 0x004}, // SP 0x1402ACD70 MP 0x000000000 - {"_func_005", 0x005}, // SP 0x1402ADB70 MP 0x000000000 - {"_func_006", 0x006}, // SP 0x1402A8E20 MP 0x000000000 - {"_func_007", 0x007}, // SP 0x1402A8B20 MP 0x000000000 - {"_func_008", 0x008}, // SP 0x1402A8B40 MP 0x000000000 - {"_func_009", 0x009}, // SP 0x1402A8BC0 MP 0x000000000 - {"_func_00A", 0x00A}, // SP 0x1402A8B60 MP 0x000000000 - {"_func_00B", 0x00B}, // SP 0x1402A8960 MP 0x000000000 - {"_func_00C", 0x00C}, // SP 0x1402ADBE0 MP 0x000000000 - {"_func_00D", 0x00D}, // SP 0x1402ADC60 MP 0x000000000 - {"_func_00E", 0x00E}, // SP 0x1402ADC90 MP 0x000000000 - {"_func_00F", 0x00F}, // SP 0x1405D92F0 MP 0x1403669E0 - {"_func_010", 0x010}, // SP 0x14029AF60 MP 0x1403669F0 - {"_func_011", 0x011}, // SP 0x14029AF60 MP 0x140366D40 - {"_func_012", 0x012}, // SP 0x1405D92F0 MP 0x140367400 - {"_func_013", 0x013}, // SP 0x1405D92F0 MP 0x140367520 - {"_func_014", 0x014}, // SP 0x1405D92F0 MP 0x140367530 - {"_func_015", 0x015}, // SP 0x1405D92F0 MP 0x1403675E0 - {"_func_016", 0x016}, // SP 0x1405D92F0 MP 0x140367660 - {"_func_017", 0x017}, // SP 0x1405D92F0 MP 0x140367890 - {"spawnturret", 0x018}, // SP 0x14029D650 MP 0x140368B10 - {"canspawnturret", 0x019}, // SP 0x14029D870 MP 0x140368E80 - {"_func_01A", 0x01A}, // SP 0x14029C9B0 MP 0x1403678A0 - {"_func_01B", 0x01B}, // SP 0x1402AB640 MP 0x000000000 - {"_func_01C", 0x01C}, // SP 0x1402AB670 MP 0x000000000 - {"_func_01D", 0x01D}, // SP 0x1402AB7A0 MP 0x000000000 - {"_func_01E", 0x01E}, // SP 0x1402AB960 MP 0x000000000 - {"badplace_delete", 0x01F}, // SP 0x14028F340 MP 0x140358600 - {"badplace_cylinder", 0x020}, // SP 0x14028F4B0 MP 0x140358C50 - {"badplace_arc", 0x021}, // SP 0x14028F830 MP 0x140359110 - {"badplace_brush", 0x022}, // SP 0x14028FF10 MP 0x140359CB0 - {"_func_023", 0x023}, // SP 0x1402AC9D0 MP 0x000000000 - {"_func_024", 0x024}, // SP 0x1402CC640 MP 0x000000000 - {"_func_025", 0x025}, // SP 0x1402CC6E0 MP 0x000000000 - {"_func_026", 0x026}, // SP 0x1402CC570 MP 0x000000000 - {"_func_027", 0x027}, // SP 0x1402CC430 MP 0x000000000 - {"_func_02A", 0x02A}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_02B", 0x02B}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_02C", 0x02C}, // SP 0x1402ACD10 MP 0x000000000 - {"_func_02D", 0x02D}, // SP 0x14029C9B0 MP 0x140367950 - {"_func_02E", 0x02E}, // SP 0x14029CAC0 MP 0x140367980 - {"isdefined", 0x02F}, // SP 0x14029D000 MP 0x140368520 - {"isvalidmissile", 0x030}, // SP 0x14029D3E0 MP 0x140368A70 - {"_func_031", 0x031}, // SP 0x14029D630 MP 0x140368D30 - {"_func_032", 0x032}, // SP 0x14029E0A0 MP 0x14036A580 - {"_func_033", 0x033}, // SP 0x14029E220 MP 0x14036A7C0 - {"setdynamicdvar", 0x034}, // SP 0x14029EB20 MP 0x14036AE70 - {"_func_035", 0x035}, // SP 0x000000000 MP 0x14036B600 - {"_func_036", 0x036}, // SP 0x14029F8F0 MP 0x14036BB60 - {"setdvar", 0x037}, // SP 0x14029F1C0 MP 0x14036B7F0 - {"_func_038", 0x038}, // SP 0x14029F8F0 MP 0x14036C070 - {"getdvar", 0x039}, // SP 0x14029FE30 MP 0x14036C350 - {"getdvarint", 0x03A}, // SP 0x1402A0270 MP 0x14036C7B0 - {"getdvarfloat", 0x03B}, // SP 0x1402A0810 MP 0x14036CDD0 - {"getdvarvector", 0x03C}, // SP 0x1402A10E0 MP 0x14036D190 - {"_func_03D", 0x03D}, // SP 0x1402A1A50 MP 0x14036DB40 - {"_func_03E", 0x03E}, // SP 0x1402A1A60 MP 0x14036DD80 - {"_func_03F", 0x03F}, // SP 0x1402A1AC0 MP 0x14036DDA0 - {"getentbynum", 0x040}, // SP 0x1402A1C50 MP 0x14036DF50 - {"_func_041", 0x041}, // SP 0x1402A1D10 MP 0x000000000 - {"_func_042", 0x042}, // SP 0x1402A1D20 MP 0x000000000 - {"_func_043", 0x043}, // SP 0x1402A1D30 MP 0x14036E110 - {"_func_044", 0x044}, // SP 0x1402ABBE0 MP 0x000000000 - {"_func_045", 0x045}, // SP 0x1402ABCF0 MP 0x000000000 - {"_func_046", 0x046}, // SP 0x1402ABD30 MP 0x000000000 - {"_func_047", 0x047}, // SP 0x1402ABD90 MP 0x1403775E0 - {"_func_048", 0x048}, // SP 0x1402ABE60 MP 0x140377840 - {"_func_049", 0x049}, // SP 0x1402ABF90 MP 0x000000000 - {"_func_04A", 0x04A}, // SP 0x1402ABFC0 MP 0x000000000 - {"_func_04B", 0x04B}, // SP 0x1402AC0E0 MP 0x000000000 - {"_func_04C", 0x04C}, // SP 0x1402AC210 MP 0x000000000 - {"_func_04D", 0x04D}, // SP 0x1402AC520 MP 0x000000000 - {"_func_04E", 0x04E}, // SP 0x1402AC6F0 MP 0x000000000 - {"_func_04F", 0x04F}, // SP 0x1402AC720 MP 0x000000000 - {"_func_050", 0x050}, // SP 0x1402AC740 MP 0x000000000 - {"_func_051", 0x051}, // SP 0x1402AC760 MP 0x000000000 - {"_func_052", 0x052}, // SP 0x1402AC780 MP 0x000000000 - {"_func_053", 0x053}, // SP 0x1402AC830 MP 0x000000000 - {"_func_054", 0x054}, // SP 0x1402AD6E0 MP 0x000000000 - {"_func_055", 0x055}, // SP 0x1402AAEC0 MP 0x000000000 - {"_func_056", 0x056}, // SP 0x1402AAF60 MP 0x000000000 - {"_func_057", 0x057}, // SP 0x1402AB040 MP 0x000000000 - {"_func_058", 0x058}, // SP 0x1402AB060 MP 0x000000000 - {"_func_059", 0x059}, // SP 0x1402AB140 MP 0x000000000 - {"_func_05A", 0x05A}, // SP 0x1402AB1E0 MP 0x000000000 - {"_func_05B", 0x05B}, // SP 0x1402AB2A0 MP 0x000000000 - {"_func_05C", 0x05C}, // SP 0x1402AB420 MP 0x000000000 - {"_func_05D", 0x05D}, // SP 0x1402AB4A0 MP 0x000000000 - {"_func_05E", 0x05E}, // SP 0x1402AB620 MP 0x000000000 - {"_func_05F", 0x05F}, // SP 0x1402A2410 MP 0x14036E740 - {"_func_060", 0x060}, // SP 0x1402A2910 MP 0x14036ED60 - {"_func_061", 0x061}, // SP 0x1402A3170 MP 0x14036F3E0 - {"_func_062", 0x062}, // SP 0x1402A34D0 MP 0x140357CA0 - {"getweaponreticlename", 0x063}, // SP 0x14028DEA0 MP 0x140358890 - {"_func_064", 0x064}, // SP 0x14028E0B0 MP 0x140358B80 - {"getanimlength", 0x065}, // SP 0x14028FB80 MP 0x14035AB80 - {"animhasnotetrack", 0x066}, // SP 0x14028FD60 MP 0x14035B110 - {"getnotetracktimes", 0x067}, // SP 0x14028FDC0 MP 0x14035B220 - {"spawn", 0x068}, // SP 0x14029D0C0 MP 0x140368410 - {"spawnloopsound", 0x069}, // SP 0x14029D0C0 MP 0x140368410 - {"_func_06A", 0x06A}, // SP 0x140444BB0 MP 0x14036AF90 - {"_func_06B", 0x06B}, // SP 0x14029E950 MP 0x140366EF0 - {"_func_06C", 0x06C}, // SP 0x1402BBCA0 MP 0x000000000 - {"_func_06D", 0x06D}, // SP 0x1402BB830 MP 0x000000000 - {"_func_06E", 0x06E}, // SP 0x1402BB990 MP 0x000000000 - {"_func_06F", 0x06F}, // SP 0x14025D860 MP 0x140375D40 - {"_func_070", 0x070}, // SP 0x14025D770 MP 0x140375F10 - {"_func_071", 0x071}, // SP 0x14025D630 MP 0x000000000 - {"_func_072", 0x072}, // SP 0x1402AB510 MP 0x000000000 - {"_func_073", 0x073}, // SP 0x1402981B0 MP 0x140364BC0 - {"_func_074", 0x074}, // SP 0x1402AFD80 MP 0x000000000 - {"_func_075", 0x075}, // SP 0x1402AFEA0 MP 0x000000000 - {"_func_076", 0x076}, // SP 0x1402A78A0 MP 0x000000000 - {"_func_077", 0x077}, // SP 0x1402A79D0 MP 0x000000000 - {"_func_078", 0x078}, // SP 0x14029E170 MP 0x140367970 - {"_func_079", 0x079}, // SP 0x14029E210 MP 0x140367990 - {"_func_07A", 0x07A}, // SP 0x14029E2D0 MP 0x140367D70 - {"_func_07B", 0x07B}, // SP 0x14029E320 MP 0x140367F30 - {"_func_07C", 0x07C}, // SP 0x14029E330 MP 0x140367F40 - {"_func_07D", 0x07D}, // SP 0x14029E730 MP 0x140367FA0 - {"_func_07E", 0x07E}, // SP 0x1402A7BF0 MP 0x000000000 - {"_func_07F", 0x07F}, // SP 0x1402A8BB0 MP 0x000000000 - {"_func_080", 0x080}, // SP 0x1402A7A80 MP 0x000000000 - {"_func_081", 0x081}, // SP 0x1402AAE30 MP 0x000000000 - {"_func_083", 0x083}, // SP 0x1402AAE50 MP 0x000000000 - {"_func_084", 0x084}, // SP 0x1402AAEA0 MP 0x000000000 - {"_func_085", 0x085}, // SP 0x1402A8CB0 MP 0x000000000 - {"_func_086", 0x086}, // SP 0x1402A9990 MP 0x000000000 - {"_func_087", 0x087}, // SP 0x1402A99B0 MP 0x000000000 - {"_func_088", 0x088}, // SP 0x1402A9100 MP 0x000000000 - {"_func_089", 0x089}, // SP 0x1402A99D0 MP 0x000000000 - {"_func_08A", 0x08A}, // SP 0x1402A9A70 MP 0x000000000 - {"_func_08B", 0x08B}, // SP 0x1402AB690 MP 0x000000000 - {"_func_08C", 0x08C}, // SP 0x1402ABB90 MP 0x000000000 - {"bullettracepassed", 0x08D}, // SP 0x14029F480 MP 0x140367410 - {"_func_08E", 0x08E}, // SP 0x14029F7A0 MP 0x140367670 - {"_func_08F", 0x08F}, // SP 0x14029FF90 MP 0x140367E20 - {"_func_090", 0x090}, // SP 0x1402A0360 MP 0x140368180 - {"_func_091", 0x091}, // SP 0x1402A2670 MP 0x14036A300 - {"getangledelta", 0x092}, // SP 0x14028F3D0 MP 0x14036E210 - {"getangledelta3d", 0x093}, // SP 0x14028FA60 MP 0x14036E910 - {"getnorthyaw", 0x094}, // SP 0x1402903E0 MP 0x140357C50 - {"_func_095", 0x095}, // SP 0x1402A7970 MP 0x000000000 - {"_func_096", 0x096}, // SP 0x1402A7A50 MP 0x000000000 - {"_func_097", 0x097}, // SP 0x1402A9B20 MP 0x000000000 - {"_func_098", 0x098}, // SP 0x1402A9B70 MP 0x000000000 - {"_func_099", 0x099}, // SP 0x1402A9AE0 MP 0x000000000 - {"_func_09A", 0x09A}, // SP 0x1402AE4D0 MP 0x000000000 - {"_func_09B", 0x09B}, // SP 0x1402BB040 MP 0x000000000 - {"_func_09C", 0x09C}, // SP 0x1402BB410 MP 0x000000000 - {"_func_09D", 0x09D}, // SP 0x1402BB6F0 MP 0x000000000 - {"_func_09E", 0x09E}, // SP 0x1402BB6B0 MP 0x000000000 - {"_func_09F", 0x09F}, // SP 0x1402BC260 MP 0x000000000 - {"_func_0A0", 0x0A0}, // SP 0x1402BBF00 MP 0x000000000 - {"_func_0A1", 0x0A1}, // SP 0x1402BB590 MP 0x000000000 - {"_func_0A2", 0x0A2}, // SP 0x1402BB520 MP 0x000000000 - {"_func_0A3", 0x0A3}, // SP 0x1402BC390 MP 0x000000000 - {"_func_0A4", 0x0A4}, // SP 0x1402BB060 MP 0x000000000 - {"_func_0A5", 0x0A5}, // SP 0x1402BB4A0 MP 0x000000000 - {"_func_0A6", 0x0A6}, // SP 0x1402BB630 MP 0x000000000 - {"_func_0A7", 0x0A7}, // SP 0x1402BB710 MP 0x000000000 - {"_func_0A8", 0x0A8}, // SP 0x1402BBB80 MP 0x000000000 - {"_func_0A9", 0x0A9}, // SP 0x1402BB510 MP 0x000000000 - {"_func_0AA", 0x0AA}, // SP 0x1402BC380 MP 0x000000000 - {"_func_0AB", 0x0AB}, // SP 0x1402BC140 MP 0x000000000 - {"_func_0AC", 0x0AC}, // SP 0x1402BB090 MP 0x000000000 - {"_func_0AD", 0x0AD}, // SP 0x1402BB2C0 MP 0x000000000 - {"_func_0AE", 0x0AE}, // SP 0x1402BB1C0 MP 0x000000000 - {"_func_0AF", 0x0AF}, // SP 0x1402BBDB0 MP 0x000000000 - {"_func_0B0", 0x0B0}, // SP 0x140290420 MP 0x140357E90 - {"setslowmotion", 0x0B1}, // SP 0x14029BC60 MP 0x140365480 - {"randomint", 0x0B2}, // SP 0x1402A2ED0 MP 0x14036A770 - {"randomfloat", 0x0B3}, // SP 0x1402A3140 MP 0x14036A9E0 - {"randomintrange", 0x0B4}, // SP 0x1402A3240 MP 0x14036ACD0 - {"randomfloatrange", 0x0B5}, // SP 0x1402A3310 MP 0x14036AE10 - {"sin", 0x0B6}, // SP 0x1402A3440 MP 0x14036B240 - {"cos", 0x0B7}, // SP 0x1402A34A0 MP 0x14036B550 - {"tan", 0x0B8}, // SP 0x1402A3610 MP 0x14036B5A0 - {"asin", 0x0B9}, // SP 0x1402A37D0 MP 0x14036B720 - {"acos", 0x0BA}, // SP 0x1402A3A60 MP 0x14036B7A0 - {"atan", 0x0BB}, // SP 0x14028D680 MP 0x14036BAE0 - {"int", 0x0BC}, // SP 0x14028DAE0 MP 0x14036BBF0 - {"float", 0x0BD}, // SP 0x14028DE30 MP 0x14036C000 - {"abs", 0x0BE}, // SP 0x14028DFC0 MP 0x14036C320 - {"_func_0BF", 0x0BF}, // SP 0x14028DFF0 MP 0x14036C580 - {"_func_0C0", 0x0C0}, // SP 0x1402B7A30 MP 0x000000000 - {"_func_0C1", 0x0C1}, // SP 0x1402B7B50 MP 0x000000000 - {"_func_0C2", 0x0C2}, // SP 0x1402B7BF0 MP 0x000000000 - {"getnode", 0x0C3}, // SP 0x1402CBED0 MP 0x14031FA00 - {"getnodearray", 0x0C4}, // SP 0x1402CBFE0 MP 0x14031FB10 - {"getallnodes", 0x0C5}, // SP 0x1402CBCD0 MP 0x14031F7E0 - {"_func_0C6", 0x0C6}, // SP 0x1402CC0F0 MP 0x14031FCC0 - {"_func_0C7", 0x0C7}, // SP 0x1402CC100 MP 0x14031FCD0 - {"_func_0C8", 0x0C8}, // SP 0x1402CBD20 MP 0x14031F830 - {"_func_0C9", 0x0C9}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_0CA", 0x0CA}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_0CB", 0x0CB}, // SP 0x140468CF0 MP 0x000000000 - {"_func_0CC", 0x0CC}, // SP 0x140468DD0 MP 0x000000000 - {"_func_0CD", 0x0CD}, // SP 0x140468CA0 MP 0x000000000 - {"isarray", 0x0CE}, // SP 0x140291BF0 MP 0x14035E620 - {"isai", 0x0CF}, // SP 0x1402ADC10 MP 0x140377460 - {"getindexforluincstring", 0x0D0}, // SP 0x14029DB50 MP 0x140369C50 - {"issentient", 0x0D1}, // SP 0x14029D7D0 MP 0x140368DA0 - {"_func_0D2", 0x0D2}, // SP 0x1402ADD90 MP 0x000000000 - {"_func_0D3", 0x0D3}, // SP 0x1402ADED0 MP 0x000000000 - {"_func_0D4", 0x0D4}, // SP 0x1402ADF60 MP 0x000000000 - {"_func_0D5", 0x0D5}, // SP 0x1402ADFD0 MP 0x000000000 - {"_func_0D6", 0x0D6}, // SP 0x1402AE020 MP 0x000000000 - {"_func_0D7", 0x0D7}, // SP 0x1402AE4E0 MP 0x000000000 - {"_func_0D8", 0x0D8}, // SP 0x1402AE4F0 MP 0x000000000 - {"_func_0D9", 0x0D9}, // SP 0x1402AE7A0 MP 0x000000000 - {"_func_0DA", 0x0DA}, // SP 0x1402AF980 MP 0x000000000 - {"_func_0DB", 0x0DB}, // SP 0x1402AFBD0 MP 0x000000000 - {"_func_0DC", 0x0DC}, // SP 0x1402AFB20 MP 0x000000000 - {"_func_0DD", 0x0DD}, // SP 0x1402AFCE0 MP 0x000000000 - {"_func_0DE", 0x0DE}, // SP 0x1402AFE20 MP 0x000000000 - {"_func_0DF", 0x0DF}, // SP 0x14029CAC0 MP 0x000000000 - {"_func_0E0", 0x0E0}, // SP 0x1402A7830 MP 0x000000000 - {"_func_0E1", 0x0E1}, // SP 0x14028E170 MP 0x14036C720 - {"floor", 0x0E2}, // SP 0x14028E1C0 MP 0x14036C750 - {"ceil", 0x0E3}, // SP 0x14028E260 MP 0x14036C770 - {"exp", 0x0E4}, // SP 0x14028E280 MP 0x14036C790 - {"exp", 0x0E5}, // SP 0x14028E370 MP 0x14036C820 - {"log", 0x0E6}, // SP 0x14028E410 MP 0x14036C840 - {"sqrt", 0x0E7}, // SP 0x14028E470 MP 0x14036CB80 - {"squared", 0x0E8}, // SP 0x14028E4B0 MP 0x14036CBA0 - {"_func_0E9", 0x0E9}, // SP 0x14028E770 MP 0x14036CE40 - {"_func_0EA", 0x0EA}, // SP 0x14028E8C0 MP 0x14036CF30 - {"angleclamp180", 0x0EB}, // SP 0x14028E920 MP 0x14036CFB0 - {"vectorfromlinetopoint", 0x0EC}, // SP 0x140290740 MP 0x14036E5A0 - {"pointonsegmentnearesttopoint", 0x0ED}, // SP 0x140290B60 MP 0x14036EB30 - {"_func_0EE", 0x0EE}, // SP 0x140291260 MP 0x14036F6E0 - {"_func_0EF", 0x0EF}, // SP 0x1402913A0 MP 0x14036F790 - {"_func_0F0", 0x0F0}, // SP 0x140291600 MP 0x140357E10 - {"_func_0F1", 0x0F1}, // SP 0x1402918C0 MP 0x140357FB0 - {"_func_0F2", 0x0F2}, // SP 0x140291930 MP 0x140358030 - {"_func_0F3", 0x0F3}, // SP 0x140291AF0 MP 0x140358130 - {"_func_0F4", 0x0F4}, // SP 0x140291B30 MP 0x140358190 - {"_func_0F5", 0x0F5}, // SP 0x140291C20 MP 0x1403581E0 - {"_func_0F6", 0x0F6}, // SP 0x140291EB0 MP 0x140358570 - {"_func_0F7", 0x0F7}, // SP 0x140291F80 MP 0x140358640 - {"axistoangles", 0x0F8}, // SP 0x140292690 MP 0x140359050 - {"_func_0F9", 0x0F9}, // SP 0x1402ABB50 MP 0x1403771E0 - {"_func_0FA", 0x0FA}, // SP 0x1402ABB60 MP 0x140377260 - {"_func_0FB", 0x0FB}, // SP 0x000000000 MP 0x14037B950 - {"_func_0FC", 0x0FC}, // SP 0x000000000 MP 0x140374E10 - {"getmapcustom", 0x0FD}, // SP 0x000000000 MP 0x140378260 - {"_func_0FE", 0x0FE}, // SP 0x000000000 MP 0x1403765A0 - {"incrementcounter", 0x0FF}, // SP 0x1402AE370 MP 0x140374FE0 - {"getcountertotal", 0x100}, // SP 0x1402AE3C0 MP 0x140375100 - {"_func_101", 0x101}, // SP 0x1402A1AE0 MP 0x000000000 - {"_func_102", 0x102}, // SP 0x14028E970 MP 0x000000000 - {"_func_103", 0x103}, // SP 0x14028ED80 MP 0x000000000 - {"_func_104", 0x104}, // SP 0x1405D92F0 MP 0x14042C2C0 - {"_func_105", 0x105}, // SP 0x1405D92F0 MP 0x14042C2D0 - {"_func_106", 0x106}, // SP 0x14028D7F0 MP 0x000000000 - {"createthreatbiasgroup", 0x107}, // SP 0x1402D79E0 MP 0x1400774E0 - {"threatbiasgroupexists", 0x108}, // SP 0x1402D7A10 MP 0x140077510 - {"getthreatbias", 0x109}, // SP 0x1402D7A50 MP 0x140077550 - {"setthreatbias", 0x10A}, // SP 0x1402D7AB0 MP 0x1400775B0 - {"setthreatbiasagainstall", 0x10B}, // SP 0x1402D7B30 MP 0x140077630 - {"setignoremegroup", 0x10C}, // SP 0x1402D7B80 MP 0x140077680 - {"isenemyteam", 0x10D}, // SP 0x1402D7CC0 MP 0x140077820 - {"_func_10E", 0x10E}, // SP 0x1402B7530 MP 0x000000000 - {"_func_10F", 0x10F}, // SP 0x1402B77F0 MP 0x000000000 - {"_func_110", 0x110}, // SP 0x1402B7800 MP 0x000000000 - {"_func_111", 0x111}, // SP 0x1402B7810 MP 0x000000000 - {"_func_112", 0x112}, // SP 0x1402B79C0 MP 0x000000000 - {"_func_113", 0x113}, // SP 0x1402B7A20 MP 0x000000000 - {"vectornormalize", 0x114}, // SP 0x140292150 MP 0x1403587A0 - {"vectortoangles", 0x115}, // SP 0x140292290 MP 0x140358A90 - {"vectortoyaw", 0x116}, // SP 0x1402924D0 MP 0x140358B10 - {"vectorlerp", 0x117}, // SP 0x140292510 MP 0x140358E60 - {"anglestoup", 0x118}, // SP 0x140292C80 MP 0x1403596E0 - {"_func_119", 0x119}, // SP 0x140292D50 MP 0x140359890 - {"_func_11A", 0x11A}, // SP 0x140292F80 MP 0x140359930 - {"anglesdelta", 0x11B}, // SP 0x1402930E0 MP 0x140359BC0 - {"_func_11C", 0x11C}, // SP 0x1402934C0 MP 0x14035A0F0 - {"_func_11D", 0x11D}, // SP 0x140293670 MP 0x14035A280 - {"_func_11E", 0x11E}, // SP 0x1402956B0 MP 0x14035B550 - {"_func_11F", 0x11F}, // SP 0x140295850 MP 0x14035B7F0 - {"issubstr", 0x120}, // SP 0x140296960 MP 0x14035CB70 - {"isendstr", 0x121}, // SP 0x1402969A0 MP 0x14035CD40 - {"getsubstr", 0x122}, // SP 0x140296BB0 MP 0x14035CF80 - {"tolower", 0x123}, // SP 0x140296DC0 MP 0x14035D360 - {"_func_124", 0x124}, // SP 0x140297230 MP 0x14035DA90 - {"_func_125", 0x125}, // SP 0x140297970 MP 0x14035E690 - {"_func_126", 0x126}, // SP 0x14029FA50 MP 0x1403679A0 - {"getuavstrengthmax", 0x127}, // SP 0x000000000 MP 0x14037B790 - {"getuavstrengthlevelshowenemyfastsweep", 0x128}, // SP 0x000000000 MP 0x14037B7A0 - {"isdedicatedserver", 0x129}, // SP 0x000000000 MP 0x14037B7B0 - {"worldentnumber", 0x12A}, // SP 0x000000000 MP 0x14037B7C0 - {"blockteamradar", 0x12B}, // SP 0x000000000 MP 0x14037B7D0 - {"unblockteamradar", 0x12C}, // SP 0x000000000 MP 0x14037B830 - {"isteamradarblocked", 0x12D}, // SP 0x000000000 MP 0x14037B8B0 - {"_func_12E", 0x12E}, // SP 0x000000000 MP 0x140378110 - {"_func_12F", 0x12F}, // SP 0x000000000 MP 0x14037A7B0 - {"_func_130", 0x130}, // SP 0x000000000 MP 0x140378420 - {"sendmatchdata", 0x131}, // SP 0x000000000 MP 0x140378490 - {"_func_132", 0x132}, // SP 0x000000000 MP 0x140378F40 - {"_func_133", 0x133}, // SP 0x000000000 MP 0x14037A820 - {"_func_134", 0x134}, // SP 0x000000000 MP 0x140378FE0 - {"setmatchdataid", 0x135}, // SP 0x000000000 MP 0x140378DD0 - {"_func_136", 0x136}, // SP 0x000000000 MP 0x140378F70 - {"getmatchdata", 0x137}, // SP 0x000000000 MP 0x140378290 - {"_func_138", 0x138}, // SP 0x000000000 MP 0x14037A8D0 - {"sendclientmatchdata", 0x139}, // SP 0x000000000 MP 0x14037ADE0 - {"getbuildversion", 0x13A}, // SP 0x000000000 MP 0x14037AEB0 - {"getsquadassaultelo", 0x13B}, // SP 0x000000000 MP 0x14037B0E0 - {"getsystemtime", 0x13C}, // SP 0x000000000 MP 0x14037B100 - {"getmatchrulesdata", 0x13D}, // SP 0x000000000 MP 0x14037AA30 - {"isusingmatchrulesdata", 0x13E}, // SP 0x000000000 MP 0x14037AB20 - {"_func_13F", 0x13F}, // SP 0x000000000 MP 0x1403769E0 - {"ishairrunning", 0x140}, // SP 0x1402ACD00 MP 0x140378030 - {"setmapcenter", 0x141}, // SP 0x000000000 MP 0x14037B550 - {"setgameendtime", 0x142}, // SP 0x000000000 MP 0x14037B5A0 - {"visionsetthermal", 0x143}, // SP 0x1402ABA00 MP 0x140376D40 - {"visionsetpain", 0x144}, // SP 0x1402ABA10 MP 0x1403770E0 - {"visionsetpostapply", 0x145}, // SP 0x1402ABA20 MP 0x140377160 - {"_func_146", 0x146}, // SP 0x1402A12A0 MP 0x1403699C0 - {"_func_147", 0x147}, // SP 0x140298040 MP 0x14035F250 - {"_func_148", 0x148}, // SP 0x140298370 MP 0x14035F7A0 - {"_func_149", 0x149}, // SP 0x14029E7B0 MP 0x140366DA0 - {"_func_14A", 0x14A}, // SP 0x14029ECC0 MP 0x140366E30 - {"_func_14B", 0x14B}, // SP 0x14029F2B0 MP 0x1403673D0 - {"_func_14C", 0x14C}, // SP 0x14029F3E0 MP 0x140367540 - {"_func_14D", 0x14D}, // SP 0x14029F5B0 MP 0x1403675F0 - {"_func_14E", 0x14E}, // SP 0x1402982C0 MP 0x14035F470 - {"_func_14F", 0x14F}, // SP 0x14029EDB0 MP 0x1403670E0 - {"loadfx", 0x150}, // SP 0x140290A80 MP 0x1403583B0 - {"_func_151", 0x151}, // SP 0x140291730 MP 0x140359620 - {"playfxontag", 0x152}, // SP 0x140292A40 MP 0x14035AF90 - {"stopfxontag", 0x153}, // SP 0x140294440 MP 0x14035C4B0 - {"_func_154", 0x154}, // SP 0x140294DD0 MP 0x14035D560 - {"playloopedfx", 0x155}, // SP 0x140474350 MP 0x14037DA70 - {"spawnfx", 0x156}, // SP 0x1404746B0 MP 0x14037E2D0 - {"triggerfx", 0x157}, // SP 0x140474940 MP 0x14037E8B0 - {"_func_158", 0x158}, // SP 0x140292ED0 MP 0x14035B2B0 - {"_func_159", 0x159}, // SP 0x140474640 MP 0x14037E1D0 - {"_func_15A", 0x15A}, // SP 0x140293D50 MP 0x14035BFE0 - {"_func_15B", 0x15B}, // SP 0x000000000 MP 0x1403778C0 - {"_func_15C", 0x15C}, // SP 0x000000000 MP 0x140377920 - {"clientannouncement", 0x15D}, // SP 0x000000000 MP 0x1403779A0 - {"setteammode", 0x15E}, // SP 0x000000000 MP 0x140377A40 - {"getteamscore", 0x15F}, // SP 0x000000000 MP 0x140377BE0 - {"setteamscore", 0x160}, // SP 0x000000000 MP 0x140377C50 - {"setclientnamemode", 0x161}, // SP 0x000000000 MP 0x140377D70 - {"updateclientnames", 0x162}, // SP 0x000000000 MP 0x140377DC0 - {"getteamplayersalive", 0x163}, // SP 0x000000000 MP 0x140377EB0 - {"_func_164", 0x164}, // SP 0x000000000 MP 0x140375460 - {"_func_165", 0x165}, // SP 0x000000000 MP 0x140375480 - {"_func_166", 0x166}, // SP 0x000000000 MP 0x1403754A0 - {"_func_167", 0x167}, // SP 0x000000000 MP 0x1403756D0 - {"_func_168", 0x168}, // SP 0x000000000 MP 0x1403759C0 - {"_func_169", 0x169}, // SP 0x000000000 MP 0x1403760D0 - {"_func_16A", 0x16A}, // SP 0x14029F100 MP 0x1403673A0 - {"_func_16B", 0x16B}, // SP 0x000000000 MP 0x140376BE0 - {"_func_16C", 0x16C}, // SP 0x000000000 MP 0x140376C60 - {"map_restart", 0x16D}, // SP 0x000000000 MP 0x140376550 - {"exitlevel", 0x16E}, // SP 0x000000000 MP 0x140376630 - {"_func_16F", 0x16F}, // SP 0x000000000 MP 0x140376680 - {"addagent", 0x170}, // SP 0x000000000 MP 0x140376860 - {"_func_171", 0x171}, // SP 0x000000000 MP 0x140378020 - {"_func_172", 0x172}, // SP 0x000000000 MP 0x140376880 - {"_func_173", 0x173}, // SP 0x000000000 MP 0x140376B60 - {"mapexists", 0x174}, // SP 0x000000000 MP 0x140376910 - {"isvalidgametype", 0x175}, // SP 0x000000000 MP 0x140376950 - {"_func_176", 0x176}, // SP 0x000000000 MP 0x140378040 - {"setplayerteamrank", 0x177}, // SP 0x000000000 MP 0x140378050 - {"_func_178", 0x178}, // SP 0x000000000 MP 0x140378100 - {"setteamradar", 0x179}, // SP 0x000000000 MP 0x14037B5D0 - {"getteamradar", 0x17A}, // SP 0x000000000 MP 0x14037B640 - {"setteamradarstrength", 0x17B}, // SP 0x000000000 MP 0x14037B6A0 - {"getteamradarstrength", 0x17C}, // SP 0x000000000 MP 0x14037B720 - {"getuavstrengthmin", 0x17D}, // SP 0x000000000 MP 0x14037B780 - {"_func_17E", 0x17E}, // SP 0x140295500 MP 0x14035E730 - {"physicsexplosionsphere", 0x17F}, // SP 0x140296890 MP 0x14035FE90 - {"physicsradiusjolt", 0x180}, // SP 0x140295F60 MP 0x14035F2D0 - {"physicsradiusjitter", 0x181}, // SP 0x1402963A0 MP 0x14035F900 - {"_func_182", 0x182}, // SP 0x140299880 MP 0x140362E20 - {"_func_183", 0x183}, // SP 0x140299900 MP 0x140363010 - {"_func_184", 0x184}, // SP 0x140299F70 MP 0x140363800 - {"_func_185", 0x185}, // SP 0x14029A180 MP 0x140363920 - {"_func_186", 0x186}, // SP 0x14029A220 MP 0x140363B00 - {"_func_187", 0x187}, // SP 0x14029A4B0 MP 0x140363E60 - {"isexplosivedamagemod", 0x188}, // SP 0x1402A2800 MP 0x14036ADB0 - {"radiusdamage", 0x189}, // SP 0x1402A3690 MP 0x14036C110 - {"setplayerignoreradiusdamage", 0x18A}, // SP 0x14028DFA0 MP 0x14036CF90 - {"_func_18B", 0x18B}, // SP 0x1402A3950 MP 0x14036C1E0 - {"_func_18C", 0x18C}, // SP 0x14029B460 MP 0x140366A00 - {"getnumparts", 0x18D}, // SP 0x14029A830 MP 0x140363F40 - {"_func_18E", 0x18E}, // SP 0x1402B76D0 MP 0x140383170 - {"_func_18F", 0x18F}, // SP 0x000000000 MP 0x1403831D0 - {"objective_team", 0x190}, // SP 0x000000000 MP 0x140383310 - {"objective_player", 0x191}, // SP 0x000000000 MP 0x1403833B0 - {"_func_192", 0x192}, // SP 0x000000000 MP 0x140383410 - {"_func_193", 0x193}, // SP 0x000000000 MP 0x1403834B0 - {"_func_194", 0x194}, // SP 0x000000000 MP 0x1403835B0 - {"_func_195", 0x195}, // SP 0x000000000 MP 0x1403835F0 - {"objective_playermask_showtoall", 0x196}, // SP 0x000000000 MP 0x140382DA0 - {"_func_197", 0x197}, // SP 0x000000000 MP 0x140382DE0 - {"_func_198", 0x198}, // SP 0x1402AD860 MP 0x140377360 - {"_func_199", 0x199}, // SP 0x1402AD8C0 MP 0x1403773E0 - {"_func_19A", 0x19A}, // SP 0x1405D92F0 MP 0x140377C30 - {"getent", 0x19B}, // SP 0x1402B9570 MP 0x1403845D0 - {"getentarray", 0x19C}, // SP 0x1402B95E0 MP 0x1403846A0 - {"_func_19D", 0x19D}, // SP 0x000000000 MP 0x140384C00 - {"spawnplane", 0x19E}, // SP 0x000000000 MP 0x140377670 - {"spawnstruct", 0x19F}, // SP 0x140374110 MP 0x140442170 - {"_func_1A0", 0x1A0}, // SP 0x000000000 MP 0x140377A90 - {"isalive", 0x1A1}, // SP 0x1402AD940 MP 0x140377410 - {"isspawner", 0x1A2}, // SP 0x1402ADB20 MP 0x1403774F0 - {"_func_1A3", 0x1A3}, // SP 0x140282D00 MP 0x14034F8E0 - {"missile_createattractorent", 0x1A4}, // SP 0x140282D10 MP 0x14034F8F0 - {"missile_createattractororigin", 0x1A5}, // SP 0x140282FD0 MP 0x14034FBA0 - {"_func_1A6", 0x1A6}, // SP 0x140282FE0 MP 0x14034FBB0 - {"_func_1A7", 0x1A7}, // SP 0x140282FF0 MP 0x14034FBC0 - {"playsoundatpos", 0x1A8}, // SP 0x000000000 MP 0x140378150 - {"newhudelem", 0x1A9}, // SP 0x14026F000 MP 0x14033CF50 - {"newclienthudelem", 0x1AA}, // SP 0x14026EFB0 MP 0x14033CEF0 - {"newteamhudelem", 0x1AB}, // SP 0x000000000 MP 0x14033CF80 - {"resettimeout", 0x1AC}, // SP 0x140375910 MP 0x1404438F0 - {"isplayer", 0x1AD}, // SP 0x1402ADB90 MP 0x140377390 - {"isplayernumber", 0x1AE}, // SP 0x000000000 MP 0x1403774C0 - {"getpartname", 0x1AF}, // SP 0x14029A9A0 MP 0x140364120 - {"_func_1B0", 0x1B0}, // SP 0x14029CDC0 MP 0x140363D50 - {"_func_1B1", 0x1B1}, // SP 0x1402999A0 MP 0x140360B10 - {"_func_1B2", 0x1B2}, // SP 0x14029AA30 MP 0x140361AC0 - {"_func_1B3", 0x1B3}, // SP 0x14029ADB0 MP 0x140361CE0 - {"_func_1B4", 0x1B4}, // SP 0x14029B360 MP 0x1403622D0 - {"_func_1B5", 0x1B5}, // SP 0x14029B580 MP 0x140362520 - {"_func_1B6", 0x1B6}, // SP 0x14029B020 MP 0x140361EC0 - {"_func_1B7", 0x1B7}, // SP 0x14029B7A0 MP 0x140362920 - {"weaponclass", 0x1B8}, // SP 0x14029B8E0 MP 0x140362A60 - {"getnextarraykey", 0x1B9}, // SP 0x1402A35D0 MP 0x14036D000 - {"_func_1BA", 0x1BA}, // SP 0x14028D850 MP 0x14036D690 - {"_func_1BB", 0x1BB}, // SP 0x14029CCC0 MP 0x1403664F0 - {"tablelookupistringbyrow", 0x1BC}, // SP 0x14029D970 MP 0x1403671B0 - {"_func_1BD", 0x1BD}, // SP 0x14029CF50 MP 0x1403667F0 - {"tablelookuprownum", 0x1BE}, // SP 0x14029DC10 MP 0x140367320 - {"_func_1BF", 0x1BF}, // SP 0x14029D280 MP 0x140366C90 - {"tableexists", 0x1C0}, // SP 0x14029D820 MP 0x140366DE0 - {"getmissileowner", 0x1C1}, // SP 0x14029AD10 MP 0x140366490 - {"_func_1C2", 0x1C2}, // SP 0x140294EF0 MP 0x14035E270 - {"getweaponflashtagname", 0x1C3}, // SP 0x140295DC0 MP 0x14035F290 - {"averagepoint", 0x1C4}, // SP 0x14029A870 MP 0x140363F90 - {"_func_1C5", 0x1C5}, // SP 0x14029AB60 MP 0x140364300 - {"getspawnerarray", 0x1C6}, // SP 0x140466C40 MP 0x140564030 - {"playrumbleonposition", 0x1C7}, // SP 0x140299410 MP 0x140360540 - {"playrumblelooponposition", 0x1C8}, // SP 0x140299470 MP 0x1403605E0 - {"_func_1C9", 0x1C9}, // SP 0x1402996F0 MP 0x140360670 - {"soundexists", 0x1CA}, // SP 0x140290B30 MP 0x14035C2D0 - {"_func_1CB", 0x1CB}, // SP 0x1405D92F0 MP 0x14036B580 - {"_func_1CC", 0x1CC}, // SP 0x1405D92F0 MP 0x14036B590 - {"_func_1CD", 0x1CD}, // SP 0x1405D92F0 MP 0x14036B710 - {"_func_1CE", 0x1CE}, // SP 0x1405D92F0 MP 0x14036B770 - {"_func_1CF", 0x1CF}, // SP 0x1405D92F0 MP 0x14036B780 - {"_func_1D0", 0x1D0}, // SP 0x1405D92F0 MP 0x14036B790 - {"setminimap", 0x1D1}, // SP 0x1402A2200 MP 0x14036C3C0 - {"_func_1D2", 0x1D2}, // SP 0x1402A28F0 MP 0x14036CA90 - {"_func_1D3", 0x1D3}, // SP 0x1402A3410 MP 0x14036CDA0 - {"getfirstarraykey", 0x1D4}, // SP 0x1402A3470 MP 0x14036CF00 - {"getglass", 0x1D5}, // SP 0x14029AD60 MP 0x1403644F0 - {"getglassarray", 0x1D6}, // SP 0x14029B110 MP 0x1403647D0 - {"getglassorigin", 0x1D7}, // SP 0x14029B410 MP 0x1403649E0 - {"isglassdestroyed", 0x1D8}, // SP 0x14029B630 MP 0x140364CF0 - {"destroyglass", 0x1D9}, // SP 0x14029B850 MP 0x140365010 - {"_func_1DA", 0x1DA}, // SP 0x14029B9F0 MP 0x1403651E0 - {"_func_1DB", 0x1DB}, // SP 0x14029C0E0 MP 0x140365F50 - {"_func_1DC", 0x1DC}, // SP 0x14029C160 MP 0x140366130 - {"objective_add", 0x1DD}, // SP 0x1402B7080 MP 0x140382E50 - {"_func_1DE", 0x1DE}, // SP 0x1402B74F0 MP 0x140382F80 - {"objective_state", 0x1DF}, // SP 0x1402B77E0 MP 0x140382FF0 - {"objective_icon", 0x1E0}, // SP 0x1402B7820 MP 0x140383090 - {"_func_1E1", 0x1E1}, // SP 0x1402B7900 MP 0x000000000 - {"objective_position", 0x1E2}, // SP 0x1402B7980 MP 0x1403830D0 - {"objective_current", 0x1E3}, // SP 0x1402B7A10 MP 0x140383230 - {"_func_1E4", 0x1E4}, // SP 0x14029BA70 MP 0x140362C20 - {"_func_1E5", 0x1E5}, // SP 0x14029BE70 MP 0x140362F00 - {"_func_1E6", 0x1E6}, // SP 0x14029BF80 MP 0x140363300 - {"_func_1E7", 0x1E7}, // SP 0x14029C9D0 MP 0x140363950 - {"isweaponcliponly", 0x1E8}, // SP 0x14029D050 MP 0x140364220 - {"_func_1E9", 0x1E9}, // SP 0x14029D330 MP 0x140364590 - {"_func_1EA", 0x1EA}, // SP 0x14029D720 MP 0x140364870 - {"_func_1EB", 0x1EB}, // SP 0x14029D9F0 MP 0x140364E70 - {"_func_1EC", 0x1EC}, // SP 0x14045D5C0 MP 0x14055A900 - {"getvehiclenodearray", 0x1ED}, // SP 0x14045D6B0 MP 0x14055A9F0 - {"_func_1EE", 0x1EE}, // SP 0x14045D550 MP 0x14055A890 - {"_func_1EF", 0x1EF}, // SP 0x1404669B0 MP 0x140563DA0 - {"_func_1F0", 0x1F0}, // SP 0x140466CC0 MP 0x140564110 - {"spawnvehicle", 0x1F1}, // SP 0x140466D20 MP 0x140564170 - {"vehicle_getarray", 0x1F2}, // SP 0x1404669F0 MP 0x140563DE0 - {"pow", 0x1F3}, // SP 0x14028E710 MP 0x14036CBC0 - {"_func_1F4", 0x1F4}, // SP 0x14028D7B0 MP 0x14036BB10 - {"botgetmemoryevents", 0x1F5}, // SP 0x000000000 MP 0x14047A600 - {"botautoconnectenabled", 0x1F6}, // SP 0x000000000 MP 0x14047ABF0 - {"botzonegetcount", 0x1F7}, // SP 0x000000000 MP 0x14047AC20 - {"botzonesetteam", 0x1F8}, // SP 0x000000000 MP 0x14047AF10 - {"_func_1F9", 0x1F9}, // SP 0x000000000 MP 0x14047AD50 - {"botmemoryflags", 0x1FA}, // SP 0x000000000 MP 0x14047A940 - {"botflagmemoryevents", 0x1FB}, // SP 0x000000000 MP 0x14047A320 - {"botzonegetindoorpercent", 0x1FC}, // SP 0x000000000 MP 0x14047ACF0 - {"botsentientswap", 0x1FD}, // SP 0x000000000 MP 0x14047A990 - {"isbot", 0x1FE}, // SP 0x000000000 MP 0x14047AF70 - {"isagent", 0x1FF}, // SP 0x000000000 MP 0x14037B2B0 - {"getmaxagents", 0x200}, // SP 0x000000000 MP 0x140450E50 - {"_func_201", 0x201}, // SP 0x000000000 MP 0x14047A310 - {"botgetclosestnavigablepoint", 0x202}, // SP 0x000000000 MP 0x14047A550 - {"getnodesintrigger", 0x203}, // SP 0x000000000 MP 0x14031FCE0 - {"nodesvisible", 0x204}, // SP 0x1402CC4A0 MP 0x140320EA0 - {"_func_205", 0x205}, // SP 0x1402CC110 MP 0x14031FDD0 - {"_func_206", 0x206}, // SP 0x000000000 MP 0x1403201B0 - {"getzonenearest", 0x207}, // SP 0x000000000 MP 0x1403201C0 - {"_func_208", 0x208}, // SP 0x000000000 MP 0x140320320 - {"_func_209", 0x209}, // SP 0x000000000 MP 0x140320A10 - {"_func_20A", 0x20A}, // SP 0x000000000 MP 0x140320960 - {"getnodezone", 0x20B}, // SP 0x000000000 MP 0x14031FC20 - {"_func_20C", 0x20C}, // SP 0x000000000 MP 0x140320600 - {"getzonenodeforindex", 0x20D}, // SP 0x000000000 MP 0x1403202E0 - {"_func_20E", 0x20E}, // SP 0x1402AFFC0 MP 0x14037AE40 - {"_func_211", 0x211}, // SP 0x000000000 MP 0x140320C70 - {"findentrances", 0x212}, // SP 0x000000000 MP 0x14031F6F0 - {"badplace_global", 0x213}, // SP 0x000000000 MP 0x14035A190 - {"_func_214", 0x214}, // SP 0x000000000 MP 0x140375150 - {"_func_215", 0x215}, // SP 0x1402CBE10 MP 0x14031F940 - {"disconnectnodepair", 0x216}, // SP 0x14028E840 MP 0x14036F800 - {"connectnodepair", 0x217}, // SP 0x14028EAC0 MP 0x140357F30 - {"_func_218", 0x218}, // SP 0x1402AE000 MP 0x000000000 - {"_func_21B", 0x21B}, // SP 0x1405D92F0 MP 0x1403780E0 - {"_func_21C", 0x21C}, // SP 0x000000000 MP 0x140374FD0 - {"_func_21D", 0x21D}, // SP 0x14037AA30 MP 0x000000000 - {"_func_21E", 0x21E}, // SP 0x14037AC70 MP 0x000000000 - {"_func_21F", 0x21F}, // SP 0x14037ABB0 MP 0x000000000 - {"_func_220", 0x220}, // SP 0x14037AB50 MP 0x000000000 - {"_func_221", 0x221}, // SP 0x14037A730 MP 0x000000000 - {"_func_222", 0x222}, // SP 0x14037A7B0 MP 0x000000000 - {"_func_223", 0x223}, // SP 0x14037A760 MP 0x000000000 - {"_func_224", 0x224}, // SP 0x14037A7F0 MP 0x000000000 - {"distance2dsquared", 0x225}, // SP 0x1402914F0 MP 0x140357BF0 - {"getangledelta3d", 0x226}, // SP 0x14028FE10 MP 0x14036F1C0 - {"activateclientexploder", 0x227}, // SP 0x140290710 MP 0x14035B7B0 - {"_func_228", 0x228}, // SP 0x1402909E0 MP 0x14035CED0 - {"_func_229", 0x229}, // SP 0x140290DF0 MP 0x14035D200 - {"trajectorycalculateexitangle", 0x22A}, // SP 0x140290FA0 MP 0x14035D4C0 - {"_func_22B", 0x22B}, // SP 0x1402911D0 MP 0x14035D830 - {"trajectorycomputedeltaheightattime", 0x22C}, // SP 0x140291530 MP 0x14035DFB0 - {"trajectoryestimatedesiredinairtime", 0x22D}, // SP 0x140291910 MP 0x14035E0B0 - {"_func_22E", 0x22E}, // SP 0x1405D92F0 MP 0x140367D60 - {"ispointinvolume", 0x22F}, // SP 0x140291190 MP 0x14036F5A0 - {"_func_230", 0x230}, // SP 0x1402AB600 MP 0x000000000 - {"_func_231", 0x231}, // SP 0x1402AB4F0 MP 0x000000000 - {"_func_232", 0x232}, // SP 0x1402AB4D0 MP 0x000000000 - {"_func_234", 0x234}, // SP 0x1405D92F0 MP 0x1403605D0 - {"getscriptablearray", 0x236}, // SP 0x140294380 MP 0x140360720 - {"_func_237", 0x237}, // SP 0x140297840 MP 0x140360C40 - {"_func_238", 0x238}, // SP 0x1402A87C0 MP 0x14037B1D0 - {"_func_239", 0x239}, // SP 0x1402AA280 MP 0x000000000 - {"_func_23A", 0x23A}, // SP 0x140292220 MP 0x14035E710 - {"_func_23B", 0x23B}, // SP 0x140292220 MP 0x14035E860 - {"_func_23D", 0x23D}, // SP 0x1402A06D0 MP 0x1403686B0 - {"_func_23E", 0x23E}, // SP 0x1402A0900 MP 0x140368C00 - {"_func_23F", 0x23F}, // SP 0x14029DDC0 MP 0x140365220 - {"_func_240", 0x240}, // SP 0x14029DDC0 MP 0x140365440 - {"_func_241", 0x241}, // SP 0x1402ACD00 MP 0x140365460 - {"_func_242", 0x242}, // SP 0x1402ACD00 MP 0x140365470 - {"_func_243", 0x243}, // SP 0x1402ACD00 MP 0x140365630 - {"_func_244", 0x244}, // SP 0x000000000 MP 0x1403784C0 - {"_func_245", 0x245}, // SP 0x140292D40 MP 0x14035FAF0 - {"_func_246", 0x246}, // SP 0x000000000 MP 0x1403784E0 - {"_func_247", 0x247}, // SP 0x000000000 MP 0x140378DA0 - {"_func_248", 0x248}, // SP 0x000000000 MP 0x140378DB0 - {"_func_249", 0x249}, // SP 0x000000000 MP 0x140378DC0 - {"_func_24A", 0x24A}, // SP 0x1402A8F70 MP 0x000000000 - {"_func_24B", 0x24B}, // SP 0x1402A8FF0 MP 0x000000000 - {"_func_24C", 0x24C}, // SP 0x1402946A0 MP 0x14035ABF0 - {"_func_24D", 0x24D}, // SP 0x140290110 MP 0x14036DF90 - {"_func_24E", 0x24E}, // SP 0x140292B00 MP 0x140359490 - {"_func_24F", 0x24F}, // SP 0x1402ABB80 MP 0x000000000 - {"_func_250", 0x250}, // SP 0x1405D92F0 MP 0x140360370 - {"_func_251", 0x251}, // SP 0x1405D92F0 MP 0x1403604B0 - {"_func_252", 0x252}, // SP 0x1405D92F0 MP 0x140360530 - {"_func_253", 0x253}, // SP 0x140293F90 MP 0x14035A6C0 - {"_func_254", 0x254}, // SP 0x140293FF0 MP 0x14035A7C0 - {"_func_255", 0x255}, // SP 0x140294500 MP 0x14035A9F0 - {"_func_256", 0x256}, // SP 0x000000000 MP 0x1403844C0 - {"_func_257", 0x257}, // SP 0x1402ADE20 MP 0x000000000 - {"_func_258", 0x258}, // SP 0x14029F640 MP 0x1403677A0 - {"_func_259", 0x259}, // SP 0x14029F710 MP 0x1403678C0 - {"getcsplinecount", 0x25A}, // SP 0x1402954E0 MP 0x1403611E0 - {"getcsplinepointcount", 0x25B}, // SP 0x1402955F0 MP 0x140361200 - {"getcsplinelength", 0x25C}, // SP 0x140295790 MP 0x1403613C0 - {"getcsplinepointid", 0x25D}, // SP 0x140295AD0 MP 0x1403615F0 - {"getcsplinepointlabel", 0x25E}, // SP 0x140295E00 MP 0x140361A30 - {"getcsplinepointtension", 0x25F}, // SP 0x140296150 MP 0x140361DD0 - {"_func_260", 0x260}, // SP 0x1402965B0 MP 0x140362020 - {"_func_261", 0x261}, // SP 0x140296740 MP 0x140362470 - {"_func_262", 0x262}, // SP 0x140296B10 MP 0x140362680 - {"getcsplinepointdisttonextpoint", 0x263}, // SP 0x140296CE0 MP 0x140362AE0 - {"_func_264", 0x264}, // SP 0x140296EE0 MP 0x140362D50 - {"_func_265", 0x265}, // SP 0x1402970D0 MP 0x140363430 - {"_func_266", 0x266}, // SP 0x140297580 MP 0x1403636C0 - {"setnojipscore", 0x267}, // SP 0x140297820 MP 0x140363AB0 - {"setnojiptime", 0x268}, // SP 0x140297820 MP 0x140363C90 - {"getpredictedentityposition", 0x269}, // SP 0x000000000 MP 0x14037AEC0 - {"_func_26A", 0x26A}, // SP 0x1405D92F0 MP 0x140363F80 - {"_func_26B", 0x26B}, // SP 0x1405D92F0 MP 0x140364110 - {"_func_26C", 0x26C}, // SP 0x1405D92F0 MP 0x1403642F0 - {"_func_26D", 0x26D}, // SP 0x1405D92F0 MP 0x1403644E0 - {"_func_26E", 0x26E}, // SP 0x1405D92F0 MP 0x140364540 - {"_func_26F", 0x26F}, // SP 0x1405D92F0 MP 0x140364700 - {"queuedialog", 0x270}, // SP 0x000000000 MP 0x140378930 - {"_func_271", 0x271}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_272", 0x272}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_273", 0x273}, // SP 0x1405D92F0 MP 0x140364710 - {"_func_274", 0x274}, // SP 0x1405D92F0 MP 0x140364860 - {"_func_275", 0x275}, // SP 0x1405D92F0 MP 0x140364970 - {"_func_276", 0x276}, // SP 0x1405D92F0 MP 0x1403649D0 - {"triggerportableradarping", 0x277}, // SP 0x000000000 MP 0x14037B980 - {"botgetteamlimit", 0x279}, // SP 0x000000000 MP 0x14047A900 - {"spawnfxforclient", 0x27A}, // SP 0x000000000 MP 0x14037E430 - {"botgetteamdifficulty", 0x27B}, // SP 0x000000000 MP 0x14047A8C0 - {"_func_27C", 0x27C}, // SP 0x1405D92F0 MP 0x1403675D0 - {"_func_27D", 0x27D}, // SP 0x14029CAC0 MP 0x14033CF40 - {"_func_27E", 0x27E}, // SP 0x1405D92F0 MP 0x140363CE0 - {"_func_27F", 0x27F}, // SP 0x1405D92F0 MP 0x140363E50 - {"_func_280", 0x280}, // SP 0x1405D92F0 MP 0x140360610 - {"_func_281", 0x281}, // SP 0x14029DC90 MP 0x140369F80 - {"getstarttime", 0x282}, // SP 0x000000000 MP 0x14037BBD0 - {"getbuildnumber", 0x283}, // SP 0x000000000 MP 0x14037BBE0 - {"_func_284", 0x284}, // SP 0x000000000 MP 0x14037BC00 - {"_func_285", 0x285}, // SP 0x000000000 MP 0x1403748B0 - {"_func_286", 0x286}, // SP 0x000000000 MP 0x140374B00 - {"_func_287", 0x287}, // SP 0x1405D92F0 MP 0x140360660 - {"_func_288", 0x288}, // SP 0x000000000 MP 0x1403772E0 - {"_func_289", 0x289}, // SP 0x000000000 MP 0x140376690 - {"_func_28A", 0x28A}, // SP 0x1402ACD00 MP 0x140365450 - {"_func_28B", 0x28B}, // SP 0x140295B60 MP 0x14035BD90 - {"_func_28C", 0x28C}, // SP 0x140296230 MP 0x14035C6E0 - {"_func_28D", 0x28D}, // SP 0x000000000 MP 0x1400777C0 - {"_func_28E", 0x28E}, // SP 0x000000000 MP 0x1403767D0 - {"_func_28F", 0x28F}, // SP 0x000000000 MP 0x140320120 - {"_func_290", 0x290}, // SP 0x000000000 MP 0x1403775D0 - {"_func_291", 0x291}, // SP 0x14029E770 MP 0x140368040 - {"_func_292", 0x292}, // SP 0x14029E7F0 MP 0x140368150 - {"_func_293", 0x293}, // SP 0x1402ADDE0 MP 0x000000000 - {"_func_294", 0x294}, // SP 0x1402988E0 MP 0x140365640 - {"_func_295", 0x295}, // SP 0x14029C2F0 MP 0x140368F40 - {"_func_296", 0x296}, // SP 0x14029B680 MP 0x140364D50 - {"_func_297", 0x297}, // SP 0x14029BD80 MP 0x140365540 - {"_func_298", 0x298}, // SP 0x14029C1B0 MP 0x140366230 - {"_func_299", 0x299}, // SP 0x1402ABA30 MP 0x000000000 - {"_func_29A", 0x29A}, // SP 0x1405D92F0 MP 0x14035B9A0 - {"_func_29B", 0x29B}, // SP 0x140291040 MP 0x14036F330 - {"_func_29C", 0x29C}, // SP 0x14029D240 MP 0x140368760 - {"_func_29D", 0x29D}, // SP 0x14029DE30 MP 0x1403674E0 - {"_func_29E", 0x29E}, // SP 0x14029DEC0 MP 0x140367620 - {"_func_29F", 0x29F}, // SP 0x000000000 MP 0x140375690 - {"_func_2A0", 0x2A0}, // SP 0x000000000 MP 0x1403756A0 - {"_func_2A1", 0x2A1}, // SP 0x14029D890 MP 0x140364AB0 - {"_func_2A2", 0x2A2}, // SP 0x1402ABC20 MP 0x000000000 - {"_func_2A3", 0x2A3}, // SP 0x1402A2F20 MP 0x14036F010 - {"_func_2A4", 0x2A4}, // SP 0x140290710 MP 0x14035B890 - {"_func_2A5", 0x2A5}, // SP 0x14029DF00 MP 0x14036D0F0 - {"_func_2A6", 0x2A6}, // SP 0x1405D92F0 MP 0x14036DAE0 - {"_func_2A7", 0x2A7}, // SP 0x1405D92F0 MP 0x14036DA60 - {"_func_2A8", 0x2A8}, // SP 0x000000000 MP 0x140376390 - {"_func_2A9", 0x2A9}, // SP 0x1402AE820 MP 0x000000000 - {"_func_2AA", 0x2AA}, // SP 0x14029AE80 MP 0x140364550 - {"_func_2AB", 0x2AB}, // SP 0x1405D92F0 MP 0x14036E590 - {"_func_2AC", 0x2AC}, // SP 0x1402ACD00 MP 0x14036E310 - {"_func_2AD", 0x2AD}, // SP 0x1405D92F0 MP 0x14036E3E0 - {"_func_2AE", 0x2AE}, // SP 0x1405D92F0 MP 0x14036E470 - {"_func_2AF", 0x2AF}, // SP 0x1405D92F0 MP 0x14036E730 - {"_func_2B0", 0x2B0}, // SP 0x000000000 MP 0x140375320 - {"_func_2B1", 0x2B1}, // SP 0x000000000 MP 0x1403753F0 - {"_func_2B2", 0x2B2}, // SP 0x000000000 MP 0x140375430 - {"_func_2B3", 0x2B3}, // SP 0x000000000 MP 0x140375A40 - {"_func_2B4", 0x2B4}, // SP 0x1405D92F0 MP 0x14035C9D0 - {"_func_2B5", 0x2B5}, // SP 0x1405D92F0 MP 0x14035D920 - {"_func_2B6", 0x2B6}, // SP 0x140291AD0 MP 0x14035E150 - {"_func_2B7", 0x2B7}, // SP 0x1402A85B0 MP 0x000000000 - {"_func_2B8", 0x2B8}, // SP 0x000000000 MP 0x140378570 - {"_func_2B9", 0x2B9}, // SP 0x000000000 MP 0x1403787D0 - {"_func_2BA", 0x2BA}, // SP 0x000000000 MP 0x140378850 - {"_func_2BB", 0x2BB}, // SP 0x000000000 MP 0x140379930 - {"_func_2BC", 0x2BC}, // SP 0x14028EBB0 MP 0x140359E00 - {"_func_2BD", 0x2BD}, // SP 0x1402A8640 MP 0x000000000 - {"_func_2BE", 0x2BE}, // SP 0x14029B310 MP 0x140366D50 - {"_func_2BF", 0x2BF}, // SP 0x000000000 MP 0x140383570 - {"_func_2C0", 0x2C0}, // SP 0x1405D92F0 MP 0x14036E8A0 - {"_func_2C1", 0x2C1}, // SP 0x1405D92F0 MP 0x14036E900 - {"_func_2C2", 0x2C2}, // SP 0x140291E10 MP 0x14035E670 - {"_func_2C3", 0x2C3}, // SP 0x1402A1A30 MP 0x14036DA40 - {"_func_2C4", 0x2C4}, // SP 0x1402A1A30 MP 0x14036DAC0 - {"_func_2C5", 0x2C5}, // SP 0x1402A8810 MP 0x000000000 - {"_func_2C6", 0x2C6}, // SP 0x000000000 MP 0x140379A80 - {"_func_2C6", 0x2C7}, // SP 0x000000000 MP 0x140320DC0 - {"_func_2C8", 0x2C8}, // SP 0x000000000 MP 0x140320E20 - {"_func_2C9", 0x2C9}, // SP 0x000000000 MP 0x14037E5E0 - {"_func_2CA", 0x2CA}, // SP 0x000000000 MP 0x14037E650 - {"_func_2CB", 0x2CB}, // SP 0x000000000 MP 0x14037BC40 - {"_func_2CC", 0x2CC}, // SP 0x000000000 MP 0x14037BD00 - {"_func_2CD", 0x2CD}, // SP 0x000000000 MP 0x140374820 - {"_func_2CE", 0x2CE}, // SP 0x1402A79A0 MP 0x000000000 - {"_func_2CF", 0x2CF}, // SP 0x000000000 MP 0x14037AB40 - {"_func_2D4", 0x2D4}, // SP 0x1402A7CB0 MP 0x000000000 - {"_func_2D5", 0x2D5}, // SP 0x14029E120 MP 0x14036D640 - {"_func_2D6", 0x2D6}, // SP 0x000000000 MP 0x14037BE30 - {"_func_2D7", 0x2D7}, // SP 0x1405D92F0 MP 0x14036DB50 - {"_func_2D8", 0x2D8}, // SP 0x1402ABB70 MP 0x000000000 - {"_func_2D9", 0x2D9}, // SP 0x000000000 MP 0x140320D50 - {"_func_2DA", 0x2DA}, // SP 0x1405D92F0 MP 0x000000000 - {"_func_2DB", 0x2DB}, // SP 0x000000000 MP 0x14037ABB0 - {"_func_2DC", 0x2DC}, // SP 0x000000000 MP 0x14037E1C0 - {"_func_2DD", 0x2DD}, // SP 0x000000000 MP 0x14037E1B0 - {"_func_2DF", 0x2DF}, // SP 0x140292220 MP 0x14036F7F0 - {"_func_2E0", 0x2E0}, // SP 0x140297C80 MP 0x14035EDE0 - {"_func_2E1", 0x2E1}, // SP 0x000000000 MP 0x1403788D0 - {"_func_2E2", 0x2E2}, // SP 0x1405D92F0 MP 0x14035B3B0 - {"_func_2E3", 0x2E3}, // SP 0x1405D92F0 MP 0x14035D0B0 - {"_func_2E4", 0x2E4}, // SP 0x1405D92F0 MP 0x14035E170 - {"_func_2E5", 0x2E5}, // SP 0x1402A8730 MP 0x000000000 - {"_func_2E6", 0x2E6}, // SP 0x140295A10 MP 0x14035EFF0 - {"_func_2E7", 0x2E7}, // SP 0x140295CF0 MP 0x14035F120 - {"_func_2E8", 0x2E8}, // SP 0x1402AC850 MP 0x000000000 - {"_func_2E9", 0x2E9}, // SP 0x14029E760 MP 0x140366680 - {"_func_2EA", 0x2EA}, // SP 0x000000000 MP 0x140376DC0 - {"_func_2EB", 0x2EB}, // SP 0x000000000 MP 0x140377540 - {"_func_2EC", 0x2EC}, // SP 0x000000000 MP 0x140377880 - {"_func_2ED", 0x2ED}, // SP 0x1402ACD00 MP 0x14036BA50 - {"_func_2EE", 0x2EE}, // SP 0x1402A1E10 MP 0x14036BA60 - {"_func_2EF", 0x2EF}, // SP 0x1402A1FB0 MP 0x14036BA70 - {"_func_2F0", 0x2F0}, // SP 0x1402A21F0 MP 0x14036BB50 - {"_func_2F1", 0x2F1}, // SP 0x1402ACD00 MP 0x14036BC60 - {"_func_2F2", 0x2F2}, // SP 0x1402A1E10 MP 0x14036BC70 - {"_func_2F3", 0x2F3}, // SP 0x1402A1FB0 MP 0x14036BF90 - {"_func_2F4", 0x2F4}, // SP 0x1402A21F0 MP 0x14036C100 - {"_func_2F5", 0x2F5}, // SP 0x1402A1E10 MP 0x14036C120 - {"_func_2F6", 0x2F6}, // SP 0x1402A1FB0 MP 0x14036C170 - {"_func_2F7", 0x2F7}, // SP 0x1402A21F0 MP 0x14036C310 - {"_func_2F8", 0x2F8}, // SP 0x14028D700 MP 0x1403582B0 - {"_func_2F9", 0x2F9}, // SP 0x14029CAC0 MP 0x14036D300 - {"_func_2FA", 0x2FA}, // SP 0x14029CAC0 MP 0x14036DDC0 - {"_func_2FB", 0x2FB}, // SP 0x14029DB60 MP 0x140365110 - {"_func_2FC", 0x2FC}, // SP 0x14029CB20 MP 0x140367DD0 - {"_func_2FD", 0x2FD}, // SP 0x14029CEA0 MP 0x140368000 - {"_func_2FE", 0x2FE}, // SP 0x14029CEE0 MP 0x140368290 - {"_func_2FF", 0x2FF}, // SP 0x000000000 MP 0x140367110 - {"_func_300", 0x300}, // SP 0x000000000 MP 0x140377870 - {"_func_301", 0x301}, // SP 0x1405D92F0 MP 0x140363E90 - }; - - std::unordered_map method_map = - { - {"motionblurhqenable", 0x8000}, // SP 0x14029B0D0 MP 0x140362FD0 - {"_meth_8001", 0x8001}, // SP 0x1402A8AC0 MP 0x000000000 - {"setdamagestage", 0x8002}, // SP 0x000000000 MP 0x14055A000 - {"_meth_8003", 0x8003}, // SP 0x000000000 MP 0x140378300 - {"playsoundtoplayer", 0x8004}, // SP 0x000000000 MP 0x1403784F0 - {"playerhide", 0x8005}, // SP 0x000000000 MP 0x14037AB70 - {"_meth_8006", 0x8006}, // SP 0x000000000 MP 0x14037ABD0 - {"showtoplayer", 0x8007}, // SP 0x000000000 MP 0x14037AC50 - {"_meth_8008", 0x8008}, // SP 0x000000000 MP 0x14037ACB0 - {"_meth_8009", 0x8009}, // SP 0x000000000 MP 0x14037ACC0 - {"enableplayeruse", 0x800A}, // SP 0x000000000 MP 0x140374B10 - {"disableplayeruse", 0x800B}, // SP 0x000000000 MP 0x140374BB0 - {"_meth_800C", 0x800C}, // SP 0x000000000 MP 0x140374D70 - {"_meth_800D", 0x800D}, // SP 0x000000000 MP 0x140374C90 - {"makescrambler", 0x800E}, // SP 0x000000000 MP 0x14037B890 - {"makeportableradar", 0x800F}, // SP 0x000000000 MP 0x14037B930 - {"clearscrambler", 0x8010}, // SP 0x000000000 MP 0x14037B910 - {"clearportableradar", 0x8011}, // SP 0x000000000 MP 0x14037B960 - {"addplayermantleblockage", 0x8012}, // SP 0x000000000 MP 0x1403760E0 - {"setteamfortrigger", 0x8013}, // SP 0x000000000 MP 0x14037B130 - {"clientclaimtrigger", 0x8014}, // SP 0x000000000 MP 0x14037B220 - {"clientreleasetrigger", 0x8015}, // SP 0x000000000 MP 0x14037B300 - {"releaseclaimedtrigger", 0x8016}, // SP 0x000000000 MP 0x14037B510 - {"_meth_8017", 0x8017}, // SP 0x000000000 MP 0x14037AC10 - {"_meth_8018", 0x8018}, // SP 0x000000000 MP 0x14037ACD0 - {"_meth_8019", 0x8019}, // SP 0x000000000 MP 0x140378210 - {"_meth_801A", 0x801A}, // SP 0x14028F380 MP 0x14036F540 - {"getcorpseanim", 0x801B}, // SP 0x000000000 MP 0x14037BD60 - {"playerforcedeathanim", 0x801C}, // SP 0x000000000 MP 0x140374A30 - {"_meth_801D", 0x801D}, // SP 0x14029DCF0 MP 0x140369D40 - {"_meth_801E", 0x801E}, // SP 0x1402AD230 MP 0x000000000 - {"_meth_801F", 0x801F}, // SP 0x1402AD490 MP 0x000000000 - {"_meth_8020", 0x8020}, // SP 0x1402AD4C0 MP 0x000000000 - {"_meth_8021", 0x8021}, // SP 0x1402AD640 MP 0x000000000 - {"_meth_8022", 0x8022}, // SP 0x1402AD660 MP 0x000000000 - {"_meth_8023", 0x8023}, // SP 0x1402AD920 MP 0x14037BA50 - {"_meth_8024", 0x8024}, // SP 0x1402ADA90 MP 0x000000000 - {"_meth_8025", 0x8025}, // SP 0x1405D92F0 MP 0x14035CB60 - {"_meth_8026", 0x8026}, // SP 0x1405D92F0 MP 0x140377C40 - {"_meth_8028", 0x8028}, // SP 0x1402ADE80 MP 0x000000000 - {"_meth_8029", 0x8029}, // SP 0x14029AEC0 MP 0x140362D10 - {"_meth_802A", 0x802A}, // SP 0x14029E0E0 MP 0x14036A480 - {"detachall", 0x802B}, // SP 0x14029E180 MP 0x14036A4C0 - {"getattachsize", 0x802C}, // SP 0x1402A0610 MP 0x14036C860 - {"getattachmodelname", 0x802D}, // SP 0x1402A0890 MP 0x14036CE90 - {"_meth_802E", 0x802E}, // SP 0x1402A0A90 MP 0x14036D040 - {"_meth_802F", 0x802F}, // SP 0x1402AE150 MP 0x000000000 - {"_meth_8030", 0x8030}, // SP 0x1402AE270 MP 0x000000000 - {"_meth_8031", 0x8031}, // SP 0x1402AE410 MP 0x000000000 - {"_meth_8032", 0x8032}, // SP 0x1402AE620 MP 0x000000000 - {"_meth_8033", 0x8033}, // SP 0x1402AE6E0 MP 0x000000000 - {"_meth_8034", 0x8034}, // SP 0x1402CBC10 MP 0x000000000 - {"gethighestnodestance", 0x8035}, // SP 0x1402CBBA0 MP 0x14031F650 - {"doesnodeallowstance", 0x8036}, // SP 0x1402CBA70 MP 0x14031F520 - {"setforcespectatorclient", 0x8037}, // SP 0x1402CBB20 MP 0x14031F5D0 - {"_meth_8038", 0x8038}, // SP 0x1402AB240 MP 0x000000000 - {"_meth_8039", 0x8039}, // SP 0x1402AB320 MP 0x000000000 - {"_meth_803A", 0x803A}, // SP 0x1402AB6D0 MP 0x000000000 - {"_meth_803B", 0x803B}, // SP 0x1402ACA20 MP 0x000000000 - {"_meth_803C", 0x803C}, // SP 0x1402ACA40 MP 0x000000000 - {"_meth_803D", 0x803D}, // SP 0x1402ACBA0 MP 0x000000000 - {"_meth_803E", 0x803E}, // SP 0x1402AFA80 MP 0x000000000 - {"_meth_803F", 0x803F}, // SP 0x1402AFAC0 MP 0x000000000 - {"_meth_8040", 0x8040}, // SP 0x1402AFB90 MP 0x000000000 - {"_meth_8041", 0x8041}, // SP 0x1402AFC50 MP 0x000000000 - {"_meth_8042", 0x8042}, // SP 0x1402AFCA0 MP 0x000000000 - {"_meth_8043", 0x8043}, // SP 0x1402A8990 MP 0x000000000 - {"_meth_8044", 0x8044}, // SP 0x1402A89F0 MP 0x000000000 - {"_meth_8045", 0x8045}, // SP 0x14028F020 MP 0x14036EDF0 - {"_meth_8046", 0x8046}, // SP 0x14028F1F0 MP 0x14036EEE0 - {"_meth_8047", 0x8047}, // SP 0x1402ACE10 MP 0x000000000 - {"_meth_8048", 0x8048}, // SP 0x1402ACE50 MP 0x000000000 - {"getattachignorecollision", 0x8049}, // SP 0x1402A1060 MP 0x14036D280 - {"hidepart", 0x804A}, // SP 0x1402A1500 MP 0x14036D940 - {"hidepartallinstances", 0x804B}, // SP 0x1402A1930 MP 0x14036DC50 - {"_meth_804C", 0x804C}, // SP 0x1402A1C90 MP 0x14036E320 - {"showpart", 0x804D}, // SP 0x1402A2000 MP 0x14036E480 - {"_meth_804E", 0x804E}, // SP 0x1402A2370 MP 0x14036ECC0 - {"_meth_804F", 0x804F}, // SP 0x1402A3670 MP 0x140358AF0 - {"_meth_8050", 0x8050}, // SP 0x1402A3AB0 MP 0x140359830 - {"_meth_8051", 0x8051}, // SP 0x1402A3AD0 MP 0x140359850 - {"_meth_8052", 0x8052}, // SP 0x1402AD0F0 MP 0x140379AD0 - {"_meth_8053", 0x8053}, // SP 0x1402A2B80 MP 0x14036B270 - {"_meth_8054", 0x8054}, // SP 0x1402AD260 MP 0x000000000 - {"show", 0x8055}, // SP 0x1402AD6A0 MP 0x14037A9E0 - {"hide", 0x8056}, // SP 0x1402AD6C0 MP 0x14037AAA0 - {"_meth_8057", 0x8057}, // SP 0x1402AD7A0 MP 0x000000000 - {"_meth_8058", 0x8058}, // SP 0x1402AD7D0 MP 0x000000000 - {"disconnectpaths", 0x8059}, // SP 0x14028E1E0 MP 0x14036F090 - {"connectpaths", 0x805A}, // SP 0x14028E390 MP 0x14036F4C0 - {"_meth_805B", 0x805B}, // SP 0x14028E490 MP 0x14036F5F0 - {"_meth_805C", 0x805C}, // SP 0x14028E750 MP 0x14036F770 - {"_meth_805D", 0x805D}, // SP 0x1402A8420 MP 0x000000000 - {"_meth_805E", 0x805E}, // SP 0x1402A8440 MP 0x000000000 - {"_meth_805F", 0x805F}, // SP 0x1402A8460 MP 0x000000000 - {"_meth_8060", 0x8060}, // SP 0x1402A8480 MP 0x000000000 - {"_meth_8061", 0x8061}, // SP 0x1402A9250 MP 0x000000000 - {"_meth_8062", 0x8062}, // SP 0x1402A92D0 MP 0x000000000 - {"_meth_8063", 0x8063}, // SP 0x1402A9BC0 MP 0x000000000 - {"_meth_8064", 0x8064}, // SP 0x1402AABA0 MP 0x000000000 - {"_meth_8065", 0x8065}, // SP 0x1402AAC10 MP 0x000000000 - {"setmode", 0x8067}, // SP 0x1402AD9A0 MP 0x140375030 - {"_meth_8068", 0x8068}, // SP 0x1402ADCD0 MP 0x140375210 - {"_meth_8069", 0x8069}, // SP 0x1402ADF10 MP 0x000000000 - {"islinked", 0x806A}, // SP 0x14028D6B0 MP 0x1403598E0 - {"enablelinkto", 0x806B}, // SP 0x14028EA50 MP 0x14035A950 - {"_meth_806C", 0x806C}, // SP 0x1402ACB60 MP 0x000000000 - {"_meth_806E", 0x806E}, // SP 0x1402A27D0 MP 0x14035AB10 - {"_meth_806F", 0x806F}, // SP 0x1402A23E0 MP 0x14035A9C0 - {"_meth_8070", 0x8070}, // SP 0x1402A2980 MP 0x14035B0D0 - {"_meth_8071", 0x8071}, // SP 0x1402A28C0 MP 0x14035AB50 - {"_meth_8072", 0x8072}, // SP 0x140291F10 MP 0x000000000 - {"_meth_8073", 0x8073}, // SP 0x1405D92F0 MP 0x000000000 - {"_meth_8074", 0x8074}, // SP 0x1405D92F0 MP 0x000000000 - {"_meth_8075", 0x8075}, // SP 0x1405D92F0 MP 0x000000000 - {"_meth_8076", 0x8076}, // SP 0x1402ACC40 MP 0x1403798B0 - {"playloopsound", 0x8077}, // SP 0x1402ACC60 MP 0x1403798F0 - {"_meth_8078", 0x8078}, // SP 0x1402ACCD0 MP 0x000000000 - {"_meth_8079", 0x8079}, // SP 0x1402ACD40 MP 0x000000000 - {"_meth_807A", 0x807A}, // SP 0x1402ACDD0 MP 0x000000000 - {"_meth_807B", 0x807B}, // SP 0x1402ACE30 MP 0x000000000 - {"_meth_807C", 0x807C}, // SP 0x1402ACEE0 MP 0x000000000 - {"getnormalhealth", 0x807D}, // SP 0x1402ACFF0 MP 0x1403799E0 - {"_meth_807E", 0x807E}, // SP 0x14028FA50 MP 0x14035B880 - {"_meth_807F", 0x807F}, // SP 0x14028FB40 MP 0x14035B8D0 - {"_meth_8080", 0x8080}, // SP 0x14028FB60 MP 0x14035BD70 - {"playerlinktoabsolute", 0x8081}, // SP 0x14028FBE0 MP 0x14035C100 - {"playerlinktoblend", 0x8082}, // SP 0x140292720 MP 0x14035DCB0 - {"playerlinkedoffsetenable", 0x8083}, // SP 0x140290050 MP 0x14035C5A0 - {"_meth_8084", 0x8084}, // SP 0x14026DC10 MP 0x14033BBF0 - {"_meth_8085", 0x8085}, // SP 0x14026DC60 MP 0x14033BC00 - {"changefontscaleovertime", 0x8086}, // SP 0x14026E020 MP 0x14033BF50 - {"scaleovertime", 0x8087}, // SP 0x14026E160 MP 0x14033C090 - {"_meth_8088", 0x8088}, // SP 0x14026E240 MP 0x14033C170 - {"_meth_8089", 0x8089}, // SP 0x14026E380 MP 0x14033C230 - {"destroy", 0x808A}, // SP 0x14026E3C0 MP 0x14033C310 - {"_meth_808B", 0x808B}, // SP 0x14026E500 MP 0x14033C3F0 - {"_meth_808C", 0x808C}, // SP 0x14026E440 MP 0x14033C360 - {"fadeovertime", 0x808D}, // SP 0x14026E0C0 MP 0x14033BFF0 - {"_meth_808E", 0x808E}, // SP 0x1402A83E0 MP 0x000000000 - {"_meth_808F", 0x808F}, // SP 0x1402A8400 MP 0x000000000 - {"_meth_8090", 0x8090}, // SP 0x1402A8970 MP 0x000000000 - {"_meth_8091", 0x8091}, // SP 0x1402A89D0 MP 0x000000000 - {"_meth_8092", 0x8092}, // SP 0x1402AD800 MP 0x000000000 - {"playersetgroundreferenceent", 0x8093}, // SP 0x1402A9070 MP 0x1403752A0 - {"dontinterpolate", 0x8094}, // SP 0x1402A0070 MP 0x140358360 - {"_meth_8095", 0x8095}, // SP 0x1402AAC80 MP 0x000000000 - {"_meth_8096", 0x8096}, // SP 0x1402AAD20 MP 0x000000000 - {"_meth_8097", 0x8097}, // SP 0x1402AADC0 MP 0x140377CA0 - {"_meth_8098", 0x8098}, // SP 0x1402AAE70 MP 0x000000000 - {"_meth_8099", 0x8099}, // SP 0x1402AAF90 MP 0x000000000 - {"_meth_809A", 0x809A}, // SP 0x1402AC1D0 MP 0x000000000 - {"useby", 0x809B}, // SP 0x1402AC470 MP 0x140377D00 - {"playsound", 0x809C}, // SP 0x1402AC9B0 MP 0x140377F40 - {"playerlinkedoffsetdisable", 0x80A1}, // SP 0x140290320 MP 0x14035CAF0 - {"playerlinkedsetviewznear", 0x80A2}, // SP 0x140290680 MP 0x14035CE40 - {"playerlinkedsetusebaseangleforviewclamp", 0x80A3}, // SP 0x140290960 MP 0x14035D290 - {"_meth_80A4", 0x80A4}, // SP 0x140294B30 MP 0x14035F4A0 - {"_meth_80A5", 0x80A5}, // SP 0x140295300 MP 0x14035FD70 - {"_meth_80A6", 0x80A6}, // SP 0x1402958C0 MP 0x000000000 - {"_meth_80A7", 0x80A7}, // SP 0x1402960D0 MP 0x000000000 - {"_meth_80A8", 0x80A8}, // SP 0x140297190 MP 0x000000000 - {"_meth_80A9", 0x80A9}, // SP 0x140297C20 MP 0x000000000 - {"_meth_80AA", 0x80AA}, // SP 0x14029DDD0 MP 0x1403663C0 - {"istouching", 0x80AB}, // SP 0x140290390 MP 0x14035B440 - {"getistouchingentities", 0x80AC}, // SP 0x1402904A0 MP 0x14035B650 - {"_meth_80AD", 0x80AD}, // SP 0x1402987B0 MP 0x14035FAA0 - {"stopsounds", 0x80AE}, // SP 0x140290F40 MP 0x14035C610 - {"playrumbleonentity", 0x80AF}, // SP 0x140299090 MP 0x140360200 - {"playrumblelooponentity", 0x80B0}, // SP 0x140299200 MP 0x1403602A0 - {"stoprumble", 0x80B1}, // SP 0x1402997D0 MP 0x1403608E0 - {"delete", 0x80B2}, // SP 0x14029DAA0 MP 0x140366320 - {"setmodel", 0x80B3}, // SP 0x14029C8F0 MP 0x1403677D0 - {"_meth_80B4", 0x80B4}, // SP 0x14029A0F0 MP 0x140361C30 - {"_meth_80B5", 0x80B5}, // SP 0x14029A250 MP 0x140361F90 - {"thermalvisionon", 0x80B8}, // SP 0x14029A450 MP 0x1403623A0 - {"thermalvisionoff", 0x80B9}, // SP 0x14029AAF0 MP 0x140362B70 - {"_meth_80BA", 0x80BA}, // SP 0x14029BF20 MP 0x140364290 - {"_meth_80BB", 0x80BB}, // SP 0x14029C080 MP 0x140364630 - {"_meth_80BC", 0x80BC}, // SP 0x000000000 MP 0x140364910 - {"autospotoverlayon", 0x80BD}, // SP 0x000000000 MP 0x140364A50 - {"_meth_80BE", 0x80BE}, // SP 0x000000000 MP 0x140364D40 - {"setcontents", 0x80C0}, // SP 0x140297CC0 MP 0x14035FDD0 - {"makeusable", 0x80C1}, // SP 0x140297E90 MP 0x1403600D0 - {"makeunusable", 0x80C2}, // SP 0x140297FF0 MP 0x140360320 - {"_meth_80C3", 0x80C3}, // SP 0x1402A1730 MP 0x140359740 - {"_meth_80C4", 0x80C4}, // SP 0x1402A1A80 MP 0x140359DC0 - {"_meth_80C5", 0x80C5}, // SP 0x140266A20 MP 0x000000000 - {"_meth_80C6", 0x80C6}, // SP 0x1402634D0 MP 0x000000000 - {"_meth_80C7", 0x80C7}, // SP 0x1404657D0 MP 0x000000000 - {"_meth_80C8", 0x80C8}, // SP 0x140463A30 MP 0x000000000 - {"_meth_80C9", 0x80C9}, // SP 0x140465630 MP 0x000000000 - {"_meth_80CA", 0x80CA}, // SP 0x1404656C0 MP 0x000000000 - {"_meth_80CB", 0x80CB}, // SP 0x140464F50 MP 0x000000000 - {"settext", 0x80CC}, // SP 0x14026CE20 MP 0x14033AF40 - {"_meth_80CD", 0x80CD}, // SP 0x1405D92F0 MP 0x14033B030 - {"setshader", 0x80CE}, // SP 0x14026CEE0 MP 0x14033B040 - {"_meth_80CF", 0x80CF}, // SP 0x14026D230 MP 0x14033B3A0 - {"_meth_80D0", 0x80D0}, // SP 0x14026D3B0 MP 0x14033B530 - {"_meth_80D1", 0x80D1}, // SP 0x14026D490 MP 0x14033B600 - {"_meth_80D2", 0x80D2}, // SP 0x14026D560 MP 0x14033B6C0 - {"_meth_80D3", 0x80D3}, // SP 0x14026D630 MP 0x14033B760 - {"_meth_80D4", 0x80D4}, // SP 0x14026D700 MP 0x14033B810 - {"_meth_80D5", 0x80D5}, // SP 0x14026D7D0 MP 0x14033B8D0 - {"_meth_80D6", 0x80D6}, // SP 0x14026D8A0 MP 0x14033B970 - {"setclock", 0x80D7}, // SP 0x14026D970 MP 0x14033BA20 - {"setclockup", 0x80D8}, // SP 0x14026D990 MP 0x14033BA40 - {"setvalue", 0x80D9}, // SP 0x14026D9B0 MP 0x14033BA60 - {"setwaypoint", 0x80DA}, // SP 0x14026DA50 MP 0x14033BAE0 - {"_meth_80DB", 0x80DB}, // SP 0x14026DBC0 MP 0x14033BBE0 - {"setcursorhint", 0x80DC}, // SP 0x1402983E0 MP 0x1403607E0 - {"sethintstring", 0x80DD}, // SP 0x140299300 MP 0x140361060 - {"_meth_80DE", 0x80DE}, // SP 0x000000000 MP 0x140375C60 - {"forceusehinton", 0x80DF}, // SP 0x140299730 MP 0x140361260 - {"_meth_80E0", 0x80E0}, // SP 0x140299930 MP 0x140361530 - {"_meth_80E1", 0x80E1}, // SP 0x140298080 MP 0x140360440 - {"_meth_80E2", 0x80E2}, // SP 0x140298160 MP 0x140360570 - {"entitywillneverchange", 0x80E3}, // SP 0x1405D92F0 MP 0x140360620 - {"_meth_80E4", 0x80E4}, // SP 0x140291140 MP 0x14035D1B0 - {"_meth_80E5", 0x80E5}, // SP 0x1402912D0 MP 0x14035D310 - {"isfiringturret", 0x80E6}, // SP 0x140291490 MP 0x14035D460 - {"startbarrelspin", 0x80E7}, // SP 0x1402915B0 MP 0x14035D650 - {"stopbarrelspin", 0x80E8}, // SP 0x1402916E0 MP 0x14035D8D0 - {"getbarrelspinrate", 0x80E9}, // SP 0x140291A10 MP 0x14035DA40 - {"_meth_80EA", 0x80EA}, // SP 0x000000000 MP 0x14035C870 - {"remotecontrolturretoff", 0x80EB}, // SP 0x000000000 MP 0x14035CDD0 - {"_meth_80EC", 0x80EC}, // SP 0x140293380 MP 0x14035E870 - {"getturretowner", 0x80ED}, // SP 0x140293430 MP 0x14035EE50 - {"_meth_80EE", 0x80EE}, // SP 0x140268590 MP 0x000000000 - {"_meth_80EF", 0x80EF}, // SP 0x1402685F0 MP 0x000000000 - {"_meth_80F0", 0x80F0}, // SP 0x140268640 MP 0x000000000 - {"_meth_80F1", 0x80F1}, // SP 0x140268690 MP 0x000000000 - {"_meth_80F2", 0x80F2}, // SP 0x1402686F0 MP 0x000000000 - {"_meth_80F3", 0x80F3}, // SP 0x140268750 MP 0x000000000 - {"_meth_80F4", 0x80F4}, // SP 0x1402687A0 MP 0x000000000 - {"_meth_80F5", 0x80F5}, // SP 0x140268AF0 MP 0x000000000 - {"_meth_80F6", 0x80F6}, // SP 0x140268CC0 MP 0x000000000 - {"_meth_80F7", 0x80F7}, // SP 0x140268D20 MP 0x000000000 - {"_meth_80F8", 0x80F8}, // SP 0x140268D80 MP 0x000000000 - {"_meth_80F9", 0x80F9}, // SP 0x140268E10 MP 0x000000000 - {"_meth_80FA", 0x80FA}, // SP 0x140268EC0 MP 0x000000000 - {"_meth_80FB", 0x80FB}, // SP 0x140262E80 MP 0x14032F050 - {"_meth_80FC", 0x80FC}, // SP 0x140268890 MP 0x000000000 - {"_meth_80FD", 0x80FD}, // SP 0x1402688E0 MP 0x000000000 - {"_meth_80FE", 0x80FE}, // SP 0x1402689B0 MP 0x000000000 - {"_meth_80FF", 0x80FF}, // SP 0x140268A40 MP 0x000000000 - {"_meth_8100", 0x8100}, // SP 0x1402611F0 MP 0x14032CF70 - {"_meth_8101", 0x8101}, // SP 0x140261420 MP 0x14032D270 - {"_meth_8102", 0x8102}, // SP 0x140268930 MP 0x000000000 - {"_meth_8103", 0x8103}, // SP 0x1402616E0 MP 0x000000000 - {"_meth_8104", 0x8104}, // SP 0x1402667A0 MP 0x000000000 - {"setsentryowner", 0x8105}, // SP 0x1402935E0 MP 0x14035EF40 - {"setsentrycarrier", 0x8106}, // SP 0x140293F00 MP 0x14035F1B0 - {"setturretminimapvisible", 0x8107}, // SP 0x1402942F0 MP 0x14035F6D0 - {"settargetentity", 0x8108}, // SP 0x140294600 MP 0x14035F860 - {"snaptotargetentity", 0x8109}, // SP 0x140294A20 MP 0x14035FB70 - {"cleartargetentity", 0x810A}, // SP 0x140294E90 MP 0x14035FE30 - {"getturrettarget", 0x810B}, // SP 0x140295270 MP 0x140360040 - {"setplayerspread", 0x810C}, // SP 0x1402957F0 MP 0x1403606C0 - {"_meth_810D", 0x810D}, // SP 0x140295A70 MP 0x140360990 - {"_meth_810E", 0x810E}, // SP 0x140295D50 MP 0x1403609A0 - {"_meth_810F", 0x810F}, // SP 0x14028A710 MP 0x000000000 - {"_meth_8110", 0x8110}, // SP 0x14028A730 MP 0x000000000 - {"_meth_8111", 0x8111}, // SP 0x14028A750 MP 0x000000000 - {"_meth_8112", 0x8112}, // SP 0x14028A770 MP 0x000000000 - {"_meth_8113", 0x8113}, // SP 0x14028A790 MP 0x000000000 - {"_meth_8114", 0x8114}, // SP 0x14028A7B0 MP 0x000000000 - {"_meth_8115", 0x8115}, // SP 0x14028A7C0 MP 0x000000000 - {"_meth_8116", 0x8116}, // SP 0x14028A7E0 MP 0x000000000 - {"_meth_8117", 0x8117}, // SP 0x14028A800 MP 0x000000000 - {"_meth_8118", 0x8118}, // SP 0x14028A8E0 MP 0x000000000 - {"_meth_8119", 0x8119}, // SP 0x14028A960 MP 0x000000000 - {"_meth_811A", 0x811A}, // SP 0x140261760 MP 0x14032D140 - {"_meth_811B", 0x811B}, // SP 0x140261870 MP 0x14032D2D0 - {"_meth_811C", 0x811C}, // SP 0x140261950 MP 0x14032D630 - {"_meth_811D", 0x811D}, // SP 0x140261A30 MP 0x14032D780 - {"_meth_811E", 0x811E}, // SP 0x140269090 MP 0x000000000 - {"_meth_811F", 0x811F}, // SP 0x140269510 MP 0x000000000 - {"_meth_8121", 0x8121}, // SP 0x1402692D0 MP 0x000000000 - {"_meth_8122", 0x8122}, // SP 0x140269350 MP 0x000000000 - {"_meth_8123", 0x8123}, // SP 0x140269650 MP 0x000000000 - {"_meth_8128", 0x8128}, // SP 0x140269650 MP 0x000000000 - {"_meth_8129", 0x8129}, // SP 0x140269370 MP 0x000000000 - {"_meth_812A", 0x812A}, // SP 0x1402680B0 MP 0x000000000 - {"_meth_812B", 0x812B}, // SP 0x1402681E0 MP 0x000000000 - {"_meth_812C", 0x812C}, // SP 0x1402691F0 MP 0x000000000 - {"_meth_812D", 0x812D}, // SP 0x140268290 MP 0x000000000 - {"_meth_812E", 0x812E}, // SP 0x140267290 MP 0x14032B170 - {"_meth_812F", 0x812F}, // SP 0x140267650 MP 0x14032B720 - {"_meth_8130", 0x8130}, // SP 0x140262E20 MP 0x14032F570 - {"_meth_8131", 0x8131}, // SP 0x1402684C0 MP 0x000000000 - {"_meth_8132", 0x8132}, // SP 0x140261580 MP 0x14032CD50 - {"_meth_8133", 0x8133}, // SP 0x140261670 MP 0x14032CF00 - {"_meth_8134", 0x8134}, // SP 0x140268530 MP 0x000000000 - {"setconvergencetime", 0x8135}, // SP 0x140295E90 MP 0x140360A40 - {"setconvergenceheightpercent", 0x8136}, // SP 0x140296650 MP 0x140360E90 - {"setturretteam", 0x8137}, // SP 0x1402967E0 MP 0x140361150 - {"_meth_8138", 0x8138}, // SP 0x140296C90 MP 0x140361320 - {"startfiring", 0x8139}, // SP 0x140296D70 MP 0x140361370 - {"stopfiring", 0x813A}, // SP 0x140296E90 MP 0x1403615A0 - {"_meth_813B", 0x813B}, // SP 0x1402D7DD0 MP 0x140077920 - {"freeentitysentient", 0x813C}, // SP 0x1402D7EE0 MP 0x140077A40 - {"_meth_813D", 0x813D}, // SP 0x1402D7FE0 MP 0x000000000 - {"_meth_813E", 0x813E}, // SP 0x1402D8040 MP 0x000000000 - {"_meth_813F", 0x813F}, // SP 0x1402D80E0 MP 0x000000000 - {"_meth_8140", 0x8140}, // SP 0x14028A390 MP 0x000000000 - {"_meth_8142", 0x8142}, // SP 0x14028A3D0 MP 0x000000000 - {"_meth_8143", 0x8143}, // SP 0x14028A370 MP 0x000000000 - {"_meth_8144", 0x8144}, // SP 0x14028A410 MP 0x000000000 - {"_meth_8145", 0x8145}, // SP 0x14028A490 MP 0x000000000 - {"_meth_8146", 0x8146}, // SP 0x14028A4B0 MP 0x000000000 - {"_meth_8147", 0x8147}, // SP 0x14028A4C0 MP 0x000000000 - {"_meth_8148", 0x8148}, // SP 0x14028A4E0 MP 0x000000000 - {"_meth_8149", 0x8149}, // SP 0x14028A500 MP 0x000000000 - {"_meth_814A", 0x814A}, // SP 0x14028A520 MP 0x000000000 - {"_meth_814B", 0x814B}, // SP 0x14028A530 MP 0x000000000 - {"_meth_814C", 0x814C}, // SP 0x14028A550 MP 0x000000000 - {"_meth_814D", 0x814D}, // SP 0x14028A570 MP 0x000000000 - {"_meth_814E", 0x814E}, // SP 0x14028A590 MP 0x000000000 - {"_meth_814F", 0x814F}, // SP 0x14028A5A0 MP 0x000000000 - {"_meth_8150", 0x8150}, // SP 0x14028A5C0 MP 0x000000000 - {"_meth_8151", 0x8151}, // SP 0x14028A5E0 MP 0x000000000 - {"_meth_8152", 0x8152}, // SP 0x14028A650 MP 0x000000000 - {"_meth_8153", 0x8153}, // SP 0x14028A690 MP 0x000000000 - {"_meth_8154", 0x8154}, // SP 0x14028A6E0 MP 0x000000000 - {"_meth_8155", 0x8155}, // SP 0x14028A700 MP 0x000000000 - {"_meth_8156", 0x8156}, // SP 0x1405D92F0 MP 0x140361680 - {"_meth_8157", 0x8157}, // SP 0x140297730 MP 0x140362260 - {"_meth_8158", 0x8158}, // SP 0x140297890 MP 0x140362410 - {"_meth_8159", 0x8159}, // SP 0x140297D20 MP 0x1403629F0 - {"_meth_815A", 0x815A}, // SP 0x140297F90 MP 0x140362CB0 - {"setautorotationdelay", 0x815B}, // SP 0x1402980D0 MP 0x140363040 - {"_meth_815C", 0x815C}, // SP 0x140298800 MP 0x1403638A0 - {"restoredefaultdroppitch", 0x815D}, // SP 0x140298880 MP 0x140363B30 - {"turretfiredisable", 0x815E}, // SP 0x140299040 MP 0x140363CF0 - {"_meth_815F", 0x815F}, // SP 0x1402495F0 MP 0x000000000 - {"_meth_8160", 0x8160}, // SP 0x1402496C0 MP 0x000000000 - {"_meth_8161", 0x8161}, // SP 0x140249790 MP 0x000000000 - {"_meth_8162", 0x8162}, // SP 0x140249810 MP 0x000000000 - {"_meth_8163", 0x8163}, // SP 0x140249950 MP 0x000000000 - {"_meth_8164", 0x8164}, // SP 0x140249A30 MP 0x000000000 - {"_meth_8165", 0x8165}, // SP 0x140249AC0 MP 0x000000000 - {"_meth_8166", 0x8166}, // SP 0x140249B00 MP 0x000000000 - {"_meth_8167", 0x8167}, // SP 0x140249BE0 MP 0x000000000 - {"_meth_8168", 0x8168}, // SP 0x140249C70 MP 0x000000000 - {"_meth_8169", 0x8169}, // SP 0x140262B90 MP 0x14032E0A0 - {"_meth_816A", 0x816A}, // SP 0x140249D10 MP 0x000000000 - {"_meth_816B", 0x816B}, // SP 0x140249EE0 MP 0x000000000 - {"_meth_816C", 0x816C}, // SP 0x14024A0E0 MP 0x000000000 - {"_meth_816D", 0x816D}, // SP 0x14024A200 MP 0x000000000 - {"_meth_816E", 0x816E}, // SP 0x14024A2D0 MP 0x000000000 - {"_meth_816F", 0x816F}, // SP 0x14024A3F0 MP 0x000000000 - {"_meth_8170", 0x8170}, // SP 0x14024A480 MP 0x000000000 - {"_meth_8171", 0x8171}, // SP 0x14024A5C0 MP 0x000000000 - {"_meth_8172", 0x8172}, // SP 0x14024A630 MP 0x000000000 - {"_meth_8173", 0x8173}, // SP 0x14024A710 MP 0x000000000 - {"_meth_8174", 0x8174}, // SP 0x14024A880 MP 0x000000000 - {"_meth_8175", 0x8175}, // SP 0x14024AAD0 MP 0x000000000 - {"_meth_8176", 0x8176}, // SP 0x14024AB30 MP 0x000000000 - {"_meth_8177", 0x8177}, // SP 0x14024AB90 MP 0x000000000 - {"_meth_8178", 0x8178}, // SP 0x14024AC50 MP 0x000000000 - {"getenemysqdist", 0x8179}, // SP 0x1402D77E0 MP 0x1400772C0 - {"_meth_817A", 0x817A}, // SP 0x1402D7820 MP 0x140077300 - {"setthreatbiasgroup", 0x817B}, // SP 0x1402D7BE0 MP 0x1400776E0 - {"getthreatbiasgroup", 0x817C}, // SP 0x1402D7C50 MP 0x140077750 - {"turretfireenable", 0x817D}, // SP 0x140299220 MP 0x140363EE0 - {"setturretmodechangewait", 0x817E}, // SP 0x1402994D0 MP 0x140364690 - {"usetriggerrequirelookat", 0x817F}, // SP 0x140297DE0 MP 0x14035EEE0 - {"getstance", 0x8180}, // SP 0x14029D1C0 MP 0x140364F90 - {"_meth_8181", 0x8181}, // SP 0x14029D430 MP 0x140365230 - {"itemweaponsetammo", 0x8182}, // SP 0x140299FA0 MP 0x140360F20 - {"_meth_8183", 0x8183}, // SP 0x14029A5A0 MP 0x140361420 - {"gettagorigin", 0x8184}, // SP 0x14029E360 MP 0x140368090 - {"gettagangles", 0x8185}, // SP 0x14029E810 MP 0x140368320 - {"_meth_8186", 0x8186}, // SP 0x14028E580 MP 0x14036D490 - {"stunplayer", 0x8187}, // SP 0x14028F160 MP 0x14036DEC0 - {"_meth_8188", 0x8188}, // SP 0x14029B970 MP 0x140366E70 - {"_meth_8189", 0x8189}, // SP 0x14029BB30 MP 0x140367230 - {"setdepthoffield", 0x818A}, // SP 0x14029EF20 MP 0x140368890 - {"setviewmodeldepthoffield", 0x818B}, // SP 0x14029F990 MP 0x140369900 - {"_meth_818C", 0x818C}, // SP 0x1402A15D0 MP 0x14036AD20 - {"_meth_818D", 0x818D}, // SP 0x140247D90 MP 0x000000000 - {"_meth_818E", 0x818E}, // SP 0x140247DE0 MP 0x000000000 - {"_meth_818F", 0x818F}, // SP 0x140247E50 MP 0x000000000 - {"_meth_8190", 0x8190}, // SP 0x140247E90 MP 0x000000000 - {"_meth_8191", 0x8191}, // SP 0x140247F00 MP 0x000000000 - {"_meth_8192", 0x8192}, // SP 0x140247F90 MP 0x000000000 - {"_meth_8193", 0x8193}, // SP 0x140248160 MP 0x000000000 - {"_meth_8194", 0x8194}, // SP 0x1402484A0 MP 0x000000000 - {"_meth_8195", 0x8195}, // SP 0x1402485A0 MP 0x000000000 - {"_meth_8196", 0x8196}, // SP 0x1402485F0 MP 0x000000000 - {"_meth_8197", 0x8197}, // SP 0x140248640 MP 0x000000000 - {"_meth_8198", 0x8198}, // SP 0x1402486A0 MP 0x000000000 - {"_meth_8199", 0x8199}, // SP 0x1402486F0 MP 0x000000000 - {"_meth_819E", 0x819E}, // SP 0x1402487C0 MP 0x000000000 - {"_meth_819F", 0x819F}, // SP 0x140248870 MP 0x000000000 - {"_meth_81A0", 0x81A0}, // SP 0x1402488C0 MP 0x000000000 - {"getnegotiationstartnode", 0x81A1}, // SP 0x140248970 MP 0x14044F980 - {"getnegotiationendnode", 0x81A2}, // SP 0x1402489E0 MP 0x14044F830 - {"getnegotiationnextnode", 0x81A3}, // SP 0x140248A50 MP 0x14044F8D0 - {"_meth_81A4", 0x81A4}, // SP 0x140248B30 MP 0x000000000 - {"_meth_81A5", 0x81A5}, // SP 0x140248BD0 MP 0x000000000 - {"_meth_81A6", 0x81A6}, // SP 0x140248CC0 MP 0x000000000 - {"_meth_81A7", 0x81A7}, // SP 0x140248DD0 MP 0x000000000 - {"_meth_81A8", 0x81A8}, // SP 0x140247750 MP 0x000000000 - {"_meth_81A9", 0x81A9}, // SP 0x140248E30 MP 0x000000000 - {"_meth_81AA", 0x81AA}, // SP 0x140248FB0 MP 0x000000000 - {"_meth_81AB", 0x81AB}, // SP 0x1402490D0 MP 0x000000000 - {"_meth_81AC", 0x81AC}, // SP 0x140249170 MP 0x000000000 - {"_meth_81AD", 0x81AD}, // SP 0x140249290 MP 0x000000000 - {"_meth_81AE", 0x81AE}, // SP 0x140249460 MP 0x000000000 - {"_meth_81AF", 0x81AF}, // SP 0x1402494B0 MP 0x000000000 - {"_meth_81B0", 0x81B0}, // SP 0x140249500 MP 0x000000000 - {"_meth_81B1", 0x81B1}, // SP 0x1402A15D0 MP 0x14036ADA0 - {"_meth_81B2", 0x81B2}, // SP 0x1402A15D0 MP 0x14036AE60 - {"viewkick", 0x81B3}, // SP 0x1402A1640 MP 0x14036AFA0 - {"_meth_81B4", 0x81B4}, // SP 0x14029B1E0 MP 0x1403668B0 - {"_meth_81B5", 0x81B5}, // SP 0x1402998B0 MP 0x140364980 - {"autoboltmissileeffects", 0x81B6}, // SP 0x140299AA0 MP 0x140364B50 - {"enablegrenadetouchdamage", 0x81B7}, // SP 0x140299CA0 MP 0x140364F40 - {"disablegrenadetouchdamage", 0x81B8}, // SP 0x140299F20 MP 0x1403650C0 - {"_meth_81B9", 0x81B9}, // SP 0x14029AF00 MP 0x1403665A0 - {"_meth_81BA", 0x81BA}, // SP 0x14024AF80 MP 0x000000000 - {"_meth_81BB", 0x81BB}, // SP 0x14024B160 MP 0x000000000 - {"_meth_81BC", 0x81BC}, // SP 0x14024B3B0 MP 0x000000000 - {"_meth_81BD", 0x81BD}, // SP 0x14024B4F0 MP 0x000000000 - {"_meth_81BE", 0x81BE}, // SP 0x14024B570 MP 0x000000000 - {"_meth_81BF", 0x81BF}, // SP 0x14024B910 MP 0x000000000 - {"_meth_81C0", 0x81C0}, // SP 0x14024BA40 MP 0x000000000 - {"_meth_81C1", 0x81C1}, // SP 0x14024BB20 MP 0x000000000 - {"_meth_81C2", 0x81C2}, // SP 0x14024BB90 MP 0x000000000 - {"_meth_81C3", 0x81C3}, // SP 0x14024BC40 MP 0x000000000 - {"_meth_81C4", 0x81C4}, // SP 0x1402D7F30 MP 0x140077AA0 - {"_meth_81C5", 0x81C5}, // SP 0x1402D7F90 MP 0x140077B00 - {"_meth_81C6", 0x81C6}, // SP 0x14024BD90 MP 0x000000000 - {"_meth_81C7", 0x81C7}, // SP 0x14024C010 MP 0x000000000 - {"_meth_81C8", 0x81C8}, // SP 0x14024C150 MP 0x000000000 - {"_meth_81C9", 0x81C9}, // SP 0x14024C240 MP 0x000000000 - {"_meth_81CA", 0x81CA}, // SP 0x14024C250 MP 0x000000000 - {"_meth_81CB", 0x81CB}, // SP 0x14024C270 MP 0x000000000 - {"_meth_81CC", 0x81CC}, // SP 0x14024C290 MP 0x000000000 - {"_meth_81CD", 0x81CD}, // SP 0x14024C2F0 MP 0x000000000 - {"_meth_81CE", 0x81CE}, // SP 0x14024C360 MP 0x000000000 - {"_meth_81CF", 0x81CF}, // SP 0x14024C430 MP 0x000000000 - {"_meth_81D0", 0x81D0}, // SP 0x14024C520 MP 0x000000000 - {"_meth_81D1", 0x81D1}, // SP 0x14024C560 MP 0x000000000 - {"_meth_81D2", 0x81D2}, // SP 0x14024C5A0 MP 0x000000000 - {"_meth_81D3", 0x81D3}, // SP 0x14024C5E0 MP 0x000000000 - {"_meth_81D4", 0x81D4}, // SP 0x140247BF0 MP 0x000000000 - {"_meth_81D5", 0x81D5}, // SP 0x140247CE0 MP 0x000000000 - {"_meth_81D6", 0x81D6}, // SP 0x140247930 MP 0x000000000 - {"_meth_81D7", 0x81D7}, // SP 0x14029B180 MP 0x140366790 - {"entityradiusdamage", 0x81D8}, // SP 0x1402A3840 MP 0x14036C130 - {"_meth_81D9", 0x81D9}, // SP 0x14028DCF0 MP 0x14036CAB0 - {"bddatachunk::deserialize", 0x81DA}, // SP 0x14028E350 MP 0x14036D0C0 - {"_meth_81DB", 0x81DB}, // SP 0x14028E430 MP 0x14036D150 - {"_meth_81DC", 0x81DC}, // SP 0x14029A340 MP 0x140365D80 - {"_meth_81DD", 0x81DD}, // SP 0x14029A4E0 MP 0x140365E90 - {"_meth_81DE", 0x81DE}, // SP 0x14029A700 MP 0x140366180 - {"missilesetflightmodedirect", 0x81DF}, // SP 0x14029AA10 MP 0x1403663A0 - {"missilesetflightmodetop", 0x81E0}, // SP 0x14029AB50 MP 0x140366480 - {"getlightintensity", 0x81E1}, // SP 0x14028EA00 MP 0x14036E8B0 - {"_meth_81E2", 0x81E2}, // SP 0x14028EB40 MP 0x14036EAB0 - {"isragdoll", 0x81E3}, // SP 0x14028F2F0 MP 0x14036F2E0 - {"setmovespeedscale", 0x81E4}, // SP 0x1402A2860 MP 0x14036EF80 - {"cameralinkto", 0x81E5}, // SP 0x14028FFC0 MP 0x1403584E0 - {"cameraunlink", 0x81E6}, // SP 0x1402900C0 MP 0x140358750 - {"_meth_81E7", 0x81E7}, // SP 0x140248F30 MP 0x000000000 - {"_meth_81E8", 0x81E8}, // SP 0x1402491F0 MP 0x000000000 - {"_meth_81E9", 0x81E9}, // SP 0x140249230 MP 0x000000000 - {"_meth_81EA", 0x81EA}, // SP 0x140249370 MP 0x000000000 - {"_meth_81EB", 0x81EB}, // SP 0x140249650 MP 0x000000000 - {"_meth_81EC", 0x81EC}, // SP 0x140249710 MP 0x000000000 - {"_meth_81ED", 0x81ED}, // SP 0x1402499B0 MP 0x000000000 - {"_meth_81EE", 0x81EE}, // SP 0x140249A70 MP 0x000000000 - {"_meth_81EF", 0x81EF}, // SP 0x140249B80 MP 0x000000000 - {"_meth_81F0", 0x81F0}, // SP 0x140249C30 MP 0x000000000 - {"_meth_81F1", 0x81F1}, // SP 0x140249CC0 MP 0x000000000 - {"_meth_81F2", 0x81F2}, // SP 0x140249E00 MP 0x000000000 - {"_meth_81F3", 0x81F3}, // SP 0x140249E50 MP 0x000000000 - {"_meth_81F4", 0x81F4}, // SP 0x14024A010 MP 0x000000000 - {"_meth_81F5", 0x81F5}, // SP 0x14024A080 MP 0x000000000 - {"_meth_81F6", 0x81F6}, // SP 0x14024A190 MP 0x000000000 - {"_meth_81F7", 0x81F7}, // SP 0x14024A330 MP 0x000000000 - {"_meth_81F8", 0x81F8}, // SP 0x14024A390 MP 0x000000000 - {"_meth_81F9", 0x81F9}, // SP 0x14024A260 MP 0x000000000 - {"_meth_81FA", 0x81FA}, // SP 0x14024A440 MP 0x000000000 - {"_meth_81FB", 0x81FB}, // SP 0x14024A4F0 MP 0x000000000 - {"_meth_81FC", 0x81FC}, // SP 0x14024A6B0 MP 0x000000000 - {"_meth_81FD", 0x81FD}, // SP 0x14024A780 MP 0x000000000 - {"_meth_81FE", 0x81FE}, // SP 0x14024A950 MP 0x000000000 - {"_meth_81FF", 0x81FF}, // SP 0x14024AC00 MP 0x000000000 - {"_meth_8200", 0x8200}, // SP 0x14024AD60 MP 0x000000000 - {"_meth_8201", 0x8201}, // SP 0x14024AE60 MP 0x000000000 - {"_meth_8202", 0x8202}, // SP 0x14024B1D0 MP 0x000000000 - {"_meth_8203", 0x8203}, // SP 0x14024B2C0 MP 0x000000000 - {"controlslinkto", 0x8204}, // SP 0x1402905D0 MP 0x140358F20 - {"controlsunlink", 0x8205}, // SP 0x1402908B0 MP 0x1403593C0 - {"_meth_8206", 0x8206}, // SP 0x000000000 MP 0x14035AB40 - {"_meth_8207", 0x8207}, // SP 0x1402AA5F0 MP 0x000000000 - {"_meth_8208", 0x8208}, // SP 0x000000000 MP 0x14035ABE0 - {"_meth_820A", 0x820A}, // SP 0x000000000 MP 0x14035B100 - {"_meth_820B", 0x820B}, // SP 0x000000000 MP 0x14035B170 - {"_meth_820C", 0x820C}, // SP 0x000000000 MP 0x14035B380 - {"_meth_820D", 0x820D}, // SP 0x000000000 MP 0x14035B210 - {"_meth_820E", 0x820E}, // SP 0x000000000 MP 0x14035B270 - {"drivevehicleandcontrolturret", 0x820F}, // SP 0x140291CD0 MP 0x14035C250 - {"drivevehicleandcontrolturretoff", 0x8210}, // SP 0x140292090 MP 0x14035C420 - {"_meth_8211", 0x8211}, // SP 0x1402923D0 MP 0x14035C930 - {"_meth_8212", 0x8212}, // SP 0x1402931B0 MP 0x14035CBB0 - {"_meth_8213", 0x8213}, // SP 0x1402940E0 MP 0x14035D6A0 - {"_meth_8214", 0x8214}, // SP 0x140296080 MP 0x14035F750 - {"_meth_8215", 0x8215}, // SP 0x1402961E0 MP 0x14035F810 - {"_meth_8216", 0x8216}, // SP 0x140296540 MP 0x14035FB00 - {"_meth_8217", 0x8217}, // SP 0x1402966E0 MP 0x14035FC80 - {"circle", 0x8218}, // SP 0x1402990B0 MP 0x1403620D0 - {"rect", 0x8219}, // SP 0x140299540 MP 0x140362730 - {"_meth_821A", 0x821A}, // SP 0x140299B00 MP 0x140362E50 - {"transfermarkstonewscriptmodel", 0x821B}, // SP 0x14029A1B0 MP 0x140363790 - {"setwatersheeting", 0x821C}, // SP 0x140290290 MP 0x140358930 - {"_meth_821D", 0x821D}, // SP 0x1402A29B0 MP 0x000000000 - {"_meth_821E", 0x821E}, // SP 0x1402A32F0 MP 0x000000000 - {"setweaponhudiconoverride", 0x821F}, // SP 0x140296A30 MP 0x14035FC90 - {"getweaponhudiconoverride", 0x8220}, // SP 0x140297010 MP 0x140360380 - {"_meth_8221", 0x8221}, // SP 0x1402976A0 MP 0x1403609B0 - {"_meth_8222", 0x8222}, // SP 0x140299CF0 MP 0x1403635A0 - {"_meth_8223", 0x8223}, // SP 0x140299B90 MP 0x1403630E0 - {"_meth_8224", 0x8224}, // SP 0x14029A2C0 MP 0x140363C10 - {"_meth_8225", 0x8225}, // SP 0x14029DF50 MP 0x140365F70 - {"_meth_8226", 0x8226}, // SP 0x1402A17F0 MP 0x14036B0B0 - {"vehicleturretcontroloff", 0x8227}, // SP 0x140464260 MP 0x140562970 - {"isturretready", 0x8228}, // SP 0x140464340 MP 0x1405629E0 - {"_meth_8229", 0x8229}, // SP 0x140464570 MP 0x140562C70 - {"dospawn", 0x822A}, // SP 0x1404646D0 MP 0x140562D90 - {"isphysveh", 0x822B}, // SP 0x1404647A0 MP 0x140562E80 - {"crash", 0x822C}, // SP 0x140464840 MP 0x140562F80 - {"launch", 0x822D}, // SP 0x140464980 MP 0x1405630A0 - {"disablecrashing", 0x822E}, // SP 0x140464B20 MP 0x140563240 - {"enablecrashing", 0x822F}, // SP 0x140464C10 MP 0x140563310 - {"setspeed", 0x8230}, // SP 0x140464C90 MP 0x1405633E0 - {"setconveyorbelt", 0x8231}, // SP 0x140464E50 MP 0x140563610 - {"freevehicle", 0x8232}, // SP 0x000000000 MP 0x1405609B0 - {"_meth_8233", 0x8233}, // SP 0x140290E70 MP 0x000000000 - {"_meth_8234", 0x8234}, // SP 0x1402910E0 MP 0x000000000 - {"_meth_8235", 0x8235}, // SP 0x140291670 MP 0x000000000 - {"_meth_8236", 0x8236}, // SP 0x140291A60 MP 0x000000000 - {"_meth_8237", 0x8237}, // SP 0x140292010 MP 0x000000000 - {"_meth_8238", 0x8238}, // SP 0x140292230 MP 0x000000000 - {"_meth_8239", 0x8239}, // SP 0x14029C2A0 MP 0x000000000 - {"_meth_823A", 0x823A}, // SP 0x14029CAD0 MP 0x000000000 - {"_meth_823B", 0x823B}, // SP 0x14029CD70 MP 0x000000000 - {"_meth_823C", 0x823C}, // SP 0x14029CF00 MP 0x000000000 - {"_meth_823D", 0x823D}, // SP 0x140292BA0 MP 0x000000000 - {"_meth_823E", 0x823E}, // SP 0x140292DF0 MP 0x000000000 - {"_meth_8240", 0x8240}, // SP 0x1402A3880 MP 0x000000000 - {"_meth_8241", 0x8241}, // SP 0x140248AD0 MP 0x000000000 - {"_meth_8242", 0x8242}, // SP 0x140248EA0 MP 0x000000000 - {"_meth_8243", 0x8243}, // SP 0x1402A1AF0 MP 0x14036B910 - {"_meth_8244", 0x8244}, // SP 0x1402A1E20 MP 0x14036BE30 - {"_meth_8245", 0x8245}, // SP 0x1402A24D0 MP 0x14036C5B0 - {"trackerupdate", 0x8246}, // SP 0x14028DC50 MP 0x14036E800 - {"pingplayer", 0x8247}, // SP 0x000000000 MP 0x140332B50 - {"_meth_8248", 0x8248}, // SP 0x140268FE0 MP 0x140332B40 - {"sayteam", 0x8249}, // SP 0x000000000 MP 0x1403345F0 - {"sayall", 0x824A}, // SP 0x000000000 MP 0x1403346A0 - {"_meth_824B", 0x824B}, // SP 0x000000000 MP 0x140332C90 - {"_meth_824C", 0x824C}, // SP 0x140265080 MP 0x140330FE0 - {"dropscavengerbag", 0x824D}, // SP 0x000000000 MP 0x140332FB0 - {"setjitterparams", 0x824E}, // SP 0x140461E80 MP 0x140560640 - {"sethoverparams", 0x824F}, // SP 0x140461F50 MP 0x140560710 - {"joltbody", 0x8250}, // SP 0x140462070 MP 0x1405607B0 - {"freevehicle", 0x8251}, // SP 0x140462250 MP 0x1405609B0 - {"_meth_8252", 0x8252}, // SP 0x140462300 MP 0x140560A20 - {"getvehicleowner", 0x8253}, // SP 0x140462550 MP 0x140560C70 - {"setvehiclelookattext", 0x8254}, // SP 0x1404625D0 MP 0x140560CF0 - {"setvehicleteam", 0x8255}, // SP 0x140462660 MP 0x140560D80 - {"neargoalnotifydist", 0x8256}, // SP 0x1404626E0 MP 0x140560F10 - {"setgoalpos", 0x8257}, // SP 0x140462750 MP 0x140560F80 - {"setgoalyaw", 0x8258}, // SP 0x140462840 MP 0x1405610A0 - {"cleargoalyaw", 0x8259}, // SP 0x1404628D0 MP 0x140561130 - {"settargetyaw", 0x825A}, // SP 0x140462950 MP 0x1405611B0 - {"cleartargetyaw", 0x825B}, // SP 0x1404629E0 MP 0x140561240 - {"helisetgoal", 0x825C}, // SP 0x140462A60 MP 0x1405612C0 - {"_meth_825D", 0x825D}, // SP 0x140463320 MP 0x140561B60 - {"setturrettargetent", 0x825E}, // SP 0x140463410 MP 0x140561C60 - {"clearturrettargetent", 0x825F}, // SP 0x140463510 MP 0x140561D60 - {"canturrettargetpoint", 0x8260}, // SP 0x1404635A0 MP 0x140561DF0 - {"setlookatent", 0x8261}, // SP 0x1404638A0 MP 0x1405620F0 - {"clearlookatent", 0x8262}, // SP 0x140463950 MP 0x1405621A0 - {"setweapon", 0x8263}, // SP 0x140463AB0 MP 0x140562280 - {"_meth_8264", 0x8264}, // SP 0x140463B20 MP 0x1405622F0 - {"vehicleturretcontrolon", 0x8265}, // SP 0x1404641D0 MP 0x1405628F0 - {"finishplayerdamage", 0x8266}, // SP 0x000000000 MP 0x1403337A0 - {"suicide", 0x8267}, // SP 0x000000000 MP 0x140333E20 - {"_meth_8268", 0x8268}, // SP 0x000000000 MP 0x140334010 - {"_meth_8269", 0x8269}, // SP 0x000000000 MP 0x1403340A0 - {"_meth_826A", 0x826A}, // SP 0x000000000 MP 0x140334120 - {"spawn", 0x826B}, // SP 0x000000000 MP 0x1403341A0 - {"_meth_826C", 0x826C}, // SP 0x000000000 MP 0x140334230 - {"_meth_826D", 0x826D}, // SP 0x000000000 MP 0x140334290 - {"istalking", 0x826E}, // SP 0x000000000 MP 0x140334570 - {"allowspectateteam", 0x826F}, // SP 0x000000000 MP 0x140334750 - {"_meth_8270", 0x8270}, // SP 0x000000000 MP 0x140334980 - {"getguid", 0x8271}, // SP 0x000000000 MP 0x140334B20 - {"_meth_8272", 0x8272}, // SP 0x1402B3CA0 MP 0x14037FA00 - {"_meth_8273", 0x8273}, // SP 0x1402B3EC0 MP 0x14037FC50 - {"clonebrushmodeltoscriptmodel", 0x8274}, // SP 0x1402B4500 MP 0x140380380 - {"_meth_8275", 0x8275}, // SP 0x000000000 MP 0x140380450 - {"scriptmodelclearanim", 0x8276}, // SP 0x000000000 MP 0x140380700 - {"_meth_8277", 0x8277}, // SP 0x000000000 MP 0x140380570 - {"_meth_8278", 0x8278}, // SP 0x140465060 MP 0x1405637F0 - {"attachpath", 0x8279}, // SP 0x1404651E0 MP 0x14055F040 - {"getattachpos", 0x827A}, // SP 0x1404652F0 MP 0x14055F170 - {"startpath", 0x827B}, // SP 0x1404654A0 MP 0x14055F340 - {"setswitchnode", 0x827C}, // SP 0x140465740 MP 0x14055F4D0 - {"setwaitspeed", 0x827D}, // SP 0x140465840 MP 0x14055F560 - {"finishdamage", 0x827E}, // SP 0x000000000 MP 0x14055F5E0 - {"setspeed", 0x827F}, // SP 0x1404658C0 MP 0x14055F840 - {"setspeedimmediate", 0x8280}, // SP 0x140465930 MP 0x14055F8B0 - {"_meth_8281", 0x8281}, // SP 0x140465AC0 MP 0x14055FA60 - {"getspeed", 0x8282}, // SP 0x140465BE0 MP 0x14055FB80 - {"getvelocity", 0x8283}, // SP 0x140465CD0 MP 0x14055FC70 - {"getbodyvelocity", 0x8284}, // SP 0x140465D40 MP 0x14055FCE0 - {"getsteering", 0x8285}, // SP 0x140465DB0 MP 0x14055FD50 - {"getthrottle", 0x8286}, // SP 0x140465E30 MP 0x14055FDE0 - {"turnengineoff", 0x8287}, // SP 0x140465EA0 MP 0x14055FE50 - {"turnengineon", 0x8288}, // SP 0x140465F00 MP 0x14055FEC0 - {"_meth_8289", 0x8289}, // SP 0x140465F60 MP 0x000000000 - {"getgoalspeedmph", 0x828A}, // SP 0x140466020 MP 0x14055FF30 - {"_meth_828B", 0x828B}, // SP 0x140466090 MP 0x14055FFA0 - {"setacceleration", 0x828C}, // SP 0x140466100 MP 0x140560010 - {"resumespeed", 0x828D}, // SP 0x140466170 MP 0x140560080 - {"setyawspeed", 0x828E}, // SP 0x140466200 MP 0x140560110 - {"setyawspeedbyname", 0x828F}, // SP 0x140466360 MP 0x140560270 - {"setmaxpitchroll", 0x8290}, // SP 0x140461CC0 MP 0x140560480 - {"setairresitance", 0x8291}, // SP 0x140461D80 MP 0x140560540 - {"setturningability", 0x8292}, // SP 0x140461E10 MP 0x1405605D0 - {"_meth_8293", 0x8293}, // SP 0x140260F20 MP 0x140334B90 - {"_meth_8294", 0x8294}, // SP 0x000000000 MP 0x140334D50 - {"ismlgspectator", 0x8295}, // SP 0x000000000 MP 0x140334DB0 - {"getclanidhigh", 0x8296}, // SP 0x000000000 MP 0x140334E10 - {"getclanidlow", 0x8297}, // SP 0x000000000 MP 0x140334E70 - {"_meth_8298", 0x8298}, // SP 0x000000000 MP 0x140334ED0 - {"getspectatingplayer", 0x8299}, // SP 0x000000000 MP 0x140334F60 - {"predictstreampos", 0x829A}, // SP 0x000000000 MP 0x140334FE0 - {"_meth_829B", 0x829B}, // SP 0x000000000 MP 0x1403350D0 - {"_meth_829C", 0x829C}, // SP 0x000000000 MP 0x1403350E0 - {"setrank", 0x829D}, // SP 0x000000000 MP 0x1403350F0 - {"_meth_829E", 0x829E}, // SP 0x000000000 MP 0x140335190 - {"setmlgspectator", 0x829F}, // SP 0x140260730 MP 0x14032CA40 - {"visionsyncwithplayer", 0x82A0}, // SP 0x000000000 MP 0x14032ED90 - {"showhudsplash", 0x82A1}, // SP 0x140263850 MP 0x14032FB10 - {"setperk", 0x82A2}, // SP 0x140265490 MP 0x1403297E0 - {"_meth_82A3", 0x82A3}, // SP 0x1402659A0 MP 0x140329D00 - {"_meth_82A4", 0x82A4}, // SP 0x1402661B0 MP 0x14032A460 - {"_meth_82A5", 0x82A5}, // SP 0x140265D40 MP 0x14032A0A0 - {"registerparty", 0x82A6}, // SP 0x000000000 MP 0x1403323C0 - {"_meth_82A7", 0x82A7}, // SP 0x000000000 MP 0x1403324F0 - {"_meth_82A8", 0x82A8}, // SP 0x1405D92F0 MP 0x14032A8F0 - {"_meth_82A9", 0x82A9}, // SP 0x1405D92F0 MP 0x14032A900 - {"moveto", 0x82AA}, // SP 0x1402B2A10 MP 0x14037E950 - {"rotatepitch", 0x82AB}, // SP 0x1402B2F60 MP 0x14037EEB0 - {"rotateyaw", 0x82AC}, // SP 0x1402B2F70 MP 0x14037EEC0 - {"rotateroll", 0x82AD}, // SP 0x1402B2F90 MP 0x14037EEE0 - {"_meth_82AE", 0x82AE}, // SP 0x1402B2C10 MP 0x14037EB00 - {"_meth_82AF", 0x82AF}, // SP 0x1402B2D70 MP 0x14037EC90 - {"_meth_82B0", 0x82B0}, // SP 0x1402B2EE0 MP 0x14037EE20 - {"rotateby", 0x82B1}, // SP 0x1402B3030 MP 0x14037EF10 - {"_meth_82B2", 0x82B2}, // SP 0x1402B3460 MP 0x14037F060 - {"_meth_82B3", 0x82B3}, // SP 0x1402B3470 MP 0x14037F070 - {"_meth_82B4", 0x82B4}, // SP 0x1402B3490 MP 0x14037F090 - {"_meth_82B5", 0x82B5}, // SP 0x1402B3410 MP 0x14037F010 - {"_meth_82B6", 0x82B6}, // SP 0x1402B3430 MP 0x14037F030 - {"_meth_82B7", 0x82B7}, // SP 0x1402B3450 MP 0x14037F050 - {"_meth_82B8", 0x82B8}, // SP 0x1402B34B0 MP 0x14037F0B0 - {"_meth_82B9", 0x82B9}, // SP 0x1402B3700 MP 0x14037F3C0 - {"solid", 0x82BA}, // SP 0x1402B45E0 MP 0x1403808A0 - {"notsolid", 0x82BB}, // SP 0x1402B4690 MP 0x140380950 - {"setcandamage", 0x82BC}, // SP 0x1402B3880 MP 0x14037F590 - {"setcanradiusdamage", 0x82BD}, // SP 0x1402B38E0 MP 0x14037F5F0 - {"physicslaunchclient", 0x82BE}, // SP 0x1402B3960 MP 0x14037F670 - {"_meth_82BF", 0x82BF}, // SP 0x000000000 MP 0x1403351A0 - {"_meth_82C0", 0x82C0}, // SP 0x000000000 MP 0x1403351B0 - {"setcarddisplayslot", 0x82C1}, // SP 0x000000000 MP 0x1403351C0 - {"regweaponforfxremoval", 0x82C2}, // SP 0x000000000 MP 0x1403352B0 - {"laststandrevive", 0x82C3}, // SP 0x000000000 MP 0x140331E00 - {"_meth_82C4", 0x82C4}, // SP 0x000000000 MP 0x140331E70 - {"setspectatedefaults", 0x82C5}, // SP 0x000000000 MP 0x140331EE0 - {"getthirdpersoncrosshairoffset", 0x82C6}, // SP 0x000000000 MP 0x140332250 - {"_meth_82C7", 0x82C7}, // SP 0x140262950 MP 0x14032EF00 - {"_meth_82C8", 0x82C8}, // SP 0x140262A60 MP 0x14032EFF0 - {"_meth_82C9", 0x82C9}, // SP 0x140262AB0 MP 0x14032F0D0 - {"_meth_82CA", 0x82CA}, // SP 0x000000000 MP 0x1403322C0 - {"getweaponslistexclusives", 0x82CB}, // SP 0x1402623D0 MP 0x14032E3A0 - {"_meth_82CC", 0x82CC}, // SP 0x1402624C0 MP 0x14032E4B0 - {"_meth_82CD", 0x82CD}, // SP 0x1402625B0 MP 0x14032E650 - {"getweaponslist", 0x82CE}, // SP 0x140262720 MP 0x14032E790 - {"canplayerplacesentry", 0x82CF}, // SP 0x140264D00 MP 0x140331530 - {"canplayerplacetank", 0x82D0}, // SP 0x1402651B0 MP 0x1403292E0 - {"visionsetnakedforplayer", 0x82D1}, // SP 0x140263410 MP 0x14032FC00 - {"visionsetnightforplayer", 0x82D2}, // SP 0x1402636D0 MP 0x14032FC10 - {"visionsetmissilecamforplayer", 0x82D3}, // SP 0x1402636F0 MP 0x14032FC30 - {"visionsetthermalforplayer", 0x82D4}, // SP 0x140263710 MP 0x14032FD20 - {"visionsetpainforplayer", 0x82D5}, // SP 0x140263730 MP 0x14032FD40 - {"setblurforplayer", 0x82D6}, // SP 0x140264890 MP 0x140330B80 - {"_meth_82D7", 0x82D7}, // SP 0x140264C80 MP 0x140331310 - {"_meth_82D8", 0x82D8}, // SP 0x140264C80 MP 0x140331330 - {"_meth_82D9", 0x82D9}, // SP 0x1402ABE90 MP 0x000000000 - {"getbuildnumber", 0x82DA}, // SP 0x1402663A0 MP 0x14032A910 - {"_meth_82DB", 0x82DB}, // SP 0x140266AF0 MP 0x14032AE90 - {"_meth_82DC", 0x82DC}, // SP 0x140266CD0 MP 0x14032B120 - {"_meth_82DD", 0x82DD}, // SP 0x140266FE0 MP 0x14032B500 - {"playfx", 0x82DE}, // SP 0x140267330 MP 0x14032B9F0 - {"playerrecoilscaleon", 0x82DF}, // SP 0x140267530 MP 0x14032BD00 - {"_meth_82E0", 0x82E0}, // SP 0x140267600 MP 0x14032BDD0 - {"weaponlockstart", 0x82E1}, // SP 0x1402676E0 MP 0x14032C000 - {"weaponlockfinalize", 0x82E2}, // SP 0x140260240 MP 0x14032C240 - {"disableautoreload", 0x82E3}, // SP 0x140260540 MP 0x14032C6C0 - {"setentertime", 0x82E4}, // SP 0x1402605E0 MP 0x14032C7F0 - {"usinggamepad", 0x82E5}, // SP 0x000000000 MP 0x140332300 - {"_meth_82E6", 0x82E6}, // SP 0x000000000 MP 0x140332380 - {"_meth_82E7", 0x82E7}, // SP 0x000000000 MP 0x140332390 - {"_meth_82E8", 0x82E8}, // SP 0x000000000 MP 0x1403323B0 - {"_meth_82E9", 0x82E9}, // SP 0x000000000 MP 0x1403323A0 - {"_meth_82EA", 0x82EA}, // SP 0x1402628A0 MP 0x14032E5C0 - {"_meth_82EB", 0x82EB}, // SP 0x1402619B0 MP 0x14032D5A0 - {"_meth_82EC", 0x82EC}, // SP 0x140261AA0 MP 0x14032D6D0 - {"issighted", 0x82ED}, // SP 0x140263D40 MP 0x14032FA10 - {"setvelocity", 0x82EE}, // SP 0x1402601C0 MP 0x14032BBE0 - {"_meth_82EF", 0x82EF}, // SP 0x140260AD0 MP 0x14032C3C0 - {"_meth_82F0", 0x82F0}, // SP 0x140260E80 MP 0x14032C5E0 - {"_meth_82F1", 0x82F1}, // SP 0x1402677A0 MP 0x14032BE30 - {"_meth_82F2", 0x82F2}, // SP 0x140260130 MP 0x14032BF20 - {"_meth_82F3", 0x82F3}, // SP 0x140264AD0 MP 0x140330E20 - {"setweaponammostock", 0x82F4}, // SP 0x140264EB0 MP 0x140331350 - {"_meth_82F5", 0x82F5}, // SP 0x140265380 MP 0x1403293A0 - {"getweaponammostock", 0x82F6}, // SP 0x1402655D0 MP 0x140329580 - {"_meth_82F7", 0x82F7}, // SP 0x140265820 MP 0x140329990 - {"stoplocalsound", 0x82F8}, // SP 0x140265F20 MP 0x14032A3B0 - {"setclientdvar", 0x82F9}, // SP 0x140266410 MP 0x14032A990 - {"_meth_82FA", 0x82FA}, // SP 0x1402666C0 MP 0x14032B260 - {"_meth_82FB", 0x82FB}, // SP 0x000000000 MP 0x14032AC30 - {"_meth_82FC", 0x82FC}, // SP 0x000000000 MP 0x14032AD80 - {"allowads", 0x82FD}, // SP 0x140261130 MP 0x14032C940 - {"_meth_82FE", 0x82FE}, // SP 0x140261440 MP 0x14032CAB0 - {"_meth_82FF", 0x82FF}, // SP 0x140261B20 MP 0x14032D890 - {"_meth_8300", 0x8300}, // SP 0x140261C00 MP 0x14032DA40 - {"weaponlocktargettooclose", 0x8301}, // SP 0x140261CE0 MP 0x14032DBB0 - {"setspreadoverride", 0x8302}, // SP 0x140262B00 MP 0x14032ED00 - {"resetspreadoverride", 0x8303}, // SP 0x140262CC0 MP 0x14032EE80 - {"_meth_8304", 0x8304}, // SP 0x140262D90 MP 0x14032EF60 - {"setactionslot", 0x8305}, // SP 0x140261F10 MP 0x14032DD50 - {"setviewkickscale", 0x8306}, // SP 0x1402608B0 MP 0x14032CB90 - {"getviewkickscale", 0x8307}, // SP 0x140260A80 MP 0x14032CCC0 - {"getweaponslistoffhands", 0x8308}, // SP 0x1402621A0 MP 0x14032E120 - {"getweaponslistitems", 0x8309}, // SP 0x1402622E0 MP 0x14032E230 - {"_meth_830A", 0x830A}, // SP 0x140261090 MP 0x14032C720 - {"_meth_830B", 0x830B}, // SP 0x140262F00 MP 0x14032EA90 - {"_meth_830C", 0x830C}, // SP 0x140263380 MP 0x14032F210 - {"takeallweapons", 0x830D}, // SP 0x1402635B0 MP 0x14032F310 - {"getcurrentweapon", 0x830E}, // SP 0x140263750 MP 0x14032F5E0 - {"getcurrentprimaryweapon", 0x830F}, // SP 0x140263A30 MP 0x14032F860 - {"getcurrentoffhand", 0x8310}, // SP 0x140263EF0 MP 0x14032FC50 - {"givestartammo", 0x8311}, // SP 0x1402647A0 MP 0x140330740 - {"switchtoweapon", 0x8312}, // SP 0x140264CA0 MP 0x140330D20 - {"switchtoweaponimmediate", 0x8313}, // SP 0x140264E50 MP 0x140330D90 - {"_meth_8314", 0x8314}, // SP 0x140265950 MP 0x140329520 - {"switchtooffhand", 0x8315}, // SP 0x140265B80 MP 0x1403296D0 - {"_meth_8316", 0x8316}, // SP 0x140264440 MP 0x140330340 - {"getcustomizationbody", 0x8317}, // SP 0x140264600 MP 0x140330520 - {"beginlocationselection", 0x8318}, // SP 0x140260C90 MP 0x14032C470 - {"_meth_8319", 0x8319}, // SP 0x140261020 MP 0x14032C780 - {"_meth_831A", 0x831A}, // SP 0x140263E90 MP 0x1403302E0 - {"_meth_831B", 0x831B}, // SP 0x140264020 MP 0x140330410 - {"_meth_831C", 0x831C}, // SP 0x140264150 MP 0x1403305B0 - {"_meth_831D", 0x831D}, // SP 0x140264270 MP 0x1403306E0 - {"_meth_831E", 0x831E}, // SP 0x140264660 MP 0x140330B20 - {"_meth_831F", 0x831F}, // SP 0x140264750 MP 0x140330CC0 - {"setaimspreadmovementscale", 0x8320}, // SP 0x1402631F0 MP 0x14032F130 - {"closemenu", 0x8321}, // SP 0x140263290 MP 0x14032F3A0 - {"_meth_8322", 0x8322}, // SP 0x140263330 MP 0x14032F4E0 - {"openpopupmenu", 0x8323}, // SP 0x140263430 MP 0x14032F6C0 - {"openpopupmenunomouse", 0x8324}, // SP 0x140263630 MP 0x14032F930 - {"freezecontrols", 0x8326}, // SP 0x140263B10 MP 0x14032FD60 - {"disableusability", 0x8327}, // SP 0x140263C10 MP 0x14032FFE0 - {"enableusability", 0x8328}, // SP 0x140263E40 MP 0x1403300F0 - {"_meth_8329", 0x8329}, // SP 0x140266C00 MP 0x14032B640 - {"_meth_832A", 0x832A}, // SP 0x140266D10 MP 0x14032B800 - {"_meth_832B", 0x832B}, // SP 0x140266EA0 MP 0x14032B9C0 - {"_meth_832C", 0x832C}, // SP 0x140267180 MP 0x14032B9E0 - {"deactivatechannelvolumes", 0x832D}, // SP 0x140267410 MP 0x14032BB00 - {"_meth_832E", 0x832E}, // SP 0x140265FA0 MP 0x140329C00 - {"_meth_832F", 0x832F}, // SP 0x140266200 MP 0x140329F00 - {"_meth_8330", 0x8330}, // SP 0x140266560 MP 0x14032A240 - {"_meth_8331", 0x8331}, // SP 0x140266820 MP 0x14032A6F0 - {"isdualwielding", 0x8332}, // SP 0x140266E10 MP 0x14032ABC0 - {"_meth_8333", 0x8333}, // SP 0x140267030 MP 0x14032AD00 - {"isreloading", 0x8334}, // SP 0x140267100 MP 0x14032AEE0 - {"setorigin", 0x8335}, // SP 0x1402677C0 MP 0x14032B8D0 - {"getvelocity", 0x8336}, // SP 0x1402604D0 MP 0x14032BC80 - {"_meth_8337", 0x8337}, // SP 0x140260930 MP 0x14032BE70 - {"forcemantle", 0x8338}, // SP 0x140260990 MP 0x14032C0D0 - {"attackbuttonpressed", 0x8339}, // SP 0x140261500 MP 0x14032CE10 - {"_meth_833A", 0x833A}, // SP 0x1402615F0 MP 0x14032D0B0 - {"meleebuttonpressed", 0x833B}, // SP 0x1402617D0 MP 0x14032D1B0 - {"jumpbuttonpressed", 0x833C}, // SP 0x1402618D0 MP 0x14032D450 - {"getviewheight", 0x833D}, // SP 0x140262070 MP 0x14032DC20 - {"_meth_833E", 0x833E}, // SP 0x1402620C0 MP 0x14032DCE0 - {"isonladder", 0x833F}, // SP 0x140262280 MP 0x14032DF80 - {"setviewmodel", 0x8340}, // SP 0x1402626A0 MP 0x14032DFF0 - {"_meth_8341", 0x8341}, // SP 0x140264090 MP 0x14032FF10 - {"_meth_8342", 0x8342}, // SP 0x1402642C0 MP 0x140330170 - {"_meth_8343", 0x8343}, // SP 0x140260360 MP 0x000000000 - {"_meth_8344", 0x8344}, // SP 0x140260640 MP 0x000000000 - {"_meth_8345", 0x8345}, // SP 0x1402607E0 MP 0x000000000 - {"_meth_8346", 0x8346}, // SP 0x1402609E0 MP 0x000000000 - {"_meth_8347", 0x8347}, // SP 0x14026D000 MP 0x14033B150 - {"forcethirdpersonwhenfollowing", 0x8348}, // SP 0x000000000 MP 0x140374D30 - {"disableforcethirdpersonwhenfollowing", 0x8349}, // SP 0x000000000 MP 0x140374DD0 - {"_meth_834A", 0x834A}, // SP 0x140260C10 MP 0x14032C5D0 - {"_meth_834B", 0x834B}, // SP 0x000000000 MP 0x14037B380 - {"secondaryoffhandbuttonpressed", 0x834C}, // SP 0x140261D40 MP 0x14032D9C0 - {"_meth_834D", 0x834D}, // SP 0x000000000 MP 0x140374B70 - {"_meth_834E", 0x834E}, // SP 0x000000000 MP 0x140374C10 - {"botsetflag", 0x834F}, // SP 0x000000000 MP 0x1404798E0 - {"botsetstance", 0x8350}, // SP 0x000000000 MP 0x14047A0F0 - {"botsetscriptmove", 0x8351}, // SP 0x000000000 MP 0x140479F70 - {"_meth_8352", 0x8352}, // SP 0x000000000 MP 0x140479BC0 - {"_meth_8353", 0x8353}, // SP 0x000000000 MP 0x140479DB0 - {"botclearscriptgoal", 0x8354}, // SP 0x000000000 MP 0x140477C80 - {"getnearestnode", 0x8355}, // SP 0x000000000 MP 0x140479B00 - {"botclearscriptenemy", 0x8356}, // SP 0x000000000 MP 0x140477C00 - {"botsetattacker", 0x8357}, // SP 0x000000000 MP 0x1404796A0 - {"botgetscriptgoal", 0x8358}, // SP 0x000000000 MP 0x1404784A0 - {"botgetscriptgoalradius", 0x8359}, // SP 0x000000000 MP 0x1404785F0 - {"botgetscriptgoalyaw", 0x835A}, // SP 0x000000000 MP 0x1404786F0 - {"botgetscriptgoaltype", 0x835B}, // SP 0x000000000 MP 0x140478670 - {"_meth_835D", 0x835D}, // SP 0x000000000 MP 0x140478850 - {"_meth_835E", 0x835E}, // SP 0x000000000 MP 0x140478E10 - {"botfindnoderandom", 0x835F}, // SP 0x000000000 MP 0x140477D00 - {"botmemoryevent", 0x8360}, // SP 0x000000000 MP 0x140478B70 - {"_meth_8362", 0x8362}, // SP 0x000000000 MP 0x140478EB0 - {"bothasscriptgoal", 0x8363}, // SP 0x000000000 MP 0x140478890 - {"botgetpersonality", 0x8364}, // SP 0x000000000 MP 0x140478420 - {"_meth_8365", 0x8365}, // SP 0x000000000 MP 0x14047A1C0 - {"botsetpersonality", 0x8367}, // SP 0x000000000 MP 0x140479A70 - {"botsetdifficulty", 0x8368}, // SP 0x000000000 MP 0x1404797B0 - {"botgetdifficulty", 0x8369}, // SP 0x000000000 MP 0x140477E90 - {"botgetworldclosestedge", 0x836A}, // SP 0x000000000 MP 0x140478770 - {"_meth_836B", 0x836B}, // SP 0x000000000 MP 0x140478990 - {"botpredictseepoint", 0x836C}, // SP 0x000000000 MP 0x140479420 - {"botcanseeentity", 0x836D}, // SP 0x000000000 MP 0x140477A90 - {"botgetnodesonpath", 0x836E}, // SP 0x000000000 MP 0x140478230 - {"_meth_836F", 0x836F}, // SP 0x000000000 MP 0x140479020 - {"_meth_8371", 0x8371}, // SP 0x000000000 MP 0x140477FD0 - {"botsetawareness", 0x8372}, // SP 0x000000000 MP 0x140479720 - {"_meth_8373", 0x8373}, // SP 0x000000000 MP 0x140479610 - {"botgetscriptgoalnode", 0x8374}, // SP 0x000000000 MP 0x140478560 - {"botgetimperfectenemyinfo", 0x8375}, // SP 0x000000000 MP 0x1404780D0 - {"botsetpathingstyle", 0x8377}, // SP 0x000000000 MP 0x1404799A0 - {"botsetdifficultysetting", 0x8378}, // SP 0x000000000 MP 0x140479840 - {"botgetdifficultysetting", 0x8379}, // SP 0x000000000 MP 0x140477F20 - {"botgetpathdist", 0x837A}, // SP 0x000000000 MP 0x1404782F0 - {"_meth_837B", 0x837B}, // SP 0x000000000 MP 0x140478910 - {"_meth_837C", 0x837C}, // SP 0x000000000 MP 0x140479510 - {"botclearbutton", 0x837D}, // SP 0x000000000 MP 0x140477B70 - {"_meth_837E", 0x837E}, // SP 0x000000000 MP 0x1404791D0 - {"getnodenumber", 0x837F}, // SP 0x000000000 MP 0x14032E760 - {"setclientowner", 0x8380}, // SP 0x000000000 MP 0x14037AD60 - {"_meth_8381", 0x8381}, // SP 0x000000000 MP 0x14037A3B0 - {"setaisightlinevisible", 0x8382}, // SP 0x1402A15D0 MP 0x140358460 - {"setentityowner", 0x8383}, // SP 0x000000000 MP 0x14037A980 - {"nodeisdisconnected", 0x8384}, // SP 0x000000000 MP 0x14032E920 - {"_meth_8385", 0x8385}, // SP 0x140262C60 MP 0x14032E340 - {"_meth_8386", 0x8386}, // SP 0x000000000 MP 0x14037B1B0 - {"_meth_8388", 0x8388}, // SP 0x000000000 MP 0x14044EF90 - {"_meth_8389", 0x8389}, // SP 0x000000000 MP 0x14044E610 - {"setagentattacker", 0x838A}, // SP 0x000000000 MP 0x14044EE40 - {"_meth_838B", 0x838B}, // SP 0x000000000 MP 0x14044E0E0 - {"agentcanseesentient", 0x838C}, // SP 0x000000000 MP 0x14044DF00 - {"setwaypoint", 0x838D}, // SP 0x000000000 MP 0x140450B20 - {"setgoalpos", 0x838E}, // SP 0x000000000 MP 0x140450120 - {"getgoalpos", 0x838F}, // SP 0x000000000 MP 0x14044F670 - {"setgoalnode", 0x8390}, // SP 0x000000000 MP 0x140450090 - {"setgoalentity", 0x8391}, // SP 0x000000000 MP 0x140450000 - {"setgoalradius", 0x8392}, // SP 0x000000000 MP 0x140450260 - {"_meth_8393", 0x8393}, // SP 0x000000000 MP 0x14044FEC0 - {"setorientmode", 0x8394}, // SP 0x000000000 MP 0x140450540 - {"setanimmode", 0x8395}, // SP 0x000000000 MP 0x14044FDA0 - {"setphysicsmode", 0x8396}, // SP 0x000000000 MP 0x140450780 - {"setclipmode", 0x8397}, // SP 0x000000000 MP 0x14044FF60 - {"setmaxturnspeed", 0x8398}, // SP 0x000000000 MP 0x140450370 - {"getmaxturnspeed", 0x8399}, // SP 0x000000000 MP 0x14044F7A0 - {"beginmelee", 0x839A}, // SP 0x000000000 MP 0x14044F2A0 - {"getmlgspectatorteam", 0x839B}, // SP 0x000000000 MP 0x140450840 - {"dotrajectory", 0x839C}, // SP 0x000000000 MP 0x14044F5D0 - {"doanimlerp", 0x839D}, // SP 0x000000000 MP 0x14044F480 - {"setviewheight", 0x839E}, // SP 0x000000000 MP 0x140450AA0 - {"claimnode", 0x839F}, // SP 0x000000000 MP 0x14044F370 - {"relinquishclaimednode", 0x83A0}, // SP 0x000000000 MP 0x14044FC90 - {"_meth_83A1", 0x83A1}, // SP 0x14026DD90 MP 0x14033BCE0 - {"_meth_83A2", 0x83A2}, // SP 0x14026DE40 MP 0x14033BD90 - {"_meth_83A3", 0x83A3}, // SP 0x14026DEB0 MP 0x14033BDF0 - {"_meth_83A4", 0x83A4}, // SP 0x14026DF20 MP 0x14033BE50 - {"_meth_83A5", 0x83A5}, // SP 0x1402A84A0 MP 0x000000000 - {"_meth_83A6", 0x83A6}, // SP 0x140260B80 MP 0x14032CDC0 - {"_meth_83A7", 0x83A7}, // SP 0x140260DE0 MP 0x14032CEA0 - {"_meth_83A8", 0x83A8}, // SP 0x140268480 MP 0x000000000 - {"_meth_83A9", 0x83A9}, // SP 0x1402A8750 MP 0x000000000 - {"_meth_83AA", 0x83AA}, // SP 0x1402A8860 MP 0x000000000 - {"_meth_83AB", 0x83AB}, // SP 0x140268330 MP 0x000000000 - {"_meth_83AC", 0x83AC}, // SP 0x140268410 MP 0x000000000 - {"_meth_83AD", 0x83AD}, // SP 0x1402683A0 MP 0x000000000 - {"_meth_83B0", 0x83B0}, // SP 0x1405D92F0 MP 0x14032CC20 - {"_meth_83B1", 0x83B1}, // SP 0x1402670A0 MP 0x14032B5D0 - {"_meth_83B2", 0x83B2}, // SP 0x140267250 MP 0x14032B7B0 - {"_meth_83B3", 0x83B3}, // SP 0x1404651B0 MP 0x14055F010 - {"_meth_83B4", 0x83B4}, // SP 0x1404651C0 MP 0x14055F020 - {"_meth_83B5", 0x83B5}, // SP 0x000000000 MP 0x14037BCD0 - {"_meth_83B6", 0x83B6}, // SP 0x14029C100 MP 0x140367570 - {"_meth_83B7", 0x83B7}, // SP 0x140299860 MP 0x140364840 - {"_meth_83B8", 0x83B8}, // SP 0x14028E830 MP 0x140364960 - {"_meth_83B9", 0x83B9}, // SP 0x140261C60 MP 0x14032D930 - {"_meth_83BA", 0x83BA}, // SP 0x140462CB0 MP 0x1405614F0 - {"_meth_83BB", 0x83BB}, // SP 0x140462D60 MP 0x1405615A0 - {"_meth_83BC", 0x83BC}, // SP 0x140462DE0 MP 0x140561620 - {"_meth_83BD", 0x83BD}, // SP 0x14028AB00 MP 0x000000000 - {"_meth_83BE", 0x83BE}, // SP 0x140263B80 MP 0x140330060 - {"_meth_83BF", 0x83BF}, // SP 0x140263C60 MP 0x140330200 - {"_meth_83C0", 0x83C0}, // SP 0x140263F70 MP 0x140330470 - {"_meth_83C1", 0x83C1}, // SP 0x1402B3B00 MP 0x14037F840 - {"_meth_83C2", 0x83C2}, // SP 0x1402D7D50 MP 0x1400778A0 - {"_meth_83C3", 0x83C3}, // SP 0x1404623A0 MP 0x140560AC0 - {"_meth_83C4", 0x83C4}, // SP 0x1405D92F0 MP 0x14032D370 - {"_meth_83C5", 0x83C5}, // SP 0x14028AA90 MP 0x000000000 - {"_meth_83C6", 0x83C6}, // SP 0x14024AEF0 MP 0x000000000 - {"_meth_83C7", 0x83C7}, // SP 0x14024B000 MP 0x000000000 - {"_meth_83C8", 0x83C8}, // SP 0x14024B340 MP 0x000000000 - {"_meth_83C9", 0x83C9}, // SP 0x14024B420 MP 0x000000000 - {"_meth_83CA", 0x83CA}, // SP 0x14024B6D0 MP 0x000000000 - {"_meth_83CB", 0x83CB}, // SP 0x14024B660 MP 0x000000000 - {"_meth_83CC", 0x83CC}, // SP 0x14024B740 MP 0x000000000 - {"_meth_83CD", 0x83CD}, // SP 0x14024B7A0 MP 0x000000000 - {"setanimclass", 0x83CE}, // SP 0x000000000 MP 0x1400781E0 - {"enableanimstate", 0x83CF}, // SP 0x000000000 MP 0x140077CB0 - {"_meth_83D0", 0x83D0}, // SP 0x000000000 MP 0x140078250 - {"getanimentry", 0x83D1}, // SP 0x000000000 MP 0x140077DF0 - {"getanimentryname", 0x83D2}, // SP 0x000000000 MP 0x140077FA0 - {"getanimentryalias", 0x83D3}, // SP 0x000000000 MP 0x140077E80 - {"getanimentrycount", 0x83D4}, // SP 0x000000000 MP 0x140077EE0 - {"_meth_83D5", 0x83D5}, // SP 0x1402AE190 MP 0x000000000 - {"issprinting", 0x83D6}, // SP 0x1402613C0 MP 0x14032CB20 - {"_meth_83D7", 0x83D7}, // SP 0x140291320 MP 0x000000000 - {"_meth_83D8", 0x83D8}, // SP 0x1402495B0 MP 0x000000000 - {"_meth_83D9", 0x83D9}, // SP 0x1405D92F0 MP 0x140358020 - {"_meth_83DA", 0x83DA}, // SP 0x140264C80 MP 0x000000000 - {"_meth_83DB", 0x83DB}, // SP 0x140264C80 MP 0x000000000 - {"_meth_83DC", 0x83DC}, // SP 0x140261B80 MP 0x14032D800 - {"rotateto", 0x83DD}, // SP 0x1402B3200 MP 0x14037EF90 - {"getlookaheaddir", 0x83DE}, // SP 0x000000000 MP 0x14044F710 - {"getpathgoalpos", 0x83DF}, // SP 0x000000000 MP 0x14044FAD0 - {"_meth_83E0", 0x83E0}, // SP 0x1402A15D0 MP 0x14036E1F0 - {"setcorpsefalling", 0x83E1}, // SP 0x000000000 MP 0x140374840 - {"setsurfacetype", 0x83E2}, // SP 0x14029FD00 MP 0x140358090 - {"_meth_83E3", 0x83E3}, // SP 0x1402A0C60 MP 0x140369520 - {"_meth_83E4", 0x83E4}, // SP 0x1402A20D0 MP 0x140369FE0 - {"_meth_83E5", 0x83E5}, // SP 0x1405D92F0 MP 0x14033B020 - {"_meth_83E6", 0x83E6}, // SP 0x1402A7B00 MP 0x000000000 - {"_meth_83E7", 0x83E7}, // SP 0x1402A7C90 MP 0x000000000 - {"visionsetstage", 0x83E8}, // SP 0x140263140 MP 0x14032F7A0 - {"hudoutlineenableforclients", 0x83E9}, // SP 0x14026D2E0 MP 0x14033B450 - {"getlinkedparent", 0x83EA}, // SP 0x14028DB50 MP 0x140359B60 - {"getmovingplatformparent", 0x83EB}, // SP 0x14028E2A0 MP 0x14035A4D0 - {"_meth_83EC", 0x83EC}, // SP 0x000000000 MP 0x14032CEF0 - {"_meth_83ED", 0x83ED}, // SP 0x1402ADF90 MP 0x000000000 - {"_meth_83EF", 0x83EF}, // SP 0x1402A0B60 MP 0x14036A5C0 - {"_meth_83F0", 0x83F0}, // SP 0x14029F670 MP 0x140369790 - {"makevehiclenotcollidewithplayers", 0x83F1}, // SP 0x1402913E0 MP 0x14035B490 - {"_meth_83F2", 0x83F2}, // SP 0x140269130 MP 0x000000000 - {"_meth_83F3", 0x83F3}, // SP 0x140269190 MP 0x000000000 - {"setscriptablepartstate", 0x83F4}, // SP 0x1402A0760 MP 0x1403589E0 - {"_meth_83F5", 0x83F5}, // SP 0x1405D92F0 MP 0x140359100 - {"_meth_83F6", 0x83F6}, // SP 0x1402A15D0 MP 0x14036E200 - {"_meth_83F7", 0x83F7}, // SP 0x140465020 MP 0x140560DF0 - {"_meth_83F8", 0x83F8}, // SP 0x1405D92F0 MP 0x1403636B0 - {"_meth_83F9", 0x83F9}, // SP 0x1405D92F0 MP 0x140363830 - {"motionblurhqdisable", 0x83FA}, // SP 0x14029BA30 MP 0x140363EA0 - {"_meth_83FB", 0x83FB}, // SP 0x14029BC20 MP 0x1403640D0 - {"_meth_83FC", 0x83FC}, // SP 0x1402AA870 MP 0x000000000 - {"_meth_83FD", 0x83FD}, // SP 0x14024AD20 MP 0x000000000 - {"worldpointtoscreenpos", 0x83FE}, // SP 0x140297A40 MP 0x140360C90 - {"_meth_83FF", 0x83FF}, // SP 0x1402974B0 MP 0x000000000 - {"_meth_8400", 0x8400}, // SP 0x1402498E0 MP 0x000000000 - {"_meth_8401", 0x8401}, // SP 0x000000000 MP 0x140477D90 - {"_meth_8402", 0x8402}, // SP 0x140263950 MP 0x000000000 - {"_meth_8403", 0x8403}, // SP 0x140268F10 MP 0x000000000 - {"_meth_8404", 0x8404}, // SP 0x1402977A0 MP 0x000000000 - {"_meth_8405", 0x8405}, // SP 0x1402978F0 MP 0x000000000 - {"_meth_8406", 0x8406}, // SP 0x14029A680 MP 0x000000000 - {"emissiveblend", 0x8407}, // SP 0x000000000 MP 0x140375810 - {"_meth_8408", 0x8408}, // SP 0x1402687F0 MP 0x000000000 - {"_meth_8409", 0x8409}, // SP 0x140268840 MP 0x000000000 - {"_meth_840A", 0x840A}, // SP 0x1402AF930 MP 0x000000000 - {"_meth_840B", 0x840B}, // SP 0x1402AE490 MP 0x000000000 - {"_meth_840C", 0x840C}, // SP 0x1402AE5D0 MP 0x000000000 - {"_meth_840D", 0x840D}, // SP 0x1402B4000 MP 0x14037FDE0 - {"_meth_840E", 0x840E}, // SP 0x1402B40B0 MP 0x14037FE90 - {"physicsgetlinspeed", 0x840F}, // SP 0x1402B4160 MP 0x14037FF40 - {"_meth_8410", 0x8410}, // SP 0x1402B41F0 MP 0x140380000 - {"physicsgetangvel", 0x8411}, // SP 0x1402B42B0 MP 0x1403800E0 - {"physicsgetangspeed", 0x8412}, // SP 0x1402B4340 MP 0x1403801A0 - {"disablemissileboosting", 0x8413}, // SP 0x000000000 MP 0x14035A430 - {"enablemissileboosting", 0x8414}, // SP 0x000000000 MP 0x14035A480 - {"canspawntestclient", 0x8415}, // SP 0x000000000 MP 0x140376790 - {"spawntestclient", 0x8416}, // SP 0x000000000 MP 0x1403767B0 - {"setgrenadethrowscale", 0x8417}, // SP 0x000000000 MP 0x14036F610 - {"ismantling", 0x8418}, // SP 0x000000000 MP 0x140357DB0 - {"_meth_8419", 0x8419}, // SP 0x000000000 MP 0x1403767E0 - {"_meth_841A", 0x841A}, // SP 0x1405D92F0 MP 0x1403630D0 - {"_meth_841B", 0x841B}, // SP 0x1405D92F0 MP 0x140363500 - {"_meth_841C", 0x841C}, // SP 0x1405D92F0 MP 0x140363590 - {"_meth_841D", 0x841D}, // SP 0x1405D92F0 MP 0x140363620 - {"turretsetbarrelspinenabled", 0x841E}, // SP 0x140299270 MP 0x140364190 - {"_meth_841F", 0x841F}, // SP 0x000000000 MP 0x1403326E0 - {"autospotoverlayoff", 0x8420}, // SP 0x000000000 MP 0x1403328E0 - {"_meth_8421", 0x8421}, // SP 0x14029FEB0 MP 0x140369B60 - {"_meth_8422", 0x8422}, // SP 0x1402A00C0 MP 0x140369E10 - {"doanimrelative", 0x8423}, // SP 0x000000000 MP 0x14044F520 - {"_meth_8424", 0x8424}, // SP 0x1402B30B0 MP 0x000000000 - {"_meth_8425", 0x8425}, // SP 0x1402B3280 MP 0x000000000 - {"_meth_8426", 0x8426}, // SP 0x1402B3320 MP 0x000000000 - {"getcorpseentity", 0x8427}, // SP 0x000000000 MP 0x1403748F0 - {"_meth_8428", 0x8428}, // SP 0x1402ABE20 MP 0x000000000 - {"_meth_8429", 0x8429}, // SP 0x000000000 MP 0x140379520 - {"_meth_842A", 0x842A}, // SP 0x000000000 MP 0x140379B70 - {"queuedialogforplayer", 0x842B}, // SP 0x000000000 MP 0x1403785F0 - {"setmlgcameradefaults", 0x842C}, // SP 0x000000000 MP 0x1403321B0 - {"_meth_842D", 0x842D}, // SP 0x000000000 MP 0x140334A60 - {"_meth_842E", 0x842E}, // SP 0x140262C10 MP 0x14032F2B0 - {"_meth_842F", 0x842F}, // SP 0x140262D40 MP 0x14032F480 - {"_meth_8430", 0x8430}, // SP 0x1405D92F0 MP 0x000000000 - {"getlinkedchildren", 0x8431}, // SP 0x14028E020 MP 0x14035A3A0 - {"_meth_8432", 0x8432}, // SP 0x000000000 MP 0x140479320 - {"playsoundonmovingent", 0x8433}, // SP 0x000000000 MP 0x140377F80 - {"cancelmantle", 0x8434}, // SP 0x140266DD0 MP 0x14032B210 - {"hasfemalecustomizationmodel", 0x8435}, // SP 0x000000000 MP 0x140332F50 - {"setscriptabledamageowner", 0x8437}, // SP 0x1402A0440 MP 0x1403586F0 - {"_meth_8438", 0x8438}, // SP 0x1402A0B00 MP 0x140358FF0 - {"_meth_8439", 0x8439}, // SP 0x000000000 MP 0x140379890 - {"_meth_843A", 0x843A}, // SP 0x14024B810 MP 0x000000000 - {"_meth_843B", 0x843B}, // SP 0x14024B8B0 MP 0x000000000 - {"_meth_843C", 0x843C}, // SP 0x140265900 MP 0x1403294C0 - {"_meth_843D", 0x843D}, // SP 0x14024BCE0 MP 0x000000000 - {"_meth_843E", 0x843E}, // SP 0x14029EC40 MP 0x140368630 - {"_meth_843F", 0x843F}, // SP 0x1405D92F0 MP 0x14032D4E0 - {"_meth_8440", 0x8440}, // SP 0x1404639C0 MP 0x140562210 - {"_meth_8441", 0x8441}, // SP 0x140462EA0 MP 0x1405616E0 - {"_meth_8442", 0x8442}, // SP 0x1402A36A0 MP 0x140358B60 - {"_meth_8443", 0x8443}, // SP 0x140266090 MP 0x14032A550 - {"_meth_8444", 0x8444}, // SP 0x1402A8A40 MP 0x000000000 - {"_meth_8445", 0x8445}, // SP 0x1402A8A80 MP 0x000000000 - {"_meth_8446", 0x8446}, // SP 0x1402A2F70 MP 0x14036CC00 - {"_meth_8447", 0x8447}, // SP 0x1405D92F0 MP 0x140363840 - {"_meth_8448", 0x8448}, // SP 0x1405D92F0 MP 0x140363A50 - {"_meth_8449", 0x8449}, // SP 0x1402611B0 MP 0x14032C860 - {"_meth_844A", 0x844A}, // SP 0x140295480 MP 0x1403602C0 - {"_meth_844B", 0x844B}, // SP 0x140295650 MP 0x1403604C0 - {"_meth_844C", 0x844C}, // SP 0x140463020 MP 0x140561860 - {"_meth_844D", 0x844D}, // SP 0x140463040 MP 0x140561880 - {"_meth_844E", 0x844E}, // SP 0x140463060 MP 0x1405618A0 - {"_meth_844F", 0x844F}, // SP 0x140463080 MP 0x1405618C0 - {"_meth_8450", 0x8450}, // SP 0x1402AC9E0 MP 0x000000000 - {"_meth_8451", 0x8451}, // SP 0x1402ACB20 MP 0x000000000 - {"_meth_8452", 0x8452}, // SP 0x140462F60 MP 0x1405617A0 - {"_meth_8453", 0x8453}, // SP 0x140261E30 MP 0x14032DC80 - {"_meth_8454", 0x8454}, // SP 0x1402612F0 MP 0x000000000 - {"_meth_8455", 0x8455}, // SP 0x1402AD1E0 MP 0x000000000 - {"getvieworigin", 0x8458}, // SP 0x14029DE70 MP 0x140366600 - {"_meth_8459", 0x8459}, // SP 0x140265E70 MP 0x140329A80 - {"_meth_845A", 0x845A}, // SP 0x000000000 MP 0x140359980 - {"stopridingvehicle", 0x845B}, // SP 0x000000000 MP 0x14035A040 - {"_meth_845C", 0x845C}, // SP 0x140264C80 MP 0x000000000 - {"_meth_845D", 0x845D}, // SP 0x14028E7C0 MP 0x14035A8D0 - {"disablemissilestick", 0x845E}, // SP 0x000000000 MP 0x1403762F0 - {"enablemissilestick", 0x845F}, // SP 0x000000000 MP 0x140376340 - {"setmissileminimapvisible", 0x8460}, // SP 0x000000000 MP 0x140347ED0 - {"isoffhandweaponreadytothrow", 0x8461}, // SP 0x1402675A0 MP 0x14032B560 - {"isleaning", 0x8462}, // SP 0x1402614A0 MP 0x14032CC30 - {"makecollidewithitemclip", 0x8463}, // SP 0x140291970 MP 0x14035B8F0 - {"_meth_8464", 0x8464}, // SP 0x140261DC0 MP 0x000000000 - {"visionsetpostapplyforplayer", 0x8465}, // SP 0x000000000 MP 0x14032FE10 - {"_meth_8466", 0x8466}, // SP 0x1402B47A0 MP 0x140380A60 - {"_meth_8467", 0x8467}, // SP 0x1402B4950 MP 0x140380C30 - {"_meth_8468", 0x8468}, // SP 0x1402A2E30 MP 0x000000000 - {"_meth_8469", 0x8469}, // SP 0x1402A3290 MP 0x000000000 - {"_meth_846A", 0x846A}, // SP 0x1402A3360 MP 0x000000000 - {"_meth_846B", 0x846B}, // SP 0x1402A36C0 MP 0x000000000 - {"_meth_846C", 0x846C}, // SP 0x14028DBB0 MP 0x000000000 - {"_meth_846D", 0x846D}, // SP 0x140260B20 MP 0x000000000 - {"_meth_846E", 0x846E}, // SP 0x1402A8530 MP 0x000000000 - {"_meth_846F", 0x846F}, // SP 0x140463100 MP 0x140561940 - {"_meth_8470", 0x8470}, // SP 0x140463140 MP 0x140561980 - {"_meth_8471", 0x8471}, // SP 0x1404631A0 MP 0x1405619E0 - {"_meth_8472", 0x8472}, // SP 0x1404631F0 MP 0x140561A30 - {"_meth_8473", 0x8473}, // SP 0x140463210 MP 0x140561A50 - {"_meth_8474", 0x8474}, // SP 0x140291B70 MP 0x14035E030 - {"_meth_8475", 0x8475}, // SP 0x140291E30 MP 0x14035E0D0 - {"_meth_8476", 0x8476}, // SP 0x140263970 MP 0x14032FE30 - {"_meth_8477", 0x8477}, // SP 0x1402A85E0 MP 0x000000000 - {"_meth_8478", 0x8478}, // SP 0x1402A86E0 MP 0x000000000 - {"_meth_8479", 0x8479}, // SP 0x1405D92F0 MP 0x14032C130 - {"_meth_847A", 0x847A}, // SP 0x1405D92F0 MP 0x14032C420 - {"_meth_847B", 0x847B}, // SP 0x140462450 MP 0x140560B70 - {"_meth_847C", 0x847C}, // SP 0x1404624D0 MP 0x140560BF0 - {"_meth_847D", 0x847D}, // SP 0x140262900 MP 0x14032E940 - {"_meth_847E", 0x847E}, // SP 0x1402629A0 MP 0x14032E9D0 - {"_meth_847F", 0x847F}, // SP 0x14029CB70 MP 0x140367C30 - {"_meth_8480", 0x8480}, // SP 0x140291DA0 MP 0x000000000 - {"_meth_8481", 0x8481}, // SP 0x1405D92F0 MP 0x14032CD40 - {"_meth_8482", 0x8482}, // SP 0x1405D92F0 MP 0x14032CD30 - {"_meth_8483", 0x8483}, // SP 0x000000000 MP 0x14044E5B0 - {"_meth_8484", 0x8484}, // SP 0x140464FB0 MP 0x140563710 - {"_meth_8485", 0x8485}, // SP 0x1404630B0 MP 0x1405618F0 - {"_meth_8486", 0x8486}, // SP 0x000000000 MP 0x14044DF90 - {"_meth_8487", 0x8487}, // SP 0x000000000 MP 0x140380630 - {"_meth_8488", 0x8488}, // SP 0x1402B3150 MP 0x000000000 - {"_meth_8489", 0x8489}, // SP 0x1405D92F0 MP 0x14032CD20 - {"_meth_848A", 0x848A}, // SP 0x140465030 MP 0x140563790 - {"_meth_848B", 0x848B}, // SP 0x140465020 MP 0x140563720 - {"_meth_848C", 0x848C}, // SP 0x1402641A0 MP 0x140330610 - {"_meth_848D", 0x848D}, // SP 0x140264320 MP 0x140330840 - {"_meth_848E", 0x848E}, // SP 0x140264550 MP 0x140330970 - {"_meth_848F", 0x848F}, // SP 0x1402694A0 MP 0x000000000 - {"_meth_8490", 0x8490}, // SP 0x1405D92F0 MP 0x14035E610 - {"_meth_8491", 0x8491}, // SP 0x000000000 MP 0x14037A4A0 - {"_meth_8492", 0x8492}, // SP 0x000000000 MP 0x14037A510 - {"_meth_8493", 0x8493}, // SP 0x1402ACF90 MP 0x000000000 - {"_meth_8494", 0x8494}, // SP 0x1402AD070 MP 0x000000000 - {"_meth_8495", 0x8495}, // SP 0x140268C60 MP 0x000000000 - {"_meth_8496", 0x8496}, // SP 0x000000000 MP 0x140375380 - {"_meth_8497", 0x8497}, // SP 0x000000000 MP 0x140376030 - {"_meth_8498", 0x8498}, // SP 0x140266500 MP 0x14032AB70 - {"_meth_8499", 0x8499}, // SP 0x140266B20 MP 0x14032AF60 - {"_meth_849A", 0x849A}, // SP 0x1405D92F0 MP 0x14032CCB0 - {"_meth_849B", 0x849B}, // SP 0x000000000 MP 0x140375470 - {"_meth_849C", 0x849C}, // SP 0x000000000 MP 0x140375490 - {"_meth_849D", 0x849D}, // SP 0x000000000 MP 0x140375640 - {"_meth_849E", 0x849E}, // SP 0x000000000 MP 0x140375650 - {"_meth_849F", 0x849F}, // SP 0x000000000 MP 0x140375660 - {"_meth_84A0", 0x84A0}, // SP 0x000000000 MP 0x140375680 - {"_meth_84A1", 0x84A1}, // SP 0x000000000 MP 0x140375670 - {"_meth_84A2", 0x84A2}, // SP 0x000000000 MP 0x1403756C0 - {"_meth_84A3", 0x84A3}, // SP 0x000000000 MP 0x1403757F0 - {"_meth_84A4", 0x84A4}, // SP 0x000000000 MP 0x1403756B0 - {"_meth_84A5", 0x84A5}, // SP 0x14029FDA0 MP 0x140369CB0 - {"_meth_84A6", 0x84A6}, // SP 0x1402A02F0 MP 0x14036A120 - {"_meth_84A7", 0x84A7}, // SP 0x1402A04A0 MP 0x14036A190 - {"_meth_84A8", 0x84A8}, // SP 0x1402A0FE0 MP 0x14036A960 - {"_meth_84A9", 0x84A9}, // SP 0x140465C50 MP 0x14055FBF0 - {"_meth_84AA", 0x84AA}, // SP 0x1402979E0 MP 0x1403625A0 - {"_meth_84AB", 0x84AB}, // SP 0x140297E40 MP 0x140362BD0 - {"_meth_84AC", 0x84AC}, // SP 0x140261E70 MP 0x14032DAE0 - {"_meth_84AD", 0x84AD}, // SP 0x1404663D0 MP 0x1405602E0 - {"_meth_84AE", 0x84AE}, // SP 0x1404664D0 MP 0x1405603E0 - {"_meth_84AF", 0x84AF}, // SP 0x000000000 MP 0x140333050 - {"_meth_84B0", 0x84B0}, // SP 0x1405D92F0 MP 0x140369850 - {"_meth_84B1", 0x84B1}, // SP 0x1402922D0 MP 0x14035E650 - {"_meth_84B2", 0x84B2}, // SP 0x1402925B0 MP 0x14035E660 - {"_meth_84B3", 0x84B3}, // SP 0x140292CD0 MP 0x14035E700 - {"_meth_84B4", 0x84B4}, // SP 0x140292FC0 MP 0x14035E720 - {"_meth_84B5", 0x84B5}, // SP 0x1405D92F0 MP 0x140364AA0 - {"_meth_84B6", 0x84B6}, // SP 0x1405D92F0 MP 0x14036BC80 - {"_meth_84B7", 0x84B7}, // SP 0x1404655C0 MP 0x14055F460 - {"_meth_84B8", 0x84B8}, // SP 0x1402A09C0 MP 0x14036A6A0 - {"_meth_84B9", 0x84B9}, // SP 0x000000000 MP 0x1403807B0 - {"_meth_84BB", 0x84BB}, // SP 0x1402643F0 MP 0x140330910 - {"_meth_84BC", 0x84BC}, // SP 0x140264500 MP 0x140330A20 - {"_meth_84BD", 0x84BD}, // SP 0x000000000 MP 0x1403330D0 - {"_meth_84BE", 0x84BE}, // SP 0x000000000 MP 0x1403335E0 - {"_meth_84BF", 0x84BF}, // SP 0x140265260 MP 0x1403311D0 - {"_meth_84C0", 0x84C0}, // SP 0x140265710 MP 0x1403291C0 - {"_meth_84C1", 0x84C1}, // SP 0x000000000 MP 0x1403766D0 - {"_meth_84C2", 0x84C2}, // SP 0x14029E430 MP 0x14036AA10 - {"_meth_84C3", 0x84C3}, // SP 0x140463250 MP 0x140561A90 - {"_meth_84C4", 0x84C4}, // SP 0x000000000 MP 0x140450E40 - {"_meth_84C5", 0x84C5}, // SP 0x000000000 MP 0x140450B10 - {"_meth_84C6", 0x84C6}, // SP 0x140260790 MP 0x14032BD80 - {"_meth_84C7", 0x84C7}, // SP 0x140260590 MP 0x000000000 - {"_meth_84C8", 0x84C8}, // SP 0x1402606E0 MP 0x000000000 - {"_meth_84C9", 0x84C9}, // SP 0x140464D30 MP 0x1405634E0 - {"_meth_84CA", 0x84CA}, // SP 0x140464DC0 MP 0x140563580 - {"_meth_84CB", 0x84CB}, // SP 0x000000000 MP 0x140334CC0 - {"_meth_84CC", 0x84CC}, // SP 0x140463270 MP 0x140561AB0 - {"_meth_84CD", 0x84CD}, // SP 0x1402A1470 MP 0x14036A8C0 - {"_meth_84CE", 0x84CE}, // SP 0x1402A15E0 MP 0x14036AD30 - {"_meth_84CF", 0x84CF}, // SP 0x14029ED60 MP 0x1403685E0 - {"_meth_84D0", 0x84D0}, // SP 0x14029EED0 MP 0x1403687A0 - {"_meth_84D1", 0x84D1}, // SP 0x14029F130 MP 0x1403687F0 - {"_meth_84D2", 0x84D2}, // SP 0x14029F300 MP 0x140368AC0 - {"_meth_84D3", 0x84D3}, // SP 0x14029F350 MP 0x140368CE0 - {"_meth_84D4", 0x84D4}, // SP 0x14029F410 MP 0x140368D50 - {"_meth_84D5", 0x84D5}, // SP 0x14029F530 MP 0x140368DF0 - {"_meth_84D6", 0x84D6}, // SP 0x14029F5E0 MP 0x140368ED0 - {"_meth_84D8", 0x84D8}, // SP 0x1402674E0 MP 0x14032B4A0 - {"_meth_84D9", 0x84D9}, // SP 0x1402B4400 MP 0x140380280 - {"_meth_84DA", 0x84DA}, // SP 0x000000000 MP 0x14035B2A0 - {"_meth_84DB", 0x84DB}, // SP 0x140248770 MP 0x000000000 - {"_meth_84DC", 0x84DC}, // SP 0x140461FF0 MP 0x000000000 - {"_meth_84DF", 0x84DF}, // SP 0x14028DF20 MP 0x14035B180 - {"_meth_84E0", 0x84E0}, // SP 0x14026E2F0 MP 0x14033C220 - {"_meth_84E1", 0x84E1}, // SP 0x1404632B0 MP 0x140561AF0 - {"_meth_84E2", 0x84E2}, // SP 0x000000000 MP 0x14036F110 - {"_meth_84E3", 0x84E3}, // SP 0x140264A30 MP 0x140331120 - {"_meth_84E4", 0x84E4}, // SP 0x1405D92F0 MP 0x1403604A0 - {"_meth_84E5", 0x84E5}, // SP 0x1402A88B0 MP 0x000000000 - {"_meth_84E6", 0x84E6}, // SP 0x1405D92F0 MP 0x14036C920 - {"_meth_84E8", 0x84E8}, // SP 0x140264970 MP 0x140330E00 - {"_meth_84E9", 0x84E9}, // SP 0x1402649D0 MP 0x140330E10 - {"_meth_84EA", 0x84EA}, // SP 0x14028ABB0 MP 0x000000000 - {"_meth_84EB", 0x84EB}, // SP 0x14029AF70 MP 0x140364720 - {"_meth_84EC", 0x84EC}, // SP 0x1402A11C0 MP 0x140359610 - {"_meth_84ED", 0x84ED}, // SP 0x140293540 MP 0x140360150 - {"_meth_84EE", 0x84EE}, // SP 0x140298540 MP 0x140361720 - {"_meth_84EF", 0x84EF}, // SP 0x14029B960 MP 0x140363B90 - {"_meth_84F0", 0x84F0}, // SP 0x1404643D0 MP 0x140562AB0 - {"_meth_84F1", 0x84F1}, // SP 0x1404644E0 MP 0x140562BE0 - {"_meth_84F2", 0x84F2}, // SP 0x1405D92F0 MP 0x14035B8C0 - {"_meth_84F3", 0x84F3}, // SP 0x1405D92F0 MP 0x14035B990 - {"_meth_84F4", 0x84F4}, // SP 0x14028E1A0 MP 0x14035B280 - {"_meth_84F5", 0x84F5}, // SP 0x14028E1A0 MP 0x14035B360 - {"_meth_84F6", 0x84F6}, // SP 0x1405D92F0 MP 0x14035B390 - {"_meth_84F7", 0x84F7}, // SP 0x14028E830 MP 0x14035B3A0 - {"_meth_84F8", 0x84F8}, // SP 0x14028E830 MP 0x14035B430 - {"_meth_84F9", 0x84F9}, // SP 0x14028E830 MP 0x14035B540 - {"_meth_84FA", 0x84FA}, // SP 0x1405D92F0 MP 0x14035B7A0 - {"_meth_84FB", 0x84FB}, // SP 0x14029EDE0 MP 0x14036EA10 - {"_meth_84FC", 0x84FC}, // SP 0x140290D70 MP 0x14035A740 - {"_meth_84FD", 0x84FD}, // SP 0x000000000 MP 0x140334AC0 - {"_meth_84FE", 0x84FE}, // SP 0x000000000 MP 0x140376800 - {"_meth_84FF", 0x84FF}, // SP 0x000000000 MP 0x1403768C0 - {"_meth_8500", 0x8500}, // SP 0x14028F5A0 MP 0x14035A550 - {"_meth_8501", 0x8501}, // SP 0x14028E4D0 MP 0x140359550 - {"_meth_8502", 0x8502}, // SP 0x000000000 MP 0x1403767F0 - {"_meth_8503", 0x8503}, // SP 0x14028F6E0 MP 0x14035C670 - {"_meth_8504", 0x8504}, // SP 0x000000000 MP 0x14037A470 - {"_meth_8505", 0x8505}, // SP 0x000000000 MP 0x140374F20 - {"_meth_8506", 0x8506}, // SP 0x000000000 MP 0x14037ADD0 - {"_meth_8507", 0x8507}, // SP 0x000000000 MP 0x14037AAF0 - {"_meth_8508", 0x8508}, // SP 0x000000000 MP 0x140332BC0 - {"_meth_8509", 0x8509}, // SP 0x1402AC990 MP 0x000000000 - {"_meth_850A", 0x850A}, // SP 0x1402646B0 MP 0x140330A80 - {"_meth_850B", 0x850B}, // SP 0x14026DCB0 MP 0x14033BC10 - {"_meth_850C", 0x850C}, // SP 0x000000000 MP 0x140376020 - {"_meth_850D", 0x850D}, // SP 0x14029E8F0 MP 0x1403682B0 - {"_meth_850E", 0x850E}, // SP 0x14029ED00 MP 0x140368570 - {"_meth_850F", 0x850F}, // SP 0x14029A7B0 MP 0x140362600 - {"_meth_8510", 0x8510}, // SP 0x140267840 MP 0x14032BE50 - {"_meth_8511", 0x8511}, // SP 0x140290ED0 MP 0x14035A8E0 - {"_meth_8512", 0x8512}, // SP 0x1404632E0 MP 0x140561B20 - {"_meth_8513", 0x8513}, // SP 0x140463300 MP 0x140561B40 - {"_meth_8514", 0x8514}, // SP 0x14028E830 MP 0x14032B9B0 - {"_meth_8515", 0x8515}, // SP 0x14028E830 MP 0x14032B9D0 - {"_meth_8516", 0x8516}, // SP 0x140299C10 MP 0x140361690 - {"_meth_8517", 0x8517}, // SP 0x000000000 MP 0x1403747A0 - {"_meth_8518", 0x8518}, // SP 0x14026D400 MP 0x14033B580 - {"_meth_8519", 0x8519}, // SP 0x000000000 MP 0x140376990 - {"_meth_851A", 0x851A}, // SP 0x140261370 MP 0x14032C9D0 - {"_meth_851B", 0x851B}, // SP 0x14029F3C0 MP 0x14036EEC0 - {"_meth_851C", 0x851C}, // SP 0x14028E830 MP 0x14036E3D0 - {"_meth_851D", 0x851D}, // SP 0x1402B4480 MP 0x140380300 - {"_meth_851E", 0x851E}, // SP 0x14028A8B0 MP 0x000000000 - {"_meth_851F", 0x851F}, // SP 0x000000000 MP 0x140333EE0 - {"_meth_8520", 0x8520}, // SP 0x000000000 MP 0x14044EEC0 - {"_meth_8521", 0x8521}, // SP 0x140263930 MP 0x000000000 - {"_meth_8522", 0x8522}, // SP 0x000000000 MP 0x140332340 - {"_meth_8523", 0x8523}, // SP 0x1405D92F0 MP 0x140358DC0 - {"_meth_8524", 0x8524}, // SP 0x14028DDD0 MP 0x140359FE0 - {"_meth_8525", 0x8525}, // SP 0x000000000 MP 0x140374C50 - {"_meth_8526", 0x8526}, // SP 0x000000000 MP 0x140374CF0 - {"_meth_8527", 0x8527}, // SP 0x14026DD20 MP 0x14033BC70 - {"_meth_8528", 0x8528}, // SP 0x000000000 MP 0x140332E80 - {"_meth_8529", 0x8529}, // SP 0x14028F7C0 MP 0x14035C9C0 - {"_meth_852A", 0x852A}, // SP 0x140297EF0 MP 0x14035F080 - {"_meth_852B", 0x852B}, // SP 0x000000000 MP 0x140332AD0 - {"_meth_852C", 0x852C}, // SP 0x000000000 MP 0x140331F50 - {"_meth_852D", 0x852D}, // SP 0x14028E830 MP 0x14035B7E0 - {"_meth_852E", 0x852E}, // SP 0x000000000 MP 0x140376A60 - {"_meth_852F", 0x852F}, // SP 0x000000000 MP 0x1404508B0 - {"_meth_8530", 0x8530}, // SP 0x000000000 MP 0x14044F1E0 - {"_meth_8531", 0x8531}, // SP 0x000000000 MP 0x1404503F0 - {"_meth_8532", 0x8532}, // SP 0x000000000 MP 0x140333250 - {"_meth_8533", 0x8533}, // SP 0x000000000 MP 0x14044EC20 - {"_meth_8534", 0x8534}, // SP 0x000000000 MP 0x140450670 - {"_meth_8535", 0x8535}, // SP 0x000000000 MP 0x14044FD10 - {"_meth_8536", 0x8536}, // SP 0x000000000 MP 0x1404504B0 - {"_meth_8537", 0x8537}, // SP 0x000000000 MP 0x1404502E0 - {"_meth_8538", 0x8538}, // SP 0x000000000 MP 0x1404506F0 - {"_meth_8539", 0x8539}, // SP 0x000000000 MP 0x140333F40 - {"_meth_853A", 0x853A}, // SP 0x000000000 MP 0x14037F320 - {"_meth_853B", 0x853B}, // SP 0x000000000 MP 0x14044E080 - {"_meth_853C", 0x853C}, // SP 0x14028F0D0 MP 0x14035BF40 - {"_meth_853D", 0x853D}, // SP 0x14028E830 MP 0x14032CCA0 - {"_meth_853E", 0x853E}, // SP 0x000000000 MP 0x140376AC0 - {"_meth_853F", 0x853F}, // SP 0x000000000 MP 0x14044DFF0 - {"_meth_8540", 0x8540}, // SP 0x140299D70 MP 0x140363160 - {"_meth_8541", 0x8541}, // SP 0x14028F260 MP 0x14035C380 - {"_meth_8542", 0x8542}, // SP 0x000000000 MP 0x140376C00 - {"_meth_8543", 0x8543}, // SP 0x000000000 MP 0x140375800 - {"_meth_8544", 0x8544}, // SP 0x000000000 MP 0x14044FA10 - {"_meth_8545", 0x8545}, // SP 0x000000000 MP 0x140333640 - {"_meth_8547", 0x8547}, // SP 0x000000000 MP 0x140450C20 - {"_meth_8548", 0x8548}, // SP 0x140262130 MP 0x14032DF00 - {"_meth_8549", 0x8549}, // SP 0x000000000 MP 0x140333FA0 - {"_meth_854A", 0x854A}, // SP 0x000000000 MP 0x140376C90 - {"_meth_854B", 0x854B}, // SP 0x000000000 MP 0x14044FBA0 - {"_meth_854C", 0x854C}, // SP 0x000000000 MP 0x1403331F0 - {"_meth_854D", 0x854D}, // SP 0x140290CE0 MP 0x14035C300 - {"_meth_854E", 0x854E}, // SP 0x000000000 MP 0x140450A10 - {"_meth_854F", 0x854F}, // SP 0x000000000 MP 0x14044FC10 - {"_meth_8550", 0x8550}, // SP 0x1402B4720 MP 0x1403809E0 - {"_meth_8551", 0x8551}, // SP 0x1402A15D0 MP 0x14035FB60 - {"_meth_8552", 0x8552}, // SP 0x000000000 MP 0x140450C30 - {"_meth_8553", 0x8553}, // SP 0x000000000 MP 0x140375E30 - {"_meth_8554", 0x8554}, // SP 0x000000000 MP 0x14044F3F0 - {"_meth_8555", 0x8555}, // SP 0x000000000 MP 0x140450D30 - {"_meth_8556", 0x8556}, // SP 0x000000000 MP 0x140374980 - {"_meth_8557", 0x8557}, // SP 0x000000000 MP 0x1403749D0 - {"_meth_8558", 0x8558}, // SP 0x000000000 MP 0x140078140 - {"_meth_8559", 0x8559}, // SP 0x1405D92F0 MP 0x14032D760 - {"_meth_855A", 0x855A}, // SP 0x1405D92F0 MP 0x14032D770 - {"_meth_855B", 0x855B}, // SP 0x1405D92F0 MP 0x14032D7F0 - {"_meth_855C", 0x855C}, // SP 0x000000000 MP 0x140376CB0 - {"_meth_855D", 0x855D}, // SP 0x1402A0220 MP 0x1403585F0 - {"_meth_855E", 0x855E}, // SP 0x140293780 MP 0x14035E8C0 - {"_meth_855F", 0x855F}, // SP 0x000000000 MP 0x140374EC0 - {"_meth_8560", 0x8560}, // SP 0x000000000 MP 0x140374F70 - {"_meth_8561", 0x8561}, // SP 0x140292D90 MP 0x14035FB10 - {"_meth_8562", 0x8562}, // SP 0x140293080 MP 0x14035FD80 - {"_meth_8563", 0x8563}, // SP 0x1402B2FB0 MP 0x14037EF00 - {"_meth_8564", 0x8564}, // SP 0x1402CBB60 MP 0x14031F610 - {"_meth_8565", 0x8565}, // SP 0x1402478E0 MP 0x000000000 - {"_meth_8566", 0x8566}, // SP 0x1402A8F10 MP 0x000000000 - {"_meth_8567", 0x8567}, // SP 0x140248F70 MP 0x000000000 - {"_meth_8568", 0x8568}, // SP 0x1402A3820 MP 0x14036E3F0 - {"_meth_8569", 0x8569}, // SP 0x1402982F0 MP 0x140363510 - {"_meth_856A", 0x856A}, // SP 0x1402984C0 MP 0x140363630 - {"_meth_856B", 0x856B}, // SP 0x140296FA0 MP 0x1403619C0 - {"_meth_856C", 0x856C}, // SP 0x140297420 MP 0x140361BA0 - {"_meth_856D", 0x856D}, // SP 0x140297640 MP 0x140361E60 - {"_meth_856E", 0x856E}, // SP 0x14028ABF0 MP 0x000000000 - {"_meth_856F", 0x856F}, // SP 0x14028AC10 MP 0x000000000 - {"_meth_8570", 0x8570}, // SP 0x14028AC60 MP 0x000000000 - {"_meth_8571", 0x8571}, // SP 0x140249010 MP 0x000000000 - {"_meth_8572", 0x8572}, // SP 0x14024AE00 MP 0x000000000 - {"_meth_8573", 0x8573}, // SP 0x140260B70 MP 0x14032C5C0 - {"_meth_8574", 0x8574}, // SP 0x140265AD0 MP 0x140329B40 - {"_meth_8575", 0x8575}, // SP 0x140265C90 MP 0x140329E40 - {"_meth_8576", 0x8576}, // SP 0x000000000 MP 0x140478050 - {"_meth_8577", 0x8577}, // SP 0x000000000 MP 0x140333650 - {"_meth_8578", 0x8578}, // SP 0x140297D90 MP 0x14035FFF0 - {"_meth_8579", 0x8579}, // SP 0x1402933D0 MP 0x14035FF90 - {"_meth_857A", 0x857A}, // SP 0x000000000 MP 0x1403336F0 - {"_meth_857B", 0x857B}, // SP 0x000000000 MP 0x14032B050 - {"_meth_857C", 0x857C}, // SP 0x1405D92F0 MP 0x14036D0E0 - {"_meth_857D", 0x857D}, // SP 0x000000000 MP 0x140334820 - {"_meth_857E", 0x857E}, // SP 0x000000000 MP 0x1403348E0 - {"_meth_857F", 0x857F}, // SP 0x000000000 MP 0x1403329F0 - }; - - std::unordered_map token_map = - { - {"pl#", 0x001}, - {"-", 0x002}, - {"radius`", 0x003}, - {"note:", 0x004}, - {"_", 0x005}, - {"_custom", 0x006}, - {"a", 0x007}, - {"ability", 0x008}, - {"accumulate", 0x009}, - {"accuracy", 0x00A}, - {"actionslot1", 0x00B}, - {"actionslot2", 0x00C}, - {"actionslot3", 0x00D}, - {"actionslot4", 0x00E}, - {"actionslot5", 0x00F}, - {"actionslot6", 0x010}, - {"actionslot7", 0x011}, - {"actionslot8", 0x012}, - {"activator", 0x013}, - {"active", 0x014}, - {"activecostume", 0x015}, - {"activeemblemslot", 0x016}, - {"activesquadmember", 0x017}, - {"activevisionset", 0x018}, - {"activevisionsetduration", 0x019}, - {"agent", 0x01A}, - {"agenthealth", 0x01B}, - {"agentname", 0x01C}, - {"agentteam", 0x01D}, - {"ai_event", 0x01E}, - {"ai_sight_line_cycle_group", 0x01F}, - {"ai_sight_line_group", 0x020}, - {"aim_highest_bone", 0x021}, - {"aim_vis_bone", 0x022}, - {"aiSpread", 0x023}, - {"aisquadmembers", 0x024}, - {"alert", 0x025}, - {"alertlevel", 0x026}, - {"alertlevelint", 0x027}, - {"alien", 0x028}, - {"alienplayerloadout", 0x029}, - {"alienplayerstats", 0x02A}, - {"aliensession", 0x02B}, - {"alignx", 0x02C}, - {"aligny", 0x02D}, - {"all", 0x02E}, - {"allies", 0x02F}, - {"allowcrouch", 0x030}, - {"allowdeath", 0x031}, - {"allowjump", 0x032}, - {"allowladders", 0x033}, - {"allowpain", 0x034}, - {"allowprone", 0x035}, - {"allstreaksrestricted", 0x036}, - {"alpha", 0x037}, - {"altmode", 0x038}, - {"always", 0x039}, - {"ambient", 0x03A}, - {"ambienttrack", 0x03B}, - {"ambienttrack_ac130", 0x03C}, - {"ambush", 0x03D}, - {"ambush_nodes_only", 0x03E}, - {"angle_deltas", 0x03F}, - {"anglelerprate", 0x040}, - {"angles", 0x041}, - {"anim_angle_delta", 0x042}, - {"anim_deltas", 0x043}, - {"anim_pose", 0x044}, - {"anim_will_finish", 0x045}, - {"animation", 0x046}, - {"animscript", 0x047}, - {"archived", 0x048}, - {"archivetime", 0x049}, - {"armor", 0x04A}, - {"asleep", 0x04B}, - {"aspectratio", 0x04C}, - {"assaultstreaks", 0x04D}, - {"assignedbucket", 0x04E}, - {"assists", 0x04F}, - {"attachment", 0x050}, - {"attachmentclassrestricted", 0x051}, - {"attachmentrestricted", 0x052}, - {"attachments", 0x053}, - {"attachtag", 0x054}, - {"attacker", 0x055}, - {"attackeraccuracy", 0x056}, - {"attackercount", 0x057}, - {"attackerisjuggernaut", 0x058}, - {"attackerpos", 0x059}, - {"author", 0x05A}, - {"auto_ai", 0x05B}, - {"auto_change", 0x05C}, - {"auto_nonai", 0x05D}, - {"avoidanceboundshalfsize", 0x05E}, - {"awards", 0x05F}, - {"axis", 0x060}, - {"b", 0x061}, - {"back", 0x062}, - {"back_left", 0x063}, - {"back_low", 0x064}, - {"back_mid", 0x065}, - {"back_right", 0x066}, - {"back_up", 0x067}, - {"background", 0x068}, - {"bad_guys", 0x069}, - {"bad_path", 0x06A}, - {"badplaceawareness", 0x06B}, - {"ball_off", 0x06C}, - {"ball_on", 0x06D}, - {"ball_pass", 0x06E}, - {"bandwidthdown", 0x06F}, - {"bandwidthtestcount", 0x070}, - {"bandwidthup", 0x071}, - {"baselineoverflow_max", 0x072}, - {"baselineoverflow_worst", 0x073}, - {"battery_discharge_begin", 0x074}, - {"battery_discharge_end", 0x075}, - {"begin", 0x076}, - {"begin_custom_anim", 0x077}, - {"begin_firing", 0x078}, - {"begin_firing_left", 0x079}, - {"bestweapon", 0x07A}, - {"bestweaponindex", 0x07B}, - {"bipods", 0x07C}, - {"birthtime", 0x07D}, - {"bl_rotor1", 0x07E}, - {"bl_rotor2", 0x07F}, - {"bl_rotor3", 0x080}, - {"blackops2prestige", 0x081}, - {"blackops2rank", 0x082}, - {"blade_hide", 0x083}, - {"blade_show", 0x084}, - {"blockfriendlies", 0x085}, - {"blurradius", 0x086}, - {"body", 0x087}, - {"body_animate_jnt", 0x088}, - {"bottomarc", 0x089}, - {"br_rotor1", 0x08A}, - {"br_rotor2", 0x08B}, - {"br_rotor3", 0x08C}, - {"breadcrumbheader", 0x08D}, - {"buff", 0x08E}, - {"bullet_hitshield", 0x08F}, - {"bullethit", 0x090}, - {"bulletwhizby", 0x091}, - {"c", 0x092}, - {"callingcardindex", 0x093}, - {"camo", 0x094}, - {"cancel_location", 0x095}, - {"canclimbladders", 0x096}, - {"canjumppath", 0x097}, - {"cardicon", 0x098}, - {"cardnameplate", 0x099}, - {"cardtitle", 0x09A}, - {"cgmchecksum", 0x09B}, - {"ch_prestige", 0x09C}, - {"ch_prestige_max", 0x09D}, - {"chainfallback", 0x09E}, - {"chainnode", 0x09F}, - {"challengeprogress", 0x0A0}, - {"challengestate", 0x0A1}, - {"chest", 0x0A2}, - {"churnscores", 0x0A3}, - {"chyron_message1", 0x0A4}, - {"chyron_message2", 0x0A5}, - {"chyron_message3", 0x0A6}, - {"civilian", 0x0A7}, - {"clanidhigh", 0x0A8}, - {"clanidlow", 0x0A9}, - {"classname", 0x0AA}, - {"clipdistance", 0x0AB}, - {"code_classname", 0x0AC}, - {"code_damageradius", 0x0AD}, - {"code_move", 0x0AE}, - {"code_move_slide", 0x0AF}, - {"codecallback_agentadded", 0x0B0}, - {"codecallback_agentdamaged", 0x0B1}, - {"codecallback_agentkilled", 0x0B2}, - {"codecallback_bullethitentity", 0x0B3}, - {"codecallback_codeendgame", 0x0B4}, - {"codecallback_entitydamage", 0x0B5}, - {"codecallback_entityoutofworld", 0x0B6}, - {"codecallback_handleinstantmessage", 0x0B7}, - {"codecallback_hostmigration", 0x0B8}, - {"codecallback_leaderdialog", 0x0B9}, - {"codecallback_partymembers", 0x0BA}, - {"codecallback_playerconnect", 0x0BB}, - {"codecallback_playerdamage", 0x0BC}, - {"codecallback_playerdisconnect", 0x0BD}, - {"codecallback_playergrenadesuicide", 0x0BE}, - {"codecallback_playerkilled", 0x0BF}, - {"codecallback_playerlaststand", 0x0C0}, - {"codecallback_playermigrated", 0x0C1}, - {"codecallback_startgametype", 0x0C2}, - {"codecallback_vehicledamage", 0x0C3}, - {"color", 0x0C4}, - {"color_blind_toggled", 0x0C5}, - {"combat", 0x0C6}, - {"combatmode", 0x0C7}, - {"combatrecord", 0x0C8}, - {"commonoption", 0x0C9}, - {"confirm_location", 0x0CA}, - {"connection_id", 0x0CB}, - {"connectionidchunkhigh", 0x0CC}, - {"connectionidchunklow", 0x0CD}, - {"consolegame", 0x0CE}, - {"consoleidchunkhigh", 0x0CF}, - {"consoleidchunklow", 0x0D0}, - {"constrained", 0x0D1}, - {"contact", 0x0D2}, - {"contextleanenabled", 0x0D3}, - {"convergencetime", 0x0D4}, - {"coopactivesquadmember", 0x0D5}, - {"coopsquadmembers", 0x0D6}, - {"costumes", 0x0D7}, - {"count", 0x0D8}, - {"cover", 0x0D9}, - {"cover_approach", 0x0DA}, - {"coversearchinterval", 0x0DB}, - {"createstruct", 0x0DC}, - {"createtime", 0x0DD}, - {"criticalbulletdamagedist", 0x0DE}, - {"crouch", 0x0DF}, - {"currency", 0x0E0}, - {"current", 0x0E1}, - {"currentanimtime", 0x0E2}, - {"currentgen", 0x0E3}, - {"currentwinstreak", 0x0E4}, - {"cursorhint", 0x0E5}, - {"custom_attach_00", 0x0E6}, - {"custom_attach_01", 0x0E7}, - {"custom_attach_02", 0x0E8}, - {"custom_attach_03", 0x0E9}, - {"custom_attach_04", 0x0EA}, - {"custom_attach_05", 0x0EB}, - {"custom_attach_06", 0x0EC}, - {"custom_attach_07", 0x0ED}, - {"custom_attach_08", 0x0EE}, - {"custom_attach_09", 0x0EF}, - {"custom_attach_10", 0x0F0}, - {"custom_attach_11", 0x0F1}, - {"custom_attach_12", 0x0F2}, - {"custom_attach_13", 0x0F3}, - {"custom_attach_14", 0x0F4}, - {"custom_attach_15", 0x0F5}, - {"customclasses", 0x0F6}, - {"customization_loaded", 0x0F7}, - {"d", 0x0F8}, - {"dailychallengeid", 0x0F9}, - {"damage", 0x0FA}, - {"damage_notdone", 0x0FB}, - {"damagedir", 0x0FC}, - {"damagelocation", 0x0FD}, - {"damagemod", 0x0FE}, - {"damagemultiplier", 0x0FF}, - {"damageshield", 0x100}, - {"damagetaken", 0x101}, - {"damageweapon", 0x102}, - {"damageyaw", 0x103}, - {"dangerreactduration", 0x104}, - {"datalength", 0x105}, - {"dcid", 0x106}, - {"dead", 0x107}, - {"death", 0x108}, - {"deathangles", 0x109}, - {"deathinvulnerabletime", 0x10A}, - {"deathplant", 0x10B}, - {"deathpos", 0x10C}, - {"deaths", 0x10D}, - {"deathshield", 0x10E}, - {"defaultclasses", 0x10F}, - {"defense", 0x110}, - {"defense_level", 0x111}, - {"delayeddeath", 0x112}, - {"deploy_riotshield", 0x113}, - {"desc", 0x114}, - {"descmodified", 0x115}, - {"desiredangle", 0x116}, - {"destructible_type", 0x117}, - {"detectable", 0x118}, - {"detected", 0x119}, - {"detonate", 0x11A}, - {"device_id_high", 0x11B}, - {"device_id_low", 0x11C}, - {"deviceconnectionhistory", 0x11D}, - {"deviceusefrequency", 0x11E}, - {"diequietly", 0x11F}, - {"diffusefraction", 0x120}, - {"direct", 0x121}, - {"disable", 0x122}, - {"disableplayeradsloscheck", 0x123}, - {"dlight", 0x124}, - {"dmg", 0x125}, - {"dodamagetoall", 0x126}, - {"dodangerreact", 0x127}, - {"doffar", 0x128}, - {"dofnear", 0x129}, - {"dofphysicalfocusdistance", 0x12A}, - {"dofphysicalfstop", 0x12B}, - {"dog", 0x12C}, - {"doghandler", 0x12D}, - {"doingambush", 0x12E}, - {"done", 0x12F}, - {"dontavoidplayer", 0x130}, - {"dotofdeath", 0x131}, - {"down", 0x132}, - {"downaimlimit", 0x133}, - {"drawoncompass", 0x134}, - {"dropweapon", 0x135}, - {"duration", 0x136}, - {"eftarc", 0x137}, - {"empty", 0x138}, - {"empty_offhand", 0x139}, - {"enable", 0x13A}, - {"enablehudlighting", 0x13B}, - {"enableshadows", 0x13C}, - {"end_firing", 0x13D}, - {"end_firing_left", 0x13E}, - {"end_script", 0x13F}, - {"enddeaths", 0x140}, - {"endkills", 0x141}, - {"enemy", 0x142}, - {"enemy_sighted", 0x143}, - {"enemy_sighted_lost", 0x144}, - {"enemy_visible", 0x145}, - {"enemyname", 0x146}, - {"enemyplatform", 0x147}, - {"enemyradarmode", 0x148}, - {"enemyxuidhigh", 0x149}, - {"enemyxuidlow", 0x14A}, - {"energy_fire", 0x14B}, - {"engagemaxdist", 0x14C}, - {"engagemaxfalloffdist", 0x14D}, - {"engagemindist", 0x14E}, - {"engageminfalloffdist", 0x14F}, - {"enhanceable", 0x150}, - {"entity", 0x151}, - {"entitydeleted", 0x152}, - {"entityoverflow_max", 0x153}, - {"entityoverflow_worst", 0x154}, - {"equipment", 0x155}, - {"equipmentsetups", 0x156}, - {"escaped", 0x157}, - {"exclusive", 0x158}, - {"exo_ability_activate", 0x159}, - {"exo_adrenaline_fire", 0x15A}, - {"exo_boost", 0x15B}, - {"exo_dodge", 0x15C}, - {"exo_power", 0x15D}, - {"exo_slide", 0x15E}, - {"exo_slide_hit_player", 0x15F}, - {"exoattachment1", 0x160}, - {"exoattachment2", 0x161}, - {"experience", 0x162}, - {"explode", 0x163}, - {"exposedduration", 0x164}, - {"extracustomclassesentitlement", 0x165}, - {"extracustomclassesprestige", 0x166}, - {"extrascore0", 0x167}, - {"extrascore1", 0x168}, - {"face_angle", 0x169}, - {"face_angle_3d", 0x16A}, - {"face_angle_abs", 0x16B}, - {"face_angle_rel", 0x16C}, - {"face_current", 0x16D}, - {"face_default", 0x16E}, - {"face_direction", 0x16F}, - {"face_enemy", 0x170}, - {"face_enemy_or_motion", 0x171}, - {"face_goal", 0x172}, - {"face_motion", 0x173}, - {"face_point", 0x174}, - {"facemotion", 0x175}, - {"failed", 0x176}, - {"falling", 0x177}, - {"fast_radar", 0x178}, - {"favoriteenemy", 0x179}, - {"finalaccuracy", 0x17A}, - {"first_person", 0x17B}, - {"firstplayedsptime", 0x17C}, - {"fixednode", 0x17D}, - {"fixednodesaferadius", 0x17E}, - {"fl_rotor1", 0x17F}, - {"fl_rotor2", 0x180}, - {"fl_rotor3", 0x181}, - {"flash", 0x182}, - {"flashbang", 0x183}, - {"foley", 0x184}, - {"follow", 0x185}, - {"followmax", 0x186}, - {"followmin", 0x187}, - {"font", 0x188}, - {"fontscale", 0x189}, - {"foot_ik_active", 0x18A}, - {"foot_ik_blend_in", 0x18B}, - {"foot_ik_blend_out", 0x18C}, - {"foot_ik_inactive", 0x18D}, - {"footstepdetectdist", 0x18E}, - {"footstepdetectdistsprint", 0x18F}, - {"footstepdetectdistwalk", 0x190}, - {"force_off", 0x191}, - {"force_on", 0x192}, - {"force_fully_on", 0x193}, - {"forcepartyskillignore", 0x194}, - {"forceragdollimmediate", 0x195}, - {"forcespectatorclient", 0x196}, - {"foregrip_off", 0x197}, - {"foreground", 0x198}, - {"forward", 0x199}, - {"fov", 0x19A}, - {"fovcosine", 0x19B}, - {"fovcosinebusy", 0x19C}, - {"fovcosinez", 0x19D}, - {"fr_rotor1", 0x19E}, - {"fr_rotor2", 0x19F}, - {"fr_rotor3", 0x1A0}, - {"fraction", 0x1A1}, - {"frag", 0x1A2}, - {"free", 0x1A3}, - {"freecamera", 0x1A4}, - {"freelook", 0x1A5}, - {"frequency", 0x1A6}, - {"friendlyfire", 0x1A7}, - {"front_left", 0x1A8}, - {"front_right", 0x1A9}, - {"frontshieldanglecos", 0x1AA}, - {"fs_concrete", 0x1AB}, - {"fs_dirt", 0x1AC}, - {"fs_metal", 0x1AD}, - {"fs_wood", 0x1AE}, - {"game_extrainfo", 0x1AF}, - {"gamecount", 0x1B0}, - {"gamertag", 0x1B1}, - {"gamesplayed", 0x1B2}, - {"gametype", 0x1B3}, - {"gender", 0x1B4}, - {"ghostsprestige", 0x1B5}, - {"ghostsrank", 0x1B6}, - {"glass", 0x1B7}, - {"glass_damaged", 0x1B8}, - {"glass_destroyed", 0x1B9}, - {"globalcostume", 0x1BA}, - {"gloves", 0x1BB}, - {"glowalpha", 0x1BC}, - {"glowcolor", 0x1BD}, - {"goal", 0x1BE}, - {"goal_changed", 0x1BF}, - {"goal_reached", 0x1C0}, - {"goal_yaw", 0x1C1}, - {"goalheight", 0x1C2}, - {"goalpos", 0x1C3}, - {"goalradius", 0x1C4}, - {"goaltime", 0x1C5}, - {"goalweight", 0x1C6}, - {"goingtoruntopos", 0x1C7}, - {"gravity", 0x1C8}, - {"gravity_noclip", 0x1C9}, - {"grenade", 0x1CA}, - {"grenade_fire", 0x1CB}, - {"grenade_off", 0x1CC}, - {"grenade_on", 0x1CD}, - {"grenade_pullback", 0x1CE}, - {"grenade_return_hand_tag", 0x1CF}, - {"grenadeammo", 0x1D0}, - {"grenadeawareness", 0x1D1}, - {"grenadedanger", 0x1D2}, - {"grenadeweapon", 0x1D3}, - {"ground_slam", 0x1D4}, - {"ground_slam_hit_player", 0x1D5}, - {"groundentchanged", 0x1D6}, - {"groundtype", 0x1D7}, - {"gunblockedbywall", 0x1D8}, - {"gunshot", 0x1D9}, - {"gunshot_teammate", 0x1DA}, - {"hardcoremodeon", 0x1DB}, - {"hasdoublexpitem", 0x1DC}, - {"hasradar", 0x1DD}, - {"hasvalidcostumeselfieimage", 0x1DE}, - {"head", 0x1DF}, - {"headicon", 0x1E0}, - {"headiconteam", 0x1E1}, - {"headshots", 0x1E2}, - {"health", 0x1E3}, - {"healthregen", 0x1E4}, - {"height", 0x1E5}, - {"helmet", 0x1E6}, - {"hidein3rdperson", 0x1E7}, - {"hidewhendead", 0x1E8}, - {"hidewhenindemo", 0x1E9}, - {"hidewheninmenu", 0x1EA}, - {"high_priority", 0x1EB}, - {"highlyawareradius", 0x1EC}, - {"hindlegstraceoffset", 0x1ED}, - {"hintstring", 0x1EE}, - {"hit_by_missile", 0x1EF}, - {"horzalign", 0x1F0}, - {"host_sucks_end_game", 0x1F1}, - {"hostfailures", 0x1F2}, - {"hostquits", 0x1F3}, - {"hostsuccesses", 0x1F4}, - {"human", 0x1F5}, - {"iconnew", 0x1F6}, - {"iconunlocked", 0x1F7}, - {"ignoreall", 0x1F8}, - {"ignoreclosefoliage", 0x1F9}, - {"ignoreexplosionevents", 0x1FA}, - {"ignoreforfixednodesafecheck", 0x1FB}, - {"ignoreme", 0x1FC}, - {"ignorerandombulletdamage", 0x1FD}, - {"ignoresuppression", 0x1FE}, - {"ignoretriggers", 0x1FF}, - {"ikweight", 0x200}, - {"index", 0x201}, - {"infinite_energy", 0x202}, - {"info_notnull", 0x203}, - {"info_player_start", 0x204}, - {"init", 0x205}, - {"initstructs", 0x206}, - {"insolid", 0x207}, - {"intermission", 0x208}, - {"interval", 0x209}, - {"inuse", 0x20A}, - {"invalid_parent", 0x20B}, - {"invisible", 0x20C}, - {"isradarblocked", 0x20D}, - {"item", 0x20E}, - {"j_exo_rcket_arm02", 0x20F}, - {"j_exoclav04_l", 0x210}, - {"j_exoclav04_r", 0x211}, - {"j_exohip04_l", 0x212}, - {"j_exohip04_r", 0x213}, - {"j_eyeball_le", 0x214}, - {"j_eyeball_ri", 0x215}, - {"j_gun", 0x216}, - {"j_head", 0x217}, - {"j_hip_l", 0x218}, - {"j_hip_r", 0x219}, - {"j_knee_le", 0x21A}, - {"j_knee_ri", 0x21B}, - {"j_left_elbow", 0x21C}, - {"j_left_hand", 0x21D}, - {"j_left_shoulder", 0x21E}, - {"j_mainroot", 0x21F}, - {"j_neck", 0x220}, - {"j_right_elbow", 0x221}, - {"j_right_hand", 0x222}, - {"j_right_hand_placement", 0x223}, - {"j_right_shoulder", 0x224}, - {"j_rocket", 0x225}, - {"j_spine4", 0x226}, - {"j_spinelower", 0x227}, - {"j_spineupper", 0x228}, - {"jumpcost", 0x229}, - {"jumping", 0x22A}, - {"justclass", 0x22B}, - {"kdratio", 0x22C}, - {"keepclaimednode", 0x22D}, - {"keepclaimednodeifvalid", 0x22E}, - {"keepnodeduringscriptedanim", 0x22F}, - {"key1", 0x230}, - {"key2", 0x231}, - {"kill_timestamp", 0x232}, - {"killanimscript", 0x233}, - {"killcamentity", 0x234}, - {"killcamentitylookat", 0x235}, - {"kills", 0x236}, - {"killstreak", 0x237}, - {"killstreakcount", 0x238}, - {"killstreakrestricted", 0x239}, - {"killstreakunlocked", 0x23A}, - {"knife_off", 0x23B}, - {"knife_on", 0x23C}, - {"known_event", 0x23D}, - {"label", 0x23E}, - {"ladder_down", 0x23F}, - {"ladder_up", 0x240}, - {"land", 0x241}, - {"last_stand_count", 0x242}, - {"lastattacker", 0x243}, - {"lastenemysightpos", 0x244}, - {"lastplayedtime", 0x245}, - {"laststand", 0x246}, - {"leanamount", 0x247}, - {"ledge", 0x248}, - {"left", 0x249}, - {"leftaimlimit", 0x24A}, - {"leftarc", 0x24B}, - {"lethal", 0x24C}, - {"lifecount", 0x24D}, - {"light", 0x24E}, - {"lives", 0x24F}, - {"loadouts", 0x250}, - {"lockorientation", 0x251}, - {"lod", 0x252}, - {"look", 0x253}, - {"lookahead", 0x254}, - {"lookaheaddir", 0x255}, - {"lookaheaddist", 0x256}, - {"lookaheadhitsstairs", 0x257}, - {"lookforward", 0x258}, - {"lookright", 0x259}, - {"looktarget", 0x25A}, - {"lookup", 0x25B}, - {"loot", 0x25C}, - {"lootnew", 0x25D}, - {"loses", 0x25E}, - {"low_priority", 0x25F}, - {"lowresbackground", 0x260}, - {"luinotifyserver", 0x261}, - {"mag_eject", 0x262}, - {"mag_eject_left", 0x263}, - {"main", 0x264}, - {"manual", 0x265}, - {"manual_ai", 0x266}, - {"manual_change", 0x267}, - {"map", 0x268}, - {"matchid", 0x269}, - {"matchmakingsettingsversion", 0x26A}, - {"matchmakingtesttype", 0x26B}, - {"max_time", 0x26C}, - {"maxfaceenemydist", 0x26D}, - {"maxhealth", 0x26E}, - {"maxrange", 0x26F}, - {"maxsightdistsqrd", 0x270}, - {"maxturnspeed", 0x271}, - {"maxvisibledist", 0x272}, - {"melee_fired", 0x273}, - {"melee_hit_react", 0x274}, - {"meleeattackdist", 0x275}, - {"menuresponse", 0x276}, - {"micro_dlc_bits_last_gen", 0x277}, - {"micro_dlc_bits_next_gen", 0x278}, - {"middle_left", 0x279}, - {"middle_right", 0x27A}, - {"migrateablequits", 0x27B}, - {"min_energy", 0x27C}, - {"min_time", 0x27D}, - {"minpaindamage", 0x27E}, - {"minusedistsq", 0x27F}, - {"missile_fire", 0x280}, - {"missile_passed_target", 0x281}, - {"missile_stuck", 0x282}, - {"mlgversion", 0x283}, - {"mod", 0x284}, - {"mod_crush", 0x285}, - {"mod_energy", 0x286}, - {"mod_explosive", 0x287}, - {"mod_explosive_bullet", 0x288}, - {"mod_falling", 0x289}, - {"mod_grenade", 0x28A}, - {"mod_grenade_splash", 0x28B}, - {"mod_head_shot", 0x28C}, - {"mod_impact", 0x28D}, - {"mod_melee", 0x28E}, - {"mod_melee_alien", 0x28F}, - {"mod_melee_alt", 0x290}, - {"mod_melee_dog", 0x291}, - {"mod_pistol_bullet", 0x292}, - {"mod_projectile", 0x293}, - {"mod_projectile_splash", 0x294}, - {"mod_rifle_bullet", 0x295}, - {"mod_suicide", 0x296}, - {"mod_trigger_hurt", 0x297}, - {"mod_unknown", 0x298}, - {"model", 0x299}, - {"modeprefix", 0x29A}, - {"modifiers", 0x29B}, - {"motiontrackerenabled", 0x29C}, - {"mounted_dlc_bits", 0x29D}, - {"movedone", 0x29E}, - {"movemode", 0x29F}, - {"munition", 0x2A0}, - {"munition_level", 0x2A1}, - {"mw3prestige", 0x2A2}, - {"mw3rank", 0x2A3}, - {"name", 0x2A4}, - {"namemodified", 0x2A5}, - {"near_goal", 0x2A6}, - {"nearz", 0x2A7}, - {"neutral", 0x2A8}, - {"never", 0x2A9}, - {"newenemyreactiondistsq", 0x2AA}, - {"newentitlement", 0x2AB}, - {"nextgen", 0x2AC}, - {"nextreadblackops2", 0x2AD}, - {"nextreadghosts0", 0x2AE}, - {"nextreadghosts1", 0x2AF}, - {"nextreadmw3", 0x2B0}, - {"night_vision_off", 0x2B1}, - {"night_vision_on", 0x2B2}, - {"no_bot_random_path", 0x2B3}, - {"no_cover", 0x2B4}, - {"no_gravity", 0x2B5}, - {"noattackeraccuracymod", 0x2B6}, - {"noclip", 0x2B7}, - {"node", 0x2B8}, - {"node_not_safe", 0x2B9}, - {"node_out_of_range", 0x2BA}, - {"node_relinquished", 0x2BB}, - {"node_taken", 0x2BC}, - {"nodeoffsetpos", 0x2BD}, - {"nododgemove", 0x2BE}, - {"nogravity", 0x2BF}, - {"nogrenadereturnthrow", 0x2C0}, - {"noncombat", 0x2C1}, - {"none", 0x2C2}, - {"nonmigrateablequits", 0x2C3}, - {"nophysics", 0x2C4}, - {"normal", 0x2C5}, - {"normal_radar", 0x2C6}, - {"northyaw", 0x2C7}, - {"notifyname", 0x2C8}, - {"notinsolid", 0x2C9}, - {"num0", 0x2CA}, - {"num1", 0x2CB}, - {"num2", 0x2CC}, - {"num3", 0x2CD}, - {"num4", 0x2CE}, - {"objective", 0x2CF}, - {"obstacle", 0x2D0}, - {"offense", 0x2D1}, - {"offense_level", 0x2D2}, - {"offhand", 0x2D3}, - {"offhand_end", 0x2D4}, - {"offhandweapon", 0x2D5}, - {"oldtime", 0x2D6}, - {"ondeactivate", 0x2D7}, - {"onenterstate", 0x2D8}, - {"only_sky", 0x2D9}, - {"onlygoodnearestnodes", 0x2DA}, - {"onwifi", 0x2DB}, - {"operationsdeadline", 0x2DC}, - {"oriented", 0x2DD}, - {"orientto_complete", 0x2DE}, - {"origin", 0x2DF}, - {"other", 0x2E0}, - {"over", 0x2E1}, - {"owner", 0x2E2}, - {"pacifist", 0x2E3}, - {"pacifistwait", 0x2E4}, - {"pain", 0x2E5}, - {"pantssize", 0x2E6}, - {"parentindex", 0x2E7}, - {"parentname", 0x2E8}, - {"partyid", 0x2E9}, - {"pasttitledata", 0x2EA}, - {"patch", 0x2EB}, - {"patchbacking", 0x2EC}, - {"path_blocked", 0x2ED}, - {"path_changed", 0x2EE}, - {"path_dir_change", 0x2EF}, - {"path_enemy", 0x2F0}, - {"path_need_dodge", 0x2F1}, - {"path_set", 0x2F2}, - {"pathenemyfightdist", 0x2F3}, - {"pathenemylookahead", 0x2F4}, - {"pathgoalpos", 0x2F5}, - {"pathlookaheaddist", 0x2F6}, - {"pathrandompercent", 0x2F7}, - {"pc", 0x2F8}, - {"pccg", 0x2F9}, - {"pelvis", 0x2FA}, - {"perk1", 0x2FB}, - {"perk2", 0x2FC}, - {"perk3", 0x2FD}, - {"perk4", 0x2FE}, - {"perk5", 0x2FF}, - {"perk6", 0x300}, - {"perkclassrestricted", 0x301}, - {"perkrestricted", 0x302}, - {"perks", 0x303}, - {"perkslots", 0x304}, - {"pers", 0x305}, - {"persistentperksunlocked", 0x306}, - {"persistentweaponsunlocked", 0x307}, - {"phone_off", 0x308}, - {"phone_on", 0x309}, - {"physics_finished", 0x30A}, - {"physics_impact", 0x30B}, - {"pickup", 0x30C}, - {"pickup_riotshield", 0x30D}, - {"pistol", 0x30E}, - {"pitchamount", 0x30F}, - {"pitchconvergencetime", 0x310}, - {"plane_waypoint", 0x311}, - {"playedblackops2", 0x312}, - {"playedghosts", 0x313}, - {"playedmw3", 0x314}, - {"player", 0x315}, - {"player_controller", 0x316}, - {"player_pushed", 0x317}, - {"playercardbackground", 0x318}, - {"playercardpatch", 0x319}, - {"playercardpatchbacking", 0x31A}, - {"playerconnectionhistory", 0x31B}, - {"playerid", 0x31C}, - {"playerip", 0x31D}, - {"playername", 0x31E}, - {"playerpositions", 0x31F}, - {"players", 0x320}, - {"playerSpread", 0x321}, - {"playerxuidhigh", 0x322}, - {"playerxuidlow", 0x323}, - {"playing", 0x324}, - {"points", 0x325}, - {"position", 0x326}, - {"positioninworld", 0x327}, - {"postsharpturnlookaheaddist", 0x328}, - {"precache", 0x329}, - {"predicted_projectile_impact", 0x32A}, - {"prestige", 0x32B}, - {"prestigedoublexp", 0x32C}, - {"prestigedoublexpmaxtimeplayed", 0x32D}, - {"prestigeshoptokens", 0x32E}, - {"prestigeshoptokensentitlement", 0x32F}, - {"prevanimdelta", 0x330}, - {"prevnode", 0x331}, - {"prevscript", 0x332}, - {"primary", 0x333}, - {"primaryattachment1", 0x334}, - {"primaryattachment2", 0x335}, - {"primaryattachment3", 0x336}, - {"primaryattachments", 0x337}, - {"primaryattachkit", 0x338}, - {"primarycamo", 0x339}, - {"primaryfurniturekit", 0x33A}, - {"primaryoffhand", 0x33B}, - {"primaryreticle", 0x33C}, - {"primaryweapon", 0x33D}, - {"privatematchactivesquadmember", 0x33E}, - {"privatematchcustomclasses", 0x33F}, - {"privatematchsquadmembers", 0x340}, - {"projectile_impact", 0x341}, - {"projectile_impact_player", 0x342}, - {"prone", 0x343}, - {"proneok", 0x344}, - {"providecoveringfire", 0x345}, - {"ps3", 0x346}, - {"ps4", 0x347}, - {"psoffsettime", 0x348}, - {"pushable", 0x349}, - {"radaralwayson", 0x34A}, - {"radarmode", 0x34B}, - {"radarshowenemydirection", 0x34C}, - {"radarstrength", 0x34D}, - {"radius", 0x34E}, - {"ragdoll_early_result", 0x34F}, - {"raise_riotshield", 0x350}, - {"rank", 0x351}, - {"rate", 0x352}, - {"reached_end_node", 0x353}, - {"reached_wait_node", 0x354}, - {"reached_wait_speed", 0x355}, - {"reactiontargetpos", 0x356}, - {"realtimedelta", 0x357}, - {"receiver", 0x358}, - {"recipename", 0x359}, - {"reciprocality", 0x35A}, - {"reflection_clear_color", 0x35B}, - {"reinforcement", 0x35C}, - {"relativedir", 0x35D}, - {"relativeoffset", 0x35E}, - {"reload", 0x35F}, - {"reload_start", 0x360}, - {"remotemissilespawn", 0x361}, - {"rendertotexture", 0x362}, - {"reportindex", 0x363}, - {"reports", 0x364}, - {"reputation", 0x365}, - {"requestarrivalnotify", 0x366}, - {"requirement_beat100waves", 0x367}, - {"requirement_beat200waves", 0x368}, - {"requirement_beat50waves", 0x369}, - {"requirement_beatenzombies", 0x36A}, - {"requirement_maxarmorproficiency", 0x36B}, - {"requirement_maxweaponproficiency", 0x36C}, - {"requirement_playedallmaps", 0x36D}, - {"requirement_unlockedprison", 0x36E}, - {"requirement_unlockedtier2", 0x36F}, - {"requirement_unlockedtier3", 0x370}, - {"reserved", 0x371}, - {"respawndelay", 0x372}, - {"result", 0x373}, - {"reticle", 0x374}, - {"return_pitch", 0x375}, - {"reverse", 0x376}, - {"revives", 0x377}, - {"right", 0x378}, - {"rightaimlimit", 0x379}, - {"rightarc", 0x37A}, - {"riotshield_damaged", 0x37B}, - {"riotshield_hit", 0x37C}, - {"rocket", 0x37D}, - {"rocket_off", 0x37E}, - {"rocket_on", 0x37F}, - {"rotatedone", 0x380}, - {"rotation", 0x381}, - {"run", 0x382}, - {"runcost", 0x383}, - {"runto_arrived", 0x384}, - {"safetochangescript", 0x385}, - {"scavenger", 0x386}, - {"scope_cap", 0x387}, - {"scope_center", 0x388}, - {"scope_top", 0x389}, - {"score", 0x38A}, - {"script", 0x38B}, - {"script_brushmodel", 0x38C}, - {"script_clut", 0x38D}, - {"script_context", 0x38E}, - {"script_delay", 0x38F}, - {"script_goal_changed", 0x390}, - {"script_label", 0x391}, - {"script_lightset", 0x392}, - {"script_linkname", 0x393}, - {"script_model", 0x394}, - {"script_noteworthy", 0x395}, - {"script_origin", 0x396}, - {"script_parent", 0x397}, - {"script_parentname", 0x398}, - {"script_pushable", 0x399}, - {"script_vehicle", 0x39A}, - {"script_vehicle_collision", 0x39B}, - {"script_vehicle_collmap", 0x39C}, - {"script_vehicle_corpse", 0x39D}, - {"script_visionset", 0x39E}, - {"script_water", 0x39F}, - {"script_reverb", 0x3A0}, - {"script_zone", 0x3A1}, - {"scriptable", 0x3A2}, - {"scriptableactor", 0x3A3}, - {"scripted_viewmodel_anim", 0x3A4}, - {"scriptedarrivalent", 0x3A5}, - {"search_end", 0x3A6}, - {"secondary", 0x3A7}, - {"secondaryattachment1", 0x3A8}, - {"secondaryattachment2", 0x3A9}, - {"secondaryattachments", 0x3AA}, - {"secondaryattachkit", 0x3AB}, - {"secondarycamo", 0x3AC}, - {"secondaryfurniturekit", 0x3AD}, - {"secondaryoffhand", 0x3AE}, - {"secondaryreticle", 0x3AF}, - {"secondaryweapon", 0x3B0}, - {"sentry", 0x3B1}, - {"sentry_manual", 0x3B2}, - {"sentry_offline", 0x3B3}, - {"servertimecount", 0x3B4}, - {"servertimeexceedcount", 0x3B5}, - {"servertimemax", 0x3B6}, - {"servertimetotal", 0x3B7}, - {"servertimetotalexceed", 0x3B8}, - {"sessionstate", 0x3B9}, - {"sessionteam", 0x3BA}, - {"sharpturn", 0x3BB}, - {"sharpturnlookaheaddist", 0x3BC}, - {"sharpturnnotifydist", 0x3BD}, - {"sharpturntooclosetodestdist", 0x3BE}, - {"shirt", 0x3BF}, - {"showinkillcam", 0x3C0}, - {"showkillcam", 0x3C1}, - {"sightlatency", 0x3C2}, - {"silenced_shot", 0x3C3}, - {"skill_points", 0x3C4}, - {"skillbucket", 0x3C5}, - {"skillrating", 0x3C6}, - {"skillratingtype", 0x3C7}, - {"slidevelocity", 0x3C8}, - {"slowmo_active", 0x3C9}, - {"slowmo_passive", 0x3CA}, - {"smoke", 0x3CB}, - {"snd_channelvolprio_holdbreath", 0x3CC}, - {"snd_channelvolprio_pain", 0x3CD}, - {"snd_channelvolprio_shellshock", 0x3CE}, - {"snd_enveffectsprio_level", 0x3CF}, - {"snd_enveffectsprio_shellshock", 0x3D0}, - {"sort", 0x3D1}, - {"sound_blend", 0x3D2}, - {"soundeventdone", 0x3D3}, - {"space", 0x3D4}, - {"spawned", 0x3D5}, - {"spawner", 0x3D6}, - {"spawnflags", 0x3D7}, - {"spawnpos", 0x3D8}, - {"spawntime", 0x3D9}, - {"specialgrenade", 0x3DA}, - {"spectatekillcam", 0x3DB}, - {"spectating_cycle", 0x3DC}, - {"spectator", 0x3DD}, - {"speechcommand", 0x3DE}, - {"speed", 0x3DF}, - {"splatter", 0x3E0}, - {"splineplanereachednode", 0x3E1}, - {"sprint_begin", 0x3E2}, - {"sprint_end", 0x3E3}, - {"sprint_slide_begin", 0x3E4}, - {"sprint_slide_end", 0x3E5}, - {"squad_base", 0x3E6}, - {"squad_mode", 0x3E7}, - {"squad_name", 0x3E8}, - {"squadhq", 0x3E9}, - {"squadmembers", 0x3EA}, - {"squadmemxp", 0x3EB}, - {"squadname", 0x3EC}, - {"stairs", 0x3ED}, - {"stairsstate", 0x3EE}, - {"stand", 0x3EF}, - {"start_blend", 0x3F0}, - {"start_move", 0x3F1}, - {"start_ragdoll", 0x3F2}, - {"startdeaths", 0x3F3}, - {"startdeploy_riotshield", 0x3F4}, - {"startingoffsetforlife", 0x3F5}, - {"startkills", 0x3F6}, - {"state_changed", 0x3F7}, - {"statelocked", 0x3F8}, - {"stencil_disable", 0x3F9}, - {"stencil_onesided", 0x3FA}, - {"stencil_twosided", 0x3FB}, - {"stencilfunc_always", 0x3FC}, - {"stencilfunc_equal", 0x3FD}, - {"stencilfunc_greater", 0x3FE}, - {"stencilfunc_greaterequal", 0x3FF}, - {"stencilfunc_less", 0x400}, - {"stencilfunc_lessequal", 0x401}, - {"stencilfunc_never", 0x402}, - {"stencilfunc_notequal", 0x403}, - {"stencilop_decr", 0x404}, - {"stencilop_decrsat", 0x405}, - {"stencilop_incr", 0x406}, - {"stencilop_incrsat", 0x407}, - {"stencilop_invert", 0x408}, - {"stencilop_keep", 0x409}, - {"stencilop_replace", 0x40A}, - {"stencilop_zero", 0x40B}, - {"stop", 0x40C}, - {"stop_soon", 0x40D}, - {"stopanimdistsq", 0x40E}, - {"stopsoonnotifydist", 0x40F}, - {"streak", 0x410}, - {"streaktype", 0x411}, - {"suckedashost", 0x412}, - {"suncolor", 0x413}, - {"sundirection", 0x414}, - {"sunlight", 0x415}, - {"support", 0x416}, - {"support_level", 0x417}, - {"suppression", 0x418}, - {"suppression_end", 0x419}, - {"suppressionduration", 0x41A}, - {"suppressionmeter", 0x41B}, - {"suppressionstarttime", 0x41C}, - {"suppressionTime", 0x41D}, - {"suppressionwait", 0x41E}, - {"surfacetype", 0x41F}, - {"surprisedbymedistsq", 0x420}, - {"swimmer", 0x421}, - {"switched_var_grenade", 0x422}, - {"syncedmeleetarget", 0x423}, - {"tactical", 0x424}, - {"tag", 0x425}, - {"tag_ai_aim_target", 0x426}, - {"tag_aim", 0x427}, - {"tag_aim_animated", 0x428}, - {"tag_aim_pivot", 0x429}, - {"tag_barrel", 0x42A}, - {"tag_blade_off", 0x42B}, - {"tag_body", 0x42C}, - {"tag_brass", 0x42D}, - {"tag_brass_2", 0x42E}, - {"tag_butt", 0x42F}, - {"tag_camera", 0x430}, - {"tag_clip", 0x431}, - {"tag_clip_dual", 0x432}, - {"tag_clip_dual2", 0x433}, - {"tag_detach", 0x434}, - {"tag_engine_left", 0x435}, - {"tag_engine_right", 0x436}, - {"tag_eotech_reticle", 0x437}, - {"tag_eye", 0x438}, - {"tag_flash", 0x439}, - {"tag_flash_11", 0x43A}, - {"tag_flash_2", 0x43B}, - {"tag_flash_22", 0x43C}, - {"tag_flash_3", 0x43D}, - {"tag_flash_launcher", 0x43E}, - {"tag_flash_silenced", 0x43F}, - {"tag_fx", 0x440}, - {"tag_gasmask", 0x441}, - {"tag_gasmask2", 0x442}, - {"tag_ik_ankle_fl", 0x443}, - {"tag_ik_ankle_fr", 0x444}, - {"tag_ik_ankle_kl", 0x445}, - {"tag_ik_ankle_kr", 0x446}, - {"tag_ik_ankle_ml", 0x447}, - {"tag_ik_ankle_mr", 0x448}, - {"tag_ik_footflat_fl", 0x449}, - {"tag_ik_footflat_fr", 0x44A}, - {"tag_ik_footflat_kl", 0x44B}, - {"tag_ik_footflat_kr", 0x44C}, - {"tag_ik_footflat_ml", 0x44D}, - {"tag_ik_footflat_mr", 0x44E}, - {"tag_ik_hip_fl", 0x44F}, - {"tag_ik_hip_fr", 0x450}, - {"tag_ik_hip_kl", 0x451}, - {"tag_ik_hip_kr", 0x452}, - {"tag_ik_hip_ml", 0x453}, - {"tag_ik_hip_mr", 0x454}, - {"tag_ik_knee_fl", 0x455}, - {"tag_ik_knee_fr", 0x456}, - {"tag_ik_knee_kl", 0x457}, - {"tag_ik_knee_kr", 0x458}, - {"tag_ik_knee_ml", 0x459}, - {"tag_ik_knee_mr", 0x45A}, - {"tag_ik_loc_le", 0x45B}, - {"tag_ik_loc_le_foregrip", 0x45C}, - {"tag_ik_loc_le_launcher", 0x45D}, - {"tag_ik_loc_le_shotgun", 0x45E}, - {"tag_ik_target", 0x45F}, - {"tag_inhand", 0x460}, - {"tag_jetblast_fx", 0x461}, - {"tag_jetpack", 0x462}, - {"tag_knife_attach", 0x463}, - {"tag_knife_fx", 0x464}, - {"tag_laser", 0x465}, - {"tag_launcher", 0x466}, - {"tag_magnifier_eotech_reticle", 0x467}, - {"tag_mobile_cover_upright", 0x468}, - {"tag_motion_tracker_bl", 0x469}, - {"tag_motion_tracker_br", 0x46A}, - {"tag_motion_tracker_fx", 0x46B}, - {"tag_motion_tracker_tl", 0x46C}, - {"tag_origin", 0x46D}, - {"tag_player", 0x46E}, - {"tag_popout", 0x46F}, - {"tag_rail_master_off", 0x470}, - {"tag_rail_master_on", 0x471}, - {"tag_rail_side_off", 0x472}, - {"tag_rail_side_on", 0x473}, - {"tag_reticle_acog", 0x474}, - {"tag_reticle_default", 0x475}, - {"tag_reticle_default2", 0x476}, - {"tag_reticle_hamr", 0x477}, - {"tag_reticle_on", 0x478}, - {"tag_reticle_red_dot", 0x479}, - {"tag_reticle_reflex", 0x47A}, - {"tag_reticle_tavor_scope", 0x47B}, - {"tag_reticle_thermal_scope", 0x47C}, - {"tag_rider", 0x47D}, - {"tag_riot_shield", 0x47E}, - {"tag_rocket", 0x47F}, - {"tag_scope_ads_off", 0x480}, - {"tag_scope_ads_on", 0x481}, - {"tag_shield_back", 0x482}, - {"tag_shotgun", 0x483}, - {"tag_show_alt", 0x484}, - {"tag_sight_off", 0x485}, - {"tag_sight_on", 0x486}, - {"tag_stow_back_mid_attach", 0x487}, - {"tag_stowed_back", 0x488}, - {"tag_stowed_hip_rear", 0x489}, - {"tag_sync", 0x48A}, - {"tag_tip", 0x48B}, - {"tag_turret", 0x48C}, - {"tag_turret_base", 0x48D}, - {"tag_turret_pitch", 0x48E}, - {"tag_turret_yaw", 0x48F}, - {"tag_weapon", 0x490}, - {"tag_weapon_chest", 0x491}, - {"tag_weapon_left", 0x492}, - {"tag_weapon_right", 0x493}, - {"tag_wheel_back_left", 0x494}, - {"tag_wheel_back_right", 0x495}, - {"tag_wheel_front_left", 0x496}, - {"tag_wheel_front_right", 0x497}, - {"tag_wheel_middle_left", 0x498}, - {"tag_wheel_middle_right", 0x499}, - {"tag_wheel_spin_left01", 0x49A}, - {"tag_wheel_spin_left02", 0x49B}, - {"tag_wheel_spin_left03", 0x49C}, - {"tag_wheel_spin_right01", 0x49D}, - {"tag_wheel_spin_right02", 0x49E}, - {"tag_wheel_spin_right03", 0x49F}, - {"takedamage", 0x4A0}, - {"target", 0x4A1}, - {"target_script_trigger", 0x4A2}, - {"targetname", 0x4A3}, - {"team", 0x4A4}, - {"team3", 0x4A5}, - {"teambalanced", 0x4A6}, - {"teammode_axisallies", 0x4A7}, - {"teammode_ffa", 0x4A8}, - {"teammovewaittime", 0x4A9}, - {"their_score", 0x4AA}, - {"thermal", 0x4AB}, - {"thermalbodymaterial", 0x4AC}, - {"third_person", 0x4AD}, - {"threatbias", 0x4AE}, - {"threatbiasgroup", 0x4AF}, - {"threatsightdelayenabled", 0x4B0}, - {"threatsightdelayfalloff", 0x4B1}, - {"threshold", 0x4B2}, - {"throwingknife", 0x4B3}, - {"time", 0x4B4}, - {"timeplayedtotal", 0x4B5}, - {"titlenew", 0x4B6}, - {"titleunlocked", 0x4B7}, - {"top", 0x4B8}, - {"toparc", 0x4B9}, - {"totalxp", 0x4BA}, - {"touch", 0x4BB}, - {"touching_platform", 0x4BC}, - {"traverse_complete", 0x4BD}, - {"traverse_soon", 0x4BE}, - {"traversecost", 0x4BF}, - {"traversesoonnotifydist", 0x4C0}, - {"trend", 0x4C1}, - {"trigger", 0x4C2}, - {"trigger_damage", 0x4C3}, - {"trigger_use", 0x4C4}, - {"trigger_use_touch", 0x4C5}, - {"truck_cam", 0x4C6}, - {"turnrate", 0x4C7}, - {"turret_deactivate", 0x4C8}, - {"turret_fire", 0x4C9}, - {"turret_no_vis", 0x4CA}, - {"turret_not_on_target", 0x4CB}, - {"turret_on_target", 0x4CC}, - {"turret_on_vistarget", 0x4CD}, - {"turret_pitch_clamped", 0x4CE}, - {"turret_rotate_stopped", 0x4CF}, - {"turret_yaw_clamped", 0x4D0}, - {"turretinvulnerability", 0x4D1}, - {"turretownerchange", 0x4D2}, - {"turretstatechange", 0x4D3}, - {"type", 0x4D4}, - {"ucdidhigh", 0x4D5}, - {"ucdidlow", 0x4D6}, - {"unlockedcamo", 0x4D7}, - {"unlockedreticles", 0x4D8}, - {"unlockpoints", 0x4D9}, - {"unresolved_collision", 0x4DA}, - {"up", 0x4DB}, - {"upaimlimit", 0x4DC}, - {"upgradechallengeprogress", 0x4DD}, - {"upgradechallengestage", 0x4DE}, - {"upgradepoints", 0x4DF}, - {"upgradepurchased", 0x4E0}, - {"useable", 0x4E1}, - {"usechokepoints", 0x4E2}, - {"usecombatscriptatcover", 0x4E3}, - {"usedemblemslots", 0x4E4}, - {"useorcaavoidance", 0x4E5}, - {"usepathsmoothingvalues", 0x4E6}, - {"veh_boatbounce", 0x4E7}, - {"veh_boost_activated", 0x4E8}, - {"veh_boost_deactivated", 0x4E9}, - {"veh_brake", 0x4EA}, - {"veh_collision", 0x4EB}, - {"veh_contact", 0x4EC}, - {"veh_jolt", 0x4ED}, - {"veh_landed", 0x4EE}, - {"veh_leftground", 0x4EF}, - {"veh_pathdir", 0x4F0}, - {"veh_pathspeed", 0x4F1}, - {"veh_pathtype", 0x4F2}, - {"veh_predictedcollision", 0x4F3}, - {"veh_speed", 0x4F4}, - {"veh_throttle", 0x4F5}, - {"veh_topspeed", 0x4F6}, - {"veh_transmission", 0x4F7}, - {"vehicle_dismount", 0x4F8}, - {"vehicle_mount", 0x4F9}, - {"vehicletype", 0x4FA}, - {"velocity", 0x4FB}, - {"vertalign", 0x4FC}, - {"visionsetmissilecam", 0x4FD}, - {"visionsetmissilecamduration", 0x4FE}, - {"visionsetnaked", 0x4FF}, - {"visionsetnakedduration", 0x500}, - {"visionsetnight", 0x501}, - {"visionsetnightduration", 0x502}, - {"visionsetpain", 0x503}, - {"visionsetpainduration", 0x504}, - {"visionsetthermal", 0x505}, - {"visionsetthermalduration", 0x506}, - {"vote", 0x507}, - {"wait", 0x508}, - {"walk", 0x509}, - {"walkdist", 0x50A}, - {"walkdistfacingmotion", 0x50B}, - {"wastacticalinsertion", 0x50C}, - {"waypoint_reached", 0x50D}, - {"weapon", 0x50E}, - {"weapon_change", 0x50F}, - {"weapon_dropped", 0x510}, - {"weapon_fired", 0x511}, - {"weapon_model_change", 0x512}, - {"weapon_switch_invalid", 0x513}, - {"weapon_switch_started", 0x514}, - {"weapon_taken", 0x515}, - {"weaponchange", 0x516}, - {"weaponclassrestricted", 0x517}, - {"weaponinfo", 0x518}, - {"weaponrank", 0x519}, - {"weaponrestricted", 0x51A}, - {"weaponsetups", 0x51B}, - {"weaponstats", 0x51C}, - {"weeklychallengeid", 0x51D}, - {"weight", 0x51E}, - {"width", 0x51F}, - {"wildcard1", 0x520}, - {"wildcard2", 0x521}, - {"wildcard3", 0x522}, - {"wildcardslots", 0x523}, - {"win_streak", 0x524}, - {"winlossratio", 0x525}, - {"wins", 0x526}, - {"won_match", 0x527}, - {"world", 0x528}, - {"worldmodel", 0x529}, - {"worldspawn", 0x52A}, - {"x", 0x52B}, - {"xb3", 0x52C}, - {"xenon", 0x52D}, - {"xp", 0x52E}, - {"xp_multiplier", 0x52F}, - {"xpmaxmultipliertimeplayed", 0x530}, - {"xpmultiplier", 0x531}, - {"xuid", 0x532}, - {"y", 0x533}, - {"yawconvergencetime", 0x534}, - {"your_score", 0x535}, - {"z", 0x536}, - {"zonly_physics", 0x537}, - {"codescripts/delete", 0x53D}, - {"codescripts/struct", 0x53E}, - {"codescripts/message", 0x53F}, - {"maps/mp/gametypes/_callbacksetup", 0x540}, - }; -} diff --git a/src/client/game/scripting/functions.cpp b/src/client/game/scripting/functions.cpp deleted file mode 100644 index 3452c767..00000000 --- a/src/client/game/scripting/functions.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include "functions.hpp" - -#include - -namespace scripting -{ - namespace - { - std::unordered_map lowercase_map( - const std::unordered_map& old_map) - { - std::unordered_map new_map{}; - for (auto& entry : old_map) - { - new_map[utils::string::to_lower(entry.first)] = entry.second; - } - - return new_map; - } - - const std::unordered_map& get_methods() - { - static auto methods = lowercase_map(method_map); - return methods; - } - - const std::unordered_map& get_functions() - { - static auto function = lowercase_map(function_map); - return function; - } - - int find_function_index(const std::string& name, const bool prefer_global) - { - const auto target = utils::string::to_lower(name); - - const auto& primary_map = prefer_global - ? get_functions() - : get_methods(); - const auto& secondary_map = !prefer_global - ? get_functions() - : get_methods(); - - auto function_entry = primary_map.find(target); - if (function_entry != primary_map.end()) - { - return function_entry->second; - } - - function_entry = secondary_map.find(target); - if (function_entry != secondary_map.end()) - { - return function_entry->second; - } - - return -1; - } - - script_function get_function_by_index(const unsigned index) - { - static const auto function_table = SELECT_VALUE(0x149668F50, 0x147DD1850); - static const auto method_table = SELECT_VALUE(0x14966A670, 0x147DD2F50); - - if (index < 0x2DF) - { - return reinterpret_cast(function_table)[index]; - } - - return reinterpret_cast(method_table)[index - 0x8000]; - } - } - - std::string find_token(unsigned int id) - { - for (const auto& token : token_map) - { - if (token.second == id) - { - return token.first; - } - } - - return utils::string::va("_ID%i", id); - } - - unsigned int find_token_id(const std::string& name) - { - const auto result = token_map.find(name); - - if (result != token_map.end()) - { - return result->second; - } - - return 0; - } - - script_function find_function(const std::string& name, const bool prefer_global) - { - const auto index = find_function_index(name, prefer_global); - if (index < 0) return nullptr; - - return get_function_by_index(index); - } -} diff --git a/src/client/game/scripting/functions.hpp b/src/client/game/scripting/functions.hpp deleted file mode 100644 index 0422bcf7..00000000 --- a/src/client/game/scripting/functions.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace scripting -{ - extern std::unordered_map method_map; - extern std::unordered_map function_map; - extern std::unordered_map token_map; - - using script_function = void(*)(game::scr_entref_t); - - std::string find_token(unsigned int id); - unsigned int find_token_id(const std::string& name); - - script_function find_function(const std::string& name, const bool prefer_global); -} diff --git a/src/client/game/scripting/lua/context.cpp b/src/client/game/scripting/lua/context.cpp deleted file mode 100644 index 7aaa9f89..00000000 --- a/src/client/game/scripting/lua/context.cpp +++ /dev/null @@ -1,542 +0,0 @@ -#include -#include "context.hpp" -#include "error.hpp" -#include "value_conversion.hpp" - -#include "../execution.hpp" -#include "../functions.hpp" - -#include "../../../component/command.hpp" -#include "../../../component/logfile.hpp" -#include "../../../component/scripting.hpp" - -#include -#include - -namespace scripting::lua -{ - namespace - { - - vector normalize_vector(const vector& vec) - { - const auto length = sqrt( - (vec.get_x() * vec.get_x()) + - (vec.get_y() * vec.get_y()) + - (vec.get_z() * vec.get_z()) - ); - - return vector( - vec.get_x() / length, - vec.get_y() / length, - vec.get_z() / length - ); - } - - void setup_io(sol::state& state) - { - state["io"]["fileexists"] = utils::io::file_exists; - state["io"]["writefile"] = utils::io::write_file; - state["io"]["remove_file"] = utils::io::remove_file; - state["io"]["filesize"] = utils::io::file_size; - state["io"]["createdirectory"] = utils::io::create_directory; - state["io"]["directoryexists"] = utils::io::directory_exists; - state["io"]["directoryisempty"] = utils::io::directory_is_empty; - state["io"]["listfiles"] = utils::io::list_files; - state["io"]["copyfolder"] = utils::io::copy_folder; - state["io"]["readfile"] = static_cast(utils::io::read_file); - } - - void setup_vector_type(sol::state& state) - { - auto vector_type = state.new_usertype("vector", sol::constructors()); - vector_type["x"] = sol::property(&vector::get_x, &vector::set_x); - vector_type["y"] = sol::property(&vector::get_y, &vector::set_y); - vector_type["z"] = sol::property(&vector::get_z, &vector::set_z); - - vector_type["r"] = sol::property(&vector::get_x, &vector::set_x); - vector_type["g"] = sol::property(&vector::get_y, &vector::set_y); - vector_type["b"] = sol::property(&vector::get_z, &vector::set_z); - - vector_type[sol::meta_function::addition] = sol::overload( - [](const vector& a, const vector& b) - { - return vector( - a.get_x() + b.get_x(), - a.get_y() + b.get_y(), - a.get_z() + b.get_z() - ); - }, - [](const vector& a, const int value) - { - return vector( - a.get_x() + value, - a.get_y() + value, - a.get_z() + value - ); - } - ); - - vector_type[sol::meta_function::subtraction] = sol::overload( - [](const vector& a, const vector& b) - { - return vector( - a.get_x() - b.get_x(), - a.get_y() - b.get_y(), - a.get_z() - b.get_z() - ); - }, - [](const vector& a, const int value) - { - return vector( - a.get_x() - value, - a.get_y() - value, - a.get_z() - value - ); - } - ); - - vector_type[sol::meta_function::multiplication] = sol::overload( - [](const vector& a, const vector& b) - { - return vector( - a.get_x() * b.get_x(), - a.get_y() * b.get_y(), - a.get_z() * b.get_z() - ); - }, - [](const vector& a, const int value) - { - return vector( - a.get_x() * value, - a.get_y() * value, - a.get_z() * value - ); - } - ); - - vector_type[sol::meta_function::division] = sol::overload( - [](const vector& a, const vector& b) - { - return vector( - a.get_x() / b.get_x(), - a.get_y() / b.get_y(), - a.get_z() / b.get_z() - ); - }, - [](const vector& a, const int value) - { - return vector( - a.get_x() / value, - a.get_y() / value, - a.get_z() / value - ); - } - ); - - vector_type[sol::meta_function::equal_to] = [](const vector& a, const vector& b) - { - return a.get_x() == b.get_x() && - a.get_y() == b.get_y() && - a.get_z() == b.get_z(); - }; - - vector_type[sol::meta_function::length] = [](const vector& a) - { - return sqrt((a.get_x() * a.get_x()) + (a.get_y() * a.get_y()) + (a.get_z() * a.get_z())); - }; - - vector_type[sol::meta_function::to_string] = [](const vector& a) - { - return utils::string::va("{x: %f, y: %f, z: %f}", a.get_x(), a.get_y(), a.get_z()); - }; - - vector_type["normalize"] = [](const vector& a) - { - return normalize_vector(a); - }; - } - - void setup_entity_type(sol::state& state, event_handler& handler, scheduler& scheduler) - { - state["level"] = entity{*game::levelEntityId}; - - auto entity_type = state.new_usertype("entity"); - - for (const auto& func : method_map) - { - const auto name = utils::string::to_lower(func.first); - entity_type[name.data()] = [name](const entity& entity, const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, entity.call(name, arguments)); - }; - } - - entity_type["set"] = [](const entity& entity, const std::string& field, - const sol::lua_value& value) - { - entity.set(field, convert(value)); - }; - - entity_type["get"] = [](const entity& entity, const sol::this_state s, const std::string& field) - { - return convert(s, entity.get(field)); - }; - - entity_type["notify"] = [](const entity& entity, const sol::this_state s, const std::string& event, - sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - notify(entity, event, arguments); - }; - - entity_type["onnotify"] = [&handler](const entity& entity, const std::string& event, - const event_callback& callback) - { - event_listener listener{}; - listener.callback = callback; - listener.entity = entity; - listener.event = event; - listener.is_volatile = false; - - return handler.add_event_listener(std::move(listener)); - }; - - entity_type["onnotifyonce"] = [&handler](const entity& entity, const std::string& event, - const event_callback& callback) - { - event_listener listener{}; - listener.callback = callback; - listener.entity = entity; - listener.event = event; - listener.is_volatile = true; - - return handler.add_event_listener(std::move(listener)); - }; - - entity_type["call"] = [](const entity& entity, const sol::this_state s, const std::string& function, - sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, entity.call(function, arguments)); - }; - - entity_type[sol::meta_function::new_index] = [](const entity& entity, const std::string& field, - const sol::lua_value& value) - { - entity.set(field, convert(value)); - }; - - entity_type[sol::meta_function::index] = [](const entity& entity, const sol::this_state s, const std::string& field) - { - return convert(s, entity.get(field)); - }; - - entity_type["getstruct"] = [](const entity& entity, const sol::this_state s) - { - const auto id = entity.get_entity_id(); - return scripting::lua::entity_to_struct(s, id); - }; - - entity_type["struct"] = sol::property([](const entity& entity, const sol::this_state s) - { - const auto id = entity.get_entity_id(); - return scripting::lua::entity_to_struct(s, id); - }); - - entity_type["scriptcall"] = [](const entity& entity, const sol::this_state s, const std::string& filename, - const std::string function, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, call_script_function(entity, filename, function, arguments)); - }; - - struct game - { - }; - auto game_type = state.new_usertype("game_"); - state["game"] = game(); - - for (const auto& func : function_map) - { - const auto name = utils::string::to_lower(func.first); - game_type[name] = [name](const game&, const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, call(name, arguments)); - }; - } - - game_type["call"] = [](const game&, const sol::this_state s, const std::string& function, - sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, call(function, arguments)); - }; - - game_type["ontimeout"] = [&scheduler](const game&, const sol::protected_function& callback, - const long long milliseconds) - { - return scheduler.add(callback, milliseconds, true); - }; - - game_type["oninterval"] = [&scheduler](const game&, const sol::protected_function& callback, - const long long milliseconds) - { - return scheduler.add(callback, milliseconds, false); - }; - - game_type["executecommand"] = [](const game&, const std::string& command) - { - command::execute(command, false); - }; - - game_type["onplayerdamage"] = [](const game&, const sol::protected_function& callback) - { - logfile::add_player_damage_callback(callback); - }; - - game_type["onplayerkilled"] = [](const game&, const sol::protected_function& callback) - { - logfile::add_player_killed_callback(callback); - }; - - game_type["getgamevar"] = [](const sol::this_state s) - { - const auto value = ::game::scr_VarGlob->childVariableValue[*::game::gameEntityId]; - - ::game::VariableValue variable{}; - variable.type = value.type; - variable.u.uintValue = value.u.u.uintValue; - - return convert(s, variable); - }; - - game_type["getfunctions"] = [entity_type](const game&, const sol::this_state s, const std::string& filename) - { - if (scripting::script_function_table.find(filename) == scripting::script_function_table.end()) - { - throw std::runtime_error("File '" + filename + "' not found"); - } - - auto functions = sol::table::create(s.lua_state()); - - for (const auto& function : scripting::script_function_table[filename]) - { - functions[function.first] = sol::overload( - [filename, function](const entity& entity, const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - gsl::finally(&logfile::enable_vm_execute_hook); - logfile::disable_vm_execute_hook(); - - return convert(s, call_script_function(entity, filename, function.first, arguments)); - }, - [filename, function](const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - gsl::finally(&logfile::enable_vm_execute_hook); - logfile::disable_vm_execute_hook(); - - return convert(s, call_script_function(*::game::levelEntityId, filename, function.first, arguments)); - } - ); - } - - return functions; - }; - - game_type["scriptcall"] = [](const game&, const sol::this_state s, const std::string& filename, - const std::string function, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - gsl::finally(&logfile::enable_vm_execute_hook); - logfile::disable_vm_execute_hook(); - - return convert(s, call_script_function(*::game::levelEntityId, filename, function, arguments)); - }; - - game_type["detour"] = [](const game&, const sol::this_state s, const std::string& filename, - const std::string function_name, const sol::protected_function& function) - { - const auto pos = get_function_pos(filename, function_name); - logfile::vm_execute_hooks[pos] = function; - - auto detour = sol::table::create(function.lua_state()); - - detour["disable"] = [pos]() - { - logfile::vm_execute_hooks.erase(pos); - }; - - detour["enable"] = [pos, function]() - { - logfile::vm_execute_hooks[pos] = function; - }; - - detour["invoke"] = sol::overload( - [filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - gsl::finally(&logfile::enable_vm_execute_hook); - logfile::disable_vm_execute_hook(); - - return convert(s, call_script_function(entity, filename, function_name, arguments)); - }, - [filename, function_name](const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - gsl::finally(&logfile::enable_vm_execute_hook); - logfile::disable_vm_execute_hook(); - - return convert(s, call_script_function(*::game::levelEntityId, filename, function_name, arguments)); - } - ); - - return detour; - }; - } - } - - context::context(std::string folder) - : folder_(std::move(folder)) - , scheduler_(state_) - , event_handler_(state_) - - { - this->state_.open_libraries(sol::lib::base, - sol::lib::package, - sol::lib::io, - sol::lib::string, - sol::lib::os, - sol::lib::math, - sol::lib::table); - - this->state_["include"] = [this](const std::string& file) - { - this->load_script(file); - }; - - sol::function old_require = this->state_["require"]; - auto base_path = utils::string::replace(this->folder_, "/", ".") + "."; - this->state_["require"] = [base_path, old_require](const std::string& path) - { - return old_require(base_path + path); - }; - - this->state_["scriptdir"] = [this]() - { - return this->folder_; - }; - - setup_io(this->state_); - setup_vector_type(this->state_); - setup_entity_type(this->state_, this->event_handler_, this->scheduler_); - - printf("Loading script '%s'\n", this->folder_.data()); - this->load_script("__init__"); - } - - context::~context() - { - this->collect_garbage(); - this->scheduler_.clear(); - this->event_handler_.clear(); - this->state_ = {}; - } - - void context::run_frame() - { - this->scheduler_.run_frame(); - this->collect_garbage(); - } - - void context::notify(const event& e) - { - this->scheduler_.dispatch(e); - this->event_handler_.dispatch(e); - } - - void context::collect_garbage() - { - this->state_.collect_garbage(); - } - - void context::load_script(const std::string& script) - { - if (!this->loaded_scripts_.emplace(script).second) - { - return; - } - - const auto file = (std::filesystem::path{this->folder_} / (script + ".lua")).generic_string(); - handle_error(this->state_.safe_script_file(file, &sol::script_pass_on_error)); - } -} diff --git a/src/client/game/scripting/lua/context.hpp b/src/client/game/scripting/lua/context.hpp deleted file mode 100644 index 79a5e905..00000000 --- a/src/client/game/scripting/lua/context.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "../event.hpp" - -#pragma warning(push) -#pragma warning(disable: 4702) - -#define SOL_ALL_SAFETIES_ON 1 -#define SOL_PRINT_ERRORS 0 -#include - -#pragma warning(pop) - -#include "scheduler.hpp" -#include "event_handler.hpp" - -namespace scripting::lua -{ - class context - { - public: - context(std::string folder); - ~context(); - - context(context&&) noexcept = delete; - context& operator=(context&&) noexcept = delete; - - context(const context&) = delete; - context& operator=(const context&) = delete; - - void run_frame(); - void notify(const event& e); - void collect_garbage(); - - private: - sol::state state_{}; - std::string folder_; - std::unordered_set loaded_scripts_; - - scheduler scheduler_; - event_handler event_handler_; - - void load_script(const std::string& script); - }; -} diff --git a/src/client/game/scripting/lua/engine.cpp b/src/client/game/scripting/lua/engine.cpp deleted file mode 100644 index 351ad04b..00000000 --- a/src/client/game/scripting/lua/engine.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include "engine.hpp" -#include "context.hpp" - -#include "../execution.hpp" -#include "../../../component/logfile.hpp" -#include "../../../component/game_module.hpp" - -#include - -namespace scripting::lua::engine -{ - namespace - { - auto& get_scripts() - { - static std::vector> scripts{}; - return scripts; - } - - void load_scripts(const std::string& script_dir) - { - if (!utils::io::directory_exists(script_dir)) - { - return; - } - - const auto scripts = utils::io::list_files(script_dir); - - for (const auto& script : scripts) - { - if (std::filesystem::is_directory(script) && utils::io::file_exists(script + "/__init__.lua")) - { - get_scripts().push_back(std::make_unique(script)); - } - } - } - } - - void stop() - { - logfile::clear_callbacks(); - get_scripts().clear(); - } - - void start() - { - // No SP until there is a concept - if (game::environment::is_sp()) - { - return; - } - - stop(); - load_scripts(game_module::get_host_module().get_folder() + "/data/scripts/"); - load_scripts("h1-mod/scripts/"); - load_scripts("data/scripts/"); - } - - void notify(const event& e) - { - for (auto& script : get_scripts()) - { - script->notify(e); - } - } - - void run_frame() - { - for (auto& script : get_scripts()) - { - script->run_frame(); - } - } -} diff --git a/src/client/game/scripting/lua/engine.hpp b/src/client/game/scripting/lua/engine.hpp deleted file mode 100644 index 471316cd..00000000 --- a/src/client/game/scripting/lua/engine.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../event.hpp" - -namespace scripting::lua::engine -{ - void start(); - void stop(); - void notify(const event& e); - void run_frame(); -} diff --git a/src/client/game/scripting/lua/error.cpp b/src/client/game/scripting/lua/error.cpp deleted file mode 100644 index 935db0f0..00000000 --- a/src/client/game/scripting/lua/error.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "error.hpp" -#include "../execution.hpp" - -#include "component/console.hpp" - -namespace scripting::lua -{ - namespace - { - void notify_error() - { - try - { - call("iprintln", {"^1Script execution error!"}); - } - catch (...) - { - } - } - } - - void handle_error(const sol::protected_function_result& result) - { - if (!result.valid()) - { - console::error("************** Script execution error **************\n"); - - const sol::error err = result; - console::error("%s\n", err.what()); - - console::error("****************************************************\n"); - - notify_error(); - } - } -} diff --git a/src/client/game/scripting/lua/error.hpp b/src/client/game/scripting/lua/error.hpp deleted file mode 100644 index dab56bee..00000000 --- a/src/client/game/scripting/lua/error.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "context.hpp" - -namespace scripting::lua -{ - void handle_error(const sol::protected_function_result& result); -} diff --git a/src/client/game/scripting/lua/event_handler.cpp b/src/client/game/scripting/lua/event_handler.cpp deleted file mode 100644 index 7121ea63..00000000 --- a/src/client/game/scripting/lua/event_handler.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "std_include.hpp" -#include "context.hpp" -#include "error.hpp" -#include "value_conversion.hpp" - -namespace scripting::lua -{ - event_handler::event_handler(sol::state& state) - : state_(state) - { - auto event_listener_handle_type = state.new_usertype("event_listener_handle"); - - event_listener_handle_type["clear"] = [this](const event_listener_handle& handle) - { - this->remove(handle); - }; - - event_listener_handle_type["endon"] = [this](const event_listener_handle& handle, const entity& entity, const std::string& event) - { - this->add_endon_condition(handle, entity, event); - }; - } - - void event_handler::dispatch(const event& event) - { - bool has_built_arguments = false; - event_arguments arguments{}; - - callbacks_.access([&](task_list& tasks) - { - this->merge_callbacks(); - this->handle_endon_conditions(event); - - for (auto i = tasks.begin(); i != tasks.end();) - { - if (i->event != event.name || i->entity != event.entity) - { - ++i; - continue; - } - - if (!i->is_deleted) - { - if(!has_built_arguments) - { - has_built_arguments = true; - arguments = this->build_arguments(event); - } - - handle_error(i->callback(sol::as_args(arguments))); - } - - if (i->is_volatile || i->is_deleted) - { - i = tasks.erase(i); - } - else - { - ++i; - } - } - }); - } - - event_listener_handle event_handler::add_event_listener(event_listener&& listener) - { - const uint64_t id = ++this->current_listener_id_; - listener.id = id; - listener.is_deleted = false; - - new_callbacks_.access([&listener](task_list& tasks) - { - tasks.emplace_back(std::move(listener)); - }); - - return {id}; - } - - void event_handler::add_endon_condition(const event_listener_handle& handle, const entity& entity, - const std::string& event) - { - auto merger = [&](task_list& tasks) - { - for(auto& task : tasks) - { - if(task.id == handle.id) - { - task.endon_conditions.emplace_back(entity, event); - } - } - }; - - callbacks_.access([&](task_list& tasks) - { - merger(tasks); - new_callbacks_.access(merger); - }); - } - - void event_handler::clear() - { - callbacks_.access([&](task_list& tasks) - { - new_callbacks_.access([&](task_list& new_tasks) - { - new_tasks.clear(); - tasks.clear(); - }); - }); - } - - void event_handler::remove(const event_listener_handle& handle) - { - auto mask_as_deleted = [&](task_list& tasks) - { - for (auto& task : tasks) - { - if (task.id == handle.id) - { - task.is_deleted = true; - break; - } - } - }; - - callbacks_.access(mask_as_deleted); - new_callbacks_.access(mask_as_deleted); - } - - void event_handler::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 = {}; - }); - }); - } - - void event_handler::handle_endon_conditions(const event& event) - { - auto deleter = [&](task_list& tasks) - { - for(auto& task : tasks) - { - for(auto& condition : task.endon_conditions) - { - if(condition.first == event.entity && condition.second == event.name) - { - task.is_deleted = true; - break; - } - } - } - }; - - callbacks_.access(deleter); - } - - event_arguments event_handler::build_arguments(const event& event) const - { - event_arguments arguments; - - for (const auto& argument : event.arguments) - { - arguments.emplace_back(convert(this->state_, argument)); - } - - return arguments; - } -} diff --git a/src/client/game/scripting/lua/event_handler.hpp b/src/client/game/scripting/lua/event_handler.hpp deleted file mode 100644 index fc95b704..00000000 --- a/src/client/game/scripting/lua/event_handler.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -namespace scripting::lua -{ - using event_arguments = std::vector; - using event_callback = sol::protected_function; - - class event_listener_handle - { - public: - uint64_t id = 0; - }; - - class event_listener final : public event_listener_handle - { - public: - std::string event = {}; - entity entity{}; - event_callback callback = {}; - bool is_volatile = false; - bool is_deleted = false; - std::vector> endon_conditions{}; - }; - - class event_handler final - { - public: - event_handler(sol::state& state); - - event_handler(event_handler&&) noexcept = delete; - event_handler& operator=(event_handler&&) noexcept = delete; - - event_handler(const scheduler&) = delete; - event_handler& operator=(const event_handler&) = delete; - - void dispatch(const event& event); - - event_listener_handle add_event_listener(event_listener&& listener); - - void clear(); - - private: - sol::state& state_; - std::atomic_int64_t current_listener_id_ = 0; - - using task_list = std::vector; - utils::concurrency::container new_callbacks_; - utils::concurrency::container callbacks_; - - void remove(const event_listener_handle& handle); - void merge_callbacks(); - void handle_endon_conditions(const event& event); - - void add_endon_condition(const event_listener_handle& handle, const entity& entity, const std::string& event); - - event_arguments build_arguments(const event& event) const; - }; -} diff --git a/src/client/game/scripting/lua/scheduler.cpp b/src/client/game/scripting/lua/scheduler.cpp deleted file mode 100644 index 1afb7df2..00000000 --- a/src/client/game/scripting/lua/scheduler.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "std_include.hpp" -#include "context.hpp" -#include "error.hpp" - -namespace scripting::lua -{ - scheduler::scheduler(sol::state& state) - { - auto task_handle_type = state.new_usertype("task_handle"); - - task_handle_type["clear"] = [this](const task_handle& handle) - { - this->remove(handle); - }; - - task_handle_type["endon"] = [this](const task_handle& handle, const entity& entity, const std::string& event) - { - this->add_endon_condition(handle, entity, event); - }; - } - - void scheduler::dispatch(const event& event) - { - auto deleter = [&](task_list& tasks) - { - for(auto& task : tasks) - { - for(auto& condition : task.endon_conditions) - { - if(condition.first == event.entity && condition.second == event.name) - { - task.is_deleted = true; - break; - } - } - } - }; - - callbacks_.access([&](task_list& tasks) - { - deleter(tasks); - new_callbacks_.access(deleter); - }); - } - - void scheduler::run_frame() - { - 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->delay) - { - ++i; - continue; - } - - i->last_call = now; - - if (!i->is_deleted) - { - handle_error(i->callback()); - } - - if (i->is_volatile || i->is_deleted) - { - i = tasks.erase(i); - } - else - { - ++i; - } - } - }); - } - - void scheduler::clear() - { - callbacks_.access([&](task_list& tasks) - { - new_callbacks_.access([&](task_list& new_tasks) - { - new_tasks.clear(); - tasks.clear(); - }); - }); - } - - task_handle scheduler::add(const sol::protected_function& callback, const long long milliseconds, - const bool is_volatile) - { - return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); - } - - task_handle scheduler::add(const sol::protected_function& callback, const std::chrono::milliseconds delay, - const bool is_volatile) - { - const uint64_t id = ++this->current_task_id_; - - task task; - task.is_volatile = is_volatile; - task.callback = callback; - task.delay = delay; - task.last_call = std::chrono::steady_clock::now(); - task.id = id; - task.is_deleted = false; - - new_callbacks_.access([&task](task_list& tasks) - { - tasks.emplace_back(std::move(task)); - }); - - return {id}; - } - - void scheduler::add_endon_condition(const task_handle& handle, const entity& entity, const std::string& event) - { - auto merger = [&](task_list& tasks) - { - for(auto& task : tasks) - { - if(task.id == handle.id) - { - task.endon_conditions.emplace_back(entity, event); - } - } - }; - - callbacks_.access([&](task_list& tasks) - { - merger(tasks); - new_callbacks_.access(merger); - }); - } - - void scheduler::remove(const task_handle& handle) - { - auto mask_as_deleted = [&](task_list& tasks) - { - for (auto& task : tasks) - { - if (task.id == handle.id) - { - task.is_deleted = true; - break; - } - } - }; - - callbacks_.access(mask_as_deleted); - new_callbacks_.access(mask_as_deleted); - } - - void scheduler::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 = {}; - }); - }); - } -} diff --git a/src/client/game/scripting/lua/scheduler.hpp b/src/client/game/scripting/lua/scheduler.hpp deleted file mode 100644 index 17c90797..00000000 --- a/src/client/game/scripting/lua/scheduler.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include - -namespace scripting::lua -{ - class context; - - class task_handle - { - public: - uint64_t id = 0; - }; - - class task final : public task_handle - { - public: - std::chrono::steady_clock::time_point last_call{}; - sol::protected_function callback{}; - std::chrono::milliseconds delay{}; - bool is_volatile = false; - bool is_deleted = false; - std::vector> endon_conditions{}; - }; - - class scheduler final - { - public: - scheduler(sol::state& state); - - scheduler(scheduler&&) noexcept = delete; - scheduler& operator=(scheduler&&) noexcept = delete; - - scheduler(const scheduler&) = delete; - scheduler& operator=(const scheduler&) = delete; - - void dispatch(const event& event); - void run_frame(); - void clear(); - - task_handle add(const sol::protected_function& callback, long long milliseconds, bool is_volatile); - task_handle add(const sol::protected_function& callback, std::chrono::milliseconds delay, bool is_volatile); - - private: - using task_list = std::vector; - utils::concurrency::container new_callbacks_; - utils::concurrency::container callbacks_; - std::atomic_int64_t current_task_id_ = 0; - - void add_endon_condition(const task_handle& handle, const entity& entity, const std::string& event); - - void remove(const task_handle& handle); - void merge_callbacks(); - }; -} diff --git a/src/client/game/scripting/lua/value_conversion.cpp b/src/client/game/scripting/lua/value_conversion.cpp deleted file mode 100644 index 3cc37e20..00000000 --- a/src/client/game/scripting/lua/value_conversion.cpp +++ /dev/null @@ -1,319 +0,0 @@ -#include -#include "value_conversion.hpp" -#include "../functions.hpp" -#include "../execution.hpp" -#include ".../../component/logfile.hpp" - -namespace scripting::lua -{ - namespace - { - struct array_value - { - int index; - script_value value; - }; - - sol::lua_value entity_to_array(lua_State* state, unsigned int id) - { - auto table = sol::table::create(state); - auto metatable = sol::table::create(state); - - std::unordered_map values; - - const auto offset = 0xA000 * (id & 3); - - auto current = game::scr_VarGlob->objectVariableChildren[id].firstChild; - auto idx = 1; - - for (auto i = offset + current; current; i = offset + current) - { - const auto var = game::scr_VarGlob->childVariableValue[i]; - - if (var.type == game::SCRIPT_NONE) - { - current = var.nextSibling; - continue; - } - - const auto string_value = (game::scr_string_t)((unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8)); - const auto* str = game::SL_ConvertToString(string_value); - - std::string key = string_value < 0x40000 && str - ? str - : std::to_string(idx++); - - game::VariableValue variable{}; - variable.type = var.type; - variable.u = var.u.u; - - array_value value; - value.index = i; - value.value = variable; - - values[key] = value; - - current = var.nextSibling; - } - - table["getkeys"] = [values]() - { - std::vector _keys; - - for (const auto& entry : values) - { - _keys.push_back(entry.first); - } - - return _keys; - }; - - metatable[sol::meta_function::new_index] = [values](const sol::table t, const sol::this_state s, - const sol::lua_value& key_value, const sol::lua_value& value) - { - const auto key = key_value.is() - ? std::to_string(key_value.as()) - : key_value.as(); - - if (values.find(key) == values.end()) - { - return; - } - - const auto i = values.at(key).index; - const auto variable = &game::scr_VarGlob->childVariableValue[i]; - - const auto new_variable = convert({s, value}).get_raw(); - - game::AddRefToValue(new_variable.type, new_variable.u); - game::RemoveRefToValue(variable->type, variable->u.u); - - variable->type = (char)new_variable.type; - variable->u.u = new_variable.u; - }; - - metatable[sol::meta_function::index] = [values](const sol::table t, const sol::this_state s, - const sol::lua_value& key_value) - { - const auto key = key_value.is() - ? std::to_string(key_value.as()) - : key_value.as(); - - if (values.find(key) == values.end()) - { - return sol::lua_value{s, sol::lua_nil}; - } - - return convert(s, values.at(key).value); - }; - - metatable[sol::meta_function::length] = [values]() - { - return values.size(); - }; - - table[sol::metatable_key] = metatable; - - return {state, table}; - } - - game::VariableValue convert_function(sol::lua_value value) - { - const auto function = value.as(); - const auto index = reinterpret_cast(logfile::vm_execute_hooks.size()); - - logfile::vm_execute_hooks[index] = function; - - game::VariableValue func; - func.type = game::SCRIPT_FUNCTION; - func.u.codePosValue = index; - - return func; - } - - sol::lua_value convert_function(lua_State* state, const char* pos) - { - return sol::overload( - [pos](const entity& entity, const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, exec_ent_thread(entity, pos, arguments)); - }, - [pos](const sol::this_state s, sol::variadic_args va) - { - std::vector arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - return convert(s, exec_ent_thread(*game::levelEntityId, pos, arguments)); - } - ); - } - } - - sol::lua_value entity_to_struct(lua_State* state, unsigned int parent_id) - { - auto table = sol::table::create(state); - auto metatable = sol::table::create(state); - - const auto offset = 64000 * (parent_id & 3); - - metatable[sol::meta_function::new_index] = [offset, parent_id](const sol::table t, const sol::this_state s, - const sol::lua_value& field, const sol::lua_value& value) - { - const auto id = field.is() - ? scripting::find_token_id(field.as()) - : field.as(); - - if (!id) - { - return; - } - - const auto variable_id = game::GetVariable(parent_id, id); - const auto variable = &game::scr_VarGlob->childVariableValue[variable_id + offset]; - const auto new_variable = convert({s, value}).get_raw(); - - game::AddRefToValue(new_variable.type, new_variable.u); - game::RemoveRefToValue(variable->type, variable->u.u); - - variable->type = (char)new_variable.type; - variable->u.u = new_variable.u; - }; - - metatable[sol::meta_function::index] = [offset, parent_id](const sol::table t, const sol::this_state s, - const sol::lua_value& field) - { - const auto id = field.is() - ? scripting::find_token_id(field.as()) - : field.as(); - - if (!id) - { - return sol::lua_value{s, sol::lua_nil}; - } - - const auto variable_id = game::FindVariable(parent_id, id); - if (!variable_id) - { - return sol::lua_value{s, sol::lua_nil}; - } - - const auto variable = game::scr_VarGlob->childVariableValue[variable_id + offset]; - - game::VariableValue result{}; - result.u = variable.u.u; - result.type = (game::scriptType_e)variable.type; - - return convert(s, result); - }; - - table[sol::metatable_key] = metatable; - - return {state, table}; - } - - script_value convert(const sol::lua_value& value) - { - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return convert_function(value); - } - - return {}; - } - - sol::lua_value convert(lua_State* state, const script_value& value) - { - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is>()) - { - return entity_to_struct(state, value.get_raw().u.uintValue); - } - - if (value.is>()) - { - return entity_to_array(state, value.get_raw().u.uintValue); - } - - if (value.is>()) - { - return convert_function(state, value.get_raw().u.codePosValue); - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - return {state, sol::lua_nil}; - } -} diff --git a/src/client/game/scripting/lua/value_conversion.hpp b/src/client/game/scripting/lua/value_conversion.hpp deleted file mode 100644 index 93256f80..00000000 --- a/src/client/game/scripting/lua/value_conversion.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "context.hpp" - -namespace scripting::lua -{ - sol::lua_value entity_to_struct(lua_State* state, unsigned int parent_id); - - script_value convert(const sol::lua_value& value); - sol::lua_value convert(lua_State* state, const script_value& value); -} diff --git a/src/client/game/scripting/safe_execution.cpp b/src/client/game/scripting/safe_execution.cpp deleted file mode 100644 index 92daa3b7..00000000 --- a/src/client/game/scripting/safe_execution.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include "safe_execution.hpp" - -#pragma warning(push) -#pragma warning(disable: 4611) - -namespace scripting::safe_execution -{ - namespace - { - bool execute_with_seh(const script_function function, const game::scr_entref_t& entref) - { - __try - { - function(entref); - return true; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return false; - } - } - } - - bool call(const script_function function, const game::scr_entref_t& entref) - { - *game::g_script_error_level += 1; - if (game::_setjmp(&game::g_script_error[*game::g_script_error_level])) - { - *game::g_script_error_level -= 1; - return false; - } - - const auto result = execute_with_seh(function, entref); - *game::g_script_error_level -= 1; - return result; - } - - bool set_entity_field(const game::scr_entref_t& entref, const int offset) - { - *game::g_script_error_level += 1; - if (game::_setjmp(&game::g_script_error[*game::g_script_error_level])) - { - *game::g_script_error_level -= 1; - return false; - } - - game::Scr_SetObjectField(entref.classnum, entref.entnum, offset); - - *game::g_script_error_level -= 1; - return true; - } - - bool get_entity_field(const game::scr_entref_t& entref, const int offset, game::VariableValue* value) - { - *game::g_script_error_level += 1; - if (game::_setjmp(&game::g_script_error[*game::g_script_error_level])) - { - value->type = game::SCRIPT_NONE; - value->u.intValue = 0; - *game::g_script_error_level -= 1; - return false; - } - - game::GetEntityFieldValue(value, entref.classnum, entref.entnum, offset); - - *game::g_script_error_level -= 1; - return true; - } -} - -#pragma warning(pop) diff --git a/src/client/game/scripting/safe_execution.hpp b/src/client/game/scripting/safe_execution.hpp deleted file mode 100644 index 6eea59d2..00000000 --- a/src/client/game/scripting/safe_execution.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "functions.hpp" - -namespace scripting::safe_execution -{ - bool call(script_function function, const game::scr_entref_t& entref); - - bool set_entity_field(const game::scr_entref_t& entref, int offset); - bool get_entity_field(const game::scr_entref_t& entref, int offset, game::VariableValue* value); -} diff --git a/src/client/game/scripting/script_value.cpp b/src/client/game/scripting/script_value.cpp deleted file mode 100644 index 7d334f17..00000000 --- a/src/client/game/scripting/script_value.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include -#include "script_value.hpp" -#include "entity.hpp" - - -namespace scripting -{ - /*************************************************************** - * Constructors - **************************************************************/ - - script_value::script_value(const game::VariableValue& value) - : value_(value) - { - } - - script_value::script_value(const int value) - { - game::VariableValue variable{}; - variable.type = game::SCRIPT_INTEGER; - variable.u.intValue = value; - - this->value_ = variable; - } - - script_value::script_value(const unsigned int value) - { - game::VariableValue variable{}; - variable.type = game::SCRIPT_INTEGER; - variable.u.uintValue = value; - - this->value_ = variable; - } - - script_value::script_value(const bool value) - : script_value(static_cast(value)) - { - } - - script_value::script_value(const float value) - { - game::VariableValue variable{}; - variable.type = game::SCRIPT_FLOAT; - variable.u.floatValue = value; - - this->value_ = variable; - } - - script_value::script_value(const double value) - : script_value(static_cast(value)) - { - } - - script_value::script_value(const char* value) - { - game::VariableValue variable{}; - variable.type = game::SCRIPT_STRING; - variable.u.stringValue = game::SL_GetString(value, 0); - - const auto _ = gsl::finally([&variable]() - { - game::RemoveRefToValue(variable.type, variable.u); - }); - - this->value_ = variable; - } - - script_value::script_value(const std::string& value) - : script_value(value.data()) - { - } - - script_value::script_value(const entity& value) - { - game::VariableValue variable{}; - variable.type = game::SCRIPT_OBJECT; - variable.u.pointerValue = value.get_entity_id(); - - this->value_ = variable; - } - - script_value::script_value(const vector& value) - { - game::VariableValue variable{}; - variable.type = game::SCRIPT_VECTOR; - variable.u.vectorValue = game::Scr_AllocVector(value); - - const auto _ = gsl::finally([&variable]() - { - game::RemoveRefToValue(variable.type, variable.u); - }); - - this->value_ = variable; - } - - /*************************************************************** - * Integer - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().type == game::SCRIPT_INTEGER; - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - int script_value::get() const - { - return this->get_raw().u.intValue; - } - - template <> - unsigned int script_value::get() const - { - return this->get_raw().u.uintValue; - } - - template <> - bool script_value::get() const - { - return this->get_raw().u.uintValue != 0; - } - - /*************************************************************** - * Float - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().type == game::SCRIPT_FLOAT; - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - float script_value::get() const - { - return this->get_raw().u.floatValue; - } - - template <> - double script_value::get() const - { - return static_cast(this->get_raw().u.floatValue); - } - - /*************************************************************** - * String - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().type == game::SCRIPT_STRING; - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - const char* script_value::get() const - { - return game::SL_ConvertToString(static_cast(this->get_raw().u.stringValue)); - } - - template <> - std::string script_value::get() const - { - return this->get(); - } - - /*************************************************************** - * Array - **************************************************************/ - - template <> - bool script_value::is>() const - { - if (this->get_raw().type != game::SCRIPT_OBJECT) - { - return false; - } - - const auto id = this->get_raw().u.uintValue; - const auto type = game::scr_VarGlob->objectVariableValue[id].w.type; - - return type == game::SCRIPT_ARRAY; - } - - /*************************************************************** - * Struct - **************************************************************/ - - template <> - bool script_value::is>() const - { - if (this->get_raw().type != game::SCRIPT_OBJECT) - { - return false; - } - - const auto id = this->get_raw().u.uintValue; - const auto type = game::scr_VarGlob->objectVariableValue[id].w.type; - - return type == game::SCRIPT_STRUCT; - } - - /*************************************************************** - * Function - **************************************************************/ - - template <> - bool script_value::is>() const - { - return this->get_raw().type == game::SCRIPT_FUNCTION; - } - - /*************************************************************** - * Entity - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().type == game::SCRIPT_OBJECT; - } - - template <> - entity script_value::get() const - { - return entity(this->get_raw().u.pointerValue); - } - - /*************************************************************** - * Vector - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().type == game::SCRIPT_VECTOR; - } - - template <> - vector script_value::get() const - { - return this->get_raw().u.vectorValue; - } - - /*************************************************************** - * - **************************************************************/ - - const game::VariableValue& script_value::get_raw() const - { - return this->value_.get(); - } -} diff --git a/src/client/game/scripting/script_value.hpp b/src/client/game/scripting/script_value.hpp deleted file mode 100644 index df8a95b6..00000000 --- a/src/client/game/scripting/script_value.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "game/game.hpp" -#include "variable_value.hpp" -#include "vector.hpp" - -namespace scripting -{ - class entity; - - class script_value - { - public: - script_value() = default; - script_value(const game::VariableValue& value); - - script_value(int value); - script_value(unsigned int value); - script_value(bool value); - - script_value(float value); - script_value(double value); - - script_value(const char* value); - script_value(const std::string& value); - - script_value(const entity& value); - - script_value(const vector& value); - - template - bool is() const; - - template - T as() const - { - if (!this->is()) - { - throw std::runtime_error("Invalid type"); - } - - return get(); - } - - const game::VariableValue& get_raw() const; - - private: - template - T get() const; - - variable_value value_{}; - }; -} diff --git a/src/client/game/scripting/stack_isolation.cpp b/src/client/game/scripting/stack_isolation.cpp deleted file mode 100644 index 646e2584..00000000 --- a/src/client/game/scripting/stack_isolation.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include "stack_isolation.hpp" - -namespace scripting -{ - stack_isolation::stack_isolation() - { - this->in_param_count_ = game::scr_VmPub->inparamcount; - this->out_param_count_ = game::scr_VmPub->outparamcount; - this->top_ = game::scr_VmPub->top; - this->max_stack_ = game::scr_VmPub->maxstack; - - game::scr_VmPub->top = this->stack_; - game::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1]; - game::scr_VmPub->inparamcount = 0; - game::scr_VmPub->outparamcount = 0; - } - - stack_isolation::~stack_isolation() - { - game::Scr_ClearOutParams(); - game::scr_VmPub->inparamcount = this->in_param_count_; - game::scr_VmPub->outparamcount = this->out_param_count_; - game::scr_VmPub->top = this->top_; - game::scr_VmPub->maxstack = this->max_stack_; - } -} diff --git a/src/client/game/scripting/stack_isolation.hpp b/src/client/game/scripting/stack_isolation.hpp deleted file mode 100644 index 8dffd4bc..00000000 --- a/src/client/game/scripting/stack_isolation.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace scripting -{ - class stack_isolation final - { - public: - stack_isolation(); - ~stack_isolation(); - - stack_isolation(stack_isolation&&) = delete; - stack_isolation(const stack_isolation&) = delete; - stack_isolation& operator=(stack_isolation&&) = delete; - stack_isolation& operator=(const stack_isolation&) = delete; - - private: - game::VariableValue stack_[512]{}; - - game::VariableValue* max_stack_; - game::VariableValue* top_; - unsigned int in_param_count_; - unsigned int out_param_count_; - }; -} diff --git a/src/client/game/scripting/variable_value.cpp b/src/client/game/scripting/variable_value.cpp deleted file mode 100644 index 69a20023..00000000 --- a/src/client/game/scripting/variable_value.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include "variable_value.hpp" - -namespace scripting -{ - variable_value::variable_value(const game::VariableValue& value) - { - this->assign(value); - } - - variable_value::variable_value(const variable_value& other) noexcept - { - this->operator=(other); - } - - variable_value::variable_value(variable_value&& other) noexcept - { - this->operator=(std::move(other)); - } - - variable_value& variable_value::operator=(const variable_value& other) noexcept - { - if (this != &other) - { - this->release(); - this->assign(other.value_); - } - - return *this; - } - - variable_value& variable_value::operator=(variable_value&& other) noexcept - { - if (this != &other) - { - this->release(); - this->value_ = other.value_; - other.value_.type = game::SCRIPT_NONE; - } - - return *this; - } - - variable_value::~variable_value() - { - this->release(); - } - - const game::VariableValue& variable_value::get() const - { - return this->value_; - } - - void variable_value::assign(const game::VariableValue& value) - { - this->value_ = value; - game::AddRefToValue(this->value_.type, this->value_.u); - } - - void variable_value::release() - { - if (this->value_.type != game::SCRIPT_NONE) - { - game::RemoveRefToValue(this->value_.type, this->value_.u); - this->value_.type = game::SCRIPT_NONE; - } - } -} diff --git a/src/client/game/scripting/variable_value.hpp b/src/client/game/scripting/variable_value.hpp deleted file mode 100644 index 7a962612..00000000 --- a/src/client/game/scripting/variable_value.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace scripting -{ - class variable_value - { - public: - variable_value() = default; - variable_value(const game::VariableValue& value); - variable_value(const variable_value& other) noexcept; - variable_value(variable_value&& other) noexcept; - - variable_value& operator=(const variable_value& other) noexcept; - variable_value& operator=(variable_value&& other) noexcept; - - ~variable_value(); - - const game::VariableValue& get() const; - - private: - void assign(const game::VariableValue& value); - void release(); - - game::VariableValue value_{{0}, game::SCRIPT_NONE}; - }; -} diff --git a/src/client/game/scripting/vector.cpp b/src/client/game/scripting/vector.cpp deleted file mode 100644 index e3b66dcd..00000000 --- a/src/client/game/scripting/vector.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include "vector.hpp" - -namespace scripting -{ - vector::vector(const float* value) - { - for (auto i = 0; i < 3; ++i) - { - this->value_[i] = value[i]; - } - } - - vector::vector(const game::vec3_t& value) - : vector(&value[0]) - { - } - - vector::vector(const float x, const float y, const float z) - { - this->value_[0] = x; - this->value_[1] = y; - this->value_[2] = z; - } - - vector::operator game::vec3_t&() - { - return this->value_; - } - - vector::operator const game::vec3_t&() const - { - return this->value_; - } - - game::vec_t& vector::operator[](const size_t i) - { - if (i >= 3) - { - throw std::runtime_error("Out of bounds."); - } - - return this->value_[i]; - } - - const game::vec_t& vector::operator[](const size_t i) const - { - if (i >= 3) - { - throw std::runtime_error("Out of bounds."); - } - - return this->value_[i]; - } - - float vector::get_x() const - { - return this->operator[](0); - } - - float vector::get_y() const - { - return this->operator[](1); - } - - float vector::get_z() const - { - return this->operator[](2); - } - - void vector::set_x(const float value) - { - this->operator[](0) = value; - } - - void vector::set_y(const float value) - { - this->operator[](1) = value; - } - - void vector::set_z(const float value) - { - this->operator[](2) = value; - } -} diff --git a/src/client/game/scripting/vector.hpp b/src/client/game/scripting/vector.hpp deleted file mode 100644 index 70b146d6..00000000 --- a/src/client/game/scripting/vector.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace scripting -{ - class vector final - { - public: - vector() = default; - vector(const float* value); - vector(const game::vec3_t& value); - vector(float x, float y, float z); - - operator game::vec3_t&(); - operator const game::vec3_t&() const; - - game::vec_t& operator[](size_t i); - const game::vec_t& operator[](size_t i) const; - - float get_x() const; - float get_y() const; - float get_z() const; - - void set_x(float value); - void set_y(float value); - void set_z(float value); - - private: - game::vec3_t value_{0}; - }; -} diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 01c5cadd..283e7cb8 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -27,6 +27,8 @@ namespace game WEAK symbol AimAssist_AddToTargetList{0, 0x9D0F0}; + WEAK symbol dwGetLogOnStatus{ 0, 0x14053CCB0 }; // S1 + WEAK symbol BG_GetWeaponNameComplete{0x430550, 0x1F9670}; diff --git a/src/client/game/ui_scripting/execution.cpp b/src/client/game/ui_scripting/execution.cpp deleted file mode 100644 index fff6b88e..00000000 --- a/src/client/game/ui_scripting/execution.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include -#include "execution.hpp" -#include "component/ui_scripting.hpp" - -#include - -namespace ui_scripting -{ - void push_value(const script_value& value) - { - const auto state = *game::hks::lua_state; - const auto value_ = value.get_raw(); - *state->m_apistack.top = value_; - state->m_apistack.top++; - } - - script_value get_return_value(int offset) - { - const auto state = *game::hks::lua_state; - return state->m_apistack.top[-1 - offset]; - } - - arguments get_return_values(int count) - { - arguments values; - - for (auto i = count - 1; i >= 0; i--) - { - values.push_back(get_return_value(i)); - } - - if (values.size() == 0) - { - values.push_back({}); - } - - return values; - } - - arguments call_script_function(const function& function, const arguments& arguments) - { - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - push_value(function); - for (auto i = arguments.begin(); i != arguments.end(); ++i) - { - push_value(*i); - } - - const auto _1 = gsl::finally(&disable_error_hook); - enable_error_hook(); - - try - { - game::hks::vm_call_internal(state, static_cast(arguments.size()), -1, 0); - const auto count = static_cast(state->m_apistack.top - state->m_apistack.base); - return get_return_values(count); - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Error executing script function: ") + e.what()); - } - } - - script_value get_field(const userdata& self, const script_value& key) - { - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - push_value(key); - - const auto _1 = gsl::finally(&disable_error_hook); - enable_error_hook(); - - game::hks::HksObject value{}; - game::hks::HksObject userdata{}; - userdata.t = game::hks::TUSERDATA; - userdata.v.ptr = self.ptr; - - try - { - game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]); - return value; - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Error getting userdata field: ") + e.what()); - } - } - - script_value get_field(const table& self, const script_value& key) - { - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - push_value(key); - - const auto _1 = gsl::finally(&disable_error_hook); - enable_error_hook(); - - game::hks::HksObject value{}; - game::hks::HksObject userdata{}; - userdata.t = game::hks::TTABLE; - userdata.v.ptr = self.ptr; - - try - { - game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]); - return value; - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Error getting table field: ") + e.what()); - } - } - - void set_field(const userdata& self, const script_value& key, const script_value& value) - { - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - const auto _1 = gsl::finally(&disable_error_hook); - enable_error_hook(); - - game::hks::HksObject userdata{}; - userdata.t = game::hks::TUSERDATA; - userdata.v.ptr = self.ptr; - - try - { - game::hks::hks_obj_settable(state, &userdata, &key.get_raw(), &value.get_raw()); - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Error setting userdata field: ") + e.what()); - } - } - - void set_field(const table& self, const script_value& key, const script_value& value) - { - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - const auto _1 = gsl::finally(&disable_error_hook); - enable_error_hook(); - - game::hks::HksObject userdata{}; - userdata.t = game::hks::TTABLE; - userdata.v.ptr = self.ptr; - - try - { - game::hks::hks_obj_settable(state, &userdata, &key.get_raw(), &value.get_raw()); - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Error setting table field: ") + e.what()); - } - } -} diff --git a/src/client/game/ui_scripting/execution.hpp b/src/client/game/ui_scripting/execution.hpp deleted file mode 100644 index 24f4dd72..00000000 --- a/src/client/game/ui_scripting/execution.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "game/game.hpp" -#include "types.hpp" -#include "script_value.hpp" - -namespace ui_scripting -{ - void push_value(const script_value& value); - script_value get_return_value(int offset); - arguments get_return_values(int count); - - arguments call_script_function(const function& function, const arguments& arguments); - - script_value get_field(const userdata& self, const script_value& key); - script_value get_field(const table& self, const script_value& key); - void set_field(const userdata& self, const script_value& key, const script_value& value); - void set_field(const table& self, const script_value& key, const script_value& value); -} diff --git a/src/client/game/ui_scripting/lua/context.cpp b/src/client/game/ui_scripting/lua/context.cpp deleted file mode 100644 index afa00d5d..00000000 --- a/src/client/game/ui_scripting/lua/context.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include -#include "context.hpp" -#include "error.hpp" -#include "value_conversion.hpp" -#include "../script_value.hpp" -#include "../execution.hpp" - -#include "../../../component/ui_scripting.hpp" -#include "../../../component/command.hpp" -#include "../../../component/updater.hpp" - -#include "component/game_console.hpp" -#include "component/scheduler.hpp" - -#include -#include -#include - -namespace ui_scripting::lua -{ - namespace - { - void setup_types(sol::state& state, scheduler& scheduler) - { - struct game - { - }; - auto game_type = state.new_usertype("game_"); - state["game"] = game(); - - game_type["ontimeout"] = [&scheduler](const game&, const sol::protected_function& callback, - const long long milliseconds) - { - return scheduler.add(callback, milliseconds, true); - }; - - game_type["oninterval"] = [&scheduler](const game&, const sol::protected_function& callback, - const long long milliseconds) - { - return scheduler.add(callback, milliseconds, false); - }; - - auto userdata_type = state.new_usertype("userdata_"); - - userdata_type["new"] = sol::property( - [](const userdata& userdata, const sol::this_state s) - { - return convert(s, userdata.get("new")); - }, - [](const userdata& userdata, const sol::this_state s, const sol::lua_value& value) - { - userdata.set("new", convert({s, value})); - } - ); - - - userdata_type["get"] = [](const userdata& userdata, const sol::this_state s, - const sol::lua_value& key) - { - return convert(s, userdata.get(convert({s, key}))); - }; - - userdata_type["set"] = [](const userdata& userdata, const sol::this_state s, - const sol::lua_value& key, const sol::lua_value& value) - { - userdata.set(convert({s, key}), convert({s, value})); - }; - - userdata_type[sol::meta_function::index] = [](const userdata& userdata, const sol::this_state s, - const sol::lua_value& key) - { - return convert(s, userdata.get(convert({s, key}))); - }; - - userdata_type[sol::meta_function::new_index] = [](const userdata& userdata, const sol::this_state s, - const sol::lua_value& key, const sol::lua_value& value) - { - userdata.set(convert({s, key}), convert({s, value})); - }; - - auto table_type = state.new_usertype("table_"); - - table_type["new"] = sol::property( - [](const table& table, const sol::this_state s) - { - return convert(s, table.get("new")); - }, - [](const table& table, const sol::this_state s, const sol::lua_value& value) - { - table.set("new", convert({s, value})); - } - ); - - table_type["get"] = [](const table& table, const sol::this_state s, - const sol::lua_value& key) - { - return convert(s, table.get(convert({s, key}))); - }; - - table_type["set"] = [](const table& table, const sol::this_state s, - const sol::lua_value& key, const sol::lua_value& value) - { - table.set(convert({s, key}), convert({s, value})); - }; - - table_type[sol::meta_function::index] = [](const table& table, const sol::this_state s, - const sol::lua_value& key) - { - return convert(s, table.get(convert({s, key}))); - }; - - table_type[sol::meta_function::new_index] = [](const table& table, const sol::this_state s, - const sol::lua_value& key, const sol::lua_value& value) - { - table.set(convert({s, key}), convert({s, value})); - }; - - auto function_type = state.new_usertype("function_"); - - function_type[sol::meta_function::call] = [](const function& function, const sol::this_state s, sol::variadic_args va) - { - arguments arguments{}; - - for (auto arg : va) - { - arguments.push_back(convert({s, arg})); - } - - const auto values = function.call(arguments); - std::vector returns; - - for (const auto& value : values) - { - returns.push_back(convert(s, value)); - } - - return sol::as_returns(returns); - }; - - state["luiglobals"] = table((*::game::hks::lua_state)->globals.v.table); - state["CoD"] = state["luiglobals"]["CoD"]; - state["LUI"] = state["luiglobals"]["LUI"]; - state["Engine"] = state["luiglobals"]["Engine"]; - state["Game"] = state["luiglobals"]["Game"]; - - auto updater_table = sol::table::create(state.lua_state()); - - updater_table["relaunch"] = updater::relaunch; - - updater_table["sethastriedupdate"] = updater::set_has_tried_update; - updater_table["gethastriedupdate"] = updater::get_has_tried_update; - updater_table["autoupdatesenabled"] = updater::auto_updates_enabled; - - updater_table["startupdatecheck"] = updater::start_update_check; - updater_table["isupdatecheckdone"] = updater::is_update_check_done; - updater_table["getupdatecheckstatus"] = updater::get_update_check_status; - updater_table["isupdateavailable"] = updater::is_update_available; - - updater_table["startupdatedownload"] = updater::start_update_download; - updater_table["isupdatedownloaddone"] = updater::is_update_download_done; - updater_table["getupdatedownloadstatus"] = updater::get_update_download_status; - updater_table["cancelupdate"] = updater::cancel_update; - updater_table["isrestartrequired"] = updater::is_restart_required; - - updater_table["getlasterror"] = updater::get_last_error; - updater_table["getcurrentfile"] = updater::get_current_file; - - state["updater"] = updater_table; - } - } - - context::context(std::string data, script_type type) - : scheduler_(state_) - { - this->state_.open_libraries(sol::lib::base, - sol::lib::package, - sol::lib::io, - sol::lib::string, - sol::lib::os, - sol::lib::math, - sol::lib::table); - - setup_types(this->state_, this->scheduler_); - - if (type == script_type::file) - { - this->folder_ = data; - - this->state_["include"] = [this](const std::string& file) - { - this->load_script(file); - }; - - sol::function old_require = this->state_["require"]; - auto base_path = utils::string::replace(this->folder_, "/", ".") + "."; - this->state_["require"] = [base_path, old_require](const std::string& path) - { - return old_require(base_path + path); - }; - - this->state_["scriptdir"] = [this]() - { - return this->folder_; - }; - - printf("Loading ui script '%s'\n", this->folder_.data()); - this->load_script("__init__"); - } - - if (type == script_type::code) - { - handle_error(this->state_.safe_script(data, &sol::script_pass_on_error)); - } - } - - context::~context() - { - this->state_.collect_garbage(); - this->scheduler_.clear(); - this->state_ = {}; - } - - void context::run_frame() - { - this->scheduler_.run_frame(); - this->state_.collect_garbage(); - } - - void context::load_script(const std::string& script) - { - if (!this->loaded_scripts_.emplace(script).second) - { - return; - } - - const auto file = (std::filesystem::path{this->folder_} / (script + ".lua")).generic_string(); - handle_error(this->state_.safe_script_file(file, &sol::script_pass_on_error)); - } -} diff --git a/src/client/game/ui_scripting/lua/context.hpp b/src/client/game/ui_scripting/lua/context.hpp deleted file mode 100644 index 866c601e..00000000 --- a/src/client/game/ui_scripting/lua/context.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#pragma warning(push) -#pragma warning(disable: 4702) - -#define SOL_ALL_SAFETIES_ON 1 -#define SOL_PRINT_ERRORS 0 -#include - -#include "scheduler.hpp" - -namespace ui_scripting::lua -{ - enum script_type - { - file, - code - }; - - class context - { - public: - context(std::string folder, script_type type); - ~context(); - - context(context&&) noexcept = delete; - context& operator=(context&&) noexcept = delete; - - context(const context&) = delete; - context& operator=(const context&) = delete; - - void run_frame(); - - private: - sol::state state_{}; - std::string folder_; - std::unordered_set loaded_scripts_; - - scheduler scheduler_; - - void load_script(const std::string& script); - }; -} diff --git a/src/client/game/ui_scripting/lua/engine.cpp b/src/client/game/ui_scripting/lua/engine.cpp deleted file mode 100644 index 93713530..00000000 --- a/src/client/game/ui_scripting/lua/engine.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include "engine.hpp" -#include "context.hpp" - -#include "../../../component/ui_scripting.hpp" -#include "../../../component/game_module.hpp" - -#include - -namespace ui_scripting::lua::engine -{ - namespace - { - const auto lui_common = utils::nt::load_resource(LUI_COMMON); - const auto lui_updater = utils::nt::load_resource(LUI_UPDATER); - - auto& get_scripts() - { - static std::vector> scripts{}; - return scripts; - } - - void load_scripts(const std::string& script_dir) - { - if (!utils::io::directory_exists(script_dir)) - { - return; - } - - const auto scripts = utils::io::list_files(script_dir); - - for (const auto& script : scripts) - { - if (std::filesystem::is_directory(script) && utils::io::file_exists(script + "/__init__.lua")) - { - get_scripts().push_back(std::make_unique(script, script_type::file)); - } - } - } - - void load_code(const std::string& code) - { - get_scripts().push_back(std::make_unique(code, script_type::code)); - } - } - - void start() - { - clear_converted_functions(); - get_scripts().clear(); - - load_code(lui_common); - load_code(lui_updater); - - load_scripts(game_module::get_host_module().get_folder() + "/data/ui_scripts/"); - load_scripts("h1-mod/ui_scripts/"); - load_scripts("data/ui_scripts/"); - } - - void stop() - { - clear_converted_functions(); - get_scripts().clear(); - } - - void run_frame() - { - for (auto& script : get_scripts()) - { - script->run_frame(); - } - } -} diff --git a/src/client/game/ui_scripting/lua/engine.hpp b/src/client/game/ui_scripting/lua/engine.hpp deleted file mode 100644 index bbcf427c..00000000 --- a/src/client/game/ui_scripting/lua/engine.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace ui_scripting::lua::engine -{ - void start(); - void stop(); - void run_frame(); -} diff --git a/src/client/game/ui_scripting/lua/error.cpp b/src/client/game/ui_scripting/lua/error.cpp deleted file mode 100644 index d13b4896..00000000 --- a/src/client/game/ui_scripting/lua/error.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include "error.hpp" - -namespace ui_scripting::lua -{ - void handle_error(const sol::protected_function_result& result) - { - if (!result.valid()) - { - printf("************** UI Script execution error **************\n"); - - const sol::error err = result; - printf("%s\n", err.what()); - - printf("****************************************************\n"); - } - } -} diff --git a/src/client/game/ui_scripting/lua/error.hpp b/src/client/game/ui_scripting/lua/error.hpp deleted file mode 100644 index 28a5c453..00000000 --- a/src/client/game/ui_scripting/lua/error.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "context.hpp" - -namespace ui_scripting::lua -{ - void handle_error(const sol::protected_function_result& result); -} diff --git a/src/client/game/ui_scripting/lua/scheduler.cpp b/src/client/game/ui_scripting/lua/scheduler.cpp deleted file mode 100644 index 18e779b6..00000000 --- a/src/client/game/ui_scripting/lua/scheduler.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "std_include.hpp" -#include "context.hpp" -#include "error.hpp" - -namespace ui_scripting::lua -{ - scheduler::scheduler(sol::state& state) - { - auto task_handle_type = state.new_usertype("task_handle"); - - task_handle_type["clear"] = [this](const task_handle& handle) - { - this->remove(handle); - }; - } - - void scheduler::run_frame() - { - 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->delay) - { - ++i; - continue; - } - - i->last_call = now; - - if (!i->is_deleted) - { - handle_error(i->callback()); - } - - if (i->is_volatile || i->is_deleted) - { - i = tasks.erase(i); - } - else - { - ++i; - } - } - }); - } - - void scheduler::clear() - { - callbacks_.access([&](task_list& tasks) - { - new_callbacks_.access([&](task_list& new_tasks) - { - new_tasks.clear(); - tasks.clear(); - }); - }); - } - - task_handle scheduler::add(const sol::protected_function& callback, const long long milliseconds, - const bool is_volatile) - { - return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); - } - - task_handle scheduler::add(const sol::protected_function& callback, const std::chrono::milliseconds delay, - const bool is_volatile) - { - const uint64_t id = ++this->current_task_id_; - - task task; - task.is_volatile = is_volatile; - task.callback = callback; - task.delay = delay; - task.last_call = std::chrono::steady_clock::now(); - task.id = id; - task.is_deleted = false; - - new_callbacks_.access([&task](task_list& tasks) - { - tasks.emplace_back(std::move(task)); - }); - - return {id}; - } - - void scheduler::remove(const task_handle& handle) - { - auto mask_as_deleted = [&](task_list& tasks) - { - for (auto& task : tasks) - { - if (task.id == handle.id) - { - task.is_deleted = true; - break; - } - } - }; - - callbacks_.access(mask_as_deleted); - new_callbacks_.access(mask_as_deleted); - } - - void scheduler::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 = {}; - }); - }); - } -} diff --git a/src/client/game/ui_scripting/lua/scheduler.hpp b/src/client/game/ui_scripting/lua/scheduler.hpp deleted file mode 100644 index 1935e25e..00000000 --- a/src/client/game/ui_scripting/lua/scheduler.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include - -namespace ui_scripting::lua -{ - class context; - - class task_handle - { - public: - uint64_t id = 0; - }; - - class task final : public task_handle - { - public: - std::chrono::steady_clock::time_point last_call{}; - sol::protected_function callback{}; - std::chrono::milliseconds delay{}; - bool is_volatile = false; - bool is_deleted = false; - }; - - class scheduler final - { - public: - scheduler(sol::state& state); - - scheduler(scheduler&&) noexcept = delete; - scheduler& operator=(scheduler&&) noexcept = delete; - - scheduler(const scheduler&) = delete; - scheduler& operator=(const scheduler&) = delete; - - void run_frame(); - void clear(); - - task_handle add(const sol::protected_function& callback, long long milliseconds, bool is_volatile); - task_handle add(const sol::protected_function& callback, std::chrono::milliseconds delay, bool is_volatile); - - private: - using task_list = std::vector; - utils::concurrency::container new_callbacks_; - utils::concurrency::container callbacks_; - std::atomic_int64_t current_task_id_ = 0; - - void remove(const task_handle& handle); - void merge_callbacks(); - }; -} diff --git a/src/client/game/ui_scripting/lua/value_conversion.cpp b/src/client/game/ui_scripting/lua/value_conversion.cpp deleted file mode 100644 index 38376cdf..00000000 --- a/src/client/game/ui_scripting/lua/value_conversion.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include "value_conversion.hpp" -#include "../execution.hpp" -#include "../../../component/ui_scripting.hpp" - -namespace ui_scripting::lua -{ - namespace - { - table convert_table(const sol::table& t) - { - table res{}; - - t.for_each([res](const sol::object& key, const sol::object& value) - { - res.set(convert(key), convert(value)); - }); - - return res; - } - - script_value convert_function(const sol::protected_function& function) - { - const auto closure = game::hks::cclosure_Create(*game::hks::lua_state, main_function_handler, 0, 0, 0); - add_converted_function(closure, function); - - game::hks::HksObject value{}; - value.t = game::hks::TCFUNCTION; - value.v.cClosure = closure; - - return value; - } - } - - script_value convert(const sol::lua_value& value) - { - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is
()) - { - return {value.as
()}; - } - - if (value.is()) - { - return {value.as()}; - } - - if (value.is()) - { - return {convert_table(value.as())}; - } - - if (value.is()) - { - return {convert_function(value.as())}; - } - - return {}; - } - - sol::lua_value convert(lua_State* state, const script_value& value) - { - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - if (value.is
()) - { - return {state, value.as
()}; - } - - if (value.is()) - { - return {state, value.as()}; - } - - return {state, sol::lua_nil}; - } -} diff --git a/src/client/game/ui_scripting/lua/value_conversion.hpp b/src/client/game/ui_scripting/lua/value_conversion.hpp deleted file mode 100644 index 21a67e33..00000000 --- a/src/client/game/ui_scripting/lua/value_conversion.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "context.hpp" -#include "../script_value.hpp" - -namespace ui_scripting::lua -{ - script_value convert(const sol::lua_value& value); - sol::lua_value convert(lua_State* state, const script_value& value); -} diff --git a/src/client/game/ui_scripting/script_value.cpp b/src/client/game/ui_scripting/script_value.cpp deleted file mode 100644 index 34d17020..00000000 --- a/src/client/game/ui_scripting/script_value.cpp +++ /dev/null @@ -1,274 +0,0 @@ -#include -#include "execution.hpp" -#include "types.hpp" -#include "script_value.hpp" - -namespace ui_scripting -{ - /*************************************************************** - * Constructors - **************************************************************/ - - script_value::script_value(const game::hks::HksObject& value) - : value_(value) - { - } - - script_value::script_value(const int value) - { - game::hks::HksObject obj{}; - obj.t = game::hks::TNUMBER; - obj.v.number = static_cast(value); - - this->value_ = obj; - } - - script_value::script_value(const unsigned int value) - { - game::hks::HksObject obj{}; - obj.t = game::hks::TNUMBER; - obj.v.number = static_cast(value); - - this->value_ = obj; - } - - script_value::script_value(const bool value) - { - game::hks::HksObject obj{}; - obj.t = game::hks::TBOOLEAN; - obj.v.boolean = value; - - this->value_ = obj; - } - - script_value::script_value(const float value) - { - game::hks::HksObject obj{}; - obj.t = game::hks::TNUMBER; - obj.v.number = static_cast(value); - - this->value_ = obj; - } - - script_value::script_value(const double value) - : script_value(static_cast(value)) - { - } - - script_value::script_value(const char* value) - { - game::hks::HksObject obj{}; - - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - game::hks::hksi_lua_pushlstring(state, value, (unsigned int)strlen(value)); - obj = state->m_apistack.top[-1]; - - this->value_ = obj; - } - - script_value::script_value(const std::string& value) - : script_value(value.data()) - { - } - - script_value::script_value(const lightuserdata& value) - { - this->value_.t = game::hks::TLIGHTUSERDATA; - this->value_.v.ptr = value.ptr; - } - - script_value::script_value(const userdata& value) - { - this->value_.t = game::hks::TUSERDATA; - this->value_.v.ptr = value.ptr; - } - - script_value::script_value(const table& value) - { - this->value_.t = game::hks::TTABLE; - this->value_.v.ptr = value.ptr; - } - - script_value::script_value(const function& value) - { - this->value_.t = value.type; - this->value_.v.ptr = value.ptr; - } - - /*************************************************************** - * Integer - **************************************************************/ - - template <> - bool script_value::is() const - { - const auto number = this->get_raw().v.number; - return this->get_raw().t == game::hks::TNUMBER && static_cast(number) == number; - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - int script_value::get() const - { - return static_cast(this->get_raw().v.number); - } - - template <> - unsigned int script_value::get() const - { - return static_cast(this->get_raw().v.number); - } - - /*************************************************************** - * Boolean - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().t == game::hks::TBOOLEAN; - } - - template <> - bool script_value::get() const - { - return this->get_raw().v.boolean; - } - - /*************************************************************** - * Float - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().t == game::hks::TNUMBER; - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - float script_value::get() const - { - return this->get_raw().v.number; - } - - template <> - double script_value::get() const - { - return static_cast(this->get_raw().v.number); - } - - /*************************************************************** - * String - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().t == game::hks::TSTRING; - } - - template <> - bool script_value::is() const - { - return this->is(); - } - - template <> - const char* script_value::get() const - { - return this->get_raw().v.str->m_data; - } - - template <> - std::string script_value::get() const - { - return this->get(); - } - - /*************************************************************** - * Lightuserdata - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().t == game::hks::TLIGHTUSERDATA; - } - - template <> - lightuserdata script_value::get() const - { - return this->get_raw().v.ptr; - } - - /*************************************************************** - * Userdata - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().t == game::hks::TUSERDATA; - } - - template <> - userdata script_value::get() const - { - return this->get_raw().v.ptr; - } - - /*************************************************************** - * Table - **************************************************************/ - - template <> - bool script_value::is
() const - { - return this->get_raw().t == game::hks::TTABLE; - } - - template <> - table script_value::get() const - { - return this->get_raw().v.table; - } - - /*************************************************************** - * Function - **************************************************************/ - - template <> - bool script_value::is() const - { - return this->get_raw().t == game::hks::TIFUNCTION - || this->get_raw().t == game::hks::TCFUNCTION; - } - - template <> - function script_value::get() const - { - return { this->get_raw().v.cClosure, this->get_raw().t }; - } - - /*************************************************************** - * - **************************************************************/ - - const game::hks::HksObject& script_value::get_raw() const - { - return this->value_; - } -} diff --git a/src/client/game/ui_scripting/script_value.hpp b/src/client/game/ui_scripting/script_value.hpp deleted file mode 100644 index 3de52ddf..00000000 --- a/src/client/game/ui_scripting/script_value.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace ui_scripting -{ - class lightuserdata; - class userdata; - class table; - class function; - - class script_value - { - public: - script_value() = default; - script_value(const game::hks::HksObject& value); - - script_value(int value); - script_value(unsigned int value); - script_value(bool value); - - script_value(float value); - script_value(double value); - - script_value(const char* value); - script_value(const std::string& value); - - script_value(const lightuserdata& value); - script_value(const userdata& value); - script_value(const table& value); - script_value(const function& value); - - template - bool is() const; - - template - T as() const - { - if (!this->is()) - { - throw std::runtime_error("Invalid type"); - } - - return get(); - } - - const game::hks::HksObject& get_raw() const; - - private: - template - T get() const; - - game::hks::HksObject value_{}; - }; - - using arguments = std::vector; -} diff --git a/src/client/game/ui_scripting/types.cpp b/src/client/game/ui_scripting/types.cpp deleted file mode 100644 index 37032b1b..00000000 --- a/src/client/game/ui_scripting/types.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include -#include "types.hpp" -#include "execution.hpp" - -namespace ui_scripting -{ - /*************************************************************** - * Lightuserdata - **************************************************************/ - - lightuserdata::lightuserdata(void* ptr_) - : ptr(ptr_) - { - } - - /*************************************************************** - * Userdata - **************************************************************/ - - userdata::userdata(void* ptr_) - : ptr(ptr_) - { - this->add(); - } - - userdata::userdata(const userdata& other) - { - this->operator=(other); - } - - userdata::userdata(userdata&& other) noexcept - { - this->ptr = other.ptr; - this->ref = other.ref; - other.ref = 0; - } - - userdata::~userdata() - { - this->release(); - } - - userdata& userdata::operator=(const userdata& other) - { - if (&other != this) - { - this->release(); - this->ptr = other.ptr; - this->ref = other.ref; - this->add(); - } - - return *this; - } - - userdata& userdata::operator=(userdata&& other) noexcept - { - if (&other != this) - { - this->release(); - this->ptr = other.ptr; - this->ref = other.ref; - other.ref = 0; - } - - return *this; - } - - void userdata::add() - { - game::hks::HksObject value{}; - value.v.ptr = this->ptr; - value.t = game::hks::TUSERDATA; - - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - push_value(value); - - this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); - } - - void userdata::release() - { - if (this->ref) - { - game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); - } - } - - void userdata::set(const script_value& key, const script_value& value) const - { - set_field(*this, key, value); - } - - script_value userdata::get(const script_value& key) const - { - return get_field(*this, key); - } - - /*************************************************************** - * Table - **************************************************************/ - - table::table() - { - const auto state = *game::hks::lua_state; - this->ptr = game::hks::Hashtable_Create(state, 0, 0); - this->add(); - } - - table::table(game::hks::HashTable* ptr_) - : ptr(ptr_) - { - this->add(); - } - - table::table(const table& other) - { - this->operator=(other); - } - - table::table(table&& other) noexcept - { - this->ptr = other.ptr; - this->ref = other.ref; - other.ref = 0; - } - - table::~table() - { - this->release(); - } - - table& table::operator=(const table& other) - { - if (&other != this) - { - this->release(); - this->ptr = other.ptr; - this->ref = other.ref; - this->add(); - } - - return *this; - } - - table& table::operator=(table&& other) noexcept - { - if (&other != this) - { - this->release(); - this->ptr = other.ptr; - this->ref = other.ref; - other.ref = 0; - } - - return *this; - } - - void table::add() - { - game::hks::HksObject value{}; - value.v.table = this->ptr; - value.t = game::hks::TTABLE; - - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - push_value(value); - - this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); - } - - void table::release() - { - if (this->ref) - { - game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); - } - } - - void table::set(const script_value& key, const script_value& value) const - { - set_field(*this, key, value); - } - - script_value table::get(const script_value& key) const - { - return get_field(*this, key); - } - - /*************************************************************** - * Function - **************************************************************/ - - function::function(game::hks::cclosure* ptr_, game::hks::HksObjectType type_) - : ptr(ptr_) - , type(type_) - { - this->add(); - } - - function::function(const function& other) - { - this->operator=(other); - } - - function::function(function&& other) noexcept - { - this->ptr = other.ptr; - this->type = other.type; - this->ref = other.ref; - other.ref = 0; - } - - function::~function() - { - this->release(); - } - - function& function::operator=(const function& other) - { - if (&other != this) - { - this->release(); - this->ptr = other.ptr; - this->type = other.type; - this->ref = other.ref; - this->add(); - } - - return *this; - } - - function& function::operator=(function&& other) noexcept - { - if (&other != this) - { - this->release(); - this->ptr = other.ptr; - this->type = other.type; - this->ref = other.ref; - other.ref = 0; - } - - return *this; - } - - void function::add() - { - game::hks::HksObject value{}; - value.v.cClosure = this->ptr; - value.t = this->type; - - const auto state = *game::hks::lua_state; - state->m_apistack.top = state->m_apistack.base; - - push_value(value); - - this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); - } - - void function::release() - { - if (this->ref) - { - game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); - } - } - - arguments function::call(const arguments& arguments) const - { - return call_script_function(*this, arguments); - } -} diff --git a/src/client/game/ui_scripting/types.hpp b/src/client/game/ui_scripting/types.hpp deleted file mode 100644 index 1924407f..00000000 --- a/src/client/game/ui_scripting/types.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include "game/game.hpp" -#include "script_value.hpp" - -namespace ui_scripting -{ - class lightuserdata - { - public: - lightuserdata(void*); - void* ptr; - }; - - class userdata - { - public: - userdata(void*); - - userdata(const userdata& other); - userdata(userdata&& other) noexcept; - - ~userdata(); - - userdata& operator=(const userdata& other); - userdata& operator=(userdata&& other) noexcept; - - script_value get(const script_value& key) const; - void set(const script_value& key, const script_value& value) const; - - void* ptr; - - private: - void add(); - void release(); - - int ref{}; - }; - - class table - { - public: - table(); - table(game::hks::HashTable* ptr_); - - table(const table& other); - table(table&& other) noexcept; - - ~table(); - - table& operator=(const table& other); - table& operator=(table&& other) noexcept; - - script_value get(const script_value& key) const; - void set(const script_value& key, const script_value& value) const; - - game::hks::HashTable* ptr; - - private: - void add(); - void release(); - - int ref{}; - }; - - class function - { - public: - function(game::hks::cclosure*, game::hks::HksObjectType); - - function(const function& other); - function(function&& other) noexcept; - - ~function(); - - function& operator=(const function& other); - function& operator=(function&& other) noexcept; - - arguments call(const arguments& arguments) const; - - game::hks::cclosure* ptr; - game::hks::HksObjectType type; - - private: - void add(); - void release(); - - int ref{}; - }; -} diff --git a/src/client/main.cpp b/src/client/main.cpp index 71979cbf..7cab2c45 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -97,7 +97,7 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) if (!utils::io::read_file(binary, &data)) { throw std::runtime_error(utils::string::va( - "Failed to read game binary (%s)!\nPlease copy the h1x.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there.", + "Failed to read game binary (%s)!\nPlease copy the h1-mod.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there.", binary.data())); } From c05aea9bd969551908a112b3a5a12732d81f54c8 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:24:04 +0200 Subject: [PATCH 12/22] no unable to load error --- src/client/component/arxan.cpp | 22 +++++++++------------- src/client/main.cpp | 19 ++++++++++++++----- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index adff7199..dd38b620 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -47,6 +47,8 @@ namespace arxan { *static_cast(info) = 1; } + + //https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess } return status; @@ -113,11 +115,6 @@ namespace arxan } } - int just_return() - { - return 1; - } - class component final : public component_interface { public: @@ -128,11 +125,6 @@ namespace arxan //return set_thread_context_stub; } - if (function == "LoadStringA" || function == "LoadStringW") - { - return just_return; - } - return nullptr; } @@ -145,7 +137,7 @@ namespace arxan 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); - + // https://www.geoffchappell.com/studies/windows/win32/ntdll/api/index.htm AddVectoredExceptionHandler(1, exception_filter); } @@ -155,8 +147,12 @@ namespace arxan if (game::environment::is_sp()) return; // some of arxan crashes - utils::hook::nop(0x14CDEFCAA, 6); - utils::hook::call(0x1405BCAD1, &just_return); + utils::hook::nop(0xCDEFCAA_b, 6); + utils::hook::nop(0x930FCAA_b, 6); + utils::hook::nop(0x867B66_b, 4); + utils::hook::nop(0x81F0C0_b, 6); + utils::hook::nop(0x5813609_b, 6); + utils::hook::nop(0x8DD678_b, 0xEB); } }; } diff --git a/src/client/main.cpp b/src/client/main.cpp index 7cab2c45..247d18a0 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -50,6 +50,10 @@ launcher::mode detect_mode_from_arguments() return launcher::mode::none; } +int returning() +{ + return 1; +} FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) { @@ -75,6 +79,11 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) return get_proc_address; } + if (function == "LoadStringA" || function == "LoadStringW") + { + return returning; + } + return component_loader::load_import(library, function); }); @@ -162,12 +171,12 @@ int main() { auto premature_shutdown = true; const auto _ = gsl::finally([&premature_shutdown]() + { + if (premature_shutdown) { - if (premature_shutdown) - { - component_loader::pre_destroy(); - } - }); + component_loader::pre_destroy(); + } + }); try { From 3d32770ed7161fe0c52886905f300889c12b19d5 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:28:44 +0200 Subject: [PATCH 13/22] game launching errors [skip ci] --- src/client/component/arxan.cpp | 1 + src/client/component/game_module.cpp | 3 +- src/client/component/splash.cpp | 141 -------------------------- src/client/component/system_check.cpp | 15 +-- 4 files changed, 5 insertions(+), 155 deletions(-) delete mode 100644 src/client/component/splash.cpp diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index dd38b620..c59ae317 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -153,6 +153,7 @@ namespace arxan utils::hook::nop(0x81F0C0_b, 6); utils::hook::nop(0x5813609_b, 6); utils::hook::nop(0x8DD678_b, 0xEB); + //utils::hook::nop(0xB3D96_b, 4); } }; } diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp index bd984624..8774634d 100644 --- a/src/client/component/game_module.cpp +++ b/src/client/component/game_module.cpp @@ -3,6 +3,7 @@ #include "game_module.hpp" #include +#include namespace game_module { @@ -90,7 +91,7 @@ namespace game_module utils::nt::library get_game_module() { - static utils::nt::library game{HMODULE(0x140000000)}; + static utils::nt::library game{HMODULE(game::base_address)}; return game; } diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp deleted file mode 100644 index 3dfd6541..00000000 --- a/src/client/component/splash.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#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(0x1403E192E, 0x1405123E2), 5); // winmain doesn't even exist in 1.15? lmao - utils::hook::jump(SELECT_VALUE(0, 0x5BE1D0_b), destroy_stub); // H1-STEAM(1.15) - utils::hook::jump(SELECT_VALUE(0, 0x5BE210_b), destroy_stub); // H1-STEAM(1.15) - } - - 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("H1 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 = "H1 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, "H1 Splash Screen", "H1", - 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/system_check.cpp b/src/client/component/system_check.cpp index 9c88bd5c..7b381f4f 100644 --- a/src/client/component/system_check.cpp +++ b/src/client/component/system_check.cpp @@ -51,27 +51,18 @@ namespace system_check { static std::unordered_map mp_zone_hashes = { - {"patch_common_mp.ff", "3F44B0CFB0B8E0FBD9687C2942204AB7F11E66E6E15C73B8B4A5EB5920115A31"}, + {"patch_common_mp.ff", "E45EF5F29D12A5A47F405F89FBBEE479C0A90D02141ABF852D481689514134A1"}, }; static std::unordered_map sp_zone_hashes = { // Steam doesn't necessarily deliver this file :( - {"patch_common.ff", "BB0617DD94AF2F511571E7184BBEDE76E64D97E5D0DAFDB457F00717F035EBF0"}, + {"patch_common.ff", "1D32A9770F90ED022AA76F4859B4AB178E194A703383E61AC2CE83B1E828B18F"}, }; 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 != 0xFFB8006D && value != 0xFFB80080) - { - throw std::runtime_error("Unsupported Call of Duty: Modern Warfare Remastered version(1.4)"); - } - } } bool is_valid() @@ -85,8 +76,6 @@ namespace system_check public: void post_load() override { - verify_binary_version(); - if (!is_valid()) { MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n" From 9dca06aebfb5433349e19471fff2b546dffb0810 Mon Sep 17 00:00:00 2001 From: quaK <38787176+Joelrau@users.noreply.github.com> Date: Wed, 23 Mar 2022 04:31:01 +0200 Subject: [PATCH 14/22] disable components --- src/client/component/auth.cpp | 2 +- src/client/component/binding.cpp | 2 +- src/client/component/branding.cpp | 2 +- src/client/component/colors.cpp | 2 +- src/client/component/command.cpp | 2 +- src/client/component/console.cpp | 2 +- src/client/component/dedicated.cpp | 2 +- src/client/component/dedicated_info.cpp | 2 +- src/client/component/demonware.cpp | 2 +- src/client/component/discord.cpp | 2 +- src/client/component/dvars.cpp | 2 +- src/client/component/exception.cpp | 2 +- src/client/component/fastfiles.cpp | 2 +- src/client/component/filesystem.cpp | 2 +- src/client/component/fps.cpp | 2 +- src/client/component/game_console.cpp | 2 +- src/client/component/input.cpp | 2 +- src/client/component/localized_strings.cpp | 2 +- src/client/component/map_rotation.cpp | 2 +- src/client/component/network.cpp | 2 +- src/client/component/party.cpp | 2 +- src/client/component/patches.cpp | 2 +- src/client/component/redirect.cpp | 2 +- src/client/component/renderer.cpp | 2 +- src/client/component/scheduler.cpp | 2 +- src/client/component/server_list.cpp | 2 +- src/client/component/steam_proxy.cpp | 2 +- src/client/component/system_check.cpp | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 346c8d80..a2842e63 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -242,4 +242,4 @@ namespace auth }; } -REGISTER_COMPONENT(auth::component) +//REGISTER_COMPONENT(auth::component) diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp index e40b7f42..15828dfe 100644 --- a/src/client/component/binding.cpp +++ b/src/client/component/binding.cpp @@ -135,4 +135,4 @@ namespace binding }; } -REGISTER_COMPONENT(binding::component) +//REGISTER_COMPONENT(binding::component) diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp index 2f74693b..a95c5aa2 100644 --- a/src/client/component/branding.cpp +++ b/src/client/component/branding.cpp @@ -62,4 +62,4 @@ namespace branding }; } -REGISTER_COMPONENT(branding::component) +//REGISTER_COMPONENT(branding::component) diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp index 75eff23a..aa2631cb 100644 --- a/src/client/component/colors.cpp +++ b/src/client/component/colors.cpp @@ -179,4 +179,4 @@ namespace colors }; } -REGISTER_COMPONENT(colors::component) +//REGISTER_COMPONENT(colors::component) diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index b5c1ad40..b0b131bb 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -645,4 +645,4 @@ namespace command }; } -REGISTER_COMPONENT(command::component) +//REGISTER_COMPONENT(command::component) diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 174beaf8..8b39323f 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -296,4 +296,4 @@ namespace console } } -REGISTER_COMPONENT(console::component) +//REGISTER_COMPONENT(console::component) diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 8de5e9ac..d1399e4d 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -330,4 +330,4 @@ namespace dedicated }; } -REGISTER_COMPONENT(dedicated::component) \ No newline at end of file +//REGISTER_COMPONENT(dedicated::component) \ No newline at end of file diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp index 55973193..65aa148e 100644 --- a/src/client/component/dedicated_info.cpp +++ b/src/client/component/dedicated_info.cpp @@ -62,4 +62,4 @@ namespace dedicated_info }; } -REGISTER_COMPONENT(dedicated_info::component) \ No newline at end of file +//REGISTER_COMPONENT(dedicated_info::component) \ No newline at end of file diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index 4cb3362c..35aa1999 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -601,4 +601,4 @@ namespace demonware }; } -REGISTER_COMPONENT(demonware::component) +//REGISTER_COMPONENT(demonware::component) diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp index 5925a64a..889fc6ec 100644 --- a/src/client/component/discord.cpp +++ b/src/client/component/discord.cpp @@ -145,4 +145,4 @@ namespace discord }; } -REGISTER_COMPONENT(discord::component) \ No newline at end of file +//REGISTER_COMPONENT(discord::component) \ No newline at end of file diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp index d9c77fdf..d9633b87 100644 --- a/src/client/component/dvars.cpp +++ b/src/client/component/dvars.cpp @@ -440,4 +440,4 @@ namespace dvars }; } -REGISTER_COMPONENT(dvars::component) +//REGISTER_COMPONENT(dvars::component) diff --git a/src/client/component/exception.cpp b/src/client/component/exception.cpp index 028bb238..3867ef27 100644 --- a/src/client/component/exception.cpp +++ b/src/client/component/exception.cpp @@ -258,4 +258,4 @@ namespace exception }; } -REGISTER_COMPONENT(exception::component) +//REGISTER_COMPONENT(exception::component) diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp index d4eda37f..ab1b2534 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -46,4 +46,4 @@ namespace fastfiles }; } -REGISTER_COMPONENT(fastfiles::component) +//REGISTER_COMPONENT(fastfiles::component) diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp index da11d2e4..66cd4a4d 100644 --- a/src/client/component/filesystem.cpp +++ b/src/client/component/filesystem.cpp @@ -91,4 +91,4 @@ namespace filesystem }; } -REGISTER_COMPONENT(filesystem::component) \ No newline at end of file +//REGISTER_COMPONENT(filesystem::component) \ No newline at end of file diff --git a/src/client/component/fps.cpp b/src/client/component/fps.cpp index db471119..e1ff307a 100644 --- a/src/client/component/fps.cpp +++ b/src/client/component/fps.cpp @@ -171,4 +171,4 @@ namespace fps }; } -REGISTER_COMPONENT(fps::component) +//REGISTER_COMPONENT(fps::component) diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp index cf7c3056..854e2f94 100644 --- a/src/client/component/game_console.cpp +++ b/src/client/component/game_console.cpp @@ -790,4 +790,4 @@ namespace game_console }; } -REGISTER_COMPONENT(game_console::component) +//REGISTER_COMPONENT(game_console::component) diff --git a/src/client/component/input.cpp b/src/client/component/input.cpp index 6d28f601..a577e01b 100644 --- a/src/client/component/input.cpp +++ b/src/client/component/input.cpp @@ -51,4 +51,4 @@ namespace input }; } -REGISTER_COMPONENT(input::component) +//REGISTER_COMPONENT(input::component) diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp index 55b41d65..00bb90f3 100644 --- a/src/client/component/localized_strings.cpp +++ b/src/client/component/localized_strings.cpp @@ -49,4 +49,4 @@ namespace localized_strings }; } -REGISTER_COMPONENT(localized_strings::component) +//REGISTER_COMPONENT(localized_strings::component) diff --git a/src/client/component/map_rotation.cpp b/src/client/component/map_rotation.cpp index 216cbfcd..0da94237 100644 --- a/src/client/component/map_rotation.cpp +++ b/src/client/component/map_rotation.cpp @@ -177,4 +177,4 @@ namespace map_rotation }; } -REGISTER_COMPONENT(map_rotation::component) +//REGISTER_COMPONENT(map_rotation::component) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index fb2a6f55..129e7ffb 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -331,4 +331,4 @@ namespace network }; } -REGISTER_COMPONENT(network::component) +//REGISTER_COMPONENT(network::component) diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 0605afad..650e8c08 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -627,4 +627,4 @@ namespace party }; } -REGISTER_COMPONENT(party::component) \ No newline at end of file +//REGISTER_COMPONENT(party::component) \ No newline at end of file diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index e9aaf21a..99a8ad2e 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -290,4 +290,4 @@ namespace patches }; } -REGISTER_COMPONENT(patches::component) +//REGISTER_COMPONENT(patches::component) diff --git a/src/client/component/redirect.cpp b/src/client/component/redirect.cpp index 0443df55..9d3cc65f 100644 --- a/src/client/component/redirect.cpp +++ b/src/client/component/redirect.cpp @@ -80,4 +80,4 @@ namespace redirect }; } -REGISTER_COMPONENT(redirect::component) +//REGISTER_COMPONENT(redirect::component) diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp index b315be76..157cae74 100644 --- a/src/client/component/renderer.cpp +++ b/src/client/component/renderer.cpp @@ -73,5 +73,5 @@ namespace renderer } #ifdef DEBUG -REGISTER_COMPONENT(renderer::component) +//REGISTER_COMPONENT(renderer::component) #endif \ No newline at end of file diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index ac837128..2182784d 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -196,4 +196,4 @@ namespace scheduler }; } -REGISTER_COMPONENT(scheduler::component) +//REGISTER_COMPONENT(scheduler::component) diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp index 1b7e759e..b5e0db1e 100644 --- a/src/client/component/server_list.cpp +++ b/src/client/component/server_list.cpp @@ -440,4 +440,4 @@ namespace server_list }; } -REGISTER_COMPONENT(server_list::component) +//REGISTER_COMPONENT(server_list::component) diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp index 5fa54708..2454e01e 100644 --- a/src/client/component/steam_proxy.cpp +++ b/src/client/component/steam_proxy.cpp @@ -185,4 +185,4 @@ namespace steam_proxy } } -REGISTER_COMPONENT(steam_proxy::component) +//REGISTER_COMPONENT(steam_proxy::component) diff --git a/src/client/component/system_check.cpp b/src/client/component/system_check.cpp index 7b381f4f..3a51c715 100644 --- a/src/client/component/system_check.cpp +++ b/src/client/component/system_check.cpp @@ -86,4 +86,4 @@ namespace system_check }; } -REGISTER_COMPONENT(system_check::component) +//REGISTER_COMPONENT(system_check::component) From 3b9006d9fe1e318554e4db75d3eeb96541164e2a Mon Sep 17 00:00:00 2001 From: quaK <38787176+Joelrau@users.noreply.github.com> Date: Wed, 23 Mar 2022 04:32:09 +0200 Subject: [PATCH 15/22] update --- src/client/component/arxan.cpp | 12 ++++++------ src/client/component/game_module.cpp | 4 ++++ src/client/main.cpp | 17 ++++++----------- src/client/std_include.cpp | 17 +++++++++++++++++ src/client/std_include.hpp | 5 ++++- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index c59ae317..528de35e 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -147,12 +147,12 @@ namespace arxan if (game::environment::is_sp()) return; // some of arxan crashes - utils::hook::nop(0xCDEFCAA_b, 6); - utils::hook::nop(0x930FCAA_b, 6); - utils::hook::nop(0x867B66_b, 4); - utils::hook::nop(0x81F0C0_b, 6); - utils::hook::nop(0x5813609_b, 6); - utils::hook::nop(0x8DD678_b, 0xEB); + // utils::hook::nop(0xCDEFCAA_b, 6); + // utils::hook::nop(0x930FCAA_b, 6); + // utils::hook::nop(0x867B66_b, 4); + // utils::hook::nop(0x81F0C0_b, 6); + // utils::hook::nop(0x5813609_b, 6); + // utils::hook::nop(0x8DD678_b, 0xEB); //utils::hook::nop(0xB3D96_b, 4); } }; diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp index 8774634d..0ec79d45 100644 --- a/src/client/component/game_module.cpp +++ b/src/client/component/game_module.cpp @@ -111,7 +111,11 @@ namespace game_module void post_load() override { +#ifdef INJECT_HOST_AS_LIB hook_module_resolving(); +#else + assert(get_host_module() == get_game_module()); +#endif } }; } diff --git a/src/client/main.cpp b/src/client/main.cpp index 247d18a0..c6f7ad62 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -22,7 +22,7 @@ BOOL WINAPI system_parameters_info_a(const UINT uiAction, const UINT uiParam, co FARPROC WINAPI get_proc_address(const HMODULE hModule, const LPCSTR lpProcName) { - if (lpProcName == "GlobalMemoryStatusEx"s) + if (lpProcName == "InitializeCriticalSectionEx"s) { component_loader::post_unpack(); } @@ -50,11 +50,6 @@ launcher::mode detect_mode_from_arguments() return launcher::mode::none; } -int returning() -{ - return 1; -} - FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) { loader loader; @@ -79,11 +74,6 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) return get_proc_address; } - if (function == "LoadStringA" || function == "LoadStringW") - { - return returning; - } - return component_loader::load_import(library, function); }); @@ -110,7 +100,12 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) binary.data())); } +#ifdef INJECT_HOST_AS_LIB return loader.load_library(binary, base_address); +#else + *base_address = 0x140000000; + return loader.load(self, data); +#endif } void remove_crash_file() diff --git a/src/client/std_include.cpp b/src/client/std_include.cpp index efe6cd64..75331ed0 100644 --- a/src/client/std_include.cpp +++ b/src/client/std_include.cpp @@ -1,6 +1,23 @@ #include +#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:0x160000000") +#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" { diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index 98a00a2d..0fd21793 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -1,6 +1,9 @@ #pragma once -#define BINARY_PAYLOAD_SIZE 0x12000000 +#define BINARY_PAYLOAD_SIZE 0x14000000 + +// Decide whether to load the game as lib or to inject it +//#define INJECT_HOST_AS_LIB #pragma warning(push) #pragma warning(disable: 4100) From 5de685e1e00f8f0fd2d463b5b7a8346d906ff656 Mon Sep 17 00:00:00 2001 From: Skull Merlin <86374920+skkuull@users.noreply.github.com> Date: Wed, 11 May 2022 23:14:48 +0300 Subject: [PATCH 16/22] remove this --- src/client/component/arxan.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index 528de35e..02989710 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -145,17 +145,8 @@ namespace arxan { // cba to implement sp, not sure if it's even needed if (game::environment::is_sp()) return; - - // some of arxan crashes - // utils::hook::nop(0xCDEFCAA_b, 6); - // utils::hook::nop(0x930FCAA_b, 6); - // utils::hook::nop(0x867B66_b, 4); - // utils::hook::nop(0x81F0C0_b, 6); - // utils::hook::nop(0x5813609_b, 6); - // utils::hook::nop(0x8DD678_b, 0xEB); - //utils::hook::nop(0xB3D96_b, 4); } }; } -REGISTER_COMPONENT(arxan::component) \ No newline at end of file +REGISTER_COMPONENT(arxan::component) From a5a3fdd67289aff17669c5e6877350e2e6ffc313 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 17 May 2022 10:38:54 +0200 Subject: [PATCH 17/22] Basic 1.15 support --- premake5.lua | 2 +- src/client/component/arxan.cpp | 20 +++++++++++++++++++- src/client/main.cpp | 3 ++- src/client/std_include.cpp | 13 +++++++------ src/client/std_include.hpp | 2 +- src/client/steam/steam.cpp | 9 +++++++++ 6 files changed, 39 insertions(+), 10 deletions(-) diff --git a/premake5.lua b/premake5.lua index 16043516..299c9b69 100644 --- a/premake5.lua +++ b/premake5.lua @@ -302,7 +302,7 @@ targetname "h1-mod" pchheader "std_include.hpp" pchsource "src/client/std_include.cpp" -linkoptions {"/IGNORE:4254", "/DYNAMICBASE:NO", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/LAST:.main", "/PDBCompress"} +linkoptions {"/IGNORE:4254", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/PDBCompress"} files {"./src/client/**.rc", "./src/client/**.hpp", "./src/client/**.cpp", "./src/client/resources/**.*"} diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index 02989710..98b3d108 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -9,6 +9,24 @@ namespace arxan { namespace { + DWORD get_steam_pid() + { + static DWORD pid = 0; //234567;//GetCurrentProcessId(); + if (pid) return pid; + + HKEY hRegKey; + + if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", 0, KEY_QUERY_VALUE, + &hRegKey) != ERROR_SUCCESS) + return pid; + + DWORD dwLength = sizeof(pid); + RegQueryValueExA(hRegKey, "pid", nullptr, nullptr, reinterpret_cast(&pid), &dwLength); + RegCloseKey(hRegKey); + + return pid; + } + utils::hook::detour nt_close_hook; utils::hook::detour nt_query_information_process_hook; @@ -31,7 +49,7 @@ namespace arxan GetWindowThreadProcessId(shell_window, &explorer_pid); } - static_cast(info)->Reserved3 = PVOID(DWORD64(explorer_pid)); + static_cast(info)->Reserved3 = PVOID(DWORD64(get_steam_pid())); } else if (info_class == 30) // ProcessDebugObjectHandle { diff --git a/src/client/main.cpp b/src/client/main.cpp index c6f7ad62..a8c3a78b 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -57,7 +57,8 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) loader.set_import_resolver([self](const std::string& library, const std::string& function) -> void* { - if (library == "steam_api64.dll") + if (library == "steam_api64.dll" + && function != "SteamAPI_GetSteamInstallPath") // Arxan requires one valid steam api import - maybe SteamAPI_Shutdown is better? { return self.get_proc(function); } diff --git a/src/client/std_include.cpp b/src/client/std_include.cpp index 75331ed0..5622d708 100644 --- a/src/client/std_include.cpp +++ b/src/client/std_include.cpp @@ -1,15 +1,15 @@ #include +#pragma comment(linker, "/stack:0x1000000") + +#ifdef INJECT_HOST_AS_LIB +//#pragma comment(linker, "/base:0x160000000") +#else +#pragma comment(linker, "/base:0x140000000") #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:0x160000000") -#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=''\"") @@ -47,3 +47,4 @@ extern "C" return -1; } } + diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index 0fd21793..e43275c3 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -3,7 +3,7 @@ #define BINARY_PAYLOAD_SIZE 0x14000000 // Decide whether to load the game as lib or to inject it -//#define INJECT_HOST_AS_LIB +#define INJECT_HOST_AS_LIB #pragma warning(push) #pragma warning(disable: 4100) diff --git a/src/client/steam/steam.cpp b/src/client/steam/steam.cpp index b6fb0dbe..bad30c5a 100644 --- a/src/client/steam/steam.cpp +++ b/src/client/steam/steam.cpp @@ -1,6 +1,8 @@ #include #include "steam.hpp" +#include + namespace steam { uint64_t callbacks::call_id_ = 0; @@ -108,6 +110,13 @@ namespace steam bool SteamAPI_Init() { + const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); + if (steam_path.empty()) return true; + + ::utils::nt::library::load(steam_path / "tier0_s64.dll"); + ::utils::nt::library::load(steam_path / "vstdlib_s64.dll"); + ::utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); + ::utils::nt::library::load(steam_path / "steamclient64.dll"); return true; } From 0d57bc01c4c02501d7c9e7c3df396407d6bc6e3e Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 17 May 2022 11:38:49 +0200 Subject: [PATCH 18/22] Fix hooking --- src/client/main.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/client/main.cpp b/src/client/main.cpp index a8c3a78b..e8d7dcff 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -20,16 +20,6 @@ BOOL WINAPI system_parameters_info_a(const UINT uiAction, const UINT uiParam, co return SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni); } -FARPROC WINAPI get_proc_address(const HMODULE hModule, const LPCSTR lpProcName) -{ - if (lpProcName == "InitializeCriticalSectionEx"s) - { - component_loader::post_unpack(); - } - - return GetProcAddress(hModule, lpProcName); -} - launcher::mode detect_mode_from_arguments() { if (utils::flags::has_flag("dedicated")) @@ -70,10 +60,6 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address) { return system_parameters_info_a; } - else if (function == "GetProcAddress") - { - return get_proc_address; - } return component_loader::load_import(library, function); }); From 939ecbb3b688fd47bd2e35d7c3de0146299643f7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 17 May 2022 11:39:16 +0200 Subject: [PATCH 19/22] Fix scheduler --- src/client/component/scheduler.cpp | 32 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index 2182784d..5a657a4c 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -75,7 +75,8 @@ namespace scheduler { new_callbacks_.access([&](task_list& new_tasks) { - tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), std::move_iterator(new_tasks.end())); + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), + std::move_iterator(new_tasks.end())); new_tasks = {}; }); }); @@ -98,7 +99,7 @@ namespace scheduler void r_end_frame_stub() { execute(pipeline::renderer); - r_end_frame_hook.invoke(); + //r_end_frame_hook.invoke(); } void server_frame_stub() @@ -115,7 +116,7 @@ namespace scheduler } void schedule(const std::function& callback, const pipeline type, - const std::chrono::milliseconds delay) + const std::chrono::milliseconds delay) { assert(type >= 0 && type < pipeline::count); @@ -128,7 +129,7 @@ namespace scheduler } void loop(const std::function& callback, const pipeline type, - const std::chrono::milliseconds delay) + const std::chrono::milliseconds delay) { schedule([callback]() { @@ -138,7 +139,7 @@ namespace scheduler } void once(const std::function& callback, const pipeline type, - const std::chrono::milliseconds delay) + const std::chrono::milliseconds delay) { schedule([callback]() { @@ -148,7 +149,7 @@ namespace scheduler } void on_game_initialized(const std::function& callback, const pipeline type, - const std::chrono::milliseconds delay) + const std::chrono::milliseconds delay) { schedule([=]() { @@ -180,8 +181,21 @@ namespace scheduler void post_unpack() override { - r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); // H1-STEAM(1.15) - g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); // H1(1.15) + utils::hook::jump(SELECT_VALUE(0, 0x6A6300_b), utils::hook::assemble([](utils::hook::assembler& a) + { + a.pushad64(); + a.call_aligned(r_end_frame_stub); + a.popad64(); + + a.sub(rsp, 0x28); + a.call(0x6A5C20_b); + a.mov(rax, 0xEAB4308_b); + a.mov(rax, qword_ptr(rax)); + a.jmp(0x6A6310_b); + }), true); + + //r_end_frame_hook.create(SELECT_VALUE(0, 0x6A6300_b), scheduler::r_end_frame_stub); // H1-STEAM(1.15) + //g_run_frame_hook.create(SELECT_VALUE(0, 0x417940_b), scheduler::server_frame_stub); // H1(1.15) //main_frame_hook.create(SELECT_VALUE(0x1401CE8D0, 0x1400D8310), scheduler::main_frame_stub); can't find } @@ -196,4 +210,4 @@ namespace scheduler }; } -//REGISTER_COMPONENT(scheduler::component) +REGISTER_COMPONENT(scheduler::component) From 4a06c810cffb16ba147b155f36d21539a8adc682 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 17 May 2022 12:05:51 +0200 Subject: [PATCH 20/22] Some branding stuff --- src/client/component/branding.cpp | 19 ++++++++++--------- src/client/game/symbols.hpp | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp index a95c5aa2..4618a9b0 100644 --- a/src/client/component/branding.cpp +++ b/src/client/component/branding.cpp @@ -34,7 +34,6 @@ namespace branding public: void post_unpack() override { - if (game::environment::is_dedi()) { return; @@ -42,24 +41,26 @@ namespace branding if (game::environment::is_mp()) { - localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER\n"); - localized_strings::override("MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER"); + //localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER\n"); + //localized_strings::override("MENU_MULTIPLAYER_CAPS", "H1-MOD: MULTIPLAYER"); } - dvars::override::set_string("version", utils::string::va("H1-Mod %s", VERSION)); + //dvars::override::set_string("version", utils::string::va("H1-Mod %s", VERSION)); ui_get_formatted_build_number_hook.create( - SELECT_VALUE(0x1403B1C40, 0x1404E74C0), ui_get_formatted_build_number_stub); + SELECT_VALUE(0x1403B1C40, 0x1DF300_b), ui_get_formatted_build_number_stub); scheduler::loop([]() { const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20); - - game::R_AddCmdDrawText("H1-Mod: " VERSION, 0x7FFFFFFF, font, 10.f, - 5.f + static_cast(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0); + if (font) + { + game::R_AddCmdDrawText("H1-Mod: " VERSION, 0x7FFFFFFF, font, 10.f, + 5.f + static_cast(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0); + } }, scheduler::pipeline::renderer); } }; } -//REGISTER_COMPONENT(branding::component) +REGISTER_COMPONENT(branding::component) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 283e7cb8..f6f58353 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -96,8 +96,8 @@ namespace game float* color, Material* material)> R_AddCmdDrawStretchPic{0x17E5C0, 0x2443A0}; WEAK symbol R_RegisterFont{ 0x4D4100, 0x67F630 }; // H1MP(1.15) WEAK symbol R_TextWidth{0x4D43B0, 0x5D94A0}; - WEAK symbol R_GetFontHeight{0x5EA360, 0x5D92C0}; - WEAK symbol R_DrawSomething{0x4D37B0, 0x5D8890}; + WEAK symbol R_GetFontHeight{0x5EA360, 0x67F710}; + WEAK symbol R_DrawSomething{0x4D37B0, 0x67ECE0}; WEAK symbol R_SyncRenderThread{0x4F8240, 0x5FF3A0}; WEAK symbol H1_AddBaseDrawTextCmd{ 0x4F3DC0,0x6A3080 }; // H1MP(1.15) From 886d384b8a0cdc8a87205a22f3c1134a1c25be0b Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Tue, 17 May 2022 19:56:53 +0200 Subject: [PATCH 21/22] Stuff --- src/client/component/console.cpp | 292 +++--------------- src/client/component/demonware.cpp | 110 ++++--- src/client/game/demonware/data_types.hpp | 37 +++ .../game/demonware/services/bdStorage.cpp | 41 ++- 4 files changed, 187 insertions(+), 293 deletions(-) diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 8b39323f..78ed8422 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -1,14 +1,10 @@ #include #include "console.hpp" #include "loader/component_loader.hpp" + #include "game/game.hpp" #include "command.hpp" -#include -#include -#include -#include - namespace game_console { void print(int type, const std::string& data); @@ -18,271 +14,50 @@ namespace console { namespace { - using message_queue = std::queue; - utils::concurrency::container messages; - - bool native_console() + DWORD WINAPI console(LPVOID) { - static const auto flag = utils::flags::has_flag("nativeconsole"); - return flag; - } + FreeConsole(); + AllocConsole(); + AttachConsole(GetCurrentProcessId()); - void hide_console() - { - auto* const con_window = GetConsoleWindow(); + (void)freopen("CONIN$", "r", stdin); + (void)freopen("CONOUT$", "w", stdout); - DWORD process; - GetWindowThreadProcessId(con_window, &process); - - if (!native_console() && (process == GetCurrentProcessId() || IsDebuggerPresent())) - { - ShowWindow(con_window, SW_HIDE); - } - } - - std::string format(va_list* ap, const char* message) - { - static thread_local char buffer[0x1000]; - - const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); - - if (count < 0) return {}; - return {buffer, static_cast(count)}; - } - - void dispatch_message(const int type, const std::string& message) - { - if (native_console()) - { - printf("%s\n", message.data()); - return; - } - - game_console::print(type, message); - messages.access([&message](message_queue& msgs) - { - msgs.emplace(message); - }); - } - - void append_text(const char* text) - { - dispatch_message(con_type_info, text); - } - } - - class component final : public component_interface - { - public: - component() - { - hide_console(); - - if (native_console()) - { - setvbuf(stdout, nullptr, _IONBF, 0); - setvbuf(stderr, nullptr, _IONBF, 0); - } - else - { - (void)_pipe(this->handles_, 1024, _O_TEXT); - (void)_dup2(this->handles_[1], 1); - (void)_dup2(this->handles_[1], 2); - } - } - - void post_start() override - { - this->terminate_runner_ = false; - - this->console_runner_ = utils::thread::create_named_thread("Console IO", [this] - { - if (native_console()) - { - this->native_input(); - } - else - { - this->runner(); - } - }); - } - - void pre_destroy() override - { - this->terminate_runner_ = true; - - printf("\r\n"); - _flushall(); - - if (this->console_runner_.joinable()) - { - this->console_runner_.join(); - } - - if (this->console_thread_.joinable()) - { - this->console_thread_.join(); - } - -#ifndef NATIVE_CONSOLE - _close(this->handles_[0]); - _close(this->handles_[1]); -#endif - - messages.access([&](message_queue& msgs) - { - msgs = {}; - }); - } - - void post_unpack() override - { - // Redirect input (]command) - utils::hook::jump(SELECT_VALUE(0x1403E34C0, 0x1405141E0), append_text); // H1(1.4) - - this->initialize(); - } - - private: - volatile bool console_initialized_ = false; - volatile bool terminate_runner_ = false; - - std::thread console_runner_; - std::thread console_thread_; - - int handles_[2]{}; - - void initialize() - { - this->console_thread_ = utils::thread::create_named_thread("Console", [this]() - { - if (!native_console() && (game::environment::is_dedi() || !utils::flags::has_flag("noconsole"))) - { - game::Sys_ShowConsole(); - } - - if (!game::environment::is_dedi()) - { - // Hide that shit - ShowWindow(console::get_window(), SW_MINIMIZE); - } - - { - messages.access([&](message_queue&) - { - this->console_initialized_ = true; - }); - } - - MSG msg; - while (!this->terminate_runner_) - { - if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - command::execute("quit", false); - break; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - this->log_messages(); - std::this_thread::sleep_for(1ms); - } - } - }); - } - - void log_messages() - { - /*while*/ - if (this->console_initialized_ && !messages.get_raw().empty()) - { - std::queue message_queue_copy; - - { - messages.access([&](message_queue& msgs) - { - message_queue_copy = std::move(msgs); - msgs = {}; - }); - } - - while (!message_queue_copy.empty()) - { - log_message(message_queue_copy.front()); - message_queue_copy.pop(); - } - } - - fflush(stdout); - fflush(stderr); - } - - static void log_message(const std::string& message) - { - OutputDebugStringA(message.data()); - game::Conbuf_AppendText(message.data()); - } - - void runner() - { - char buffer[1024]; - - while (!this->terminate_runner_ && this->handles_[0]) - { - const auto len = _read(this->handles_[0], buffer, sizeof(buffer)); - if (len > 0) - { - dispatch_message(con_type_info, std::string(buffer, len)); - } - else - { - std::this_thread::sleep_for(1ms); - } - } - - std::this_thread::yield(); - } - - void native_input() - { std::string cmd; - while (!this->terminate_runner_) + while (true) { std::getline(std::cin, cmd); - command::execute(cmd); + } - std::this_thread::yield(); + return 0; } - }; - - HWND get_window() - { - return *reinterpret_cast((SELECT_VALUE(0x14CF56C00, 0x14DDFC2D0))); // H1(1.4) } - void set_title(std::string title) + std::string format(va_list* ap, const char* message) { - SetWindowText(get_window(), title.data()); + static thread_local char buffer[0x1000]; + + const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); + + if (count < 0) return {}; + return { buffer, static_cast(count) }; } - void set_size(const int width, const int height) + void dispatch_message(const int type, const std::string& message) { - RECT rect; - GetWindowRect(get_window(), &rect); + //if (native_console()) + //{ + printf("%s\n", message.data()); + // return; + //} - SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0); - - auto* const logo_window = *reinterpret_cast(SELECT_VALUE(0x14CF56C10, 0x14DDFC2E0)); // H1(1.4) - SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0); + //game_console::print(type, message); + //messages.access([&message](message_queue& msgs) + // { + // msgs.emplace(message); + // }); } void print(const int type, const char* fmt, ...) @@ -294,6 +69,15 @@ namespace console dispatch_message(type, result); } + + class component final : public component_interface + { + public: + void post_start() override + { + CreateThread(0, 0, console, 0, 0, 0); + } + }; } -//REGISTER_COMPONENT(console::component) +REGISTER_COMPONENT(console::component) diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index 35aa1999..7c2b1460 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -297,7 +297,7 @@ namespace demonware if (server) { - server->handle_input(buf, len, {s, to, tolen}); + server->handle_input(buf, len, { s, to, tolen }); return len; } @@ -425,9 +425,9 @@ namespace demonware } } - void bd_logger_stub(char* a1, void* a2, void* a3, void* a4, const char* function, ...) + void bd_logger_stub() { - + //printf("logged\n"); } #ifdef DEBUG @@ -481,6 +481,32 @@ namespace demonware printf("bdAuth: Unknown error\n"); } #endif + + utils::hook::detour kekw_hook; + bool kekw_stub(__int64 a1, __int64 a2, __int64* a3) + { + // Checks X-Signature header or something + utils::hook::set(0x7D4AB0_b, 0xC301B0); + // Checks extended_data and extra_data in json object + utils::hook::set(0x7D55C0_b, 0xC301B0); + return kekw_hook.invoke(a1, a2, a3); + } + + void* allocate_somewhere_near(uint8_t* base_address) + { + const size_t PAGE_SIZE = 0x1000; + size_t offset = 0; + while (true) + { + offset += PAGE_SIZE; + auto res = VirtualAlloc(base_address - offset, PAGE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (res) + { + std::memset(res, 0, PAGE_SIZE); + return res; + } + } + } } class component final : public component_interface @@ -542,52 +568,64 @@ namespace demonware gethostbyname has been replaced with getaddrinfo btw, still you can't get online.. */ - utils::hook::jump(SELECT_VALUE(0x140610320, 0x1407400B0), bd_logger_stub); // H1MP64(1.4) + //utils::hook::jump(SELECT_VALUE(0, 0x7EBC20_b), bd_logger_stub); if (game::environment::is_sp()) { - utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) - utils::hook::set(0x140333A00, 0xC3); // dwNet H1(1.4) + // utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) + // utils::hook::set(0x140333A00, 0xC3); // dwNet H1(1.4) return; } - utils::hook::set(0x140715039, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.4) - utils::hook::set(0x140715025, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.4) - utils::hook::set(0x14095433C, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] + utils::hook::set(0x7C0AD9_b, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.15) + utils::hook::set(0x7C0AC5_b, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.15) + utils::hook::set(0xA1327C_b, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] //HTTPS -> HTTP - utils::hook::inject(0x14006DDA9, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003852E] - utils::hook::inject(0x14006E11C, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003884F] - utils::hook::inject(0x14006E2FB, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x140038A07] - utils::hook::inject(0x14006E9A9, "http://prod.uno.demonware.net/v1.0/"); - utils::hook::inject(0x14006ED49, "http://prod.uno.demonware.net/v1.0/"); - utils::hook::inject(0x140728170, "http://%s:%d/auth/"); + char* umbrella = (char*)allocate_somewhere_near((uint8_t*)game::base_address); + std::memcpy(umbrella, "http://prod.umbrella.demonware.net/v1.0/", sizeof("http://prod.umbrella.demonware.net/v1.0/")); - utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) - utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) + utils::hook::inject(0x8615F_b, umbrella); + utils::hook::inject(0x8638C_b, umbrella); -#ifdef DEBUG - // yes - utils::hook::call(0x140727BEB, l); - utils::hook::call(0x140727AFC, i); - utils::hook::call(0x140727E49, h); - utils::hook::call(0x140727E30, g); - utils::hook::call(0x140727E37, f); - utils::hook::call(0x140727DF2, e); - utils::hook::call(0x140727DF9, d); - utils::hook::call(0x140727CFC, c); - utils::hook::call(0x140727C82, b); - utils::hook::call(0x140727E6A, a); -#endif + char* uno = (char*)allocate_somewhere_near((uint8_t*)game::base_address); + std::memcpy(uno, "http://prod.uno.demonware.net/v1.0/", sizeof("http://prod.uno.demonware.net/v1.0/")); + + utils::hook::inject(0x86C56_b, uno); + utils::hook::inject(0x86F96_b, uno); + + BYTE bytes[] = { 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2F, 0x61, 0x75, 0x74, 0x68, 0x2F, 0x0 }; // KEKW + std::memcpy((void*)0x9EDB08_b, bytes, sizeof(bytes)); //utils::hook::inject(0x140728170, "http://%s:%d/auth/"); :DDD + + //utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) + //utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) + +//#ifdef DEBUG +// // yes +// utils::hook::call(0x140727BEB, l); +// utils::hook::call(0x140727AFC, i); +// utils::hook::call(0x140727E49, h); +// utils::hook::call(0x140727E30, g); +// utils::hook::call(0x140727E37, f); +// utils::hook::call(0x140727DF2, e); +// utils::hook::call(0x140727DF9, d); +// utils::hook::call(0x140727CFC, c); +// utils::hook::call(0x140727C82, b); +// utils::hook::call(0x140727E6A, a); +//#endif // Checks X-Signature header or something - utils::hook::set(0x140728380, 0xC301B0); + //utils::hook::set(0x7D4AB0_b, 0xC301B0); // Checks extended_data and extra_data in json object - utils::hook::set(0x140728E90, 0xC301B0); + //utils::hook::set(0x7D55C0_b, 0xC301B0); // Update check - utils::hook::set(0x1403A5390, 0xC301B0); - + //utils::hook::set(0x1403A5390, 0xC301B0); + // Remove some while loop in demonware that freezes the rendering for a few secs at launch - utils::hook::nop(0x14057DBC5, 5); + //utils::hook::nop(0x14057DBC5, 5); + + MessageBoxA(0, "TEST", "", 0); + kekw_hook.create(0x7AC600_b, kekw_stub); + MessageBoxA(0, "TEST2", "", 0); } void pre_destroy() override @@ -601,4 +639,4 @@ namespace demonware }; } -//REGISTER_COMPONENT(demonware::component) +REGISTER_COMPONENT(demonware::component) diff --git a/src/client/game/demonware/data_types.hpp b/src/client/game/demonware/data_types.hpp index fb108190..579e2248 100644 --- a/src/client/game/demonware/data_types.hpp +++ b/src/client/game/demonware/data_types.hpp @@ -170,4 +170,41 @@ namespace demonware buffer->read_blob(&this->data); } }; + + class bdFile2 final : public bdTaskResult + { + public: + uint32_t unk1; + uint32_t unk2; + uint32_t unk3; + bool priv; + uint64_t owner_id; + std::string platform; + std::string filename; + std::string data; + + void serialize(byte_buffer* buffer) override + { + buffer->write_uint32(this->unk1); + buffer->write_uint32(this->unk2); + buffer->write_uint32(this->unk3); + buffer->write_bool(this->priv); + buffer->write_uint64(this->owner_id); + buffer->write_string(this->platform); + buffer->write_string(this->filename); + buffer->write_blob(this->data); + } + + void deserialize(byte_buffer* buffer) override + { + buffer->read_uint32(&this->unk1); + buffer->read_uint32(&this->unk2); + buffer->read_uint32(&this->unk3); + buffer->read_bool(&this->priv); + buffer->read_uint64(&this->owner_id); + buffer->read_string(&this->platform); + buffer->read_string(&this->filename); + buffer->read_blob(&this->data); + } + }; } diff --git a/src/client/game/demonware/services/bdStorage.cpp b/src/client/game/demonware/services/bdStorage.cpp index 2e7f026c..9f398868 100644 --- a/src/client/game/demonware/services/bdStorage.cpp +++ b/src/client/game/demonware/services/bdStorage.cpp @@ -172,15 +172,45 @@ namespace demonware const auto path = get_user_file_path(filename); utils::io::write_file(path, data); - auto* info = new bdFileInfo; + auto* info = new bdFile2; - info->file_id = *reinterpret_cast(utils::cryptography::sha1::compute(filename).data()); + // int + // int + // int + // byte (priv) + // int64 (owner) + // string (platform) + // string (file) + // blob + // size + // data + // int + // int + // int + // byte + // int64 + // string (platform) + // string (file) + // blob + // size + // data + + info->unk1 = 0; + info->unk2 = 0; + info->unk3 = 0; + info->priv = false; + info->owner_id = owner; + info->platform = platform; + info->filename = filename; + info->data = data; + + /*info->file_id = *reinterpret_cast(utils::cryptography::sha1::compute(filename).data()); info->filename = filename; info->create_time = uint32_t(time(nullptr)); info->modified_time = info->create_time; info->file_size = uint32_t(data.size()); info->owner_id = uint64_t(owner); - info->priv = priv; + info->priv = priv;*/ #ifdef DEBUG printf("[DW]: [bdStorage]: set user file: %s\n", filename.data()); @@ -213,6 +243,8 @@ namespace demonware auto reply = server->create_reply(this->task_id()); + printf("%i\n", numfiles); + for (uint32_t i = 0; i < numfiles; i++) { std::string filename, data; @@ -221,6 +253,9 @@ namespace demonware const auto path = get_user_file_path(filename); if (!utils::io::read_file(path, &data)) { +#ifdef DEBUG + printf("[DW]: [bdStorage]: get user file: missing file: %s, %s, %s\n", game.data(), filename.data(), platform.data()); +#endif continue; } From 8efcb7b8bc061126f11d36688fdfbde6f35d866e Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Wed, 18 May 2022 01:56:15 +0200 Subject: [PATCH 22/22] Fixes + some cleanup --- src/client/component/auth.cpp | 35 +++++++------ src/client/component/demonware.cpp | 50 ++++++++----------- .../game/demonware/services/bdStorage.cpp | 31 ------------ .../game/demonware/services/bdUNK80.cpp | 3 +- 4 files changed, 42 insertions(+), 77 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index a2842e63..f633f740 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -213,33 +213,36 @@ namespace auth // Patch steam id bit check if (game::environment::is_sp()) { - utils::hook::jump(0x140475C17, 0x140475C6A); // H1(1.4) - utils::hook::jump(0x140476AFF, 0x140476B40); // H1(1.4) - utils::hook::jump(0x140476FA4, 0x140476FF2); // H1(1.4) + //utils::hook::jump(0x140475C17, 0x140475C6A); // H1(1.4) + //utils::hook::jump(0x140476AFF, 0x140476B40); // H1(1.4) + //utils::hook::jump(0x140476FA4, 0x140476FF2); // H1(1.4) } else { - utils::hook::jump(0x1D6193_b, 0x1D61FA_b); // STEAM - utils::hook::jump(0x60153_b, 0x60426_b); // STEAM - utils::hook::jump(0x603E1_b, 0x60426_b); // STEAM - utils::hook::jump(0x1D7542_b, 0x1D7587_b); // STEAM MAYBE `1401D7553` ON FIRST - utils::hook::jump(0x1D7A82_b, 0x1D7AC8_b); // STEAM + // kill "disconnected from steam" error + utils::hook::nop(0x1D61DF_b, 0x11); + + /*utils::hook::nop(0x1D6193_b, 103); // STEAM + utils::hook::nop(0x60153_b, 0x60426 - 0x60153); // STEAM + utils::hook::nop(0x603E1_b, 0x60426 - 0x603E1); // STEAM + utils::hook::nop(0x1D7553_b, 0x1D7587 - 0x1D7553); // STEAM MAYBE `1401D7553` ON FIRST + utils::hook::nop(0x1D7A82_b, 0x1D7AC8 - 0x1D7A82); // STEAM*/ //utils::hook::jump(0x140488BC1, get_direct_connect_stub(), true); // H1(1.4) can't find - utils::hook::call(0x12D437_b, send_connect_data_stub); // H1(1.4) + //utils::hook::call(0x12D437_b, send_connect_data_stub); // H1(1.4) // Skip checks for sending connect packet - utils::hook::jump(0x1402508FC, 0x140250946); + //utils::hook::jump(0x1402508FC, 0x140250946); // Don't instantly timeout the connecting client ? not sure about this - utils::hook::set(0x14025136B, 0xC3); + //utils::hook::set(0x14025136B, 0xC3); } - command::add("guid", []() - { - printf("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits); - }); + //command::add("guid", []() + //{ + // printf("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits); + //}); } }; } -//REGISTER_COMPONENT(auth::component) +REGISTER_COMPONENT(auth::component) diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index 7c2b1460..fd5afcae 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -482,14 +482,15 @@ namespace demonware } #endif - utils::hook::detour kekw_hook; - bool kekw_stub(__int64 a1, __int64 a2, __int64* a3) + utils::hook::detour handle_auth_reply_hook; + bool handle_auth_reply_stub(void* a1, void* a2, void* a3) { - // Checks X-Signature header or something + // Skip bdAuth::validateResponseSignature utils::hook::set(0x7D4AB0_b, 0xC301B0); - // Checks extended_data and extra_data in json object + // Skip bdAuth::processPlatformData utils::hook::set(0x7D55C0_b, 0xC301B0); - return kekw_hook.invoke(a1, a2, a3); + + return handle_auth_reply_hook.invoke(a1, a2, a3); } void* allocate_somewhere_near(uint8_t* base_address) @@ -563,13 +564,6 @@ namespace demonware void post_unpack() override { - /* - mwr has upgraded some networking methods and the gethostbyname import from winsock library is no longer used - gethostbyname has been replaced with getaddrinfo - btw, still you can't get online.. - */ - //utils::hook::jump(SELECT_VALUE(0, 0x7EBC20_b), bd_logger_stub); - if (game::environment::is_sp()) { // utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) @@ -577,11 +571,11 @@ namespace demonware return; } - utils::hook::set(0x7C0AD9_b, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.15) - utils::hook::set(0x7C0AC5_b, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.15) - utils::hook::set(0xA1327C_b, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] + utils::hook::set(0x7C0AD9_b, 0x0); // CURLOPT_SSL_VERIFYPEER + utils::hook::set(0x7C0AC5_b, 0xAF); // CURLOPT_SSL_VERIFYHOST + utils::hook::set(0xA1327C_b, 0x0); // HTTPS -> HTTP - //HTTPS -> HTTP + // HTTPS -> HTTP char* umbrella = (char*)allocate_somewhere_near((uint8_t*)game::base_address); std::memcpy(umbrella, "http://prod.umbrella.demonware.net/v1.0/", sizeof("http://prod.umbrella.demonware.net/v1.0/")); @@ -597,8 +591,10 @@ namespace demonware BYTE bytes[] = { 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2F, 0x61, 0x75, 0x74, 0x68, 0x2F, 0x0 }; // KEKW std::memcpy((void*)0x9EDB08_b, bytes, sizeof(bytes)); //utils::hook::inject(0x140728170, "http://%s:%d/auth/"); :DDD - //utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) - //utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) + // utils::hook::set(0x4DCCE0_b, 0xC301B0); + + // utils::hook::set(0x19F8C0_b, 0xC3); SV_SendMatchData, not sure + utils::hook::set(0x1A3340_b, 0xC3); // Live_CheckForFullDisconnect //#ifdef DEBUG // // yes @@ -613,19 +609,15 @@ namespace demonware // utils::hook::call(0x140727C82, b); // utils::hook::call(0x140727E6A, a); //#endif - // Checks X-Signature header or something - //utils::hook::set(0x7D4AB0_b, 0xC301B0); - // Checks extended_data and extra_data in json object - //utils::hook::set(0x7D55C0_b, 0xC301B0); - // Update check - //utils::hook::set(0x1403A5390, 0xC301B0); + // Remove some while loop that freezes the rendering for a few secs while connecting + utils::hook::nop(0x625555_b, 5); - // Remove some while loop in demonware that freezes the rendering for a few secs at launch - //utils::hook::nop(0x14057DBC5, 5); + handle_auth_reply_hook.create(0x7AC600_b, handle_auth_reply_stub); - MessageBoxA(0, "TEST", "", 0); - kekw_hook.create(0x7AC600_b, kekw_stub); - MessageBoxA(0, "TEST2", "", 0); + // Skip update check in Live_SyncOnlineDataFlags + utils::hook::set(0x47A6D0_b, 0xC301B0); + // Remove update failed popup + utils::hook::set(0x47B2B0_b, 0xC301B0); } void pre_destroy() override diff --git a/src/client/game/demonware/services/bdStorage.cpp b/src/client/game/demonware/services/bdStorage.cpp index 9f398868..873a8119 100644 --- a/src/client/game/demonware/services/bdStorage.cpp +++ b/src/client/game/demonware/services/bdStorage.cpp @@ -174,27 +174,6 @@ namespace demonware auto* info = new bdFile2; - // int - // int - // int - // byte (priv) - // int64 (owner) - // string (platform) - // string (file) - // blob - // size - // data - // int - // int - // int - // byte - // int64 - // string (platform) - // string (file) - // blob - // size - // data - info->unk1 = 0; info->unk2 = 0; info->unk3 = 0; @@ -204,14 +183,6 @@ namespace demonware info->filename = filename; info->data = data; - /*info->file_id = *reinterpret_cast(utils::cryptography::sha1::compute(filename).data()); - info->filename = filename; - info->create_time = uint32_t(time(nullptr)); - info->modified_time = info->create_time; - info->file_size = uint32_t(data.size()); - info->owner_id = uint64_t(owner); - info->priv = priv;*/ - #ifdef DEBUG printf("[DW]: [bdStorage]: set user file: %s\n", filename.data()); #endif @@ -243,8 +214,6 @@ namespace demonware auto reply = server->create_reply(this->task_id()); - printf("%i\n", numfiles); - for (uint32_t i = 0; i < numfiles; i++) { std::string filename, data; diff --git a/src/client/game/demonware/services/bdUNK80.cpp b/src/client/game/demonware/services/bdUNK80.cpp index 7478d3f5..65c458c4 100644 --- a/src/client/game/demonware/services/bdUNK80.cpp +++ b/src/client/game/demonware/services/bdUNK80.cpp @@ -5,7 +5,8 @@ namespace demonware { bdUNK80::bdUNK80() : service(80, "bdUNK80") { - this->register_task(42, &bdUNK80::unk42); + this->register_task(42, &bdUNK80::unk42); // COD POINTS purchase ? + // this->register_task(43, &bdUNK80::unk43); COD POINTS purchase ? this->register_task(49, &bdUNK80::unk49); this->register_task(60, &bdUNK80::unk60); this->register_task(130, &bdUNK80::unk130);