#include #include "loader/component_loader.hpp" #include "command.hpp" #include #include #include #include namespace command { namespace { std::unordered_map& get_command_map() { static std::unordered_map command_map{}; return command_map; } void execute_custom_command() { const params params{}; const auto command = utils::string::to_lower(params[0]); auto& map = get_command_map(); const auto entry = map.find(command); if (entry != map.end()) { entry->second(params); } } game::CmdArgs* get_cmd_args() { return game::Sys_GetTLS()->cmdArgs; } void update_whitelist_stub() { game::cmd_function_s* current_function = game::cmd_functions; while (current_function) { current_function->autoComplete = 1; current_function = current_function->next; } } } struct component final : generic_component { void post_unpack() override { // Disable whitelist utils::hook::jump(game::select(0x1420EF190, 0x1404F9CD0), update_whitelist_stub); } }; params::params() : nesting_(get_cmd_args()->nesting) { assert(this->nesting_ < game::CMD_MAX_NESTING); } int params::size() const { return get_cmd_args()->argc[this->nesting_]; } const char* params::get(const int index) const { if (index >= this->size()) { return ""; } return get_cmd_args()->argv[this->nesting_][index]; } std::string params::join(const int index) const { std::string result = {}; for (auto i = index; i < this->size(); i++) { if (i > index) result.append(" "); result.append(this->get(i)); } return result; } void add(const std::string& command, command_function function) { add(command, [f = std::move(function)](const params&) { f(); }); } void add(const std::string& command, command_param_function function) { auto lower_command = utils::string::to_lower(command); auto& map = get_command_map(); const auto is_registered = map.contains(lower_command); map[std::move(lower_command)] = std::move(function); if (is_registered) { return; } auto& allocator = *utils::memory::get_allocator(); auto* cmd_function = allocator.allocate(); const auto* cmd_string = allocator.duplicate_string(command); game::Cmd_AddCommandInternal(cmd_string, execute_custom_command, cmd_function); cmd_function->autoComplete = 1; } } REGISTER_COMPONENT(command::component)