From 50438cef275b2f6009488afca89101582c19fdb9 Mon Sep 17 00:00:00 2001 From: alice <58637860+alicealys@users.noreply.github.com> Date: Sun, 26 Jul 2026 02:06:25 +0200 Subject: [PATCH] fixes --- src/component/command.cpp | 17 +- src/component/command.hpp | 2 +- src/component/gsc.cpp | 255 ++++++++--------------------- src/component/gsc.hpp | 23 ++- src/component/io.cpp | 75 ++------- src/component/json.cpp | 4 +- src/component/notifies.cpp | 74 --------- src/component/scheduler.cpp | 4 +- src/component/scripting.cpp | 92 +---------- src/component/scripting.hpp | 3 - src/component/signatures.cpp | 92 ----------- src/component/signatures.hpp | 6 - src/component/string.cpp | 11 +- src/component/userinfo.cpp | 35 ++-- src/dllmain.cpp | 10 +- src/game/scripting/entity.cpp | 16 -- src/game/scripting/entity.hpp | 16 -- src/game/scripting/execution.cpp | 167 ------------------- src/game/scripting/execution.hpp | 12 -- src/game/scripting/functions.cpp | 59 ------- src/game/scripting/functions.hpp | 5 - src/game/symbols.hpp | 7 - src/loader/component_interface.hpp | 12 +- src/loader/component_loader.cpp | 123 ++++---------- src/loader/component_loader.hpp | 20 +-- src/plugin.cpp | 20 +-- src/stdinc.hpp | 1 - src/utils/concurrent_list.hpp | 144 ---------------- src/utils/hook.cpp | 55 ++----- src/utils/hook.hpp | 34 +--- 30 files changed, 215 insertions(+), 1179 deletions(-) delete mode 100644 src/component/notifies.cpp delete mode 100644 src/component/signatures.cpp delete mode 100644 src/component/signatures.hpp delete mode 100644 src/utils/concurrent_list.hpp diff --git a/src/component/command.cpp b/src/component/command.cpp index 88c88b0..f083050 100644 --- a/src/component/command.cpp +++ b/src/component/command.cpp @@ -8,6 +8,8 @@ namespace command { std::unordered_map> handlers; + std::vector script_commands; + utils::memory::allocator allocator; void main_handler() { @@ -46,7 +48,11 @@ namespace command for (auto i = index; i < this->size(); i++) { - if (i > index) result.append(" "); + if (i > index) + { + result.append(" "); + } + result.append(this->get(i)); } @@ -70,14 +76,11 @@ namespace command handlers[command] = callback; } - std::vector script_commands; - utils::memory::allocator allocator; - void add_script_command(const std::string& name, const std::function& callback) { script_commands.push_back(name); - const auto _name = allocator.duplicate_string(name); - add(_name, callback); + const auto name_str = allocator.duplicate_string(name); + add(name_str, callback); } void clear_script_commands() @@ -95,7 +98,7 @@ namespace command class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { } }; diff --git a/src/component/command.hpp b/src/component/command.hpp index 54f08c4..5e93bab 100644 --- a/src/component/command.hpp +++ b/src/component/command.hpp @@ -25,4 +25,4 @@ namespace command void add_script_command(const std::string& name, const std::function& callback); void clear_script_commands(); -} \ No newline at end of file +} diff --git a/src/component/gsc.cpp b/src/component/gsc.cpp index 048853d..c4b8081 100644 --- a/src/component/gsc.cpp +++ b/src/component/gsc.cpp @@ -14,41 +14,8 @@ namespace gsc { - std::unordered_map functions; - std::unordered_map methods; - namespace { - std::string method_name(unsigned int id) - { - const auto& map = (*game::plutonium::gsc_ctx)->meth_map(); - - for (const auto& function : map) - { - if (function.second == id) - { - return function.first.data(); - } - } - - return {}; - } - - std::string function_name(unsigned int id) - { - const auto& map = (*game::plutonium::gsc_ctx)->func_map(); - - for (const auto& function : map) - { - if (function.second == id) - { - return function.first.data(); - } - } - - return {}; - } - function_args get_arguments() { std::vector args; @@ -72,9 +39,6 @@ namespace gsc scripting::push_value(value); } - auto function_map_start = 0x200; - auto method_map_start = 0x8400; - auto token_map_start = 0x8000; auto field_offset_start = 0xA000; struct entity_field @@ -87,16 +51,11 @@ namespace gsc std::vector> post_load_callbacks; std::unordered_map> custom_fields; - void call_function(unsigned int id) + void call_function(const script_function* function, const char* name) { - if (id < 0x200) - { - return reinterpret_cast(game::plutonium::function_table.get())[id](); - } - try { - const auto result = functions[id](get_arguments()); + const auto result = function->operator()(get_arguments()); const auto type = result.get_raw().type; if (type) @@ -106,23 +65,18 @@ namespace gsc } catch (const std::exception& e) { - printf("************** Script execution error **************\n"); - printf("Error executing function %s:\n", function_name(id).data()); - printf(" %s\n", e.what()); - printf("****************************************************\n"); + printf("************** Script execution error **************"); + printf("Error executing function %s:", name); + printf(" %s", e.what()); + printf("****************************************************"); } } - void call_method(game::scr_entref_t ent, unsigned int id) + void call_method(const script_method* method, const char* name, game::scr_entref_t ent) { - if (id < 0x8400) - { - return reinterpret_cast(game::plutonium::method_table.get())[id - 0x8000](ent); - } - try { - const auto result = methods[id](ent, get_arguments()); + const auto result = method->operator()(ent, get_arguments()); const auto type = result.get_raw().type; if (type) @@ -132,55 +86,10 @@ namespace gsc } catch (const std::exception& e) { - printf("************** Script execution error **************\n"); - printf("Error executing method %s:\n", method_name(id).data()); - printf(" %s\n", e.what()); - printf("****************************************************\n"); - } - } - - __declspec(naked) void call_builtin_stub() - { - __asm - { - push eax - - mov eax, 0x20B4A5C - mov [eax], esi - - mov eax, 0x20B4A90 - mov [eax], edx - - pop eax - - pushad - push eax - call call_function - pop eax - popad - - push 0x56C900 - retn - } - } - - __declspec(naked) void call_builtin_method_stub() - { - __asm - { - pushad - push ecx - push ebx - call call_method - pop ebx - pop ecx - popad - - push ebx - add esp, 0xC - - push 0x56CBE9 - retn + printf("************** Script execution error **************"); + printf("Error executing method %s:", name); + printf(" %s", e.what()); + printf("****************************************************"); } } @@ -201,10 +110,10 @@ namespace gsc } catch (const std::exception& e) { - printf("************** Script execution error **************\n"); - printf("Error getting field %s:\n", field.name.data()); - printf(" %s\n", e.what()); - printf("****************************************************\n"); + printf("************** Script execution error **************"); + printf("Error getting field %s:", field.name.data()); + printf(" %s", e.what()); + printf("****************************************************"); } } @@ -225,10 +134,10 @@ namespace gsc } catch (const std::exception& e) { - printf("************** Script execution error **************\n"); - printf("Error setting field %s:\n", field.name.data()); - printf(" %s\n", e.what()); - printf("****************************************************\n"); + printf("************** Script execution error **************"); + printf("Error setting field %s:", field.name.data()); + printf(" %s", e.what()); + printf("****************************************************"); } } @@ -244,53 +153,51 @@ namespace gsc } } - namespace function + void* make_function_thunk(const char* name, const script_function* func) { - void add(const std::string& name, const script_function& func) + static std::uint8_t bytes[] = { - auto index = 0u; - auto& ctx = (*game::plutonium::gsc_ctx); - - if (ctx->func_exists(name)) - { - printf("[iw5-gsc-utils] Warning: function '%s' already defined\n", name.data()); - index = ctx->func_id(name); - } - else - { - index = function_map_start++; - ctx->func_add(name, index); - } + 0x68, 0x44, 0x33, 0x22, 0x11, // push + 0x68, 0x44, 0x33, 0x22, 0x11, // push + 0x00, 0x00, 0x00, 0x00, 0x00, // call + 0x83, 0xC4, 0x08, // add esp, 8 + 0xC3 // ret + }; - functions.insert(std::make_pair(index, func)); - } + const auto stub = utils::memory::allocate_array(sizeof(bytes)); + std::memcpy(stub, bytes, sizeof(bytes)); + + utils::hook::unprotect(stub, sizeof(bytes)); + + *reinterpret_cast(stub + 1) = reinterpret_cast(name); + *reinterpret_cast(stub + 6) = reinterpret_cast(func); + utils::hook::call(stub + 10, call_function); + + return stub; } - namespace method + void* make_method_thunk(const char* name, const script_method* func) { - void add(const std::string& name, const script_method& func) + static std::uint8_t bytes[] = { - if (true) - { - return; - } + 0xFF, 0x74, 0x24, 0x04, // push [esp+4] + 0x68, 0x44, 0x33, 0x22, 0x11, // push + 0x68, 0x44, 0x33, 0x22, 0x11, // push + 0x00, 0x00, 0x00, 0x00, 0x00, // call + 0x83, 0xC4, 0x0C, // add esp, 8 + 0xC3 // ret + }; - auto index = 0u; - auto& ctx = (*game::plutonium::gsc_ctx); + const auto stub = utils::memory::allocate_array(sizeof(bytes)); + std::memcpy(stub, bytes, sizeof(bytes)); - if (ctx->meth_exists(name)) - { - printf("[iw5-gsc-utils] Warning: method '%s' already defined\n", name.data()); - index = ctx->meth_id(name); - } - else - { - index = method_map_start++; - ctx->meth_add(name, index); - } + utils::hook::unprotect(stub, sizeof(bytes)); - methods.insert(std::make_pair(index, func)); - } + *reinterpret_cast(stub + 5) = reinterpret_cast(name); + *reinterpret_cast(stub + 10) = reinterpret_cast(func); + utils::hook::call(stub + 14, call_method); + + return stub; } namespace field @@ -338,7 +245,7 @@ namespace gsc class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { scr_get_object_field_hook.create(0x52BDB0, scr_get_object_field_stub); scr_set_object_field_hook.create(0x52BCC0, scr_set_object_field_stub); @@ -394,14 +301,6 @@ namespace gsc return {}; }); - function::add("say", [](const function_args& args) -> scripting::script_value - { - const auto message = args[0].as(); - game::SV_GameSendServerCommand(-1, 0, utils::string::va("%c \"%s\"", 84, message.data())); - - return {}; - }); - function::add("dropallbots", [](const function_args&) -> scripting::script_value { for (auto i = 0; i < *game::svs_clientCount; i++) @@ -416,45 +315,26 @@ namespace gsc return {}; }); - method::add("tell", [](const game::scr_entref_t ent, const function_args& args) -> scripting::script_value - { - if (ent.classnum != 0) - { - throw std::runtime_error("Invalid entity"); - } - - const auto client = ent.entnum; - - if (game::g_entities[client].client == nullptr) - { - throw std::runtime_error("Not a player entity"); - } - - const auto message = args[0].as(); - game::SV_GameSendServerCommand(client, 0, utils::string::va("%c \"%s\"", 84, message.data())); - - return {}; - }); - method::add("specialtymarathon", [](const game::scr_entref_t ent, const function_args& args) -> scripting::script_value { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } const auto client = ent.entnum; if (game::g_entities[client].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } const auto toggle = args[0].as(); auto flags = game::g_entities[client].client->ps.perks[0]; game::g_entities[client].client->ps.perks[0] = toggle - ? flags | 0x4000u : flags & ~0x4000u; + ? flags | 0x4000u + : flags & ~0x4000u; return {}; }); @@ -463,14 +343,14 @@ namespace gsc { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } const auto client = ent.entnum; if (game::g_entities[client].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } return game::svs_clients[client].bIsTestClient; @@ -480,25 +360,18 @@ namespace gsc { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } const auto client = ent.entnum; if (game::g_entities[client].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } return {(game::g_entities[client].client->flags & 4) != 0}; }); - - // let other plugins read the pointers - post_load_callbacks.push_back([]() - { - utils::hook::jump(0x56C8EB, call_builtin_stub); - utils::hook::jump(0x56CBDC, call_builtin_method_stub); - }); } }; } diff --git a/src/component/gsc.hpp b/src/component/gsc.hpp index 712e402..22e4e0b 100644 --- a/src/component/gsc.hpp +++ b/src/component/gsc.hpp @@ -36,14 +36,33 @@ namespace gsc using script_function = std::function; using script_method = std::function; + void* make_function_thunk(const char* name, const script_function* func); + void* make_method_thunk(const char* name, const script_method* meth); + namespace function { - void add(const std::string& name, const script_function& func); + template + void add(const std::string& name, F&& f) + { + const auto name_str = utils::memory::duplicate_string(name); + const auto func = new script_function(std::forward(f)); + const auto thunk = reinterpret_cast< + plutonium::sdk::interfaces::gsc::function_callback>(make_function_thunk(name_str, func)); + plugin::get()->get_interface()->gsc()->register_function(name, thunk); + } } namespace method { - void add(const std::string& name, const script_method& func); + template + void add(const std::string& name, F&& f) + { + const auto name_str = utils::memory::duplicate_string(name); + const auto func = new script_method(std::forward(f)); + const auto thunk = reinterpret_cast< + plutonium::sdk::interfaces::gsc::method_callback>(make_method_thunk(name_str, func)); + plugin::get()->get_interface()->gsc()->register_method(name, thunk); + } } namespace field diff --git a/src/component/io.cpp b/src/component/io.cpp index 66e3f0d..9136bae 100644 --- a/src/component/io.cpp +++ b/src/component/io.cpp @@ -10,79 +10,34 @@ namespace io class component final : public component_interface { public: - void post_unpack() override + void on_after_dvar_init([[maybe_unused]] plugin::plugin* plugin) override { - const auto path = game::Dvar_FindVar("fs_basegame")->current.string; - std::filesystem::current_path(path); + const auto fs_basegame = game::Dvar_FindVar("fs_basegame"); + if (fs_basegame == nullptr) + { + return; + } + printf("working directory: %s", fs_basegame->current.string); + std::filesystem::current_path(fs_basegame->current.string); + } + + void on_startup([[maybe_unused]] plugin::plugin* plugin) override + { gsc::function::add("jsonprint", [](const gsc::function_args& args) -> scripting::script_value { std::string buffer; - for (const auto arg : args.get_raw()) + for (const auto& arg : args.get_raw()) { buffer.append(json::gsc_to_string(arg)); buffer.append("\t"); } - printf("%s\n", buffer.data()); + printf("%s", buffer.data()); return {}; }); - gsc::function::add("fremove", [](const gsc::function_args& args) - { - const auto path = args[0].as(); - return std::remove(path); - }); - - gsc::function::add("fopen", [](const gsc::function_args& args) - { - const auto* path = args[0].as(); - const auto* mode = args[1].as(); - - const auto handle = fopen(path, mode); - - if (!handle) - { - printf("fopen: Invalid path\n"); - } - - return handle; - }); - - gsc::function::add("fclose", [](const gsc::function_args& args) - { - const auto handle = args[0].as_ptr(); - return fclose(handle); - }); - - gsc::function::add("fwrite", [](const gsc::function_args& args) - { - const auto handle = args[0].as_ptr(); - const auto text = args[1].as(); - - return fprintf(handle, text); - }); - - gsc::function::add("fread", [](const gsc::function_args& args) - { - const auto handle = args[0].as_ptr(); - - fseek(handle, 0, SEEK_END); - const auto length = ftell(handle); - - fseek(handle, 0, SEEK_SET); - char* buffer = (char*)calloc(length, sizeof(char)); - - fread(buffer, sizeof(char), length, handle); - - const std::string result = buffer; - - free(buffer); - - return result; - }); - gsc::function::add("fileexists", [](const gsc::function_args& args) { const auto path = args[0].as(); @@ -179,4 +134,4 @@ namespace io }; } -//REGISTER_COMPONENT(io::component) +REGISTER_COMPONENT(io::component) diff --git a/src/component/json.cpp b/src/component/json.cpp index 5b5fc84..eac4ddd 100644 --- a/src/component/json.cpp +++ b/src/component/json.cpp @@ -144,7 +144,7 @@ namespace json class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { gsc::function::add("array", [](const gsc::function_args& args) { @@ -194,4 +194,4 @@ namespace json }; } -//REGISTER_COMPONENT(json::component) +REGISTER_COMPONENT(json::component) diff --git a/src/component/notifies.cpp b/src/component/notifies.cpp deleted file mode 100644 index cdc6f73..0000000 --- a/src/component/notifies.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "scheduler.hpp" -#include "gsc.hpp" -#include "scripting.hpp" - -namespace notifies -{ - namespace - { - std::vector say_callbacks; - utils::hook::detour client_command_hook; - - void client_command_stub(int clientNum) - { - char cmd[1024] = {0}; - const auto* entity = &game::g_entities[clientNum]; - - if (entity->client == nullptr) - { - return; // Client is not fully in game yet - } - - game::SV_Cmd_ArgvBuffer(0, cmd, 1024); - - auto hidden = false; - if (cmd == "say"s || cmd == "say_team"s) - { - std::string message = game::ConcatArgs(1); - message.erase(0, 1); - - for (const auto& callback : say_callbacks) - { - const auto entity_id = game::Scr_GetEntityId(clientNum, 0); - const auto result = callback(entity_id, {message, cmd == "say_team"s}); - - if (result.is() && !hidden) - { - hidden = result.as() == 0; - } - } - } - - if (!hidden) - { - client_command_hook.invoke(clientNum); - } - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - client_command_hook.create(0x502CB0, client_command_stub); - - scripting::on_shutdown([]() - { - say_callbacks.clear(); - }); - - gsc::function::add("onplayersay", [](const gsc::function_args& args) -> scripting::script_value - { - const auto function = args[0].as(); - say_callbacks.push_back(function); - return {}; - }); - } - }; -} - -//REGISTER_COMPONENT(notifies::component) diff --git a/src/component/scheduler.cpp b/src/component/scheduler.cpp index 3a31878..8be9a1b 100644 --- a/src/component/scheduler.cpp +++ b/src/component/scheduler.cpp @@ -128,7 +128,7 @@ namespace scheduler class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { thread = std::thread([]() { @@ -144,4 +144,4 @@ namespace scheduler }; } -//REGISTER_COMPONENT(scheduler::component) +REGISTER_COMPONENT(scheduler::component) diff --git a/src/component/scripting.cpp b/src/component/scripting.cpp index 7b375b7..3e7d195 100644 --- a/src/component/scripting.cpp +++ b/src/component/scripting.cpp @@ -13,68 +13,12 @@ namespace scripting { - std::unordered_map> fields_table; - std::unordered_map> script_function_table; - namespace { - utils::hook::detour vm_notify_hook; - utils::hook::detour scr_add_class_field_hook; - - utils::hook::detour scr_load_level_hook; utils::hook::detour g_shutdown_game_hook; - utils::hook::detour scr_set_thread_position_hook; - utils::hook::detour process_script_hook; - - std::string current_file; - std::vector> shutdown_callbacks; - void vm_notify_stub(const unsigned int notify_list_owner_id, const unsigned int string_value, - game::VariableValue* top) - { - const auto* name = game::SL_ConvertToString(string_value); - - if (name) - { - event e; - e.name = name; - e.entity = notify_list_owner_id; - - for (auto* value = top; value->type != game::SCRIPT_END; --value) - { - e.arguments.emplace_back(*value); - } - - if (e.name == "connected") - { - const auto player = e.arguments[0].as(); - const auto client = player.call("getentitynumber").as(); - userinfo::clear_client_overrides(client); - } - } - - vm_notify_hook.invoke(notify_list_owner_id, string_value, top); - } - - void scr_add_class_field_stub(unsigned int classnum, unsigned int _name, unsigned int canonicalString, unsigned int offset) - { - const auto name = game::SL_ConvertToString(_name); - - if (fields_table[classnum].find(name) == fields_table[classnum].end()) - { - fields_table[classnum][name] = offset; - } - - scr_add_class_field_hook.invoke(classnum, _name, canonicalString, offset); - } - - void scr_load_level_stub() - { - scr_load_level_hook.invoke(); - } - void g_shutdown_game_stub(const int free_scripts) { userinfo::clear_overrides(); @@ -87,31 +31,6 @@ namespace scripting g_shutdown_game_hook.invoke(free_scripts); } - - void process_script_stub(const char* filename) - { - current_file = filename; - - const auto file_id = atoi(filename); - if (file_id) - { - current_file = scripting::find_file(file_id); - } - - process_script_hook.invoke(filename); - } - - void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) - { - const auto function_name = scripting::find_token(threadName); - - if (!function_name.empty()) - { - script_function_table[current_file][function_name] = codePos; - } - - scr_set_thread_position_hook.invoke(threadName, codePos); - } } void on_shutdown(const std::function& callback) @@ -122,18 +41,11 @@ namespace scripting class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { - scr_load_level_hook.create(0x527AF0, scr_load_level_stub); g_shutdown_game_hook.create(0x50C100, g_shutdown_game_stub); - - scr_add_class_field_hook.create(0x567CD0, scr_add_class_field_stub); - vm_notify_hook.create(0x569720, vm_notify_stub); - - scr_set_thread_position_hook.create(0x5616D0, scr_set_thread_position_stub); - process_script_hook.create(0x56B130, process_script_stub); } }; } -//REGISTER_COMPONENT(scripting::component) +REGISTER_COMPONENT(scripting::component) diff --git a/src/component/scripting.hpp b/src/component/scripting.hpp index 446d8ef..003b623 100644 --- a/src/component/scripting.hpp +++ b/src/component/scripting.hpp @@ -2,8 +2,5 @@ namespace scripting { - extern std::unordered_map> fields_table; - extern std::unordered_map> script_function_table; - void on_shutdown(const std::function& callback); } \ No newline at end of file diff --git a/src/component/signatures.cpp b/src/component/signatures.cpp deleted file mode 100644 index edc6292..0000000 --- a/src/component/signatures.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "signatures.hpp" -#include - -namespace signatures -{ - size_t load_image_size() - { - MODULEINFO info{}; - GetModuleInformation(GetCurrentProcess(), - GetModuleHandle("plutonium-bootstrapper-win32.exe"), &info, sizeof(MODULEINFO)); - return info.SizeOfImage; - } - - size_t get_image_size() - { - static const auto image_size = load_image_size(); - return image_size; - } - - void load_function_tables() - { - static const auto ptr = *reinterpret_cast(0x56CBDC + 0x1) + 0x56CBDC + 0x5; - static const auto function_table = *reinterpret_cast(0x56C8EB + 0x3); - static const auto method_table = *reinterpret_cast(ptr + 0xA); - - game::plutonium::function_table.set(function_table); - game::plutonium::method_table.set(method_table); - } - - size_t find_string_ptr(const std::string& string) - { - const char* string_ptr = nullptr; - std::string mask(string.size(), 'x'); - const auto base = reinterpret_cast(GetModuleHandle("plutonium-bootstrapper-win32.exe")); - utils::hook::signature signature(base, get_image_size() - base); - OutputDebugString(utils::string::va("%p %p\n", base, get_image_size())); - auto found = false; - signature.add({ - string, - mask, - [&](char* address) - { - if (found) - { - return; - } - - found = true; - string_ptr = address; - } - }); - - signature.process(); - return reinterpret_cast(string_ptr); - } - - size_t find_string_ref(const std::string& string) - { - char bytes[4] = {0}; - const auto string_ptr = find_string_ptr(string); - if (!string_ptr) - { - return 0; - } - - std::memcpy(bytes, &string_ptr, sizeof(bytes)); - return find_string_ptr({bytes, 4}); - } - - bool process_gsc_ctx() - { - OutputDebugString("HELLOOO"); - - const auto string_ref = find_string_ref("in call to builtin %s \"%s\""); - if (!string_ref) - { - return false; - } - - const auto gsc_ctx_ptr = *reinterpret_cast(string_ref + 215); - OutputDebugString(utils::string::va("gsc_ctx_ptr: %p\n", gsc_ctx_ptr)); - game::plutonium::gsc_ctx.set(gsc_ctx_ptr); - return true; - } - - bool process() - { - load_function_tables(); - return process_gsc_ctx(); - } -} diff --git a/src/component/signatures.hpp b/src/component/signatures.hpp deleted file mode 100644 index 046cf80..0000000 --- a/src/component/signatures.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace signatures -{ - bool process(); -} \ No newline at end of file diff --git a/src/component/string.cpp b/src/component/string.cpp index 27fbaf9..00fda69 100644 --- a/src/component/string.cpp +++ b/src/component/string.cpp @@ -10,13 +10,8 @@ namespace string class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { - gsc::function::add("toupper", [](const gsc::function_args& args) - { - return utils::string::to_upper(args[0].as()); - }); - gsc::function::add("getchar", [](const gsc::function_args& args) { auto index = 0; @@ -28,7 +23,7 @@ namespace string const auto string = args[0].as(); if (index >= static_cast(string.size())) { - throw std::runtime_error("Char index out of bounds"); + throw std::runtime_error("char index out of bounds"); } return static_cast(string[index]); @@ -43,4 +38,4 @@ namespace string }; } -//REGISTER_COMPONENT(string::component) +REGISTER_COMPONENT(string::component) diff --git a/src/component/userinfo.cpp b/src/component/userinfo.cpp index 66c1936..a209c9c 100644 --- a/src/component/userinfo.cpp +++ b/src/component/userinfo.cpp @@ -71,11 +71,11 @@ namespace userinfo const auto userinfo = map_to_userinfo(map); strcpy_s(buffer, 1024, userinfo.data()); } - } - void clear_client_overrides(int client) - { - userinfo_overrides[client].clear(); + void clear_client_overrides(unsigned int client) + { + userinfo_overrides[client].clear(); + } } void clear_overrides() @@ -86,20 +86,23 @@ namespace userinfo class component final : public component_interface { public: - void post_unpack() override + void on_startup([[maybe_unused]] plugin::plugin* plugin) override { sv_getuserinfo_hook.create(0x573E00, sv_getuserinfo_stub); + plugin->get_interface()->callbacks()->on_player_connect(clear_client_overrides); + plugin->get_interface()->callbacks()->on_player_disconnect(clear_client_overrides); + gsc::method::add("setname", [](const game::scr_entref_t ent, const gsc::function_args& args) -> scripting::script_value { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } if (game::g_entities[ent.entnum].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } const auto name = args[0].as(); @@ -114,12 +117,12 @@ namespace userinfo { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } if (game::g_entities[ent.entnum].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } userinfo_overrides[ent.entnum].erase("name"); @@ -132,12 +135,12 @@ namespace userinfo { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } if (game::g_entities[ent.entnum].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } const auto name = args[0].as(); @@ -154,12 +157,12 @@ namespace userinfo { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } if (game::g_entities[ent.entnum].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } userinfo_overrides[ent.entnum].erase("clantag"); @@ -174,12 +177,12 @@ namespace userinfo { if (ent.classnum != 0) { - throw std::runtime_error("Invalid entity"); + throw std::runtime_error("invalid entity"); } if (game::g_entities[ent.entnum].client == nullptr) { - throw std::runtime_error("Not a player entity"); + throw std::runtime_error("not a player entity"); } userinfo_overrides[ent.entnum]["clantag"] = ""; @@ -193,4 +196,4 @@ namespace userinfo }; } -//REGISTER_COMPONENT(userinfo::component) +REGISTER_COMPONENT(userinfo::component) diff --git a/src/dllmain.cpp b/src/dllmain.cpp index d853866..baf1fd5 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -8,17 +8,17 @@ PLUTONIUM_API plutonium::sdk::plugin* PLUTONIUM_CALLBACK on_initialize() return plugin::get(); } -BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) +BOOL APIENTRY DllMain(HMODULE /*module*/, DWORD reason, LPVOID /*reserved*/) { - if (ul_reason_for_call == DLL_PROCESS_ATTACH) + if (reason == DLL_PROCESS_ATTACH) { } - if (ul_reason_for_call == DLL_PROCESS_DETACH) + if (reason == DLL_PROCESS_DETACH) { - component_loader::pre_destroy(); + component_loader::on_shutdown(); } return TRUE; -} \ No newline at end of file +} diff --git a/src/game/scripting/entity.cpp b/src/game/scripting/entity.cpp index 6ded7df..f55ca38 100644 --- a/src/game/scripting/entity.cpp +++ b/src/game/scripting/entity.cpp @@ -96,20 +96,4 @@ namespace scripting game::RemoveRefToValue(game::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); } } - - void entity::set(const std::string& field, const script_value& value) const - { - set_entity_field(*this, field, value); - } - - template <> - script_value entity::get(const std::string& field) const - { - return get_entity_field(*this, field); - } - - script_value entity::call(const std::string& name, const std::vector& arguments) const - { - return call_function(name, *this, arguments); - } } diff --git a/src/game/scripting/entity.hpp b/src/game/scripting/entity.hpp index 76fd66c..7a53238 100644 --- a/src/game/scripting/entity.hpp +++ b/src/game/scripting/entity.hpp @@ -18,13 +18,6 @@ namespace scripting entity& operator=(const entity& other); entity& operator=(entity&& other) noexcept; - void set(const std::string& field, const script_value& value) const; - - template - T get(const std::string& field) const; - - script_value call(const std::string& name, const std::vector& arguments = {}) const; - unsigned int get_entity_id() const; game::scr_entref_t get_entity_reference() const; @@ -37,13 +30,4 @@ namespace scripting void add() const; void release() const; }; - - template <> - script_value entity::get(const std::string& field) const; - - template - T entity::get(const std::string& field) const - { - return this->get(field).as(); - } } diff --git a/src/game/scripting/execution.cpp b/src/game/scripting/execution.cpp index 9e1769f..e89c17e 100644 --- a/src/game/scripting/execution.cpp +++ b/src/game/scripting/execution.cpp @@ -32,16 +32,6 @@ namespace scripting return script_value(game::scr_VmPub->top[1 - game::scr_VmPub->outparamcount]); } - int get_field_id(const int classnum, const std::string& field) - { - if (scripting::fields_table[classnum].find(field) != scripting::fields_table[classnum].end()) - { - return scripting::fields_table[classnum][field]; - } - - return -1; - } - void scr_notify_id(int id, unsigned int stringValue, unsigned int paramcount) { if (game::scr_VmPub->outparamcount) @@ -95,47 +85,6 @@ namespace scripting scr_notify_id(entity.get_entity_id(), event_id, game::scr_VmPub->inparamcount); } - script_value call_function(const std::string& name, const entity& entity, - const std::vector& arguments) - { - const auto entref = entity.get_entity_reference(); - - const auto is_method_call = *reinterpret_cast(&entref) != -1; - const auto function = find_function(name, !is_method_call); - if (!function) - { - throw std::runtime_error("Unknown function '" + name + "'"); - } - - stack_isolation _; - - for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) - { - push_value(*i); - } - - game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; - game::scr_VmPub->inparamcount = 0; - - if (!safe_execution::call(function, entref)) - { - throw std::runtime_error("Error executing function '" + name + "'"); - } - - return get_return_value(); - } - - script_value call_function(const std::string& name, const std::vector& arguments) - { - return call_function(name, entity(), arguments); - } - - template <> - script_value call(const std::string& name, const std::vector& arguments) - { - return call_function(name, arguments); - } - script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector& arguments) { const auto id = entity.get_entity_id(); @@ -155,122 +104,6 @@ namespace scripting return get_return_value(); } - const char* get_function_pos(const std::string& filename, const std::string& function) - { - if (scripting::script_function_table.find(filename) == scripting::script_function_table.end()) - { - throw std::runtime_error("File '" + filename + "' not found"); - }; - - const auto functions = scripting::script_function_table[filename]; - if (functions.find(function) == functions.end()) - { - throw std::runtime_error("Function '" + function + "' in file '" + filename + "' not found"); - } - - return functions.at(function); - } - - script_value call_script_function(const entity& entity, const std::string& filename, - const std::string& function, const std::vector& arguments) - { - const auto pos = get_function_pos(filename, function); - return exec_ent_thread(entity, pos, arguments); - } - - static std::unordered_map> custom_fields; - - script_value get_custom_field(const entity& entity, const std::string& field) - { - auto fields = custom_fields[entity.get_entity_id()]; - const auto _field = fields.find(field); - if (_field != fields.end()) - { - return _field->second; - } - return {}; - } - - void set_custom_field(const entity& entity, const std::string& field, const script_value& value) - { - const auto id = entity.get_entity_id(); - - if (custom_fields[id].find(field) != custom_fields[id].end()) - { - custom_fields[id][field] = value; - return; - } - - custom_fields[id].insert(std::make_pair(field, value)); - } - - void clear_entity_fields(const entity& entity) - { - const auto id = entity.get_entity_id(); - - if (custom_fields.find(id) != custom_fields.end()) - { - custom_fields[id].clear(); - } - } - - void clear_custom_fields() - { - custom_fields.clear(); - } - - void set_entity_field(const entity& entity, const std::string& field, const script_value& value) - { - const auto entref = entity.get_entity_reference(); - const int id = get_field_id(entref.classnum, field); - - if (id != -1) - { - stack_isolation _; - push_value(value); - - game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount; - game::scr_VmPub->inparamcount = 0; - - if (!safe_execution::set_entity_field(entref, id)) - { - throw std::runtime_error("Failed to set value for field '" + field + "'"); - } - } - else - { - set_custom_field(entity, field, value); - } - } - - script_value get_entity_field(const entity& entity, const std::string& field) - { - const auto entref = entity.get_entity_reference(); - const auto id = get_field_id(entref.classnum, field); - - if (id != -1) - { - stack_isolation _; - - game::VariableValue value{}; - if (!safe_execution::get_entity_field(entref, id, &value)) - { - throw std::runtime_error("Failed to get value for field '" + field + "'"); - } - - const auto __ = gsl::finally([value]() - { - game::RemoveRefToValue(value.type, value.u); - }); - - return value; - } - else - { - return get_custom_field(entity, field); - } - } - unsigned int make_array() { unsigned int index = 0; diff --git a/src/game/scripting/execution.hpp b/src/game/scripting/execution.hpp index c2c6a42..14c6cf6 100644 --- a/src/game/scripting/execution.hpp +++ b/src/game/scripting/execution.hpp @@ -9,10 +9,6 @@ namespace scripting { void push_value(const script_value& value); - script_value call_function(const std::string& name, const std::vector& arguments); - script_value call_function(const std::string& name, const entity& entity, - const std::vector& arguments); - template T call(const std::string& name, const std::vector& arguments = {}); @@ -26,14 +22,6 @@ namespace scripting } script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector& arguments); - script_value call_script_function(const entity& entity, const std::string& filename, - const std::string& function, const std::vector& arguments); - - void clear_entity_fields(const entity& entity); - void clear_custom_fields(); - - void set_entity_field(const entity& entity, const std::string& field, const script_value& value); - script_value get_entity_field(const entity& entity, const std::string& field); void notify(const entity& entity, const std::string& event, const std::vector& arguments); diff --git a/src/game/scripting/functions.cpp b/src/game/scripting/functions.cpp index fc23899..3d88a8e 100644 --- a/src/game/scripting/functions.cpp +++ b/src/game/scripting/functions.cpp @@ -5,64 +5,5 @@ namespace scripting { - namespace - { - int find_function_index(const std::string& name, [[maybe_unused]] const bool prefer_global) - { - const auto target = utils::string::to_lower(name); - auto const& first = (*game::plutonium::gsc_ctx)->func_map(); - auto const& second = (*game::plutonium::gsc_ctx)->meth_map(); - if (const auto itr = first.find(name); itr != first.end()) - { - return static_cast(itr->second); - } - - if (const auto itr = second.find(name); itr != second.end()) - { - return static_cast(itr->second); - } - - return -1; - } - - script_function get_function_by_index(const unsigned index) - { - static const auto function_table = game::plutonium::function_table.get(); - static const auto method_table = game::plutonium::method_table.get(); - - if (index < 0x1C7) - { - return reinterpret_cast(function_table)[index]; - } - - return reinterpret_cast(method_table)[index - 0x8000]; - } - } - - std::string find_token(unsigned int id) - { - return (*game::plutonium::gsc_ctx)->token_name(id); - } - - std::string find_file(unsigned int id) - { - return find_token(id); - } - - int find_token_id(const std::string& name) - { - return (*game::plutonium::gsc_ctx)->token_id(name); - } - - script_function find_function(const std::string& name, const bool prefer_global) - { - const auto index = find_function_index(name, prefer_global); - if (index < 0) - { - return nullptr; - } - - return get_function_by_index(index); - } } diff --git a/src/game/scripting/functions.hpp b/src/game/scripting/functions.hpp index d6fd8ff..8fbb0fd 100644 --- a/src/game/scripting/functions.hpp +++ b/src/game/scripting/functions.hpp @@ -4,9 +4,4 @@ namespace scripting { using script_function = void(*)(game::scr_entref_t); - - script_function find_function(const std::string& name, const bool prefer_global); - int find_token_id(const std::string& name); - std::string find_token(unsigned int id); - std::string find_file(unsigned int id); } diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 8d8ddd7..a47fbb9 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -83,11 +83,4 @@ namespace game WEAK symbol sv_maxclients{0x1BA0E4C}; WEAK symbol svs_clientCount{0x4B5CF8C}; WEAK symbol svs_clients{0x4B5CF90}; - - namespace plutonium - { - WEAK symbol> gsc_ctx{0}; - WEAK symbol function_table{0}; - WEAK symbol method_table{0}; - } } diff --git a/src/loader/component_interface.hpp b/src/loader/component_interface.hpp index e1ee433..2f5b7c6 100644 --- a/src/loader/component_interface.hpp +++ b/src/loader/component_interface.hpp @@ -1,4 +1,5 @@ #pragma once +#include "../plugin.hpp" class component_interface { @@ -7,25 +8,24 @@ public: { } - virtual void post_start() + virtual void on_startup([[maybe_unused]] plugin::plugin* plugin) { } - virtual void post_load() + virtual void on_dvar_init([[maybe_unused]] plugin::plugin* plugin) { } - virtual void pre_destroy() + virtual void on_after_dvar_init([[maybe_unused]] plugin::plugin* plugin) { } - virtual void post_unpack() + virtual void on_game_init([[maybe_unused]] plugin::plugin* plugin) { } - virtual void* load_import([[maybe_unused]] const std::string& library, [[maybe_unused]] const std::string& function) + virtual void on_shutdown([[maybe_unused]] plugin::plugin* plugin) { - return nullptr; } virtual bool is_supported() diff --git a/src/loader/component_loader.cpp b/src/loader/component_loader.cpp index d6a0090..ad4f5b9 100644 --- a/src/loader/component_loader.cpp +++ b/src/loader/component_loader.cpp @@ -1,87 +1,48 @@ #include #include "component_loader.hpp" -void component_loader::register_component(std::unique_ptr&& component_) +void component_loader::register_component(const std::string& name, std::unique_ptr&& component_) { - get_components().push_back(std::move(component_)); + get_components().push_back(std::make_pair(name, std::move(component_))); } -bool component_loader::post_start() -{ - static auto handled = false; - if (handled) return true; - handled = true; +#define ON_CALLBACK(__name__) \ + void component_loader::__name__() \ + { \ + static auto handled = false; \ + if (handled) \ + { \ + return; \ + } \ + \ + handled = true; \ + \ + for (const auto& component_ : get_components()) \ + { \ + try \ + { \ + component_.second->__name__(plugin::get()); \ + } \ + catch (const std::exception& e) \ + { \ + printf("error executing component \"%s\" callback \"%s\": %s\n", component_.first.data(), #__name__, e.what()); \ + } \ + } \ + } \ - try - { - for (const auto& component_ : get_components()) - { - component_->post_start(); - } - } - catch (premature_shutdown_trigger&) - { - return false; - } - - return true; -} - -bool component_loader::post_load() -{ - static auto handled = false; - if (handled) return true; - handled = true; - - clean(); - - try - { - for (const auto& component_ : get_components()) - { - component_->post_load(); - } - } - catch (premature_shutdown_trigger&) - { - return false; - } - - return true; -} - -void component_loader::post_unpack() -{ - static auto handled = false; - if (handled) return; - handled = true; - - for (const auto& component_ : get_components()) - { - component_->post_unpack(); - } -} - -void component_loader::pre_destroy() -{ - static auto handled = false; - if (handled) return; - handled = true; - - for (const auto& component_ : get_components()) - { - component_->pre_destroy(); - } -} +ON_CALLBACK(on_startup); +ON_CALLBACK(on_dvar_init); +ON_CALLBACK(on_after_dvar_init); +ON_CALLBACK(on_shutdown); void component_loader::clean() { auto& components = get_components(); for (auto i = components.begin(); i != components.end();) { - if (!(*i)->is_supported()) + if (!(*i).second->is_supported()) { - (*i)->pre_destroy(); + (*i).second->on_shutdown(plugin::get()); i = components.erase(i); } else @@ -91,35 +52,19 @@ void component_loader::clean() } } -void* component_loader::load_import(const std::string& library, const std::string& function) -{ - void* function_ptr = nullptr; - - for (const auto& component_ : get_components()) - { - auto* const component_function_ptr = component_->load_import(library, function); - if (component_function_ptr) - { - function_ptr = component_function_ptr; - } - } - - return function_ptr; -} - void component_loader::trigger_premature_shutdown() { throw premature_shutdown_trigger(); } -std::vector>& component_loader::get_components() +std::vector>>& component_loader::get_components() { - using component_vector = std::vector>; + using component_vector = std::vector>>; using component_vector_container = std::unique_ptr>; static component_vector_container components(new component_vector, [](component_vector* component_vector) { - pre_destroy(); + on_shutdown(); delete component_vector; }); diff --git a/src/loader/component_loader.hpp b/src/loader/component_loader.hpp index 1f6b4d1..6d6f73f 100644 --- a/src/loader/component_loader.hpp +++ b/src/loader/component_loader.hpp @@ -18,9 +18,9 @@ public: static_assert(std::is_base_of::value, "component has invalid base class"); public: - installer() + installer(const std::string& name) { - register_component(std::make_unique()); + register_component(name, std::make_unique()); } }; @@ -38,12 +38,12 @@ public: return nullptr; } - static void register_component(std::unique_ptr&& component); + static void register_component(const std::string& name, std::unique_ptr&& component); - static bool post_start(); - static bool post_load(); - static void post_unpack(); - static void pre_destroy(); + static void on_startup(); + static void on_dvar_init(); + static void on_after_dvar_init(); + static void on_shutdown(); static void clean(); static void* load_import(const std::string& library, const std::string& function); @@ -51,11 +51,11 @@ public: static void trigger_premature_shutdown(); private: - static std::vector>& get_components(); + static std::vector>>& get_components(); }; -#define REGISTER_COMPONENT(name) \ +#define REGISTER_COMPONENT(name) \ namespace \ { \ - static component_loader::installer __component; \ + static component_loader::installer __component(#name); \ } diff --git a/src/plugin.cpp b/src/plugin.cpp index b45fb1a..e774f6c 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -3,8 +3,6 @@ #include "plugin.hpp" -#include "component/signatures.hpp" - #include #include @@ -37,7 +35,7 @@ namespace plugin return "iw5-gsc-utils"; } - bool plugin::is_game_supported([[maybe_unused]] plutonium::sdk::game game) + bool plugin::is_game_supported([[maybe_unused]] plutonium::sdk::game game) { return game == plutonium::sdk::game::iw5; } @@ -47,23 +45,15 @@ namespace plugin this->interface_ = interface_ptr; this->game_ = game; utils::hook::jump(reinterpret_cast(&printf), printf_stub); + component_loader::on_startup(); - if (!signatures::process()) - { - MessageBoxA(NULL, - "This version of iw5-gsc-utils is outdated.\n" \ - "Download the latest dll from here: https://github.com/alicealys/iw5-gsc-utils/releases", - "ERROR", MB_ICONERROR); - } - else - { - component_loader::post_unpack(); - } + interface_ptr->callbacks()->on_dvar_init(component_loader::on_dvar_init); + interface_ptr->callbacks()->on_after_dvar_init(component_loader::on_after_dvar_init); } void plugin::on_shutdown() { - component_loader::pre_destroy(); + component_loader::on_shutdown(); } plutonium::sdk::iinterface* plugin::get_interface() diff --git a/src/stdinc.hpp b/src/stdinc.hpp index 9ce4fd7..0c40cb8 100644 --- a/src/stdinc.hpp +++ b/src/stdinc.hpp @@ -43,7 +43,6 @@ using namespace std::literals; #include "utils/memory.hpp" #include "utils/string.hpp" #include "utils/hook.hpp" -#include "utils/concurrent_list.hpp" #include "utils/io.hpp" #include "utils/concurrency.hpp" #include "utils/http.hpp" diff --git a/src/utils/concurrent_list.hpp b/src/utils/concurrent_list.hpp deleted file mode 100644 index 1014e7f..0000000 --- a/src/utils/concurrent_list.hpp +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once - -#include -#include - -// This class is trash. Need to get rid of it. - -namespace utils -{ - template - class concurrent_list final - { - public: - class element final - { - public: - explicit element(std::recursive_mutex* mutex, std::shared_ptr entry = {}, - std::shared_ptr next = {}) : - mutex_(mutex), - entry_(std::move(entry)), - next_(std::move(next)) - { - } - - void remove(const std::shared_ptr& element) - { - std::lock_guard _(*this->mutex_); - if (!this->next_) return; - - if (this->next_->entry_.get() == element.get()) - { - this->next_ = this->next_->next_; - } - else - { - this->next_->remove(element); - } - } - - [[nodiscard]] std::shared_ptr get_next() const - { - std::lock_guard _(*this->mutex_); - return this->next_; - } - - std::shared_ptr operator*() const - { - std::lock_guard _(*this->mutex_); - return this->entry_; - } - - element& operator++() - { - std::lock_guard _(*this->mutex_); - *this = this->next_ ? *this->next_ : element(this->mutex_); - return *this; - } - - element operator++(int) - { - std::lock_guard _(*this->mutex_); - auto result = *this; - this->operator++(); - return result; - } - - bool operator==(const element& other) - { - std::lock_guard _(*this->mutex_); - return this->entry_.get() == other.entry_.get(); - } - - bool operator!=(const element& other) - { - std::lock_guard _(*this->mutex_); - return !(*this == other); - } - - private: - std::recursive_mutex* mutex_; - std::shared_ptr entry_; - std::shared_ptr next_; - }; - - element begin() - { - std::lock_guard _(this->mutex_); - return this->entry_ ? *this->entry_ : this->end(); - } - - element end() - { - std::lock_guard _(this->mutex_); - return element(&this->mutex_); - } - - void remove(const element& entry) - { - std::lock_guard _(this->mutex_); - this->remove(*entry); - } - - void remove(const std::shared_ptr& element) - { - std::lock_guard _(this->mutex_); - if (!this->entry_) return; - - if ((**this->entry_).get() == element.get()) - { - this->entry_ = this->entry_->get_next(); - } - else - { - this->entry_->remove(element); - } - } - - void add(const T& object) - { - std::lock_guard _(this->mutex_); - - const auto object_ptr = std::make_shared(object); - this->entry_ = std::make_shared(&this->mutex_, object_ptr, this->entry_); - } - - void add(T&& object) - { - std::lock_guard _(this->mutex_); - - const auto object_ptr = std::make_shared(std::move(object)); - this->entry_ = std::make_shared(&this->mutex_, object_ptr, this->entry_); - } - - void clear() - { - std::lock_guard _(this->mutex_); - this->entry_ = {}; - } - - private: - std::recursive_mutex mutex_; - std::shared_ptr entry_; - }; -} \ No newline at end of file diff --git a/src/utils/hook.cpp b/src/utils/hook.cpp index 8dc578c..f4b4366 100644 --- a/src/utils/hook.cpp +++ b/src/utils/hook.cpp @@ -4,48 +4,6 @@ namespace utils::hook { - // open-iw5 - - void signature::process() - { - if (this->signatures_.empty()) return; - - const auto start = static_cast(this->start_); - - const unsigned int sig_count = this->signatures_.size(); - const auto containers = this->signatures_.data(); - - for (size_t i = 0; i < this->length_; ++i) - { - const auto address = start + i; - - for (unsigned int k = 0; k < sig_count; ++k) - { - const auto container = &containers[k]; - - unsigned int j; - for (j = 0; j < static_cast(container->mask.size()); ++j) - { - if (container->mask[j] != '?' && container->signature[j] != address[j]) - { - break; - } - } - - if (j == container->mask.size()) - { - container->callback(address); - } - } - } - } - - void signature::add(const container& container) - { - signatures_.push_back(container); - } - - namespace { [[maybe_unused]] class _ @@ -219,4 +177,17 @@ namespace utils::hook delete[] bytes; } + + DWORD unprotect(void* place, const size_t size) + { + DWORD old_protect{}; + VirtualProtect(place, size, PAGE_EXECUTE_READWRITE, &old_protect); + return old_protect; + } + + void protect(void* place, const size_t size, DWORD old_protect) + { + VirtualProtect(place, size, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, size); + } } \ No newline at end of file diff --git a/src/utils/hook.hpp b/src/utils/hook.hpp index 6430134..1ca94ab 100644 --- a/src/utils/hook.hpp +++ b/src/utils/hook.hpp @@ -4,37 +4,6 @@ namespace utils::hook { - class signature final - { - public: - struct container final - { - std::string signature; - std::string mask; - std::function callback; - }; - - signature(void* start, const size_t length) : start_(start), length_(length) - { - } - - signature(const DWORD start, const size_t length) : signature(reinterpret_cast(start), length) - { - } - - signature() : signature(0x400000, 0x800000) - { - } - - void process(); - void add(const container& container); - - private: - void* start_; - size_t length_; - std::vector signatures_; - }; - class detour { public: @@ -144,4 +113,7 @@ namespace utils::hook { return static_cast(func)(args...); } + + DWORD unprotect(void* place, const size_t size); + void protect(void* place, const size_t size, DWORD old_protect); } \ No newline at end of file