#include "STDInclude.hpp" namespace Components { Utils::Memory::Allocator Command::MemAllocator; std::map> Command::FunctionMap; std::map> Command::FunctionMapSV; char* Command::Params::operator[](size_t index) { if (index >= this->Length()) return ""; if (this->IsSV) return Game::cmd_argv_sv[this->CommandId][index]; else return Game::cmd_argv[this->CommandId][index]; } size_t Command::Params::Length() { if (this->IsSV) return Game::cmd_argc_sv[this->CommandId]; else return Game::cmd_argc[this->CommandId]; } std::string Command::Params::Join(size_t startIndex) { std::string result; for (size_t i = startIndex; i < this->Length(); ++i) { if (i > startIndex) result.append(" "); result.append(this->operator[](i)); } return result; } void Command::Add(const char* name, Command::Callback* callback) { std::string command = Utils::String::ToLower(name); if (Command::FunctionMap.find(command) == Command::FunctionMap.end()) { Command::AddRaw(name, Command::MainCallback); } Command::FunctionMap[command] = callback; } void Command::AddSV(const char* name, Command::Callback* callback) { if (Loader::IsPregame()) { MessageBoxA(0, "Registering server commands in pregamestate is illegal!", 0, MB_ICONERROR); #ifdef DEBUG __debugbreak(); #endif return; } std::string command = Utils::String::ToLower(name); if (Command::FunctionMapSV.find(command) == Command::FunctionMapSV.end()) { Command::AddRawSV(name, Command::MainCallbackSV); // If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler Command::AddRaw(name, Game::Cbuf_AddServerText); } Command::FunctionMapSV[command] = callback; } void Command::AddRaw(const char* name, void(*callback)(), bool key) { Game::Cmd_AddCommand(name, callback, Command::Allocate(), key); } void Command::AddRawSV(const char* name, void(*callback)()) { Game::Cmd_AddServerCommand(name, callback, Command::Allocate()); // If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler Command::AddRaw(name, Game::Cbuf_AddServerText); } void Command::Execute(std::string command, bool sync) { command.append("\n"); // Make sure it's terminated if (sync) { Game::Cmd_ExecuteSingleCommand(0, 0, command.data()); } else { Game::Cbuf_AddText(0, command.data()); } } Game::cmd_function_t* Command::Find(std::string command) { Game::cmd_function_t* cmdFunction = *Game::cmd_functions; while (cmdFunction) { if (cmdFunction->name && cmdFunction->name == command) { return cmdFunction; } cmdFunction = cmdFunction->next; } return nullptr; } Game::cmd_function_t* Command::Allocate() { return Command::MemAllocator.Allocate(); } void Command::MainCallback() { Command::Params params(false, *Game::cmd_id); std::string command = Utils::String::ToLower(params[0]); if (Command::FunctionMap.find(command) != Command::FunctionMap.end()) { Command::FunctionMap[command](params); } } void Command::MainCallbackSV() { Command::Params params(true, *Game::cmd_id_sv); std::string command = Utils::String::ToLower(params[0]); if (Command::FunctionMapSV.find(command) != Command::FunctionMapSV.end()) { Command::FunctionMapSV[command](params); } } Command::Command() { Assert_Size(Game::cmd_function_t, 24); // Disable native noclip command Utils::Hook::Nop(0x474846, 5); Command::Add("noclip", [] (Command::Params) { int clientNum = Game::CG_GetClientNum(); if (!Game::CL_IsCgameInitialized() || clientNum >= 18 || clientNum < 0 || !Game::g_entities[clientNum].client) { Logger::Print("You are not hosting a match!\n"); Toast::Show("cardicon_stop", "Error", "You are not hosting a match!", 3000); return; } if (!Dvar::Var("sv_cheats").Get()) { Logger::Print("Cheats disabled!\n"); Toast::Show("cardicon_stop", "Error", "Cheats disabled!", 3000); return; } Game::g_entities[clientNum].client->flags ^= Game::PLAYER_FLAG_NOCLIP; Logger::Print("Noclip toggled\n"); Toast::Show("cardicon_abduction", "Success", "Noclip toggled", 3000); }); Command::Add("ufo", [] (Command::Params) { int clientNum = Game::CG_GetClientNum(); if (!Game::CL_IsCgameInitialized() || clientNum >= 18 || clientNum < 0 || !Game::g_entities[clientNum].client) { Logger::Print("You are not hosting a match!\n"); Toast::Show("cardicon_stop", "Error", "You are not hosting a match!", 3000); return; } if (!Dvar::Var("sv_cheats").Get()) { Logger::Print("Cheats disabled!\n"); Toast::Show("cardicon_stop", "Error", "Cheats disabled!", 3000); return; } Game::g_entities[clientNum].client->flags ^= Game::PLAYER_FLAG_UFO; Logger::Print("UFO toggled\n"); Toast::Show("cardicon_abduction", "Success", "UFO toggled", 3000); }); } Command::~Command() { Command::MemAllocator.Clear(); Command::FunctionMap.clear(); Command::FunctionMapSV.clear(); } }