From 4d51ee436f3d2a705b1ff61c5aa8e79e7bacb567 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Tue, 25 Oct 2022 22:13:49 +0100 Subject: [PATCH] GSC: expand and enhance --- deps/gsc-tool | 2 +- src/client/component/command.cpp | 10 +- src/client/component/dedicated.cpp | 11 +- src/client/component/dvar_cheats.cpp | 12 +- src/client/component/filesystem.cpp | 8 +- src/client/component/game_log.cpp | 116 ++ src/client/component/game_log.hpp | 6 + src/client/component/gsc/script_error.cpp | 126 ++ src/client/component/gsc/script_error.hpp | 6 + src/client/component/gsc/script_extension.cpp | 196 ++- src/client/component/gsc/script_extension.hpp | 12 + src/client/component/gsc/script_loading.cpp | 44 +- src/client/component/gsc/script_loading.hpp | 6 + .../component/{logfile.cpp => notifies.cpp} | 158 +- .../component/{logfile.hpp => notifies.hpp} | 9 +- src/client/component/scripting.cpp | 129 +- src/client/component/scripting.hpp | 8 + src/client/game/dvars.cpp | 1 + src/client/game/dvars.hpp | 1 + src/client/game/scripting/function_tables.cpp | 1535 ----------------- src/client/game/scripting/functions.cpp | 118 +- src/client/game/scripting/functions.hpp | 10 +- src/client/game/scripting/lua/context.cpp | 151 +- src/client/game/scripting/lua/engine.cpp | 9 +- .../game/scripting/lua/value_conversion.cpp | 60 +- src/client/game/structs.hpp | 3 + src/client/game/symbols.hpp | 19 +- src/client/game/ui_scripting/execution.cpp | 3 - src/client/game/ui_scripting/script_value.cpp | 1 - src/client/std_include.hpp | 2 + 30 files changed, 921 insertions(+), 1851 deletions(-) create mode 100644 src/client/component/game_log.cpp create mode 100644 src/client/component/game_log.hpp create mode 100644 src/client/component/gsc/script_error.cpp create mode 100644 src/client/component/gsc/script_error.hpp create mode 100644 src/client/component/gsc/script_extension.hpp create mode 100644 src/client/component/gsc/script_loading.hpp rename src/client/component/{logfile.cpp => notifies.cpp} (62%) rename src/client/component/{logfile.hpp => notifies.hpp} (51%) delete mode 100644 src/client/game/scripting/function_tables.cpp diff --git a/deps/gsc-tool b/deps/gsc-tool index 2ab5118..842f168 160000 --- a/deps/gsc-tool +++ b/deps/gsc-tool @@ -1 +1 @@ -Subproject commit 2ab5118d168a1889b3b59d3d8996509046e2642b +Subproject commit 842f168a67878f18ea6a42b9d3ce56ff9fafff0d diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index a6b4f51..18f79a6 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -21,6 +21,8 @@ namespace command { namespace { + constexpr auto CMD_MAX_NESTING = 8; + utils::hook::detour client_command_hook; std::unordered_map> handlers; @@ -31,7 +33,7 @@ namespace command params params = {}; const auto command = utils::string::to_lower(params[0]); - if (handlers.find(command) != handlers.end()) + if (handlers.contains(command)) { handlers[command](params); } @@ -131,6 +133,7 @@ namespace command params::params() : nesting_(game::cmd_args->nesting) { + assert(this->nesting_ < CMD_MAX_NESTING); } int params::size() const @@ -163,6 +166,7 @@ namespace command params_sv::params_sv() : nesting_(game::sv_cmd_args->nesting) { + assert(this->nesting_ < CMD_MAX_NESTING); } int params_sv::size() const @@ -201,7 +205,7 @@ namespace command { const auto command = utils::string::to_lower(name); - if (handlers.find(command) == handlers.end()) + if (!handlers.contains(command)) add_raw(name, main_handler); handlers[command] = callback; @@ -222,7 +226,7 @@ namespace command const auto command = utils::string::to_lower(name); - if (handlers_sv.find(command) == handlers_sv.end()) + if (!handlers_sv.contains(command)) handlers_sv[command] = std::move(callback); } diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 9ee3d83..88b9965 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -78,12 +78,11 @@ namespace dedicated return console_command_queue; } - void execute_console_command(const int client, const char* command) + void execute_console_command([[maybe_unused]] const int local_client_num, const char* command) { if (game::Live_SyncOnlineDataFlags(0) == 0) { - game::Cbuf_AddText(client, command); - game::Cbuf_AddText(client, "\n"); + command::execute(command); } else { @@ -145,7 +144,7 @@ namespace dedicated va_end(ap); - scheduler::once([]() + scheduler::once([] { command::execute("map_rotate"); }, scheduler::main, 3s); @@ -285,7 +284,7 @@ namespace dedicated { if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2()) { - scheduler::once([]() + scheduler::once([] { command::execute("xstartprivateparty", true); command::execute("disconnect", true); // 32 -> 0 @@ -296,7 +295,7 @@ namespace dedicated return scheduler::cond_continue; }, scheduler::pipeline::main, 1s); - scheduler::on_game_initialized([]() + scheduler::on_game_initialized([] { initialize(); diff --git a/src/client/component/dvar_cheats.cpp b/src/client/component/dvar_cheats.cpp index cd81ec1..8db4550 100644 --- a/src/client/component/dvar_cheats.cpp +++ b/src/client/component/dvar_cheats.cpp @@ -5,7 +5,6 @@ #include "game/dvars.hpp" #include "console.hpp" -#include "scheduler.hpp" #include #include @@ -177,17 +176,14 @@ namespace dvar_cheats utils::hook::call(0x1401BB782, cg_set_client_dvar_from_server); // check for dvars being sent as string before parsing ids - scheduler::once([]() - { #ifdef _DEBUG - constexpr auto value = true; + constexpr auto value = true; #else - constexpr auto value = false; + constexpr auto value = false; #endif - dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", value, game::DvarFlags::DVAR_FLAG_REPLICATED, - "Allow cheat commands and dvars on this server"); - }, scheduler::pipeline::main); + dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", value, game::DVAR_FLAG_REPLICATED, + "Allow cheat commands and dvars on this server"); } }; } diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp index 50ca527..4a67396 100644 --- a/src/client/component/filesystem.cpp +++ b/src/client/component/filesystem.cpp @@ -53,9 +53,15 @@ namespace filesystem custom_path_registered = false; register_path(get_binary_directory() + "\\data"); - register_path("."); register_path("s1x"); + // game's search paths + register_path("devraw"); + register_path("devraw_shared"); + register_path("raw_shared"); + register_path("raw"); + register_path("main"); + game::FS_Startup(gamename); } diff --git a/src/client/component/game_log.cpp b/src/client/component/game_log.cpp new file mode 100644 index 0000000..ee53479 --- /dev/null +++ b/src/client/component/game_log.cpp @@ -0,0 +1,116 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "scheduler.hpp" +#include "scripting.hpp" +#include "console.hpp" +#include "game_log.hpp" + +#include "gsc/script_extension.hpp" + +#include +#include +#include + +namespace game_log +{ + namespace + { + void gscr_log_print() + { + char buf[1024]{}; + std::size_t out_chars = 0; + + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + const auto* value = game::Scr_GetString(i); + const auto len = std::strlen(value); + + out_chars += len; + if (out_chars >= sizeof(buf)) + { + break; + } + + strncat_s(buf, value, _TRUNCATE); + } + + g_log_printf("%s", buf); + } + } + + void g_log_printf(const char* fmt, ...) + { + const auto* log = dvars::g_log->current.string; + if (*log == '\0') + { + return; + } + + char buffer[0x400]{}; + + va_list ap; + va_start(ap, fmt); + + vsprintf_s(buffer, fmt, ap); + + va_end(ap); + + const auto time = *game::level_time / 1000; + utils::io::write_file(log, utils::string::va("%3i:%i%i %s", + time / 60, + time % 60 / 10, + time % 60 % 10, + buffer + ), true); + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_sp()) + { + return; + } + + gsc::override_function("logprint", &gscr_log_print); + + scheduler::once([] + { + dvars::g_log = game::Dvar_RegisterString("g_log", "logs/games_mp.log", game::DVAR_FLAG_NONE, "Log file name"); + }, scheduler::pipeline::main); + + scripting::on_init([] + { + console::info("------- Game Initialization -------\n"); + console::info("gamename: S1\n"); + console::info("gamedate: " __DATE__ "\n"); + + const auto* log = dvars::g_log->current.string; + if (*log == '\0') + { + console::info("Not logging to disk.\n"); + return; + } + + console::info("Logging to disk: '%s'.\n", log); + g_log_printf("------------------------------------------------------------\n"); + g_log_printf("InitGame\n"); + }); + + scripting::on_shutdown([](int free_scripts) + { + console::info("==== ShutdownGame (%d) ====\n", free_scripts); + + g_log_printf("ShutdownGame:\n"); + g_log_printf("------------------------------------------------------------\n"); + }); + } + }; +} + +REGISTER_COMPONENT(game_log::component) diff --git a/src/client/component/game_log.hpp b/src/client/component/game_log.hpp new file mode 100644 index 0000000..4135e71 --- /dev/null +++ b/src/client/component/game_log.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace game_log +{ + void g_log_printf(const char* fmt, ...); +} diff --git a/src/client/component/gsc/script_error.cpp b/src/client/component/gsc/script_error.cpp new file mode 100644 index 0000000..9f62d39 --- /dev/null +++ b/src/client/component/gsc/script_error.cpp @@ -0,0 +1,126 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "script_extension.hpp" +#include "script_error.hpp" + +#include "component/scripting.hpp" + +#include + +namespace gsc +{ + namespace + { + utils::hook::detour scr_emit_function_hook; + + unsigned int current_filename = 0; + + std::string unknown_function_error; + + void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos) + { + current_filename = filename; + scr_emit_function_hook.invoke(filename, thread_name, code_pos); + } + + std::string get_filename_name() + { + const auto filename_str = game::SL_ConvertToString(static_cast(current_filename)); + const auto id = std::atoi(filename_str); + if (!id) + { + return filename_str; + } + + return scripting::get_token(id); + } + + void get_unknown_function_error(const char* code_pos) + { + const auto function = find_function(code_pos); + if (function.has_value()) + { + const auto& pos = function.value(); + unknown_function_error = std::format( + "while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file + ); + } + else + { + unknown_function_error = std::format("unknown script '{}'", scripting::current_file); + } + } + + void get_unknown_function_error(unsigned int thread_name) + { + const auto filename = get_filename_name(); + const auto name = scripting::get_token(thread_name); + + unknown_function_error = std::format( + "while processing script '{}':\nunknown function '{}::{}'", scripting::current_file, filename, name + ); + } + + void compile_error_stub(const char* code_pos, [[maybe_unused]] const char* msg) + { + get_unknown_function_error(code_pos); + game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data()); + } + + unsigned int find_variable_stub(unsigned int parent_id, unsigned int thread_name) + { + const auto res = game::FindVariable(parent_id, thread_name); + if (!res) + { + get_unknown_function_error(thread_name); + game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data()); + } + + return res; + } + } + + std::optional> find_function(const char* pos) + { + for (const auto& file : scripting::script_function_table_sort) + { + for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i) + { + const auto next = std::next(i); + if (pos >= i->second && pos < next->second) + { + return {std::make_pair(i->first, file.first)}; + } + } + } + + return {}; + } + + class error final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + scr_emit_function_hook.create(0x1403ED900, &scr_emit_function_stub); + + utils::hook::call(0x1403ED7E6, compile_error_stub); // LinkFile + utils::hook::call(0x1403ED8D0, compile_error_stub); // LinkFile + utils::hook::call(0x1403ED9DB, find_variable_stub); // Scr_EmitFunction + } + + void pre_destroy() override + { + scr_emit_function_hook.clear(); + } + }; +} + +REGISTER_COMPONENT(gsc::error) diff --git a/src/client/component/gsc/script_error.hpp b/src/client/component/gsc/script_error.hpp new file mode 100644 index 0000000..284af43 --- /dev/null +++ b/src/client/component/gsc/script_error.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace gsc +{ + std::optional> find_function(const char* pos); +} diff --git a/src/client/component/gsc/script_extension.cpp b/src/client/component/gsc/script_extension.cpp index cd5f2f6..6721be2 100644 --- a/src/client/component/gsc/script_extension.cpp +++ b/src/client/component/gsc/script_extension.cpp @@ -1,27 +1,172 @@ #include #include "loader/component_loader.hpp" #include "game/game.hpp" +#include "game/scripting/functions.hpp" #include #include "component/console.hpp" +#include "script_error.hpp" +#include "script_extension.hpp" + #include #include namespace gsc { + std::uint16_t function_id_start = 0x2DF; + void* func_table[0x1000]; + + const game::dvar_t* developer_script = nullptr; + namespace { - typedef void(*builtin_function)(); - std::unordered_map builtin_funcs_overrides; + #define RVA(ptr) static_cast(reinterpret_cast(ptr) - 0x140000000) + + struct gsc_error : public std::runtime_error + { + using std::runtime_error::runtime_error; + }; + + std::unordered_map functions; + + bool force_error_print = false; + std::optional gsc_error_msg; + + std::unordered_map builtin_funcs_overrides; utils::hook::detour scr_register_function_hook; - void override_function(const std::string& name, builtin_function func) + unsigned int scr_get_function_stub(const char** p_name, int* type) { - const auto id = xsk::gsc::s1::resolver::function_id(name); - builtin_funcs_overrides.emplace(id, func); + const auto result = utils::hook::invoke(0x1403318B0, p_name, type); + + for (const auto& [name, func] : functions) + { + game::Scr_RegisterFunction(func, 0, name); + } + + return result; + } + + void execute_custom_function(game::BuiltinFunction function) + { + auto error = false; + + try + { + function(); + } + catch (const std::exception& ex) + { + error = true; + force_error_print = true; + gsc_error_msg = ex.what(); + } + + if (error) + { + game::Scr_ErrorInternal(); + } + } + + void vm_call_builtin_function(const std::uint32_t index) + { + const auto func = reinterpret_cast(scripting::get_function_by_index(index)); + + const auto custom = functions.contains(static_cast(index)); + if (!custom) + { + func(); + } + else + { + execute_custom_function(func); + } + } + + void builtin_call_error(const std::string& error) + { + const auto pos = game::scr_function_stack->pos; + const auto function_id = *reinterpret_cast(reinterpret_cast(pos - 2)); + + if (function_id > 0x1000) + { + console::warn("in call to builtin method \"%s\"%s", xsk::gsc::s1::resolver::method_name(function_id).data(), error.data()); + } + else + { + console::warn("in call to builtin function \"%s\"%s", xsk::gsc::s1::resolver::function_name(function_id).data(), error.data()); + } + } + + std::optional get_opcode_name(const std::uint8_t opcode) + { + try + { + return {xsk::gsc::s1::resolver::opcode_name(opcode)}; + } + catch (...) + { + return {}; + } + } + + void print_callstack() + { + for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame) + { + const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos; + const auto function = find_function(frame->fs.pos); + + if (function.has_value()) + { + console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), function.value().second.data()); + } + else + { + console::warn("\tat unknown location %p\n", pos); + } + } + } + + void vm_error_stub(int mark_pos) + { + if (!developer_script->current.enabled && !force_error_print) + { + utils::hook::invoke(0x1404B6790, mark_pos); + return; + } + + console::warn("******* script runtime error ********\n"); + const auto opcode_id = *reinterpret_cast(0x148806768); + + const std::string error = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string(); + + if ((opcode_id >= 0x1A && opcode_id <= 0x20) || (opcode_id >= 0xA9 && opcode_id <= 0xAF)) + { + builtin_call_error(error); + } + else + { + const auto opcode = get_opcode_name(opcode_id); + if (opcode.has_value()) + { + console::warn("while processing instruction %s%s\n", opcode.value().data(), error.data()); + } + else + { + console::warn("while processing instruction 0x%X%s\n", opcode_id, error.data()); + } + } + + force_error_print = false; + gsc_error_msg = {}; + + print_callstack(); + console::warn("************************************\n"); + utils::hook::invoke(0x1404B6790, mark_pos); } void scr_register_function_stub(void* func, int type, unsigned int name) @@ -53,6 +198,27 @@ namespace gsc } } + void scr_error(const char* error) + { + force_error_print = true; + gsc_error_msg = error; + + game::Scr_ErrorInternal(); + } + + void override_function(const std::string& name, game::BuiltinFunction func) + { + const auto id = xsk::gsc::s1::resolver::function_id(name); + builtin_funcs_overrides.emplace(id, func); + } + + void add_function(const std::string& name, game::BuiltinFunction function) + { + ++function_id_start; + functions[function_id_start] = function; + xsk::gsc::s1::resolver::add_function(name, function_id_start); + } + class extension final : public component_interface { public: @@ -62,6 +228,26 @@ namespace gsc override_function("print", &scr_print); override_function("println", &scr_print_ln); + + utils::hook::set(SELECT_VALUE(0x1403115BC, 0x1403EDAEC), 0x1000); // Scr_RegisterFunction + + utils::hook::set(SELECT_VALUE(0x1403115C2 + 4, 0x1403EDAF2 + 4), RVA(&func_table)); // Scr_RegisterFunction + utils::hook::set(SELECT_VALUE(0x14031F097 + 3, 0x1403FB7F7 + 3), RVA(&func_table)); // VM_Execute_0 + utils::hook::inject(SELECT_VALUE(0x140311964 + 3, 0x1403EDEE4 + 3), &func_table); // Scr_BeginLoadScripts + + if (game::environment::is_sp()) + { + return; + } + + developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); + + utils::hook::nop(0x1403FB7F7 + 5, 2); + utils::hook::call(0x1403FB7F7, vm_call_builtin_function); + + utils::hook::call(0x1403FCAB0, vm_error_stub); // LargeLocalResetToMark + + utils::hook::call(0x1403EDF1F, scr_get_function_stub); } }; } diff --git a/src/client/component/gsc/script_extension.hpp b/src/client/component/gsc/script_extension.hpp new file mode 100644 index 0000000..bdd44ff --- /dev/null +++ b/src/client/component/gsc/script_extension.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace gsc +{ + extern void* func_table[0x1000]; + + extern const game::dvar_t* developer_script; + + void scr_error(const char* error); + void override_function(const std::string& name, game::BuiltinFunction func); + void add_function(const std::string& name, game::BuiltinFunction function); +} diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp index 2a49eb2..249c466 100644 --- a/src/client/component/gsc/script_loading.cpp +++ b/src/client/component/gsc/script_loading.cpp @@ -10,6 +10,8 @@ #include "component/scripting.hpp" #include "component/fastfiles.hpp" +#include "script_loading.hpp" + #include #include #include @@ -226,24 +228,6 @@ namespace gsc } } - game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/) - { - std::string real_name = name; - const auto id = static_cast(std::atoi(name)); - if (id) - { - real_name = xsk::gsc::s1::resolver::token_name(id); - } - - auto* script = load_custom_script(name, real_name); - if (script) - { - return script; - } - - return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name, 1).scriptfile; - } - int db_is_x_asset_default(game::XAssetType type, const char* name) { if (loaded_scripts.contains(name)) @@ -254,9 +238,9 @@ namespace gsc return game::DB_IsXAssetDefault(type, name); } - void gscr_load_game_type_script_stub() + void gscr_post_load_scripts_stub() { - utils::hook::invoke(0x140330490); + utils::hook::invoke(0x140323F20); clear(); @@ -315,6 +299,24 @@ namespace gsc } } + game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default) + { + std::string real_name = name; + const auto id = static_cast(std::atoi(name)); + if (id) + { + real_name = xsk::gsc::s1::resolver::token_name(id); + } + + auto* script = load_custom_script(name, real_name); + if (script) + { + return script; + } + + return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile; + } + class loading final : public component_interface { public: @@ -353,7 +355,7 @@ namespace gsc utils::hook::call(0x1403F7327, db_is_x_asset_default); // GScr_LoadScripts - utils::hook::call(0x140330B19, gscr_load_game_type_script_stub); + utils::hook::call(0x140330B97, gscr_post_load_scripts_stub); // Load our scripts with an uncompressed stack utils::hook::call(0x1403F7380, db_get_raw_buffer_stub); diff --git a/src/client/component/gsc/script_loading.hpp b/src/client/component/gsc/script_loading.hpp new file mode 100644 index 0000000..2a07774 --- /dev/null +++ b/src/client/component/gsc/script_loading.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace gsc +{ + game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default); +} diff --git a/src/client/component/logfile.cpp b/src/client/component/notifies.cpp similarity index 62% rename from src/client/component/logfile.cpp rename to src/client/component/notifies.cpp index 535d521..18dc242 100644 --- a/src/client/component/logfile.cpp +++ b/src/client/component/notifies.cpp @@ -1,6 +1,5 @@ #include #include "loader/component_loader.hpp" -#include "scheduler.hpp" #include "game/scripting/entity.hpp" #include "game/scripting/execution.hpp" @@ -9,23 +8,32 @@ #include -#include "logfile.hpp" +#include "scheduler.hpp" +#include "notifies.hpp" +#include "scripting.hpp" -namespace logfile +namespace notifies { - std::unordered_map vm_execute_hooks; + bool hook_enabled = true; namespace { + struct gsc_hook + { + bool is_lua_hook{}; + const char* target_pos{}; + sol::protected_function lua_function; + }; + + std::unordered_map vm_execute_hooks; 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; + const char* target_function = nullptr; sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent) { @@ -41,7 +49,7 @@ namespace logfile std::string get_weapon_name(unsigned int weapon, bool isAlternate) { - char output[1024] = { 0 }; + char output[1024]{}; game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024); return output; @@ -68,13 +76,13 @@ namespace logfile } 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 int means_of_death, const unsigned int weapon, const bool is_alternate, const float* v_dir, const unsigned int hit_loc, int ps_time_offset, int death_anim_duration) { { - const std::string _hitLoc = reinterpret_cast(0x1409B5400)[hitLoc]; - const auto _mod = convert_mod(meansOfDeath); + const std::string _hit_loc = reinterpret_cast(0x1409E62B0)[hit_loc]; + const auto _mod = convert_mod(means_of_death); - const auto _weapon = get_weapon_name(weapon, isAlternate); + const auto _weapon = get_weapon_name(weapon, is_alternate); for (const auto& callback : player_killed_callbacks) { @@ -84,9 +92,9 @@ namespace logfile const auto _inflictor = convert_entity(state, inflictor); const auto _attacker = convert_entity(state, attacker); - const auto _vDir = convert_vector(state, vDir); + const auto _v_dir = convert_vector(state, v_dir); - const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _vDir, _hitLoc, psTimeOffset, deathAnimDuration); + const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _v_dir, _hit_loc, ps_time_offset, death_anim_duration); scripting::lua::handle_error(result); @@ -102,17 +110,17 @@ namespace logfile } } - scr_player_killed_hook.invoke(self, inflictor, attacker, damage, meansOfDeath, weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration); + scr_player_killed_hook.invoke(self, inflictor, attacker, damage, means_of_death, weapon, is_alternate, v_dir, hit_loc, ps_time_offset, death_anim_duration); } 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 int means_of_death, const unsigned int weapon, const bool is_alternate, const float* v_point, const float* v_dir, const unsigned int hit_loc, const int time_offset) { { - const std::string _hitLoc = reinterpret_cast(0x1409B5400)[hitLoc]; - const auto _mod = convert_mod(meansOfDeath); + const std::string _hit_loc = reinterpret_cast(0x1409E62B0)[hit_loc]; + const auto _mod = convert_mod(means_of_death); - const auto _weapon = get_weapon_name(weapon, isAlternate); + const auto _weapon = get_weapon_name(weapon, is_alternate); for (const auto& callback : player_damage_callbacks) { @@ -122,10 +130,10 @@ namespace logfile const auto _inflictor = convert_entity(state, inflictor); const auto _attacker = convert_entity(state, attacker); - const auto _vPoint = convert_vector(state, vPoint); - const auto _vDir = convert_vector(state, vDir); + const auto _v_point = convert_vector(state, v_point); + const auto _v_dir = convert_vector(state, v_dir); - const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _vPoint, _vDir, _hitLoc); + const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _v_point, _v_dir, _hit_loc); scripting::lua::handle_error(result); @@ -141,15 +149,20 @@ namespace logfile } } - scr_player_damage_hook.invoke(self, inflictor, attacker, damage, dflags, meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset); + scr_player_damage_hook.invoke(self, inflictor, attacker, damage, dflags, means_of_death, weapon, is_alternate, v_point, v_dir, hit_loc, time_offset); } - void client_command_stub(const int clientNum) + void client_command_stub(const int client_num) { - auto self = &game::mp::g_entities[clientNum]; - char cmd[1024]{}; + auto self = &game::mp::g_entities[client_num]; - game::SV_Cmd_ArgvBuffer(0, cmd, 1024); + if (!self->client) + { + return; + } + + char cmd[1024]{}; + game::SV_Cmd_ArgvBuffer(0, cmd, sizeof(cmd)); if (cmd == "say"s || cmd == "say_team"s) { @@ -175,18 +188,7 @@ namespace logfile } // ClientCommand - return reinterpret_cast(0x1402E98F0)(clientNum); - } - - void g_shutdown_game_stub(const int freeScripts) - { - { - const scripting::entity level{*game::levelEntityId}; - scripting::notify(level, "shutdownGame_called", {1}); - } - - // G_ShutdownGame - return reinterpret_cast(0x1402F8C10)(freeScripts); + utils::hook::invoke(0x1402E98F0, client_num); } unsigned int local_id_to_entity(unsigned int local_id) @@ -197,7 +199,7 @@ namespace logfile bool execute_vm_hook(const char* pos) { - if (vm_execute_hooks.find(pos) == vm_execute_hooks.end()) + if (!vm_execute_hooks.contains(pos)) { hook_enabled = true; return false; @@ -210,21 +212,28 @@ namespace logfile } 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) + if (hook.is_lua_hook) { - args.push_back(scripting::lua::convert(state, *value)); - } + const auto& function = hook.lua_function; + const auto state = function.lua_state(); - const auto result = hook(self, sol::as_args(args)); - scripting::lua::handle_error(result); + 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 = function(self, sol::as_args(args)); + scripting::lua::handle_error(result); + target_function = empty_function; + } + else + { + target_function = hook.target_pos; + } return true; } @@ -257,7 +266,8 @@ namespace logfile a.bind(replace); a.popad64(); - a.mov(r14, reinterpret_cast(empty_function)); + a.mov(rax, qword_ptr(reinterpret_cast(&target_function))); + a.mov(r14, rax); a.jmp(end); } } @@ -289,6 +299,32 @@ namespace logfile hook_enabled = false; } + void set_lua_hook(const char* pos, const sol::protected_function& callback) + { + gsc_hook hook; + hook.is_lua_hook = true; + hook.lua_function = callback; + vm_execute_hooks[pos] = hook; + } + + void set_gsc_hook(const char* source, const char* target) + { + gsc_hook hook; + hook.is_lua_hook = false; + hook.target_pos = target; + vm_execute_hooks[source] = hook; + } + + void clear_hook(const char* pos) + { + vm_execute_hooks.erase(pos); + } + + std::size_t get_hook_count() + { + return vm_execute_hooks.size(); + } + class component final : public component_interface { public: @@ -304,12 +340,20 @@ namespace logfile scr_player_damage_hook.create(0x140332150, scr_player_damage_stub); scr_player_killed_hook.create(0x1403323D0, scr_player_killed_stub); - utils::hook::call(0x14043E550, g_shutdown_game_stub); - utils::hook::call(0x14043EA11, g_shutdown_game_stub); - utils::hook::jump(0x1403FA134, utils::hook::assemble(vm_execute_stub), true); + + scripting::on_shutdown([](bool free_scripts) + { + if (free_scripts) + { + vm_execute_hooks.clear(); + } + + const scripting::entity level{*game::levelEntityId}; + scripting::notify(level, "shutdownGame_called", {free_scripts}); + }); } }; } -REGISTER_COMPONENT(logfile::component) +REGISTER_COMPONENT(notifies::component) diff --git a/src/client/component/logfile.hpp b/src/client/component/notifies.hpp similarity index 51% rename from src/client/component/logfile.hpp rename to src/client/component/notifies.hpp index f0609a1..ffd995d 100644 --- a/src/client/component/logfile.hpp +++ b/src/client/component/notifies.hpp @@ -1,8 +1,13 @@ #pragma once -namespace logfile +namespace notifies { - extern std::unordered_map vm_execute_hooks; + extern bool hook_enabled; + + void set_lua_hook(const char* pos, const sol::protected_function&); + void set_gsc_hook(const char* source, const char* target); + void clear_hook(const char* pos); + std::size_t get_hook_count(); void add_player_damage_callback(const sol::protected_function& callback); void add_player_killed_callback(const sol::protected_function& callback); diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp index f97e8e6..7427680 100644 --- a/src/client/component/scripting.cpp +++ b/src/client/component/scripting.cpp @@ -1,8 +1,6 @@ #include #include "loader/component_loader.hpp" - #include "game/game.hpp" -#include #include "game/scripting/entity.hpp" #include "game/scripting/functions.hpp" @@ -13,9 +11,17 @@ #include "scheduler.hpp" #include "scripting.hpp" +#include "gsc/script_loading.hpp" + +#include + namespace scripting { std::unordered_map> script_function_table; + std::unordered_map>> script_function_table_sort; + std::unordered_map> script_function_table_rev; + + std::string current_file; namespace { @@ -25,10 +31,15 @@ namespace scripting utils::hook::detour scr_set_thread_position_hook; utils::hook::detour process_script_hook; + utils::hook::detour sl_get_canonical_string_hook; - std::string current_file; + std::string current_script_file; + std::uint32_t current_file_id = 0; + + std::unordered_map canonical_string_table; std::vector> shutdown_callbacks; + std::vector> init_callbacks; void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, game::VariableValue* top) @@ -49,7 +60,7 @@ namespace scripting if (e.name == "connected") { - scripting::clear_entity_fields(e.entity); + clear_entity_fields(e.entity); } lua::engine::notify(e); @@ -65,6 +76,11 @@ namespace scripting if (!game::VirtualLobby_Loaded()) { lua::engine::start(); + + for (const auto& callback : init_callbacks) + { + callback(); + } } } @@ -72,6 +88,13 @@ namespace scripting { lua::engine::stop(); + if (free_scripts) + { + script_function_table_sort.clear(); + script_function_table.clear(); + canonical_string_table.clear(); + } + for (const auto& callback : shutdown_callbacks) { callback(free_scripts); @@ -82,25 +105,85 @@ namespace scripting void process_script_stub(const char* filename) { + current_script_file = filename; + const auto file_id = atoi(filename); if (file_id) { - current_file = scripting::find_token(file_id); + current_file_id = static_cast(file_id); } else { + current_file_id = 0; current_file = filename; } process_script_hook.invoke(filename); } - void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) + void add_function_sort(unsigned int id, const char* pos) { - const auto function_name = scripting::find_token(threadName); - script_function_table[current_file][function_name] = codePos; - scr_set_thread_position_hook.invoke(threadName, codePos); + std::string filename = current_file; + if (current_file_id) + { + filename = get_token(current_file_id); + } + + if (!script_function_table_sort.contains(filename)) + { + const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file.data(), false); + if (script) + { + const auto* end = &script->bytecode[script->bytecodeLen]; + script_function_table_sort[filename].emplace_back("__end__", reinterpret_cast(end)); + } + } + + const auto name = scripting::get_token(id); + auto& itr = script_function_table_sort[filename]; + itr.insert(itr.end() - 1, {name, pos}); } + + void add_function(const std::string& file, unsigned int id, const char* pos) + { + const auto name = get_token(id); + script_function_table[file][name] = pos; + script_function_table_rev[pos] = {file, name}; + } + + void scr_set_thread_position_stub(unsigned int thread_name, const char* code_pos) + { + add_function_sort(thread_name, code_pos); + + if (current_file_id) + { + const auto name = get_token(current_file_id); + add_function(name, thread_name, code_pos); + } + else + { + add_function(current_file, thread_name, code_pos); + } + + scr_set_thread_position_hook.invoke(thread_name, code_pos); + } + + unsigned int sl_get_canonical_string_stub(const char* str) + { + const auto result = sl_get_canonical_string_hook.invoke(str); + canonical_string_table[result] = str; + return result; + } + } + + std::string get_token(unsigned int id) + { + if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end()) + { + return itr->second; + } + + return find_token(id); } void on_shutdown(const std::function& callback) @@ -108,20 +191,36 @@ namespace scripting shutdown_callbacks.push_back(callback); } + void on_init(const std::function& callback) + { + init_callbacks.push_back(callback); + } + + std::optional get_canonical_string(const unsigned int id) + { + if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end()) + { + return {itr->second}; + } + + return {}; + } + class component final : public component_interface { public: void post_unpack() override { - vm_notify_hook.create(SELECT_VALUE(0x140320E50, 0x1403FD5B0), vm_notify_stub); + vm_notify_hook.create(SELECT_VALUE(0x140320E50, 0x1403FD5B0), &vm_notify_stub); // SP address is wrong, but should be ok - scr_load_level_hook.create(SELECT_VALUE(0x140005260, 0x140325B90), scr_load_level_stub); - g_shutdown_game_hook.create(SELECT_VALUE(0x140228BA0, 0x1402F8C10), g_shutdown_game_stub); + scr_load_level_hook.create(SELECT_VALUE(0x140005260, 0x140325B90), &scr_load_level_stub); + g_shutdown_game_hook.create(SELECT_VALUE(0x140228BA0, 0x1402F8C10), &g_shutdown_game_stub); - scr_set_thread_position_hook.create(SELECT_VALUE(0x1403115E0, 0x1403EDB10), scr_set_thread_position_stub); - process_script_hook.create(SELECT_VALUE(0x14031AB30, 0x1403F7300), process_script_stub); + scr_set_thread_position_hook.create(SELECT_VALUE(0x1403115E0, 0x1403EDB10), &scr_set_thread_position_stub); + process_script_hook.create(SELECT_VALUE(0x14031AB30, 0x1403F7300), &process_script_stub); + sl_get_canonical_string_hook.create(game::SL_GetCanonicalString, &sl_get_canonical_string_stub); - scheduler::loop([]() + scheduler::loop([] { lua::engine::run_frame(); }, scheduler::pipeline::server); diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp index 8053d71..c841903 100644 --- a/src/client/component/scripting.hpp +++ b/src/client/component/scripting.hpp @@ -3,6 +3,14 @@ namespace scripting { extern std::unordered_map> script_function_table; + extern std::unordered_map>> script_function_table_sort; + extern std::unordered_map> script_function_table_rev; + + extern std::string current_file; void on_shutdown(const std::function& callback); + void on_init(const std::function& callback); + + std::optional get_canonical_string(unsigned int id); + std::string get_token(unsigned int id); } diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index dd10299..8bc3766 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -25,6 +25,7 @@ namespace dvars game::dvar_t* g_gravity = nullptr; game::dvar_t* g_speed = nullptr; game::dvar_t* g_elevators = nullptr; + game::dvar_t* g_log = nullptr; game::dvar_t* jump_height = nullptr; game::dvar_t* jump_ladderPushVel = nullptr; diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index 7387f9d..ecf645f 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -24,6 +24,7 @@ namespace dvars extern game::dvar_t* g_gravity; extern game::dvar_t* g_speed; extern game::dvar_t* g_elevators; + extern game::dvar_t* g_log; extern game::dvar_t* jump_height; extern game::dvar_t* jump_ladderPushVel; diff --git a/src/client/game/scripting/function_tables.cpp b/src/client/game/scripting/function_tables.cpp deleted file mode 100644 index 6eac3d9..0000000 --- a/src/client/game/scripting/function_tables.cpp +++ /dev/null @@ -1,1535 +0,0 @@ -#include - -// This file has been generated. -// Do not touch! - -namespace scripting -{ - std::unordered_map function_map = - { - {"precacheturret", 0}, - {"getweaponarray", 1}, - {"getnumparam", 15}, - {"getnumparam", 16}, - {"spawnturret", 23}, - {"canspawnturret", 24}, - {"assertexcmd", 25}, - {"badplace_delete", 30}, - {"badplace_cylinder", 31}, - {"badplace_arc", 32}, - {"badplace_brush", 33}, - {"assertexcmd0", 44}, - {"isdefined", 46}, - {"isvalidmissile", 47}, - {"isstring", 48}, - {"setomnvar", 49}, - {"getomnvar", 50}, - {"setdvar", 51}, - {"setdynamicdvar", 52}, - {"setdvarifuninitialized", 53}, - {"setdevdvar", 54}, - {"setdevdvarifuninitialized", 55}, - {"getdvar", 56}, - {"getdvarint", 57}, - {"getdvarfloat", 58}, - {"getdvarvector", 59}, - {"gettime", 60}, - {"getutc", 61}, - {"getradiometricunit", 62}, - {"getentbynum", 63}, - {"getweaponmodel", 64}, - {"setsunlight", 68}, - {"resetsunlight", 69}, - {"getweapondisplayname", 92}, - {"getweaponbasename", 93}, - {"getweaponattachments", 94}, - {"getweaponattachmentdisplaynames", 95}, - {"getweaponcamoname", 96}, - {"getweaponreticlename", 97}, - {"getanimlength", 98}, - {"animhasnotetrack", 99}, - {"getnotetracktimes", 100}, - {"spawn", 101}, - {"spawnloopingsound", 103}, - {"bullettrace", 104}, - {"getstartorigin", 108}, - {"getstartangles", 109}, - {"magicgrenademanual", 112}, - {"sub_140311ad0", 117}, - {"sub_140311d80", 118}, - {"sub_140311d90", 119}, - {"sub_140311df0", 120}, - {"sub_140311ef0", 121}, - {"sub_140311f50", 122}, - {"sub_14031fb60", 127}, - {"bullettracepassed", 138}, - {"sighttracepassed", 139}, - {"physicstrace", 140}, - {"playerphysicstrace", 141}, - {"getgroundposition", 142}, - {"getmovedelta", 143}, - {"getangledelta", 144}, - {"getnorthyaw", 145}, - {"setnorthyaw", 172}, - {"setslowmotion", 173}, - {"randomint", 174}, - {"randomfloat", 175}, - {"randomintrange", 176}, - {"randomfloatrange", 177}, - {"sin", 178}, - {"cos", 179}, - {"tan", 180}, - {"asin", 181}, - {"acos", 182}, - {"atan", 183}, - {"castint", 184}, - {"castfloat", 185}, - {"abs", 186}, - {"min", 187}, - {"getnode", 191}, - {"getnodearray", 192}, - {"getallnodes", 193}, - {"getnodesinradius", 194}, - {"getnodesinradiussorted", 195}, - {"getclosestnodeinsight", 196}, - {"isarray", 202}, - {"isai", 203}, - {"getindexforluincstring", 204}, - {"issentient", 205}, - {"max", 221}, - {"floor", 222}, - {"ceil", 223}, - {"exp", 224}, - {"log", 225}, - {"sqrt", 226}, - {"squared", 227}, - {"clamp", 228}, - {"angleclamp360", 229}, - {"angleclamp180", 230}, - {"vectorfromlinetopoint", 231}, - {"pointonsegmentnearesttopoint", 232}, - {"distance", 233}, - {"distance2d", 234}, - {"distancesquared", 235}, - {"length", 236}, - {"length2d", 237}, - {"lengthsquared", 238}, - {"length2dsquared", 239}, - {"closer", 240}, - {"vectordot", 241}, - {"vectorcross", 242}, - {"axistoangles", 243}, - {"visionsetthermal", 244}, - {"visionsetpain", 245}, - {"startservermigration", 246}, - {"setac130ambience", 247}, - {"getmapcustomfield", 248}, - {"spawnsighttrace", 249}, - {"incrementcounter", 250}, - {"getcountertotal", 251}, - {"createthreatbiasgroup", 258}, - {"threatbiasgroupexists", 259}, - {"getthreatbias", 260}, - {"setthreatbias", 261}, - {"setthreatbiasagainstall", 262}, - {"setignoremegroup", 263}, - {"isenemyteam", 264}, - {"vectornormalize", 271}, - {"vectortoangles", 272}, - {"vectortoyaw", 273}, - {"vectorlerp", 274}, - {"anglestoup", 275}, - {"anglestoright", 276}, - {"anglestoforward", 277}, - {"anglesdelta", 278}, - {"combineangles", 279}, - {"transformmove", 280}, - {"rotatevector", 281}, - {"rotatepointaroundvector", 282}, - {"issubstr", 283}, - {"isendstr", 284}, - {"getsubstr", 285}, - {"tolower", 286}, - {"strtok", 287}, - {"stricmp", 288}, - {"ambientplay", 289}, - {"getuavstrengthmax", 290}, - {"getuavstrengthlevelneutral", 291}, - {"getuavstrengthlevelshowenemyfastsweep", 292}, - {"getuavstrengthlevelshowenemydirectional", 293}, - {"blockteamradar", 294}, - {"unblockteamradar", 295}, - {"isteamradarblocked", 296}, - {"sub_140328710", 297}, - {"setmatchdata", 298}, - {"getmatchdata", 299}, - {"sendmatchdata", 300}, - {"clearmatchdata", 301}, - {"setmatchdatadef", 302}, - {"setmatchclientip", 303}, - {"setmatchdataid", 304}, - {"setclientmatchdata", 305}, - {"getclientmatchdata", 306}, - {"setclientmatchdatadef", 307}, - {"sendclientmatchdata", 308}, - {"getbuildversion", 309}, - {"getbuildnumber", 310}, - {"getsystemtime", 311}, - {"getmatchrulesdata", 312}, - {"isusingmatchrulesdata", 313}, - {"kickplayer", 314}, - {"issplitscreen", 315}, - {"setmapcenter", 316}, - {"setgameendtime", 317}, - {"visionsetnaked", 318}, - {"visionsetnight", 319}, - {"visionsetmissilecam", 320}, - {"ambientstop", 321}, - {"precachemodel", 322}, - {"precacheshellshock", 323}, - {"precacheitem", 324}, - {"precachematerial", 325}, - {"precachestring", 326}, - {"precachemenu", 327}, - {"precacherumble", 328}, - {"precachelocationselector", 329}, - {"precacheleaderboards", 330}, - {"loadfx", 331}, - {"playfx", 332}, - {"playfxontag", 333}, - {"stopfxontag", 334}, - {"killfxontag", 335}, - {"playloopedfx", 336}, - {"spawnfx", 337}, - {"triggerfx", 338}, - {"playfxontagforclients", 339}, - {"sub_1403326a0", 340}, - {"sub_14031be80", 341}, - {"setwinningteam", 342}, - {"announcement", 343}, - {"clientannouncement", 344}, - {"setteammode", 345}, - {"getteamscore", 346}, - {"setteamscore", 347}, - {"setclientnamemode", 348}, - {"updateclientnames", 349}, - {"getteamplayersalive", 350}, - {"worldentnumber", 352}, - {"obituary", 353}, - {"positionwouldtelefrag", 354}, - {"canspawn", 355}, - {"getstarttime", 356}, - {"precacheheadicon", 357}, - {"precacheminimapicon", 358}, - {"precachempanim", 359}, - {"maprestart", 360}, - {"exitlevel", 361}, - {"addtestclient", 362}, - {"addagent", 363}, - {"allclientsprint", 365}, - {"clientprint", 366}, - {"mapexists", 367}, - {"isvalidgametype", 368}, - {"setplayerteamrank", 370}, - {"setteamradar", 372}, - {"getteamradar", 373}, - {"setteamradarstrength", 374}, - {"getteamradarstrength", 375}, - {"getuavstrengthmin", 376}, - {"physicsexplosionsphere", 377}, - {"physicsexplosioncylinder", 378}, - {"physicsradiusjolt", 379}, - {"physicsradiusjitter", 380}, - {"setexpfog", 381}, - {"setexpfogext", 382}, - {"setexpfogdvarsonly", 383}, - {"setexpfogextdvarsonly", 384}, - {"setatmosfog", 385}, - {"setatmosfogdvarsonly", 386}, - {"isexplosivedamagemod", 387}, - {"radiusdamage", 388}, - {"setplayerignoreradiusdamage", 389}, - {"glassradiusdamage", 390}, - {"earthquake", 391}, - {"getnumparts", 392}, - {"objective_onentity", 393}, - {"objective_onentitywithrotation", 394}, - {"objective_team", 395}, - {"objective_player", 396}, - {"objective_playerteam", 397}, - {"objective_playerenemyteam", 398}, - {"objective_playermask_hidefromall", 399}, - {"objective_playermask_hidefrom", 400}, - {"objective_playermask_showtoall", 401}, - {"objective_playermask_showto", 402}, - {"iprintln", 403}, - {"iprintlnbold", 404}, - {"getent", 406}, - {"getentarray", 407}, - {"getspawnarray", 408}, - {"spawnplane", 409}, - {"addstruct", 410}, - {"spawnhelicopter", 411}, - {"isalive", 412}, - {"isspawner", 413}, - {"missilecreateattractorent", 414}, - {"missilecreateattractororigin", 415}, - {"missilecreaterepulsorent", 416}, - {"missilecreaterepulsororigin", 417}, - {"missiledeleteattractor", 418}, - {"playsoundatpos", 419}, - {"newhudelem", 420}, - {"newclienthudelem", 421}, - {"newteamhudelem", 422}, - {"resettimeout", 423}, - {"isplayer", 424}, - {"isplayernumber", 425}, - {"getpartname", 426}, - {"weaponfiretime", 427}, - {"weaponclipsize", 428}, - {"weaponisauto", 429}, - {"weaponissemiauto", 430}, - {"weaponisboltaction", 431}, - {"weaponinheritsperks", 432}, - {"weaponburstcount", 433}, - {"weapontype", 434}, - {"weaponclass", 435}, - {"getnextarraykey", 436}, - {"sortbydistance", 437}, - {"tablelookup", 438}, - {"tablelookupbyrow", 439}, - {"tablelookupistring", 440}, - {"tablelookupistringbyrow", 441}, - {"tablelookuprownum", 442}, - {"tableexists", 443}, - {"getmissileowner", 444}, - {"magicbullet", 445}, - {"getweaponflashtagname", 446}, - {"averagepoint", 447}, - {"averagenormal", 448}, - {"getspawnerarray", 449}, - {"playrumbleonposition", 450}, - {"playrumblelooponposition", 451}, - {"stopallrumbles", 452}, - {"soundexists", 453}, - {"setminimap", 460}, - {"setthermalbodymaterial", 461}, - {"getarraykeys", 462}, - {"getfirstarraykey", 463}, - {"getglass", 464}, - {"getglassarray", 465}, - {"getglassorigin", 466}, - {"isglassdestroyed", 467}, - {"destroyglass", 468}, - {"deleteglass", 469}, - {"getentchannelscount", 470}, - {"getentchannelname", 471}, - {"objective_add", 472}, - {"objective_delete", 473}, - {"objective_state", 474}, - {"objective_icon", 475}, - {"objective_position", 476}, - {"objective_current", 477}, - {"weaponinventorytype", 478}, - {"weaponstartammo", 479}, - {"weaponmaxammo", 480}, - {"weaponaltweaponname", 481}, - {"isweaponcliponly", 482}, - {"sub_14030dfc0", 483}, - {"sub_14030e400", 484}, - {"weaponhasthermalscope", 485}, - {"getvehiclenode", 486}, - {"getvehiclenodearray", 487}, - {"getallvehiclenodes", 488}, - {"getactivecount", 489}, - {"precache", 490}, - {"spawnvehicle", 491}, - {"getarray", 492}, - {"pow", 493}, - {"atan2", 494}, - {"botgetmemoryevents", 495}, - {"botautoconnectenabled", 496}, - {"botzonegetcount", 497}, - {"botzonesetteam", 498}, - {"botzonenearestcount", 499}, - {"botmemoryflags", 500}, - {"botflagmemoryevents", 501}, - {"botzonegetindoorpercent", 502}, - {"botsentientswap", 503}, - {"isbot", 504}, - {"isagent", 505}, - {"getmaxagents", 506}, - {"botgetclosestnavigablepoint", 508}, - {"getnodesintrigger", 509}, - {"nodesvisible", 510}, - {"getnodesonpath", 511}, - {"getzonecount", 512}, - {"getzonenearest", 513}, - {"getzonenodes", 514}, - {"getzonepath", 515}, - {"getzoneorigin", 516}, - {"getnodezone", 517}, - {"getzonenodesbydist", 518}, - {"getzonenodeforindex", 519}, - {"getweaponexplosionradius", 520}, - {"nodeexposedtosky", 523}, - {"findentrances", 524}, - {"badplace_global", 525}, - {"getpathdist", 526}, - {"getlinkednodes", 527}, - {"disconnectnodepair", 528}, - {"connectnodepair", 529}, - {"precachesound", 533}, - {"distance2dsquared", 543}, - {"getangledelta3d", 544}, - {"activateclientexploder", 545}, - {"trajectorycalculateinitialvelocity", 546}, - {"trajectorycalculateminimumvelocity", 547}, - {"trajectorycalculateexitangle", 548}, - {"trajectoryestimatedesiredinairtime", 549}, - {"trajectorycomputedeltaheightattime", 550}, - {"trajectorycanattemptaccuratejump", 551}, - {"ispointinvolume", 553}, - {"getscriptablearray", 560}, - {"clearfog", 561}, - {"setleveldopplerpreset", 562}, - {"isusinghdr", 564}, - {"sub_140321c40", 565}, - {"sub_140311a40", 567}, - {"sub_14030ec50", 568}, - {"sub_14030f050", 569}, - {"sub_14030f340", 570}, - {"sub_14030f550", 571}, - {"sub_14030f710", 572}, - {"sub_1403295e0", 573}, - {"sub_140322690", 574}, - {"sub_140329600", 575}, - {"sub_14031a690", 580}, - {"sub_1403163c0", 581}, - {"anglestoaxis", 582}, - {"invertangles", 587}, - {"rotatevectorinverted", 588}, - {"calculatestartorientation", 589}, - {"droptoground", 590}, - {"precachelaser", 592}, - {"getcsplinecount", 593}, - {"getcsplinepointcount", 594}, - {"getcsplinelength", 595}, - {"getcsplinepointid", 596}, - {"getcsplinepointlabel", 597}, - {"getcsplinepointtension", 598}, - {"getcsplinepointposition", 599}, - {"getcsplinepointcorridordims", 600}, - {"getcsplinepointtangent", 601}, - {"getcsplinepointdisttonextpoint", 602}, - {"calccsplineposition", 603}, - {"calccsplinetangent", 604}, - {"calccsplinecorridor", 605}, - {"setnojipscore", 606}, - {"setnojiptime", 607}, - {"getpredictedentityposition", 608}, - {"queuedialog", 615}, - {"triggerportableradarping", 622}, - {"botgetteamlimit", 624}, - {"spawnfxforclient", 625}, - {"botgetteamdifficulty", 626}, - {"loadluifile", 632}, - {"isdedicatedserver", 633}, - {"getplaylistversion", 634}, - {"getplaylistid", 635}, - {"getactiveclientcount", 636}, - {"issquadsmode", 637}, - {"visionsetpostapply", 639}, - {"addbot", 640}, - {"sub_140310ec0", 641}, - {"sub_14031bae0", 642}, - {"sub_14031c2b0", 643}, - {"isalliedsentient", 644}, - {"istestclient", 645}, - {"sub_1402d2850", 646}, - {"sub_140311ff0", 648}, - {"sub_140312040", 649}, - {"sub_140311100", 651}, - {"sub_140314c70", 652}, - {"sub_14030d340", 653}, - {"sub_14030da60", 654}, - {"sub_14030e5c0", 655}, - {"sub_14031fda0", 657}, - {"sub_140317140", 658}, - {"isremovedentity", 659}, - {"tablegetrowcount", 660}, - {"tablegetcolumncount", 661}, - {"batteryusepershot", 662}, - {"batteryreqtouse", 663}, - {"sub_14030e700", 664}, - {"getentityweaponname", 666}, - {"sub_14031fc20", 667}, - {"deployriotshield", 668}, - {"validatecostume", 669}, - {"randomcostume", 670}, - {"shootblank", 671}, - {"debugstringtostring", 673}, - {"sub_140319680", 675}, - {"playcinematicforall", 679}, - {"preloadcinematicforall", 680}, - {"stopcinematicforall", 681}, - {"capsuletracepassed", 682}, - {"sub_14031ca40", 683}, - {"sub_14031e1f0", 684}, - {"sub_140321880", 685}, - {"lootservicestarttrackingplaytime", 687}, - {"sub_1403297b0", 688}, - {"lootservicevalidateplaytime", 689}, - {"recordbreadcrumbdataforplayer", 690}, - {"sub_140317df0", 691}, - {"sysprint", 693}, - {"sub_140337920", 694}, - {"sub_140321ae0", 697}, - {"isonlinegame", 698}, - {"issystemlink", 699}, - {"getstanceandmotionstateforplayer", 701}, - {"sub_1402d3540", 702}, - {"sub_1402d35b0", 703}, - {"sub_140332a70", 704}, - {"sub_140332ae0", 705}, - {"getplaylistname", 706}, - {"getlocaltime", 707}, - {"sub_14032c820", 708}, - {"getchallengeid", 710}, - {"nodegetremotemissilename", 711}, - {"nodehasremotemissileset", 712}, - {"remotemissileenttracetooriginpassed", 713}, - {"bombingruntracepassed", 714}, - {"handlepickupdeployedriotshield", 716}, - {"sub_14032c6b0", 717}, - {"getcostumefromtable", 718}, - {"sub_1402d3460", 720}, - {"getchallenerewarditem", 722}, - {"setentplayerxuidforemblem", 723}, - {"resetentplayerxuidforemblems", 724}, - {"nodesetremotemissilename", 725}, - {"sub_14031aa80", 726}, - {"sub_14031ead0", 727}, - {"iszombie", 728}, - {"sub_14031b670", 729}, - {"sub_14031d3f0", 730}, - {"sub_14031e670", 731}, - {"getactiveplayerlist", 732}, - {"sub_140319200", 733}, - {"sub_140331e00", 734}, - }; - - std::unordered_map method_map = - { - {"thermaldrawdisable", 32768}, - {"heli_setdamagestage", 32770}, - {"playsoundtoteam", 32771}, - {"playsoundtoplayer", 32772}, - {"playerhide", 32773}, - {"playershow", 32774}, - {"showtoplayer", 32775}, - {"threatdetectedtoplayer", 32776}, - {"clearthreatdetected", 32777}, - {"enableplayeruse", 32778}, - {"disableplayeruse", 32779}, - {"enableammogeneration", 32780}, - {"disableammogeneration", 32781}, - {"makescrambler", 32782}, - {"makeportableradar", 32783}, - {"clearscrambler", 32784}, - {"clearportableradar", 32785}, - {"placespawnpoint", 32786}, - {"setteamfortrigger", 32787}, - {"clientclaimtrigger", 32788}, - {"clientreleasetrigger", 32789}, - {"releaseclaimedtrigger", 32790}, - {"isusingonlinedataoffline", 32791}, - {"getrestedtime", 32792}, - {"sendleaderboards", 32793}, - {"isonladder", 32794}, - {"getcorpseanim", 32795}, - {"playerforcedeathanim", 32796}, - {"attach", 32797}, - {"startragdoll", 32803}, - {"thermaldrawenable", 32809}, - {"detach", 32810}, - {"detachall", 32811}, - {"getattachsize", 32812}, - {"getattachmodelname", 32813}, - {"getattachtagname", 32814}, - {"gethighestnodestance", 32820}, - {"doesnodeallowstance", 32821}, - {"getlightcolor", 32835}, - {"setlightcolor", 32836}, - {"getattachignorecollision", 32839}, - {"hidepart", 32840}, - {"hidepartallinstances", 32841}, - {"hideallparts", 32842}, - {"showpart", 32843}, - {"showallparts", 32844}, - {"linkto", 32845}, - {"linktoblendtotag", 32846}, - {"unlink", 32847}, - {"setnormalhealth", 32848}, - {"dodamage", 32849}, - {"show", 32851}, - {"hide", 32852}, - {"disconnectpaths", 32855}, - {"connectpaths", 32856}, - {"disconnectnode", 32857}, - {"connectnode", 32858}, - {"digitaldistortsetparams", 32868}, - {"setmode", 32869}, - {"getmode", 32870}, - {"islinked", 32872}, - {"enablelinkto", 32873}, - {"setpitch", 32876}, - {"scalepitch", 32877}, - {"setvolume", 32878}, - {"scalevolume", 32879}, - {"playsound", 32884}, - {"playloopsound", 32885}, - {"getnormalhealth", 32891}, - {"playerlinkto", 32892}, - {"playerlinktodelta", 32893}, - {"playerlinkweaponviewtodelta", 32894}, - {"playerlinktoabsolute", 32895}, - {"playerlinktoblend", 32896}, - {"playerlinkedoffsetenable", 32897}, - {"setwaypointedgestyle_secondaryarrow", 32898}, - {"setwaypointiconoffscreenonly", 32899}, - {"fadeovertime", 32900}, - {"scaleovertime", 32901}, - {"moveovertime", 32902}, - {"reset", 32903}, - {"destroy", 32904}, - {"setpulsefx", 32905}, - {"setplayernamestring", 32906}, - {"changefontscaleovertime", 32907}, - {"playersetgroundreferenceent", 32913}, - {"dontinterpolate", 32914}, - {"getorigin", 32917}, - {"useby", 32921}, - {"playsoundasmaster", 32922}, - {"playerlinkedoffsetdisable", 32927}, - {"playerlinkedsetviewznear", 32928}, - {"playerlinkedsetusebaseangleforviewclamp", 32929}, - {"lerpviewangleclamp", 32930}, - {"geteye", 32936}, - {"istouching", 32937}, - {"getistouchingentities", 32938}, - {"stoploopsound", 32939}, - {"stopsounds", 32940}, - {"playrumbleonentity", 32941}, - {"playrumblelooponentity", 32942}, - {"stoprumble", 32943}, - {"delete", 32944}, - {"setmodel", 32945}, - {"laseron", 32946}, - {"laseroff", 32947}, - {"thermalvisionon", 32950}, - {"thermalvisionoff", 32951}, - {"thermalvisionfofoverlayon", 32952}, - {"thermalvisionfofoverlayoff", 32953}, - {"autospotoverlayon", 32954}, - {"autospotoverlayoff", 32955}, - {"seteyesonuplinkenabled", 32956}, - {"setcontents", 32958}, - {"makeusable", 32959}, - {"makeunusable", 32960}, - {"makeglobalusable", 32961}, - {"makeglobalunusable", 32962}, - {"settext", 32970}, - {"setmaterial", 32972}, - {"settargetent", 32973}, - {"cleartargetent", 32974}, - {"settimer", 32975}, - {"settimerup", 32976}, - {"settimerstatic", 32977}, - {"settenthstimer", 32978}, - {"settenthstimerup", 32979}, - {"settenthstimerstatic", 32980}, - {"setclock", 32981}, - {"setclockup", 32982}, - {"setvalue", 32983}, - {"setwaypoint", 32984}, - {"setwaypointedgestyle_rotatingicon", 32985}, - {"setcursorhint", 32986}, - {"sethintstring", 32987}, - {"setsecondaryhintstring", 32988}, - {"forceusehinton", 32989}, - {"forceusehintoff", 32990}, - {"makesoft", 32991}, - {"makehard", 32992}, - {"entitywillneverchange", 32993}, - {"startfiring", 32994}, - {"stopfiring", 32995}, - {"isfiringturret", 32996}, - {"startbarrelspin", 32997}, - {"stopbarrelspin", 32998}, - {"getbarrelspinrate", 32999}, - {"remotecontrolturret", 33000}, - {"remotecontrolturretoff", 33001}, - {"shootturret", 33002}, - {"getturretowner", 33003}, - {"giveachievement", 33017}, - {"sub_1402ddb00", 33022}, - {"sub_1402ddcc0", 33023}, - {"setsentryowner", 33027}, - {"setsentrycarrier", 33028}, - {"setturretminimapvisible", 33029}, - {"settargetentity", 33030}, - {"snaptotargetentity", 33031}, - {"cleartargetentity", 33032}, - {"getturrettarget", 33033}, - {"setplayerspread", 33034}, - {"setaispread", 33035}, - {"setsuppressiontime", 33036}, - {"allowstand", 33048}, - {"allowcrouch", 33049}, - {"allowprone", 33050}, - {"sub_1402dd9e0", 33051}, - {"isthrowinggrenade", 33068}, - {"isfiring", 33069}, - {"ismeleeing", 33070}, - {"allowmelee", 33072}, - {"allowfire", 33073}, - {"setconvergencetime", 33075}, - {"setconvergenceheightpercent", 33076}, - {"setturretteam", 33077}, - {"maketurretsolid", 33078}, - {"maketurretoperable", 33079}, - {"maketurretinoperable", 33080}, - {"makeentitysentient", 33081}, - {"freeentitysentient", 33082}, - {"setrightarc", 33109}, - {"setleftarc", 33110}, - {"settoparc", 33111}, - {"setbottomarc", 33112}, - {"setautorotationdelay", 33113}, - {"setdefaultdroppitch", 33114}, - {"restoredefaultdroppitch", 33115}, - {"turretfiredisable", 33116}, - {"getenemyinfo", 33125}, - {"getenemysqdist", 33141}, - {"getclosestenemysqdist", 33142}, - {"setthreatbiasgroup", 33143}, - {"getthreatbiasgroup", 33144}, - {"turretfireenable", 33145}, - {"setturretmodechangewait", 33146}, - {"usetriggerrequirelookat", 33147}, - {"getstance", 33148}, - {"setstance", 33149}, - {"itemweaponsetammo", 33150}, - {"getammocount", 33151}, - {"gettagorigin", 33152}, - {"gettagangles", 33153}, - {"shellshock", 33154}, - {"stunplayer", 33155}, - {"stopshellshock", 33156}, - {"fadeoutshellshock", 33157}, - {"setdepthoffield", 33158}, - {"setviewmodeldepthoffield", 33159}, - {"setmotionblurmovescale", 33160}, - {"getnegotiationstartnode", 33181}, - {"getnegotiationendnode", 33182}, - {"getnegotiationnextnode", 33183}, - {"setmotionblurturnscale", 33197}, - {"setmotionblurzoomscale", 33198}, - {"viewkick", 33199}, - {"localtoworldcoords", 33200}, - {"getentitynumber", 33201}, - {"getentityvelocity", 33202}, - {"enablegrenadetouchdamage", 33203}, - {"disablegrenadetouchdamage", 33204}, - {"enableaimassist", 33205}, - {"lastknowntime", 33216}, - {"lastknownpos", 33217}, - {"disableaimassist", 33236}, - {"entityradiusdamage", 33237}, - {"detonate", 33238}, - {"damageconetrace", 33239}, - {"sightconetrace", 33240}, - {"missilesettargetent", 33241}, - {"missilesettargetpos", 33242}, - {"missilecleartarget", 33243}, - {"missilesetflightmodedirect", 33244}, - {"missilesetflightmodetop", 33245}, - {"getlightintensity", 33246}, - {"setlightintensity", 33247}, - {"isragdoll", 33248}, - {"setmovespeedscale", 33249}, - {"cameralinkto", 33250}, - {"cameraunlink", 33251}, - {"controlslinkto", 33280}, - {"controlsunlink", 33281}, - {"makevehiclesolidcapsule", 33282}, - {"makevehiclesolidsphere", 33284}, - {"remotecontrolvehicle", 33286}, - {"remotecontrolvehicleoff", 33287}, - {"isfiringvehicleturret", 33288}, - {"remotecontrolvehicletarget", 33289}, - {"remotecontrolvehicletargetoff", 33290}, - {"drivevehicleandcontrolturret", 33291}, - {"drivevehicleandcontrolturretoff", 33292}, - {"getplayersetting", 33293}, - {"getlocalplayerprofiledata", 33294}, - {"setlocalplayerprofiledata", 33295}, - {"remotecamerasoundscapeon", 33296}, - {"remotecamerasoundscapeoff", 33297}, - {"setmotiontrackervisible", 33298}, - {"getmotiontrackervisible", 33299}, - {"worldpointinreticle_circle", 33300}, - {"worldpointinreticle_rect", 33301}, - {"getpointinbounds", 33302}, - {"transfermarkstonewscriptmodel", 33303}, - {"setwatersheeting", 33304}, - {"setweaponhudiconoverride", 33307}, - {"getweaponhudiconoverride", 33308}, - {"setempjammed", 33309}, - {"playersetexpfogext", 33310}, - {"playersetexpfog", 33311}, - {"playersetatmosfog", 33312}, - {"isitemunlocked", 33313}, - {"getplayerdata", 33314}, - {"getrankedplayerdata", 33315}, - {"getprivateplayerdata", 33316}, - {"getcoopplayerdata", 33317}, - {"getcommonplayerdata", 33318}, - {"vehicleturretcontroloff", 33319}, - {"isturretready", 33320}, - {"vehicledriveto", 33321}, - {"dospawn", 33322}, - {"isphysveh", 33323}, - {"crash", 33324}, - {"launch", 33325}, - {"disablecrashing", 33326}, - {"enablecrashing", 33327}, - {"setphysvehspeed", 33328}, - {"setconveyorbelt", 33329}, - {"freevehicle", 33330}, - {"setplayerdata", 33347}, - {"setrankedplayerdata", 33348}, - {"setprivateplayerdata", 33349}, - {"setcoopplayerdata", 33350}, - {"setcommonplayerdata", 33351}, - {"getcacplayerdata", 33352}, - {"setcacplayerdata", 33353}, - {"trackerupdate", 33354}, - {"pingplayer", 33355}, - {"buttonpressed", 33356}, - {"sayall", 33357}, - {"sayteam", 33358}, - {"setspawnweapon", 33359}, - {"dropitem", 33360}, - {"dropscavengerbag", 33361}, - {"setjitterparams", 33362}, - {"sethoverparams", 33363}, - {"joltbody", 33364}, - {"getwheelsurface", 33366}, - {"getvehicleowner", 33367}, - {"setvehiclelookattext", 33368}, - {"setvehicleteam", 33369}, - {"neargoalnotifydist", 33370}, - {"setvehgoalpos", 33371}, - {"setgoalyaw", 33372}, - {"cleargoalyaw", 33373}, - {"settargetyaw", 33374}, - {"cleartargetyaw", 33375}, - {"helisetgoal", 33376}, - {"setturrettargetvec", 33377}, - {"setturrettargetent", 33378}, - {"clearturrettargetent", 33379}, - {"canturrettargetpoint", 33380}, - {"setlookatent", 33381}, - {"clearlookatent", 33382}, - {"setweapon", 33383}, - {"fireweapon", 33384}, - {"vehicleturretcontrolon", 33385}, - {"finishplayerdamage", 33386}, - {"suicide", 33387}, - {"closeingamemenu", 33388}, - {"iclientprintln", 33389}, - {"iclientprintlnbold", 33390}, - {"spawn", 33391}, - {"setentertime", 33392}, - {"cloneplayer", 33393}, - {"istalking", 33394}, - {"allowspectateteam", 33395}, - {"forcespectatepov", 33396}, - {"getguid", 33397}, - {"physicslaunchserver", 33398}, - {"physicslaunchserveritem", 33399}, - {"clonebrushmodeltoscriptmodel", 33400}, - {"scriptmodelplayanim", 33401}, - {"scriptmodelclearanim", 33402}, - {"scriptmodelplayanimdeltamotion", 33403}, - {"teleport", 33404}, - {"attachpath", 33405}, - {"getattachpos", 33406}, - {"startpath", 33407}, - {"setswitchnode", 33408}, - {"setwaitspeed", 33409}, - {"finishdamage", 33410}, - {"setspeed", 33411}, - {"setspeedimmediate", 33412}, - {"rotatevehyaw", 33413}, - {"getspeed", 33414}, - {"getvehvelocity", 33415}, - {"getbodyvelocity", 33416}, - {"getsteering", 33417}, - {"getthrottle", 33418}, - {"turnengineoff", 33419}, - {"turnengineon", 33420}, - {"getgoalspeedmph", 33422}, - {"setacceleration", 33423}, - {"setdeceleration", 33424}, - {"resumespeed", 33425}, - {"setyawspeed", 33426}, - {"setyawspeedbyname", 33427}, - {"setmaxpitchroll", 33428}, - {"setairresitance", 33429}, - {"setturningability", 33430}, - {"getxuid", 33431}, - {"getucdidhigh", 33432}, - {"getucdidlow", 33433}, - {"getclanidhigh", 33434}, - {"getclanidlow", 33435}, - {"ishost", 33436}, - {"getspectatingplayer", 33437}, - {"predictstreampos", 33438}, - {"setrank", 33441}, - {"weaponlocknoclearance", 33443}, - {"visionsyncwithplayer", 33444}, - {"showhudsplash", 33445}, - {"setperk", 33446}, - {"hasperk", 33447}, - {"clearperks", 33448}, - {"unsetperk", 33449}, - {"registerparty", 33450}, - {"getfireteammembers", 33451}, - {"moveto", 33454}, - {"movex", 33455}, - {"movey", 33456}, - {"movez", 33457}, - {"gravitymove", 33458}, - {"moveslide", 33459}, - {"stopmoveslide", 33460}, - {"rotateto", 33461}, - {"rotatepitch", 33462}, - {"rotateyaw", 33463}, - {"rotateroll", 33464}, - {"addpitch", 33465}, - {"addyaw", 33466}, - {"addroll", 33467}, - {"vibrate", 33468}, - {"rotatevelocity", 33469}, - {"solid", 33470}, - {"notsolid", 33471}, - {"setcandamage", 33472}, - {"setcanradiusdamage", 33473}, - {"physicslaunchclient", 33474}, - {"setcarddisplayslot", 33477}, - {"kc_regweaponforfxremoval", 33478}, - {"laststandrevive", 33479}, - {"laststand", 33480}, - {"setspectatedefaults", 33481}, - {"getthirdpersoncrosshairoffset", 33482}, - {"disableweaponpickup", 33483}, - {"enableweaponpickup", 33484}, - {"issplitscreenplayer", 33485}, - {"getweaponslistoffhands", 33486}, - {"getweaponslistitems", 33487}, - {"getweaponslistexclusives", 33488}, - {"getweaponslist", 33489}, - {"canplayerplacesentry", 33490}, - {"canplayerplacetank", 33491}, - {"visionsetnakedforplayer", 33492}, - {"visionsetnightforplayer", 33493}, - {"visionsetmissilecamforplayer", 33494}, - {"visionsetthermalforplayer", 33495}, - {"visionsetpainforplayer", 33496}, - {"setblurforplayer", 33497}, - {"getplayerweaponmodel", 33498}, - {"getplayerknifemodel", 33499}, - {"notifyonplayercommand", 33501}, - {"canmantle", 33502}, - {"forcemantle", 33503}, - {"ismantling", 33504}, - {"playfx", 33505}, - {"playerrecoilscaleon", 33506}, - {"playerrecoilscaleoff", 33507}, - {"weaponlockstart", 33508}, - {"weaponlockfinalize", 33509}, - {"weaponlockfree", 33510}, - {"weaponlocktargettooclose", 33511}, - {"issplitscreenplayerprimary", 33512}, - {"markforeyeson", 33513}, - {"issighted", 33514}, - {"getsightedplayers", 33515}, - {"getplayerssightingme", 33516}, - {"getviewmodel", 33517}, - {"fragbuttonpressed", 33518}, - {"secondaryoffhandbuttonpressed", 33519}, - {"getcurrentweaponclipammo", 33520}, - {"setvelocity", 33521}, - {"getviewheight", 33522}, - {"getnormalizedmovement", 33523}, - {"playlocalsound", 33524}, - {"stoplocalsound", 33525}, - {"setweaponammoclip", 33526}, - {"setweaponammostock", 33527}, - {"getweaponammoclip", 33528}, - {"getweaponammostock", 33529}, - {"anyammoforweaponmodes", 33530}, - {"setclientomnvar", 33531}, - {"setclientdvar", 33532}, - {"setclientdvars", 33533}, - {"setclientspawnsighttraces", 33534}, - {"clientspawnsighttracepassed", 33535}, - {"allowads", 33536}, - {"allowjump", 33537}, - {"allowladder", 33538}, - {"allowmantle", 33539}, - {"allowsprint", 33540}, - {"setspreadoverride", 33541}, - {"resetspreadoverride", 33542}, - {"setaimspreadmovementscale", 33543}, - {"setactionslot", 33544}, - {"setviewkickscale", 33545}, - {"getviewkickscale", 33546}, - {"getweaponslistall", 33547}, - {"getweaponslistprimaries", 33548}, - {"getnormalizedcameramovement", 33549}, - {"giveweapon", 33550}, - {"takeweapon", 33551}, - {"takeallweapons", 33552}, - {"getcurrentweapon", 33553}, - {"getcurrentprimaryweapon", 33554}, - {"getcurrentoffhand", 33555}, - {"hasweapon", 33556}, - {"switchtoweapon", 33557}, - {"switchtoweaponimmediate", 33558}, - {"sub_1402e1d60", 33559}, - {"switchtooffhand", 33560}, - {"setoffhandsecondaryclass", 33561}, - {"getoffhandsecondaryclass", 33562}, - {"beginlocationselection", 33563}, - {"endlocationselection", 33564}, - {"disableweapons", 33565}, - {"enableweapons", 33566}, - {"disableoffhandweapons", 33567}, - {"enableoffhandweapons", 33568}, - {"disableweaponswitch", 33569}, - {"enableweaponswitch", 33570}, - {"openpopupmenu", 33571}, - {"openpopupmenunomouse", 33572}, - {"closepopupmenu", 33573}, - {"openmenu", 33574}, - {"closemenu", 33575}, - {"freezecontrols", 33577}, - {"disableusability", 33578}, - {"enableusability", 33579}, - {"setwhizbyspreads", 33580}, - {"setwhizbyradii", 33581}, - {"setchannelvolume", 33584}, - {"givestartammo", 33585}, - {"givemaxammo", 33586}, - {"getfractionstartammo", 33587}, - {"getfractionmaxammo", 33588}, - {"isdualwielding", 33589}, - {"isreloading", 33590}, - {"isswitchingweapon", 33591}, - {"setorigin", 33592}, - {"getvelocity", 33593}, - {"setangles", 33594}, - {"getangles", 33595}, - {"usebuttonpressed", 33596}, - {"attackbuttonpressed", 33597}, - {"adsbuttonpressed", 33598}, - {"meleebuttonpressed", 33599}, - {"playerads", 33600}, - {"isonground", 33601}, - {"isusingturret", 33602}, - {"setviewmodel", 33603}, - {"setoffhandprimaryclass", 33604}, - {"getoffhandprimaryclass", 33605}, - {"sub_14032dff0", 33610}, - {"sub_14032e040", 33611}, - {"enablemousesteer", 33612}, - {"setscriptmoverkillcam", 33613}, - {"usinggamepad", 33614}, - {"forcethirdpersonwhenfollowing", 33615}, - {"disableforcethirdpersonwhenfollowing", 33616}, - {"botsetflag", 33617}, - {"botsetstance", 33618}, - {"botsetscriptmove", 33619}, - {"botsetscriptgoal", 33620}, - {"botsetscriptgoalnode", 33621}, - {"botclearscriptgoal", 33622}, - {"botsetscriptenemy", 33623}, - {"botclearscriptenemy", 33624}, - {"botsetattacker", 33625}, - {"botgetscriptgoal", 33626}, - {"botgetscriptgoalradius", 33627}, - {"botgetscriptgoalyaw", 33628}, - {"botgetscriptgoaltype", 33629}, - {"botgetworldsize", 33631}, - {"botnodeavailable", 33632}, - {"botfindnoderandom", 33633}, - {"botmemoryevent", 33634}, - {"botnodepick", 33636}, - {"bothasscriptgoal", 33637}, - {"botgetpersonality", 33638}, - {"botthrowgrenade", 33639}, - {"botsetpersonality", 33641}, - {"botsetdifficulty", 33642}, - {"botgetdifficulty", 33643}, - {"botgetworldclosestedge", 33644}, - {"botlookatpoint", 33645}, - {"botpredictseepoint", 33646}, - {"botcanseeentity", 33647}, - {"botgetnodesonpath", 33648}, - {"botnodepickmultiple", 33649}, - {"botgetfovdot", 33651}, - {"botsetawareness", 33652}, - {"botpursuingscriptgoal", 33653}, - {"botgetscriptgoalnode", 33654}, - {"botgetimperfectenemyinfo", 33655}, - {"botsetpathingstyle", 33657}, - {"botsetdifficultysetting", 33658}, - {"botgetdifficultysetting", 33659}, - {"botgetpathdist", 33660}, - {"botisrandomized", 33661}, - {"botpressbutton", 33662}, - {"botclearbutton", 33663}, - {"botnodescoremultiple", 33664}, - {"getnodenumber", 33665}, - {"setclientowner", 33666}, - {"setotherent", 33667}, - {"setaisightlinevisible", 33668}, - {"setentityowner", 33669}, - {"nodeisdisconnected", 33670}, - {"getnearestnode", 33671}, - {"makeentitynomeleetarget", 33672}, - {"spawnagent", 33674}, - {"finishagentdamage", 33675}, - {"setagentattacker", 33676}, - {"cloneagent", 33677}, - {"agentcanseesentient", 33678}, - {"setagentwaypoint", 33679}, - {"setgoalpos", 33680}, - {"getgoalpos", 33681}, - {"setgoalnode", 33682}, - {"setgoalentity", 33683}, - {"setgoalradius", 33684}, - {"setanimscale", 33685}, - {"setorientmode", 33686}, - {"setanimmode", 33687}, - {"setphysicsmode", 33688}, - {"setclipmode", 33689}, - {"setmaxturnspeed", 33690}, - {"getmaxturnspeed", 33691}, - {"beginmelee", 33692}, - {"setscripted", 33693}, - {"dotrajectory", 33694}, - {"doanimlerp", 33695}, - {"setviewheight", 33696}, - {"claimnode", 33697}, - {"relinquishclaimednode", 33698}, - {"setradarping", 33699}, - {"visitfxent", 33700}, - {"sub_1402ef480", 33701}, - {"sub_1402ef4e0", 33702}, - {"sub_1402dd560", 33704}, - {"sub_1402dd590", 33705}, - {"allowhighjump", 33714}, - {"isjumping", 33715}, - {"ishighjumping", 33716}, - {"sub_140529a10", 33717}, - {"sub_140529a20", 33718}, - {"getbraggingright", 33719}, - {"getmodelfromentity", 33720}, - {"getweaponheatlevel", 33721}, - {"isweaponoverheated", 33722}, - {"isshiftbuttonpresseddown", 33723}, - {"sub_14052be00", 33724}, - {"sub_14052beb0", 33725}, - {"sub_14052bf30", 33726}, - {"lightsetforplayer", 33728}, - {"lightsetoverrideenableforplayer", 33729}, - {"lightsetoverridedisableforplayer", 33730}, - {"sub_140333c10", 33731}, - {"sub_140043710", 33732}, - {"sub_14052b420", 33733}, - {"sub_1402ddd70", 33734}, - {"setanimclass", 33744}, - {"enableanimstate", 33745}, - {"setanimstate", 33746}, - {"getanimentry", 33747}, - {"getanimentryname", 33748}, - {"getanimentryalias", 33749}, - {"getanimentrycount", 33750}, - {"issprinting", 33752}, - {"jumpbuttonpressed", 33758}, - {"rotateby", 33759}, - {"getlookaheaddir", 33760}, - {"getpathgoalpos", 33761}, - {"sub_140316940", 33762}, - {"setcorpsefalling", 33763}, - {"setsurfacetype", 33764}, - {"aiphysicstrace", 33765}, - {"aiphysicstracepassed", 33766}, - {"visionsetstage", 33770}, - {"linkwaypointtotargetwithoffset", 33771}, - {"getlinkedparent", 33772}, - {"getmovingplatformparent", 33773}, - {"setnameplatematerial", 33774}, - {"sub_140313d20", 33777}, - {"sub_1403131d0", 33778}, - {"makevehiclenotcollidewithplayers", 33779}, - {"setscriptablepartstate", 33782}, - {"stopsliding", 33783}, - {"sub_140316a60", 33784}, - {"setdronegoalpos", 33785}, - {"hudoutlineenable", 33786}, - {"hudoutlinedisable", 33787}, - {"worldpointtoscreenpos", 33792}, - {"botfirstavailablegrenade", 33795}, - {"emissiveblend", 33801}, - {"sub_1402e66d0", 33804}, - {"sub_1402e66e0", 33805}, - {"sub_1402e66f0", 33806}, - {"physicssetmaxlinvel", 33810}, - {"physicssetmaxangvel", 33811}, - {"physicsgetlinvel", 33812}, - {"physicsgetlinspeed", 33813}, - {"physicsgetangvel", 33814}, - {"physicsgetangspeed", 33815}, - {"disablemissileboosting", 33816}, - {"enablemissileboosting", 33817}, - {"canspawntestclient", 33818}, - {"spawntestclient", 33819}, - {"loadcustomizationplayerview", 33820}, - {"setgrenadethrowscale", 33821}, - {"setgrenadecookscale", 33822}, - {"setplanesplineid", 33823}, - {"hudoutlineenableforclient", 33824}, - {"hudoutlinedisableforclient", 33825}, - {"hudoutlineenableforclients", 33826}, - {"hudoutlinedisableforclients", 33827}, - {"turretsetbarrelspinenabled", 33828}, - {"hasloadedcustomizationplayerview", 33829}, - {"sub_140313420", 33830}, - {"sub_1403136f0", 33831}, - {"doanimrelative", 33832}, - {"getcorpseentity", 33836}, - {"logmatchdatalife", 33838}, - {"logmatchdatadeath", 33839}, - {"queuedialogforplayer", 33840}, - {"setmlgcameradefaults", 33841}, - {"ismlgspectator", 33842}, - {"disableautoreload", 33843}, - {"enableautoreload", 33844}, - {"getlinkedchildren", 33846}, - {"botpredictenemycampspots", 33847}, - {"playsoundonmovingent", 33848}, - {"cancelmantle", 33849}, - {"hasfemalecustomizationmodel", 33850}, - {"sub_1402e6bb0", 33851}, - {"setscriptabledamageowner", 33852}, - {"setfxkilldefondelete", 33853}, - {"sub_1402e1b80", 33856}, - {"sub_140310fb0", 33858}, - {"challengenotification", 33859}, - {"sub_140528300", 33860}, - {"sub_14052bff0", 33861}, - {"linktosynchronizedparent", 33862}, - {"getclientomnvar", 33863}, - {"getcacplayerdataforgroup", 33866}, - {"cloakingenable", 33867}, - {"cloakingdisable", 33868}, - {"getunnormalizedcameramovement", 33869}, - {"sub_14031edf0", 33870}, - {"isturretoverheated", 33871}, - {"sub_14052c170", 33872}, - {"sub_14052c190", 33873}, - {"sub_14052c1b0", 33874}, - {"sub_14052c1d0", 33875}, - {"sub_14052c0b0", 33878}, - {"sub_1402de140", 33879}, - {"getvieworigin", 33884}, - {"setweaponmodelvariant", 33885}, - {"ridevehicle", 33886}, - {"stopridingvehicle", 33887}, - {"autoboltmissileeffects", 33889}, - {"disablemissilestick", 33890}, - {"enablemissilestick", 33891}, - {"setmissileminimapvisible", 33892}, - {"isoffhandweaponreadytothrow", 33893}, - {"makecollidewithitemclip", 33895}, - {"visionsetpostapplyforplayer", 33897}, - {"setlookattarget", 33898}, - {"clearlookattarget", 33899}, - {"sub_14052c250", 33907}, - {"sub_14052c290", 33908}, - {"sub_14052c2f0", 33909}, - {"sub_14052c340", 33910}, - {"sub_14052c360", 33911}, - {"sub_14031c170", 33912}, - {"sub_14031c590", 33913}, - {"setclienttriggervisionset", 33914}, - {"sub_1402e41c0", 33917}, - {"sub_1402e43b0", 33918}, - {"sub_14052b4d0", 33919}, - {"sub_14052b550", 33920}, - {"showviewmodel", 33921}, - {"hideviewmodel", 33922}, - {"setpickupweapon", 33923}, - {"allowpowerslide", 33925}, - {"allowhighjumpdrop", 33926}, - {"sub_1404045e0", 33927}, - {"sub_1405297e0", 33928}, - {"sub_14052c200", 33929}, - {"clearentity", 33930}, - {"sub_140334a40", 33931}, - {"allowdodge", 33933}, - {"sub_140529860", 33934}, - {"setminimapvisible", 33935}, - {"sub_1402e0a90", 33936}, - {"sub_1402e0bc0", 33937}, - {"sub_1402e0cf0", 33938}, - {"setplayermech", 33940}, - {"setdamagecallbackon", 33941}, - {"finishentitydamage", 33942}, - {"designatefoftarget", 33946}, - {"sethintstringvisibleonlytoowner", 33947}, - {"notifyonplayercommandremove", 33948}, - {"sub_1402e3bf0", 33949}, - {"allowboostjump", 33950}, - {"batterydischargebegin", 33951}, - {"batterydischargeend", 33952}, - {"batterydischargeonce", 33953}, - {"batterygetcharge", 33954}, - {"batterysetcharge", 33955}, - {"batteryfullrecharge", 33956}, - {"batterygetsize", 33957}, - {"batterysetdischargescale", 33958}, - {"batterygetdischargerate", 33959}, - {"batteryisinuse", 33960}, - {"enablephysicaldepthoffieldscripting", 33961}, - {"disablephysicaldepthoffieldscripting", 33962}, - {"setphysicaldepthoffield", 33963}, - {"sub_140313860", 33964}, - {"sub_14052a560", 33965}, - {"sub_140321790", 33966}, - {"sub_140321a50", 33967}, - {"sub_1402dda50", 33968}, - {"sub_14052ac50", 33969}, - {"sub_14052ad50", 33970}, - {"setdemigod", 33971}, - {"sub_140310840", 33972}, - {"setcostumemodels", 33978}, - {"sub_140529e00", 33979}, - {"sub_140313510", 33980}, - {"scriptmodelpauseanim", 33981}, - {"digitaldistortsetmaterial", 33982}, - {"disableoffhandsecondaryweapons", 33983}, - {"enableoffhandsecondaryweapons", 33984}, - {"canplaceriotshield", 33985}, - {"setriotshieldfailhint", 33986}, - {"enabledetonate", 33987}, - {"getdetonateenabled", 33988}, - {"playergetuseent", 33989}, - {"refreshshieldmodels", 33990}, - {"sub_14052c3a0", 33991}, - {"locret_140406a70", 33993}, - {"getgravity", 33994}, - {"sub_140529560", 33997}, - {"sub_140529650", 33998}, - {"setcommonplayerdatareservedint", 33999}, - {"getrankedplayerdatareservedint", 34000}, - {"setrankedplayerdatareservedint", 34001}, - {"getcommonplayerdatareservedint", 34002}, - {"sub_1402e8a20", 34003}, - {"sub_14052c3c0", 34004}, - {"addsoundmutedevice", 34005}, - {"removesoundmutedevice", 34006}, - {"clientaddsoundsubmix", 34007}, - {"clientclearsoundsubmix", 34008}, - {"sub_140312520", 34009}, - {"sub_140312ba0", 34010}, - {"sub_140312bf0", 34011}, - {"sub_140312cb0", 34012}, - {"sub_140312df0", 34013}, - {"sub_140312ff0", 34014}, - {"isusingoffhand", 34016}, - {"physicsstop", 34017}, - {"sub_14031b9e0", 34018}, - {"sub_14031e3c0", 34023}, - {"sub_1402ef8a0", 34024}, - {"sub_14052c400", 34025}, - {"initwaterclienttrigger", 34026}, - {"getcurrentweaponmodelname", 34027}, - {"sub_14031f000", 34028}, - {"setignorefoliagesightingme", 34030}, - {"loadcostumemodels", 34031}, - {"sub_14030cd90", 34036}, - {"sub_14030b1c0", 34038}, - {"sub_140322450", 34039}, - {"iscloaked", 34040}, - {"sub_140528bc0", 34041}, - {"sub_140528cf0", 34042}, - {"sub_14031fb80", 34043}, - {"sub_140320180", 34044}, - {"selfieaccessselfievalidflaginplayerdef", 34045}, - {"selfieaccessselfiecustomassetsarestreamed", 34046}, - {"sub_14031ede0", 34048}, - {"selfiescreenshottaken", 34049}, - {"sub_14031f190", 34050}, - {"sub_140319de0", 34052}, - {"setmissilecoasting", 34053}, - {"setmlgspectator", 34054}, - {"gettotalmpxp", 34055}, - {"turretsetgroundaimentity", 34056}, - {"sub_140318610", 34057}, - {"sub_140317760", 34058}, - {"sub_14032e9a0", 34059}, - {"sub_140320830", 34060}, - {"sub_140329bc0", 34061}, - {"sub_14032e370", 34062}, - {"consumereinforcement", 34063}, - {"ghost", 34064}, - {"loadweapons", 34065}, - {"sub_1402e0e80", 34067}, - {"setwaypointiconfadeatcenter", 34068}, - {"setreinforcementhintstrings", 34069}, - {"playgoliathentryanim", 34070}, - {"playgoliathtoidleanim", 34071}, - {"sub_140312210", 34072}, - {"sub_140312280", 34073}, - {"sub_140321660", 34074}, - {"playlocalannouncersound", 34075}, - {"setmissilespecialclipmask", 34076}, - {"sub_140527c40", 34077}, - {"sub_140527c60", 34078}, - {"isdodging", 34079}, - {"ispowersliding", 34080}, - {"sub_140320ab0", 34081}, - {"getcurrentping", 34082}, - {"sub_1402eeb60", 34083}, - {"sub_140329390", 34084}, - {"gethordeplayerdata", 34085}, - {"sethordeplayerdata", 34086}, - {"sub_1402dcbc0", 34087}, - {"sub_14031a0b0", 34088}, - {"sub_1403198a0", 34089}, - {"sub_1403345e0", 34090}, - {"sub_1402e7d80", 34092}, - {"sub_140404f00", 34093}, - {"issplitscreenplayer2", 34095}, - {"setowneroriginal", 34096}, - {"getlinkedtagname", 34097}, - {"sub_14032de80", 34098}, - {"sub_14032dfb0", 34099}, - {"setwaypointaerialtargeting", 34100}, - {"worldweaponsloaded", 34101}, - {"sub_140320aa0", 34102}, - {"usetriggertouchcheckstance", 34103}, - {"onlystreamactiveweapon", 34104}, - {"precachekillcamiconforweapon", 34105}, - {"selfierequestupdate", 34106}, - {"getclanwarsbonus", 34107}, - {"sub_140406810", 34108}, - {"sub_1404051d0", 34109}, - {"sub_140406340", 34110}, - {"sub_1402e72a0", 34111}, - {"sub_140404c70", 34112}, - {"sub_1404065c0", 34113}, - {"sub_140405c60", 34114}, - {"sub_140406400", 34115}, - {"sub_140406230", 34116}, - {"sub_140406650", 34117}, - {"sub_1402e7de0", 34118}, - {"sub_140333550", 34119}, - {"sub_140403fe0", 34120}, - {"sub_140320360", 34121}, - {"canhighjump", 34122}, - {"setprestigemastery", 34123}, - {"sub_140403f50", 34124}, - {"sub_14030c7b0", 34125}, - {"sub_1403206b0", 34126}, - {"sub_140329960", 34127}, - {"sub_140328100", 34128}, - {"sub_140405990", 34129}, - {"sub_1402e70c0", 34130}, - {"sub_1403335f0", 34131}, - {"getcoopplayerdatareservedint", 34132}, - {"setcoopplayerdatareservedint", 34133}, - {"sub_140406b50", 34134}, - {"sub_1402de070", 34135}, - {"sub_1402e7e40", 34136}, - {"sub_140329ba0", 34137}, - {"sub_140405af0", 34138}, - {"sub_1402e7240", 34139}, - {"sub_14031a370", 34140}, - {"sub_140406970", 34141}, - {"sub_140405b60", 34142}, - {"sub_140334e10", 34143}, - {"sub_140320a90", 34144}, - {"sub_140406c00", 34145}, - {"sub_140328bf0", 34146}, - {"sub_1404053e0", 34147}, - {"sub_140406d20", 34148}, - {"sub_14032c900", 34149}, - {"sub_14032c9e0", 34150}, - {"sub_140044360", 34151}, - {"sub_140333680", 34152}, - {"sub_1402e7130", 34153}, - {"sub_1403294b0", 34154}, - {"sub_140320b40", 34155}, - {"sub_140333710", 34156}, - }; - - std::unordered_map token_map = - { - {"CodeCallback_BulletHitEntity", 180}, - {"CodeCallback_CodeEndGame", 181}, - {"CodeCallback_EntityDamage", 182}, - {"CodeCallback_EntityOutOfWorld", 183}, - {"CodeCallback_HostMigration", 185}, - {"CodeCallback_PartyMembers", 187}, - {"CodeCallback_PlayerConnect", 188}, - {"CodeCallback_PlayerDamage", 189}, - {"CodeCallback_PlayerDisconnect", 190}, - {"CodeCallback_PlayerGrenadeSuicide", 191}, - {"CodeCallback_PlayerKilled", 192}, - {"CodeCallback_PlayerLastStand", 193}, - {"CodeCallback_PlayerMigrated", 194}, - {"CodeCallback_StartGameType", 195}, - {"CodeCallback_VehicleDamage", 196}, - {"CreateStruct", 221}, - {"InitStructs", 522}, - {"main", 619}, - {"AbortLevel", 1727}, - {"callbackVoid", 6662}, - {"CodeCallback_GiveKillstreak", 8192}, - {"SetDefaultCallbacks", 32577}, - {"SetupCallbacks", 33531}, - {"SetupDamageFlags", 33542}, - {"struct", 36698}, - {"codescripts/delete", 0x053D}, - {"codescripts/struct", 0x053E}, - {"maps/mp/gametypes/_callbacksetup", 0x0540}, - {"codescripts/character", 0xA4E5}, - {"common_scripts/_artcommon", 42214}, - {"common_scripts/_bcs_location_trigs", 42215}, - {"common_scripts/_createfx", 42216}, - {"common_scripts/_createfxmenu", 42217}, - {"common_scripts/_destructible", 42218}, - {"common_scripts/_dynamic_world", 42219}, - {"maps/createart/mp_vlobby_room_art", 42735}, - {"maps/createart/mp_vlobby_room_fog", 42736}, - {"maps/createart/mp_vlobby_room_fog_hdr", 42737} - }; -} diff --git a/src/client/game/scripting/functions.cpp b/src/client/game/scripting/functions.cpp index 3452c76..d7e8965 100644 --- a/src/client/game/scripting/functions.cpp +++ b/src/client/game/scripting/functions.cpp @@ -3,97 +3,89 @@ #include +#include "component/gsc/script_extension.hpp" + +#include +#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()) + auto first = xsk::gsc::s1::resolver::function_id; + auto second = xsk::gsc::s1::resolver::method_id; + if (!prefer_global) { - return function_entry->second; + std::swap(first, second); } - function_entry = secondary_map.find(target); - if (function_entry != secondary_map.end()) + const auto first_res = first(target); + if (first_res) { - return function_entry->second; + return first_res; + } + + const auto second_res = second(target); + if (second_res) + { + return second_res; } 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) + std::uint32_t parse_token_id(const std::string& name) { - for (const auto& token : token_map) + if (name.starts_with("_ID")) { - if (token.second == id) - { - return token.first; - } + return static_cast(std::strtol(name.substr(3).data(), nullptr, 10)); } - return utils::string::va("_ID%i", id); + return 0; + } + + std::string find_token(std::uint32_t id) + { + return xsk::gsc::s1::resolver::token_name(static_cast(id)); + } + + std::string find_token_single(std::uint32_t id) + { + return xsk::gsc::s1::resolver::token_name(static_cast(id)); } unsigned int find_token_id(const std::string& name) { - const auto result = token_map.find(name); - - if (result != token_map.end()) + const auto id = xsk::gsc::s1::resolver::token_id(name); + if (id) { - return result->second; + return id; } - return 0; + const auto parsed_id = parse_token_id(name); + if (parsed_id) + { + return parsed_id; + } + + return game::SL_GetCanonicalString(name.data()); + } + + script_function get_function_by_index(const std::uint32_t index) + { + static const auto function_table = &gsc::func_table; + static const auto method_table = SELECT_VALUE(0x14966A670, 0x147DD2F50); + + if (index < 0x1000) + { + return reinterpret_cast(function_table)[index - 1]; + } + + return reinterpret_cast(method_table)[index - 0x8000]; } script_function find_function(const std::string& name, const bool prefer_global) diff --git a/src/client/game/scripting/functions.hpp b/src/client/game/scripting/functions.hpp index 0422bcf..ea74812 100644 --- a/src/client/game/scripting/functions.hpp +++ b/src/client/game/scripting/functions.hpp @@ -3,14 +3,12 @@ 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); + std::string find_token(std::uint32_t id); + std::string find_token_single(std::uint32_t id); unsigned int find_token_id(const std::string& name); - script_function find_function(const std::string& name, const bool prefer_global); + script_function get_function_by_index(std::uint32_t index); + script_function find_function(const std::string& name, bool prefer_global); } diff --git a/src/client/game/scripting/lua/context.cpp b/src/client/game/scripting/lua/context.cpp index e5b188a..5c0ef0f 100644 --- a/src/client/game/scripting/lua/context.cpp +++ b/src/client/game/scripting/lua/context.cpp @@ -3,15 +3,17 @@ #include "error.hpp" #include "value_conversion.hpp" -#include "../execution.hpp" -#include "../functions.hpp" +#include "game/scripting/execution.hpp" -#include "../../../component/command.hpp" -#include "../../../component/logfile.hpp" -#include "../../../component/scripting.hpp" +#include "component/command.hpp" +#include "component/notifies.hpp" +#include "component/scripting.hpp" #include +#include +#include + namespace scripting::lua { namespace @@ -244,10 +246,10 @@ namespace scripting::lua auto entity_type = state.new_usertype("entity"); - for (const auto& func : method_map) + for (const auto& func : xsk::gsc::s1::resolver::get_methods()) { - 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) + const auto name = std::string(func.first); + entity_type[name] = [name](const entity& entity, const sol::this_state s, sol::variadic_args va) { std::vector arguments{}; @@ -376,9 +378,9 @@ namespace scripting::lua auto game_type = state.new_usertype("game_"); state["game"] = game(); - for (const auto& func : function_map) + for (const auto& func : xsk::gsc::s1::resolver::get_functions()) { - const auto name = utils::string::to_lower(func.first); + const auto name = std::string(func.first); game_type[name] = [name](const game&, const sol::this_state s, sol::variadic_args va) { std::vector arguments{}; @@ -424,12 +426,12 @@ namespace scripting::lua game_type["onplayerdamage"] = [](const game&, const sol::protected_function& callback) { - logfile::add_player_damage_callback(callback); + notifies::add_player_damage_callback(callback); }; game_type["onplayerkilled"] = [](const game&, const sol::protected_function& callback) { - logfile::add_player_killed_callback(callback); + notifies::add_player_killed_callback(callback); }; game_type["getgamevar"] = [](const sol::this_state s) @@ -455,43 +457,40 @@ namespace scripting::lua 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) + 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) { - 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)); + arguments.push_back(convert({s, arg})); } - ); + + const auto _0 = gsl::finally(¬ifies::enable_vm_execute_hook); + notifies::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})); + } + + const auto _0 = gsl::finally(¬ifies::enable_vm_execute_hook); + notifies::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) + 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{}; @@ -500,8 +499,8 @@ namespace scripting::lua arguments.push_back(convert({s, arg})); } - gsl::finally(&logfile::enable_vm_execute_hook); - logfile::disable_vm_execute_hook(); + const auto _0 = gsl::finally(¬ifies::enable_vm_execute_hook); + notifies::disable_vm_execute_hook(); return convert(s, call_script_function(*::game::levelEntityId, filename, function, arguments)); }; @@ -510,50 +509,48 @@ namespace scripting::lua 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; + notifies::set_lua_hook(pos, function); auto detour = sol::table::create(function.lua_state()); - detour["disable"] = [pos]() + detour["disable"] = [pos] { - logfile::vm_execute_hooks.erase(pos); + notifies::clear_hook(pos); }; - detour["enable"] = [pos, function]() + detour["enable"] = [pos, function] { - logfile::vm_execute_hooks[pos] = function; + notifies::set_lua_hook(pos, function); }; - detour["invoke"] = sol::overload( - [filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va) + 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) { - 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)); + arguments.push_back(convert({s, arg})); } - ); + + const auto _0 = gsl::finally(¬ifies::enable_vm_execute_hook); + notifies::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})); + } + + const auto _0 = gsl::finally(¬ifies::enable_vm_execute_hook); + notifies::disable_vm_execute_hook(); + + return convert(s, call_script_function(*::game::levelEntityId, filename, function_name, arguments)); + }); return detour; }; diff --git a/src/client/game/scripting/lua/engine.cpp b/src/client/game/scripting/lua/engine.cpp index 15863c1..f364533 100644 --- a/src/client/game/scripting/lua/engine.cpp +++ b/src/client/game/scripting/lua/engine.cpp @@ -1,10 +1,11 @@ #include + #include "engine.hpp" #include "context.hpp" +#include "game/scripting/execution.hpp" -#include "../execution.hpp" -#include "../../../component/logfile.hpp" -#include "../../../component/game_module.hpp" +#include "component/notifies.hpp" +#include "component/game_module.hpp" #include @@ -39,7 +40,7 @@ namespace scripting::lua::engine void stop() { - logfile::clear_callbacks(); + notifies::clear_callbacks(); get_scripts().clear(); } diff --git a/src/client/game/scripting/lua/value_conversion.cpp b/src/client/game/scripting/lua/value_conversion.cpp index defbe14..34323f7 100644 --- a/src/client/game/scripting/lua/value_conversion.cpp +++ b/src/client/game/scripting/lua/value_conversion.cpp @@ -1,8 +1,9 @@ #include #include "value_conversion.hpp" -#include "../functions.hpp" -#include "../execution.hpp" -#include ".../../component/logfile.hpp" + +#include "game/scripting/functions.hpp" +#include "game/scripting/execution.hpp" +#include "component/notifies.hpp" namespace scripting::lua { @@ -120,9 +121,8 @@ namespace scripting::lua 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; + const auto index = reinterpret_cast(notifies::get_hook_count() + 1); + notifies::set_lua_hook(index, function); game::VariableValue func; func.type = game::SCRIPT_FUNCTION; @@ -133,30 +133,28 @@ namespace scripting::lua 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) + return sol::overload([pos](const entity& entity, const sol::this_state s, sol::variadic_args va) + { + std::vector arguments{}; + + for (auto arg : 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)); + 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)); + }); } } @@ -167,8 +165,7 @@ namespace scripting::lua 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) + 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()) @@ -190,8 +187,7 @@ namespace scripting::lua 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) + 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()) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index e000055..0542788 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -22,6 +22,9 @@ namespace game unsigned short classnum; }; + typedef void(*BuiltinMethod)(scr_entref_t); + typedef void(*BuiltinFunction)(); + enum scriptType_e { SCRIPT_NONE = 0, diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 1968ea5..53f9a31 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -36,8 +36,7 @@ namespace game WEAK symbol Cbuf_AddCall{0x1402ED820, 0x1403AECF0}; WEAK symbol Cbuf_AddText{0x1402ED890, 0x1403AED70}; - WEAK symbol Cbuf_ExecuteBufferInternal{0x1402ED9A0, 0x1403AEE80}; + WEAK symbol Cbuf_ExecuteBufferInternal{0x1402ED9A0, 0x1403AEE80}; WEAK symbol CL_IsCgameInitialized{0x140136560, 0x1401FD510}; WEAK symbol CL_ForwardCommandToServer{0x0, 0x14020B310}; @@ -66,9 +65,7 @@ namespace game WEAK symbol Dvar_Reset{0x140372950, 0x1404C1DB0}; WEAK symbol Dvar_SetCommand{0x1403730D0, 0x1404C2520}; WEAK symbol Dvar_SetString{0x140373DE0, 0x1404C3610}; - WEAK symbol Dvar_SetFromStringByNameFromSource{ - 0x1403737D0, 0x1404C2E40 - }; + WEAK symbol Dvar_SetFromStringByNameFromSource{0x1403737D0, 0x1404C2E40}; WEAK symbol Dvar_ValueToString{0x140374E10, 0x1404C47B0}; WEAK symbol @@ -100,9 +97,7 @@ namespace game WEAK symbol FindVariable{0x1403165D0, 0x1403F2DC0}; WEAK symbol FindEntityId{0x1403166D0, 0x1403F2CC0}; WEAK symbol GetVariableName{0x1403170E0, 0x1403F37F0}; - WEAK symbol GetEntityFieldValue{ - 0x14031AAD0, 0x1403F72A0 - }; + WEAK symbol GetEntityFieldValue{0x14031AAD0, 0x1403F72A0}; WEAK symbol GetObjectType{0x140316F70, 0x1403F3670}; WEAK symbol GetVariable{0x0, 0x1403F3730}; @@ -110,9 +105,7 @@ namespace game WEAK symbol G_GetClientScore{0, 0x1402F6AB0}; WEAK symbol G_GetWeaponForName{0x140274590, 0x14033FF60}; - WEAK symbol - G_GivePlayerWeapon{0x1402749B0, 0x140340470}; + WEAK symbol G_GivePlayerWeapon{0x1402749B0, 0x140340470}; WEAK symbol G_InitializeAmmo{0x1402217F0, 0x1402F22B0}; WEAK symbol G_SelectWeapon{0x140275380, 0x140340D50}; WEAK symbol G_TakePlayerWeapon{0x1402754E0, 0x1403411D0}; @@ -167,10 +160,12 @@ namespace game WEAK symbol Scr_RegisterFunction{0x1403115B0, 0x1403EDAE0}; WEAK symbol VM_Execute{0x0, 0x1403F9E40}; + WEAK symbol Scr_ErrorInternal{0x0, 0x1403F80A0}; WEAK symbol SL_ConvertToString{0x140314850, 0x1403F0F10}; WEAK symbol SL_FindString{0x140314AF0, 0x1403F11C0}; WEAK symbol SL_GetString{0x140314D90, 0x1403F1440}; + WEAK symbol SL_GetCanonicalString{0x140311770, 0x1403EDCA0}; WEAK symbol SV_Cmd_ArgvBuffer{0x1402EEFD0, 0x1403B05C0}; WEAK symbol SV_Cmd_TokenizeString{0, 0x1403B0640}; @@ -253,6 +248,8 @@ namespace game WEAK symbol query_socket{0, 0x14B5B9180}; + WEAK symbol level_time{0x0, 0x144959C2C}; + WEAK symbol DB_XAssetPool{0x140804690, 0x1409B40D0}; WEAK symbol db_hashTable{0x142C3E050, 0x143716B10}; WEAK symbol g_assetEntryPool{0x142CC2400, 0x14379F100}; diff --git a/src/client/game/ui_scripting/execution.cpp b/src/client/game/ui_scripting/execution.cpp index efce447..c61bd09 100644 --- a/src/client/game/ui_scripting/execution.cpp +++ b/src/client/game/ui_scripting/execution.cpp @@ -1,10 +1,7 @@ #include #include "execution.hpp" -#include "component/ui_scripting.hpp" #include "component/console.hpp" -#include - namespace ui_scripting { namespace diff --git a/src/client/game/ui_scripting/script_value.cpp b/src/client/game/ui_scripting/script_value.cpp index 5f728f7..bffd048 100644 --- a/src/client/game/ui_scripting/script_value.cpp +++ b/src/client/game/ui_scripting/script_value.cpp @@ -2,7 +2,6 @@ #include "execution.hpp" #include "types.hpp" #include "script_value.hpp" -#include "../../component/ui_scripting.hpp" namespace ui_scripting { diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index a0d25e9..758cc18 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -55,6 +55,7 @@ #undef min #endif +#include #include #include #include @@ -72,6 +73,7 @@ #include #include #include +#include #include #include