diff --git a/src/component/command.cpp b/src/component/command.cpp index c01196f..0655f8d 100644 --- a/src/component/command.cpp +++ b/src/component/command.cpp @@ -9,14 +9,19 @@ #include #include +#include namespace command { std::unordered_map> handlers; + std::unordered_map> handlers_sv; std::vector script_commands; + std::vector script_sv_commands; utils::memory::allocator allocator; + utils::hook::detour client_command_hook; + game::CmdArgs* get_cmd_args() { return reinterpret_cast(game::Sys_GetValue(4)); @@ -34,6 +39,19 @@ namespace command } } + void client_command_stub(const int client_num) + { + params_sv params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (handlers_sv.find(command) != handlers_sv.end()) + { + handlers_sv[command](client_num, params); + } + + client_command_hook.invoke(client_num); + } + params::params() : nesting_(get_cmd_args()->nesting) { @@ -73,6 +91,43 @@ namespace command return result; } + params_sv::params_sv() + : nesting_(game::sv_cmd_args->nesting) + { + } + + int params_sv::size() const + { + return game::sv_cmd_args->argc[this->nesting_]; + } + + const char* params_sv::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::sv_cmd_args->argv[this->nesting_][index]; + } + + std::string params_sv::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) + { + result.append(" "); + } + + result.append(this->get(i)); + } + + return result; + } + void add_raw(const char* name, void (*callback)()) { game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate()); @@ -90,6 +145,15 @@ namespace command handlers[command] = callback; } + void add_sv(const std::string& name, std::function callback) + { + const auto command = utils::string::to_lower(name); + if (handlers_sv.find(command) == handlers_sv.end()) + { + handlers_sv[command] = std::move(callback); + } + } + void add_script_command(const std::string& name, const std::function& callback) { script_commands.push_back(name); @@ -97,6 +161,12 @@ namespace command add(name_, callback); } + void add_script_sv_command(const std::string& name, const std::function& callback) + { + script_sv_commands.push_back(name); + add_sv(name, callback); + } + void clear_script_commands() { for (const auto& name : script_commands) @@ -105,8 +175,14 @@ namespace command game::Cmd_RemoveCommand(name.data()); } + for (const auto& name : script_sv_commands) + { + handlers_sv.erase(name); + } + allocator.clear(); script_commands.clear(); + script_sv_commands.clear(); } void execute(std::string command, const bool sync) @@ -129,33 +205,13 @@ namespace command void post_unpack() override { scripting::on_shutdown(clear_script_commands); - - const auto execute_command = [](const std::string& command) - { - execute(command, false); - }; - - const auto add_command = [](const std::string& name, const scripting::function& function) - { - command::add_script_command(name, [function](const command::params& params) - { - scripting::array array; - - for (auto i = 0; i < params.size(); i++) - { - array.push(params[i]); - } - - function({array}); - }); - }; + client_command_hook.create(SELECT_VALUE(0x4AF770, 0x63DB70), client_command_stub); gsc::function::add_multiple([](const std::string& command) { execute(command, false); }, "executecommand", "command::execute"); - gsc::function::add_multiple([](const std::string& name, const scripting::function& function) { command::add_script_command(name, [function](const command::params& params) @@ -170,6 +226,23 @@ namespace command function({array}); }); }, "addcommand", "command::add"); + + gsc::function::add_multiple([](const std::string& name, const scripting::function& function) + { + command::add_script_sv_command(name, [function](const int client_num, const command::params_sv& params) + { + const scripting::entity player = game::Scr_GetEntityId(game::SCRIPTINSTANCE_SERVER, client_num, 0, 0); + + scripting::array array; + + for (auto i = 0; i < params.size(); i++) + { + array.push(params[i]); + } + + function(player, {array}); + }); + }, "addclientcommand", "command::add_sv"); } }; } diff --git a/src/component/command.hpp b/src/component/command.hpp index 62e8323..dbfaa51 100644 --- a/src/component/command.hpp +++ b/src/component/command.hpp @@ -20,10 +20,30 @@ namespace command int nesting_; }; + class params_sv + { + public: + params_sv(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); + } + + private: + int nesting_; + }; + void add_raw(const char* name, void (*callback)()); void add(const char* name, std::function callback); + void add_sv(const std::string& name, std::function callback); void add_script_command(const std::string& name, const std::function& callback); + void add_script_sv_command(const std::string& name, const std::function& callback); void clear_script_commands(); void execute(std::string command, const bool sync = false); diff --git a/src/component/scripting.cpp b/src/component/scripting.cpp index ea97eb5..c9d8a41 100644 --- a/src/component/scripting.cpp +++ b/src/component/scripting.cpp @@ -49,9 +49,9 @@ namespace scripting public: void post_unpack() override { - //g_shutdown_game_hook.create(SELECT(0x60DCF0, 0x688A40), g_shutdown_game_stub); + g_shutdown_game_hook.create(SELECT_VALUE(0x607700, 0x540950), g_shutdown_game_stub); } }; } -//REGISTER_COMPONENT(scripting::component) +REGISTER_COMPONENT(scripting::component) diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 638e4b9..cd0e47a 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -128,4 +128,6 @@ namespace game WEAK symbol levelEntityId{0x32C86A0, 0x3DCB2A0}; WEAK symbol svs_clients{0x0, 0x0}; + + WEAK symbol sv_cmd_args{0x243D208, 0x355BD88}; }