#include #include "loader/component_loader.hpp" #include "game/game.hpp" #include #include "game/scripting/entity.hpp" #include "game/scripting/functions.hpp" #include "game/scripting/event.hpp" #include "game/scripting/lua/engine.hpp" #include "game/scripting/execution.hpp" #include "scheduler.hpp" #include "scripting.hpp" namespace scripting { std::unordered_map> script_function_table; namespace { utils::hook::detour vm_notify_hook; utils::hook::detour scr_load_level_hook; utils::hook::detour g_shutdown_game_hook; utils::hook::detour scr_set_thread_position_hook; utils::hook::detour process_script_hook; std::string current_file; void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, game::VariableValue* top) { if (!game::VirtualLobby_Loaded()) { const auto* string = game::SL_ConvertToString(string_value); if (string) { event e; e.name = string; e.entity = notify_list_owner_id; for (auto* value = top; value->type != game::SCRIPT_END; --value) { e.arguments.emplace_back(*value); } if (e.name == "connected") { scripting::clear_entity_fields(e.entity); } lua::engine::notify(e); } } vm_notify_hook.invoke(notify_list_owner_id, string_value, top); } void scr_load_level_stub() { scr_load_level_hook.invoke(); if (!game::VirtualLobby_Loaded()) { lua::engine::start(); } } void g_shutdown_game_stub(const int free_scripts) { lua::engine::stop(); return g_shutdown_game_hook.invoke(free_scripts); } void process_script_stub(const char* filename) { const auto file_id = atoi(filename); if (file_id) { current_file = scripting::find_token(file_id); } else { current_file = filename; } process_script_hook.invoke(filename); } void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) { const auto function_name = scripting::find_token(threadName); script_function_table[current_file][function_name] = codePos; scr_set_thread_position_hook.invoke(threadName, codePos); } } class component final : public component_interface { public: void post_unpack() override { vm_notify_hook.create(SELECT_VALUE(0x140320E50, 0x1404479F0 ), vm_notify_stub); // H1MP // SP address is wrong, but should be ok scr_load_level_hook.create(SELECT_VALUE(0x140005260, 0x1403727C0), scr_load_level_stub); // H1MP g_shutdown_game_hook.create(SELECT_VALUE(0x140228BA0, 0x140345A60), g_shutdown_game_stub); // H1MP scr_set_thread_position_hook.create(SELECT_VALUE(0x1403115E0, 0x140437D10), scr_set_thread_position_stub); // H1MP process_script_hook.create(SELECT_VALUE(0x14031AB30, 0x1404417E0), process_script_stub); // H1MP scheduler::loop([]() { lua::engine::run_frame(); }, scheduler::pipeline::server); } }; } REGISTER_COMPONENT(scripting::component)