diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index d179cc7b..8e43cc2d 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -174,7 +174,7 @@ namespace Components return; } - if (*Game::svs_numclients <= num) + if (*Game::svs_clientCount <= num) { Logger::Print("Player %d is not on the server\n", num); return; @@ -185,9 +185,9 @@ namespace Components SteamID guid; guid.bits = client->steamID; - Bans::InsertBan({ guid, client->netchan.remoteAddress.ip }); + Bans::InsertBan({guid, client->netchan.remoteAddress.ip}); - Game::SV_KickClientError(client, reason); + Game::SV_GameDropClient(num, reason.data()); } void Bans::UnbanClient(SteamID id) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 27c44409..492ff427 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -341,15 +341,15 @@ namespace Components { if (params->get(1) == "all"s) { - count = *Game::svs_numclients; + count = *Game::svs_clientCount; } else { - char* endptr; + char* end; const auto* input = params->get(1); - count = std::strtoul(input, &endptr, 10); + count = std::strtoul(input, &end, 10); - if (input == endptr) + if (input == end) { Logger::Print("Warning: %s is not a valid input\n" "Usage: %s optional or optional <\"all\">\n", @@ -359,7 +359,7 @@ namespace Components } } - count = std::min(static_cast(*Game::svs_numclients), count); + count = std::min(static_cast(*Game::svs_clientCount), count); // Check if ingame and host if (!Game::SV_Loaded()) diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index 45a696e3..8cc40d1c 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -2,7 +2,7 @@ namespace Components { - std::unordered_map> ClientCommand::FunctionMap; + std::unordered_map> ClientCommand::HandlersSV; bool ClientCommand::CheatsOk(const Game::gentity_s* ent) { @@ -25,50 +25,38 @@ namespace Components return true; } - bool ClientCommand::CallbackHandler(Game::gentity_s* ent, const char* cmd) - { - const auto command = Utils::String::ToLower(cmd); - const auto got = ClientCommand::FunctionMap.find(command); - - if (got != ClientCommand::FunctionMap.end()) - { - got->second(ent); - return true; - } - - return false; - } - - void ClientCommand::Add(const char* name, Utils::Slot callback) + void ClientCommand::Add(const char* name, std::function callback) { const auto command = Utils::String::ToLower(name); - ClientCommand::FunctionMap[command] = std::move(callback); + ClientCommand::HandlersSV[command] = std::move(callback); } void ClientCommand::ClientCommandStub(const int clientNum) { - char cmd[1024]{}; - const auto entity = &Game::g_entities[clientNum]; + const auto ent = &Game::g_entities[clientNum]; - if (entity->client == nullptr) + if (ent->client == nullptr) { Logger::Print("ClientCommand: client %d is not fully in game yet\n", clientNum); return; } - Game::SV_Cmd_ArgvBuffer(0, cmd, sizeof(cmd)); + Command::ServerParams params; + const auto command = Utils::String::ToLower(params.get(0)); - if (!ClientCommand::CallbackHandler(entity, cmd)) + if (const auto got = HandlersSV.find(command); got != HandlersSV.end()) { - // If no callback was found call original game function - Utils::Hook::Call(0x416790)(clientNum); + got->second(ent, ¶ms); + return; } + + Utils::Hook::Call(0x416790)(clientNum); } void ClientCommand::AddCheatCommands() { - ClientCommand::Add("noclip", [](Game::gentity_s* ent) + ClientCommand::Add("noclip", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { if (!ClientCommand::CheatsOk(ent)) return; @@ -82,7 +70,7 @@ namespace Components (ent->client->flags & Game::PLAYER_FLAG_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF")); }); - ClientCommand::Add("ufo", [](Game::gentity_s* ent) + ClientCommand::Add("ufo", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { if (!ClientCommand::CheatsOk(ent)) return; @@ -96,7 +84,7 @@ namespace Components (ent->client->flags & Game::PLAYER_FLAG_UFO) ? "GAME_UFOON" : "GAME_UFOOFF")); }); - ClientCommand::Add("god", [](Game::gentity_s* ent) + ClientCommand::Add("god", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { if (!ClientCommand::CheatsOk(ent)) return; @@ -110,7 +98,7 @@ namespace Components (ent->flags & Game::FL_GODMODE) ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF")); }); - ClientCommand::Add("demigod", [](Game::gentity_s* ent) + ClientCommand::Add("demigod", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { if (!ClientCommand::CheatsOk(ent)) return; @@ -124,7 +112,7 @@ namespace Components (ent->flags & Game::FL_DEMI_GODMODE) ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF")); }); - ClientCommand::Add("notarget", [](Game::gentity_s* ent) + ClientCommand::Add("notarget", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { if (!ClientCommand::CheatsOk(ent)) return; @@ -138,17 +126,16 @@ namespace Components (ent->flags & Game::FL_NOTARGET) ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF")); }); - ClientCommand::Add("setviewpos", [](Game::gentity_s* ent) + ClientCommand::Add("setviewpos", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { assert(ent != nullptr); if (!ClientCommand::CheatsOk(ent)) return; - Command::ServerParams params = {}; Game::vec3_t origin, angles{0.f, 0.f, 0.f}; - if (params.size() < 4 || params.size() > 6) + if (params->size() < 4 || params->size() > 6) { Game::SV_GameSendServerCommand(ent->s.number, 0, Utils::String::VA("%c \"GAME_USAGE\x15: setviewpos x y z [yaw] [pitch]\n\"", 0x65)); @@ -157,23 +144,109 @@ namespace Components for (auto i = 0; i < 3; i++) { - origin[i] = std::strtof(params.get(i + 1), nullptr); + origin[i] = std::strtof(params->get(i + 1), nullptr); } - if (params.size() >= 5) + if (params->size() >= 5) { - angles[1] = std::strtof(params.get(4), nullptr); // Yaw + angles[1] = std::strtof(params->get(4), nullptr); // Yaw } - if (params.size() == 6) + if (params->size() == 6) { - angles[0] = std::strtof(params.get(5), nullptr); // Pitch + angles[0] = std::strtof(params->get(5), nullptr); // Pitch } Game::TeleportPlayer(ent, origin, angles); }); } + void ClientCommand::AddDevelopmentCommands() + { + ClientCommand::Add("dropallbots", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + Game::SV_DropAllBots(); + }); + + ClientCommand::Add("entitylist", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + Game::Svcmd_EntityList_f(); + }); + + ClientCommand::Add("printentities", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + Game::G_PrintEntities(); + }); + + ClientCommand::Add("entitycount", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + Logger::Print("Entity count = %i\n", *Game::level_num_entities); + }); + + // Also known as: "vis" + ClientCommand::Add("visionsetnaked", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + if (params->size() < 2) + { + Logger::Print("USAGE: visionSetNaked \n"); + return; + } + + auto duration = 1000; + if (params->size() > 2) + { + const auto input = std::strtof(params->get(2), nullptr); + duration = static_cast(std::floorf(input * 1000.0f + 0.5f)); + } + + assert(ent->client != nullptr); + + constexpr auto visMode = Game::visionSetMode_t::VISIONSET_NORMAL; + const auto* name = params->get(1); + + ent->client->visionDuration[visMode] = duration; + strncpy_s(ent->client->visionName[visMode], + sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE); + + Game::SV_GameSendServerCommand(ent->s.number, 1, + Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); + }); + + ClientCommand::Add("visionsetnight", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + if (params->size() < 2) + { + Logger::Print("USAGE: visionSetNight \n"); + return; + } + + auto duration = 1000; + if (params->size() > 2) + { + const auto input = std::strtof(params->get(2), nullptr); + duration = static_cast(std::floorf(input * 1000.0f + 0.5f)); + } + + assert(ent->client != nullptr); + + constexpr auto visMode = Game::visionSetMode_t::VISIONSET_NIGHT; + const auto* name = params->get(1); + + ent->client->visionDuration[visMode] = duration; + strncpy_s(ent->client->visionName[visMode], + sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE); + + Game::SV_GameSendServerCommand(ent->s.number, 1, + Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); + }); + + ClientCommand::Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + { + assert(ent != nullptr); + ent->client->ps.stunTime = 1000 + *Game::level_time; // 1000 is the default test stun time + }); + } + void ClientCommand::AddScriptFunctions() { Script::AddMethod("Noclip", [](Game::scr_entref_t entref) // gsc: Noclip(); @@ -280,6 +353,11 @@ namespace Components ent->flags ^= Game::FL_NOTARGET; } }); + + Script::AddFunction("DropAllBots", []() // gsc: DropAllBots(); + { + Game::SV_DropAllBots(); + }); } ClientCommand::ClientCommand() @@ -289,5 +367,8 @@ namespace Components ClientCommand::AddCheatCommands(); ClientCommand::AddScriptFunctions(); +#ifdef _DEBUG + ClientCommand::AddDevelopmentCommands(); +#endif } } diff --git a/src/Components/Modules/ClientCommand.hpp b/src/Components/Modules/ClientCommand.hpp index ca9bc2a3..984b597f 100644 --- a/src/Components/Modules/ClientCommand.hpp +++ b/src/Components/Modules/ClientCommand.hpp @@ -5,19 +5,17 @@ namespace Components class ClientCommand : public Component { public: - typedef void(Callback)(Game::gentity_s* entity); - ClientCommand(); - static void Add(const char* name, Utils::Slot callback); + static void Add(const char* name, std::function callback); static bool CheatsOk(const Game::gentity_s* ent); private: - static std::unordered_map> FunctionMap; + static std::unordered_map> HandlersSV; - static bool CallbackHandler(Game::gentity_s* ent, const char* cmd); static void ClientCommandStub(const int clientNum); static void AddCheatCommands(); + static void AddDevelopmentCommands(); static void AddScriptFunctions(); }; } diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index cbe13615..4e5e99b8 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -2,8 +2,8 @@ namespace Components { - std::unordered_map> Command::FunctionMap; - std::unordered_map> Command::FunctionMapSV; + std::unordered_map> Command::FunctionMap; + std::unordered_map> Command::FunctionMapSV; std::string Command::Params::join(const int index) { @@ -60,7 +60,7 @@ namespace Components return Game::sv_cmd_args->argv[this->nesting_][index]; } - void Command::Add(const char* name, Utils::Slot callback) + void Command::Add(const char* name, std::function callback) { const auto command = Utils::String::ToLower(name); @@ -69,10 +69,10 @@ namespace Components Command::AddRaw(name, Command::MainCallback); } - Command::FunctionMap[command] = std::move(callback); + Command::FunctionMap.insert_or_assign(command, std::move(callback)); } - void Command::AddSV(const char* name, Utils::Slot callback) + void Command::AddSV(const char* name, std::function callback) { if (Loader::IsPregame()) { @@ -95,7 +95,7 @@ namespace Components Command::AddRaw(name, Game::Cbuf_AddServerText); } - FunctionMapSV[command] = std::move(callback); + FunctionMapSV.insert_or_assign(command, std::move(callback)); } void Command::AddRaw(const char* name, void(*callback)(), bool key) @@ -127,11 +127,11 @@ namespace Components Game::cmd_function_t* Command::Find(const std::string& command) { - Game::cmd_function_t* cmdFunction = *Game::cmd_functions; + auto* cmdFunction = *Game::cmd_functions; - while (cmdFunction) + while (cmdFunction != nullptr) { - if (cmdFunction->name && cmdFunction->name == command) + if (cmdFunction->name != nullptr && cmdFunction->name == command) { return cmdFunction; } @@ -149,12 +149,10 @@ namespace Components void Command::MainCallback() { - Command::ClientParams params; - + ClientParams params; const auto command = Utils::String::ToLower(params[0]); - const auto got = Command::FunctionMap.find(command); - if (got != Command::FunctionMap.end()) + if (const auto got = FunctionMap.find(command); got != FunctionMap.end()) { got->second(¶ms); } @@ -162,12 +160,10 @@ namespace Components void Command::MainCallbackSV() { - Command::ServerParams params; - + ServerParams params; const auto command = Utils::String::ToLower(params[0]); - const auto got = Command::FunctionMapSV.find(command); - if (got != Command::FunctionMapSV.end()) + if (const auto got = FunctionMapSV.find(command); got != FunctionMapSV.end()) { got->second(¶ms); } diff --git a/src/Components/Modules/Command.hpp b/src/Components/Modules/Command.hpp index d6379a94..ce949cc2 100644 --- a/src/Components/Modules/Command.hpp +++ b/src/Components/Modules/Command.hpp @@ -8,7 +8,8 @@ namespace Components class Params { public: - Params() {}; + Params() = default; + virtual ~Params() = default; virtual int size() = 0; virtual const char* get(int index) = 0; @@ -20,7 +21,7 @@ namespace Components } }; - class ClientParams : public Params + class ClientParams final : public Params { public: ClientParams(); @@ -32,7 +33,7 @@ namespace Components int nesting_; }; - class ServerParams : public Params + class ServerParams final : public Params { public: ServerParams(); @@ -44,14 +45,12 @@ namespace Components int nesting_; }; - typedef void(Callback)(Command::Params* params); - Command(); static Game::cmd_function_t* Allocate(); - static void Add(const char* name, Utils::Slot callback); - static void AddSV(const char* name, Utils::Slot callback); + static void Add(const char* name, std::function callback); + static void AddSV(const char* name, std::function callback); static void AddRaw(const char* name, void(*callback)(), bool key = false); static void AddRawSV(const char* name, void(*callback)()); static void Execute(std::string command, bool sync = true); @@ -59,8 +58,8 @@ namespace Components static Game::cmd_function_t* Find(const std::string& command); private: - static std::unordered_map> FunctionMap; - static std::unordered_map> FunctionMapSV; + static std::unordered_map> FunctionMap; + static std::unordered_map> FunctionMapSV; static void MainCallback(); static void MainCallbackSV(); diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index c50f723c..973679ca 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -51,8 +51,8 @@ namespace Components { SetConsoleTitleA(hostname.data()); - int clientCount = 0; - int maxclientCount = *Game::svs_numclients; + auto clientCount = 0; + auto maxclientCount = *Game::svs_clientCount; if (maxclientCount) { diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 39529219..c9d875da 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -381,7 +381,7 @@ namespace Components { Network::Address address(nc->sa.sa); - for (int i = 0; i < *Game::svs_numclients; ++i) + for (int i = 0; i < *Game::svs_clientCount; ++i) { Game::client_t* client = &Game::svs_clients[i]; diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 0c85313c..6be17612 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -307,7 +307,7 @@ namespace Components { int botCount = 0; int clientCount = 0; - int maxclientCount = *Game::svs_numclients; + int maxclientCount = *Game::svs_clientCount; if (maxclientCount) { diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 6aa19501..bbe73384 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -18,16 +18,16 @@ namespace Components void Script::FunctionError() { - std::string funcName = Game::SL_ConvertToString(Script::FunctionName); + const auto* funcName = Game::SL_ConvertToString(Script::FunctionName); Game::Scr_ShutdownAllocNode(); Logger::Print(23, "\n"); Logger::Print(23, "******* script compile error *******\n"); - Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data()); + Logger::Print(23, "Error: unknown function %s in %s\n", funcName, Script::ScriptName.data()); Logger::Print(23, "************************************\n"); - Logger::Error(Game::ERR_SCRIPT_DROP, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data()); + Logger::Error(Game::ERR_SCRIPT_DROP, "script compile error\nunknown function %s\n%s\n\n", funcName, Script::ScriptName.data()); } __declspec(naked) void Script::StoreFunctionNameStub() @@ -270,27 +270,27 @@ namespace Components Game::GScr_LoadGameTypeScript(); } - void Script::AddFunction(const char* name, Game::xfunction_t func, int type) + void Script::AddFunction(const char* name, Game::BuiltinFunction func, int type) { Game::BuiltinFunctionDef toAdd; toAdd.actionString = name; toAdd.actionFunc = func; toAdd.type = type; - CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); + CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), toAdd); } - void Script::AddMethod(const char* name, Game::xmethod_t func, int type) + void Script::AddMethod(const char* name, Game::BuiltinMethod func, int type) { Game::BuiltinMethodDef toAdd; toAdd.actionString = name; toAdd.actionFunc = func; toAdd.type = type; - CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); + CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), toAdd); } - Game::xfunction_t Script::BuiltIn_GetFunctionStub(const char** pName, int* type) + Game::BuiltinFunction Script::BuiltIn_GetFunctionStub(const char** pName, int* type) { if (pName != nullptr) { @@ -311,10 +311,10 @@ namespace Components } } - return Utils::Hook::Call(0x5FA2B0)(pName, type); // BuiltIn_GetFunction + return Utils::Hook::Call(0x5FA2B0)(pName, type); // BuiltIn_GetFunction } - Game::xmethod_t Script::BuiltIn_GetMethod(const char** pName, int* type) + Game::BuiltinMethod Script::BuiltIn_GetMethod(const char** pName, int* type) { if (pName != nullptr) { @@ -335,7 +335,7 @@ namespace Components } } - return Utils::Hook::Call(0x5FA360)(pName, type); // Player_GetMethod + return Utils::Hook::Call(0x5FA360)(pName, type); // Player_GetMethod } void Script::StoreScriptBaseProgramNum() @@ -538,7 +538,7 @@ namespace Components return nullptr; } - if (ent->s.number >= *Game::svs_numclients) + if (ent->s.number >= *Game::svs_clientCount) { Game::Scr_ObjectError(Utils::String::VA("Entity %i is out of bounds", ent->s.number)); return nullptr; diff --git a/src/Components/Modules/Script.hpp b/src/Components/Modules/Script.hpp index 09a63c22..2885e53e 100644 --- a/src/Components/Modules/Script.hpp +++ b/src/Components/Modules/Script.hpp @@ -11,8 +11,8 @@ namespace Components static int LoadScriptAndLabel(const std::string& script, const std::string& label); - static void AddFunction(const char* name, Game::xfunction_t func, int type = 0); - static void AddMethod(const char* name, Game::xmethod_t func, int type = 0); + static void AddFunction(const char* name, Game::BuiltinFunction func, int type = 0); + static void AddMethod(const char* name, Game::BuiltinMethod func, int type = 0); static void OnVMShutdown(Utils::Slot callback); @@ -49,8 +49,8 @@ namespace Components static void LoadGameType(); static void LoadGameTypeScript(); - static Game::xfunction_t BuiltIn_GetFunctionStub(const char** pName, int* type); - static Game::xmethod_t BuiltIn_GetMethod(const char** pName, int* type); + static Game::BuiltinFunction BuiltIn_GetFunctionStub(const char** pName, int* type); + static Game::BuiltinMethod BuiltIn_GetMethod(const char** pName, int* type); static void ScrShutdownSystemStub(unsigned char sys); static void StoreScriptBaseProgramNumStub(); diff --git a/src/Components/Modules/ServerCommands.cpp b/src/Components/Modules/ServerCommands.cpp index 7e54f8a8..8c67c49b 100644 --- a/src/Components/Modules/ServerCommands.cpp +++ b/src/Components/Modules/ServerCommands.cpp @@ -2,24 +2,24 @@ namespace Components { - std::unordered_map> ServerCommands::Commands; + std::unordered_map> ServerCommands::Commands; - void ServerCommands::OnCommand(std::int32_t cmd, Utils::Slot cb) + void ServerCommands::OnCommand(std::int32_t cmd, std::function callback) { - ServerCommands::Commands[cmd] = cb; + ServerCommands::Commands.insert_or_assign(cmd, std::move(callback)); } bool ServerCommands::OnServerCommand() { Command::ClientParams params; - for (const auto& serverCommandCB : ServerCommands::Commands) + for (const auto& [id, callback] : ServerCommands::Commands) { if (params.size() >= 1) { - if (params.get(0)[0] == serverCommandCB.first) + if (params.get(0)[0] == id) // Compare ID of server command { - return serverCommandCB.second(¶ms); + return callback(¶ms); } } } @@ -27,7 +27,7 @@ namespace Components return false; } - __declspec(naked) void ServerCommands::OnServerCommandStub() + __declspec(naked) void ServerCommands::CG_DeployServerCommand_Stub() { __asm { @@ -44,7 +44,7 @@ namespace Components test eax, eax jle error - mov eax, DWORD PTR[edx * 4 + 1AAC634h] + mov eax, dword ptr [edx * 4 + 1AAC634h] mov eax, [eax] push 5944B3h @@ -63,6 +63,6 @@ namespace Components ServerCommands::ServerCommands() { // Server command receive hook - Utils::Hook(0x59449F, ServerCommands::OnServerCommandStub).install()->quick(); + Utils::Hook(0x59449F, ServerCommands::CG_DeployServerCommand_Stub).install()->quick(); } } diff --git a/src/Components/Modules/ServerCommands.hpp b/src/Components/Modules/ServerCommands.hpp index 61f823a6..3ba04c5f 100644 --- a/src/Components/Modules/ServerCommands.hpp +++ b/src/Components/Modules/ServerCommands.hpp @@ -7,12 +7,12 @@ namespace Components public: ServerCommands(); - static void OnCommand(std::int32_t cmd, Utils::Slot cb); + static void OnCommand(std::int32_t cmd, std::function callback); private: - static std::unordered_map> Commands; + static std::unordered_map> Commands; static bool OnServerCommand(); - static void OnServerCommandStub(); + static void CG_DeployServerCommand_Stub(); }; } diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 69df260b..abefa873 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -125,7 +125,7 @@ namespace Components Utils::InfoString ServerInfo::GetInfo() { - int maxclientCount = *Game::svs_numclients; + int maxclientCount = *Game::svs_clientCount; if (!maxclientCount) { diff --git a/src/Components/Modules/SlowMotion.cpp b/src/Components/Modules/SlowMotion.cpp index 268a2a0a..12f74e7e 100644 --- a/src/Components/Modules/SlowMotion.cpp +++ b/src/Components/Modules/SlowMotion.cpp @@ -68,7 +68,7 @@ namespace Components SlowMotion::Delay = delay; // set snapshot num to 1 behind (T6 does this, why shouldn't we?) - for (int i = 0; i < *Game::svs_numclients; ++i) + for (int i = 0; i < *Game::svs_clientCount; ++i) { Game::svs_clients[i].snapNum = *reinterpret_cast(0x31D9384) - 1; } diff --git a/src/Components/Modules/Weapon.cpp b/src/Components/Modules/Weapon.cpp index e1becfe7..3f57f50a 100644 --- a/src/Components/Modules/Weapon.cpp +++ b/src/Components/Modules/Weapon.cpp @@ -41,7 +41,17 @@ namespace Components if (params.size() <= 1) return 0; - int index = atoi(params[1]); + char* end; + const auto* input = params.get(1); + auto index = std::strtol(input, &end, 10); + + if (input == end) + { + Logger::Print("Warning: %s is not a valid input\n" + "Usage: %s \n", + input, params.get(0)); + return 0; + } if (index >= 4139) { @@ -56,7 +66,7 @@ namespace Components return 0; } - Utils::Hook::Call(0x4BD520)(0, index); + Game::CG_SetupWeaponDef(0, index); return 1; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 0a04d18f..6e2ff06e 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -5,19 +5,19 @@ namespace Game std::vector Sys_ListFilesWrapper(const std::string& directory, const std::string& extension) { auto fileCount = 0; - auto files = Game::Sys_ListFiles(directory.data(), extension.data(), 0, &fileCount, 0); + auto** const files = Sys_ListFiles(directory.data(), extension.data(), nullptr, &fileCount, 0); std::vector result; for (auto i = 0; i < fileCount; i++) { - if (files[i]) + if (files[i] != nullptr) { - result.push_back(files[i]); + result.emplace_back(files[i]); } } - Game::FS_FreeFileList(files); + FS_FreeFileList(files); return result; } @@ -31,6 +31,7 @@ namespace Game BG_GetWeaponName_t BG_GetWeaponName = BG_GetWeaponName_t(0x4E6EC0); BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = BG_LoadWeaponDef_LoadObj_t(0x57B5F0); BG_GetWeaponDef_t BG_GetWeaponDef = BG_GetWeaponDef_t(0x440EB0); + BG_GetEntityTypeName_t BG_GetEntityTypeName = BG_GetEntityTypeName_t(0x43A0E0); Cbuf_AddServerText_t Cbuf_AddServerText = Cbuf_AddServerText_t(0x4BB9B0); Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20); @@ -44,7 +45,9 @@ namespace Game CG_ScoresUp_f_t CG_ScoresUp_f = CG_ScoresUp_f_t(0x5802C0); CG_ScrollScoreboardUp_t CG_ScrollScoreboardUp = CG_ScrollScoreboardUp_t(0x47A5C0); CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown = CG_ScrollScoreboardDown_t(0x493B50); - + CG_GetTeamName_t CG_GetTeamName = CG_GetTeamName_t(0x4B6210); + CG_SetupWeaponDef_t CG_SetupWeaponDef = CG_SetupWeaponDef_t(0x4BD520); + CL_GetClientName_t CL_GetClientName = CL_GetClientName_t(0x4563D0); CL_IsCgameInitialized_t CL_IsCgameInitialized = CL_IsCgameInitialized_t(0x43EB20); CL_ConnectFromParty_t CL_ConnectFromParty = CL_ConnectFromParty_t(0x433D30); @@ -152,6 +155,10 @@ namespace Game G_GetWeaponIndexForName_t G_GetWeaponIndexForName = G_GetWeaponIndexForName_t(0x49E540); G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = G_SpawnEntitiesFromString_t(0x4D8840); + G_PrintEntities_t G_PrintEntities = G_PrintEntities_t(0x4E6A50); + G_GetEntityTypeName_t G_GetEntityTypeName = G_GetEntityTypeName_t(0x4EB810); + + Svcmd_EntityList_f_t Svcmd_EntityList_f = Svcmd_EntityList_f_t(0x4B6A70); GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript = GScr_LoadGameTypeScript_t(0x4ED9A0); @@ -339,6 +346,7 @@ namespace Game SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0); SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0); SV_ClientThink_t SV_ClientThink = SV_ClientThink_t(0x44ADD0); + SV_DropClient_t SV_DropClient = SV_DropClient_t(0x4D1600); SV_GetPlayerByName_t SV_GetPlayerByName = SV_GetPlayerByName_t(0x6242B0); SV_GetPlayerByNum_t SV_GetPlayerByNum = SV_GetPlayerByNum_t(0x624390); @@ -421,7 +429,7 @@ namespace Game float* cgameFOVSensitivityScale = reinterpret_cast(0xB2F884); int* svs_time = reinterpret_cast(0x31D9384); - int* svs_numclients = reinterpret_cast(0x31D938C); + int* svs_clientCount = reinterpret_cast(0x31D938C); client_t* svs_clients = reinterpret_cast(0x31D9390); UiContext *uiContext = reinterpret_cast(0x62E2858); @@ -452,6 +460,8 @@ namespace Game gentity_t* g_entities = reinterpret_cast(0x18835D8); + int* level_num_entities = reinterpret_cast(0x1A831B0); + int* level_time = reinterpret_cast(0x1A83554); int* level_scriptPrintChannel = reinterpret_cast(0x1A860FC); netadr_t* connectedHost = reinterpret_cast(0xA1E888); @@ -520,6 +530,10 @@ namespace Game GraphFloat* aaInputGraph = reinterpret_cast(0x7A2FC0); + const char* MY_CMDS = reinterpret_cast(0x73C9C4); // Count 5 + + XModel** cached_models = reinterpret_cast(0x1AA20C8); + FastCriticalSection* db_hashCritSect = reinterpret_cast(0x16B8A54); vec3_t* CorrectSolidDeltas = reinterpret_cast(0x739BB8); // Count 26 @@ -536,6 +550,13 @@ namespace Game InterlockedDecrement(&critSect->readCount); } + XModel* G_GetModel(const int index) + { + assert(index > 0); + assert(index < MAX_MODELS); + return cached_models[index]; + } + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); @@ -722,14 +743,27 @@ namespace Game return hash; } - void SV_KickClientError(client_t* client, const std::string& reason) + void SV_GameDropClient(int clientNum, const char* reason) { - if (client->state < 5) - { - Components::Network::SendCommand(client->netchan.remoteAddress, "error", reason); - } + const auto maxClients = Dvar_FindVar("sv_maxclients")->current.integer; + assert(maxClients >= 1 && maxClients <= 18); - SV_KickClient(client, reason.data()); + if (clientNum >= 0 && clientNum < maxClients) + { + SV_DropClient(&svs_clients[clientNum], reason, true); + } + } + + void SV_DropAllBots() + { + for (auto i = 0; i < *svs_clientCount; ++i) + { + if (svs_clients[i].state != clientstate_t::CS_FREE + && svs_clients[i].netchan.remoteAddress.type == netadrtype_t::NA_BOT) + { + SV_GameDropClient(i, "GAME_GET_TO_COVER"); + } + } } void IncInParam() @@ -1199,28 +1233,6 @@ namespace Game } } - __declspec(naked) void SV_KickClient(client_t* /*client*/, const char* /*reason*/) - { - __asm - { - pushad - - mov edi, 0 - mov esi, [esp + 24h] - push [esp + 28h] - push 0 - push 0 - - mov eax, 6249A0h - call eax - add esp, 0Ch - - popad - - retn - } - } - __declspec(naked) void Scr_NotifyId(unsigned int /*id*/, unsigned __int16 /*stringValue*/, unsigned int /*paramcount*/) { __asm diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index ee0d4d0c..aa0d8869 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -43,6 +43,9 @@ namespace Game typedef WeaponDef* (__cdecl * BG_GetWeaponDef_t)(int weaponIndex); extern BG_GetWeaponDef_t BG_GetWeaponDef; + typedef const char*(__cdecl * BG_GetEntityTypeName_t)(const int eType); + extern BG_GetEntityTypeName_t BG_GetEntityTypeName; + typedef void(__cdecl * Cbuf_AddServerText_t)(); extern Cbuf_AddServerText_t Cbuf_AddServerText; @@ -75,7 +78,13 @@ namespace Game typedef void(__cdecl * CG_ScrollScoreboardDown_t)(cg_s* cgameGlob); extern CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown; - + + typedef const char*(__cdecl * CG_GetTeamName_t)(team_t team); + extern CG_GetTeamName_t CG_GetTeamName; + + typedef void(__cdecl * CG_SetupWeaponDef_t)(int localClientNum, unsigned int weapIndex); + extern CG_SetupWeaponDef_t CG_SetupWeaponDef; + typedef char*(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, size_t size); extern CL_GetClientName_t CL_GetClientName; @@ -374,9 +383,18 @@ namespace Game typedef unsigned int(__cdecl * G_GetWeaponIndexForName_t)(const char*); extern G_GetWeaponIndexForName_t G_GetWeaponIndexForName; - typedef void(__cdecl* G_SpawnEntitiesFromString_t)(); + typedef void(__cdecl * G_SpawnEntitiesFromString_t)(); extern G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString; + typedef void(__cdecl * G_PrintEntities_t)(); + extern G_PrintEntities_t G_PrintEntities; + + typedef const char*(__cdecl * G_GetEntityTypeName_t)(const gentity_s* ent); + extern G_GetEntityTypeName_t G_GetEntityTypeName; + + typedef void(__cdecl * Svcmd_EntityList_f_t)(); + extern Svcmd_EntityList_f_t Svcmd_EntityList_f; + typedef void(__cdecl * GScr_LoadGameTypeScript_t)(); extern GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript; @@ -750,7 +768,7 @@ namespace Game typedef unsigned int(__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); extern SEH_ReadCharFromString_t SEH_ReadCharFromString; - typedef char*(__cdecl * SL_ConvertToString_t)(unsigned short stringValue); + typedef const char*(__cdecl * SL_ConvertToString_t)(scr_string_t stringValue); extern SL_ConvertToString_t SL_ConvertToString; typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user); @@ -816,6 +834,9 @@ namespace Game typedef void(__cdecl * SV_ClientThink_t)(client_s*, usercmd_s*); extern SV_ClientThink_t SV_ClientThink; + typedef void(__cdecl * SV_DropClient_t)(client_t* drop, const char* reason, bool tellThem); + extern SV_DropClient_t SV_DropClient; + typedef client_t*(__cdecl * SV_GetPlayerByName_t)(); extern SV_GetPlayerByName_t SV_GetPlayerByName; @@ -979,7 +1000,7 @@ namespace Game extern float* cgameFOVSensitivityScale; extern int* svs_time; - extern int* svs_numclients; + extern int* svs_clientCount; extern client_t* svs_clients; extern source_t **sourceFiles; @@ -1015,6 +1036,8 @@ namespace Game constexpr auto ENTITYNUM_NONE = MAX_GENTITIES - 1; extern gentity_t* g_entities; + extern int* level_num_entities; + extern int* level_time; extern int* level_scriptPrintChannel; extern netadr_t* connectedHost; @@ -1085,6 +1108,11 @@ namespace Game constexpr auto AIM_ASSIST_GRAPH_COUNT = 4u; extern GraphFloat* aaInputGraph; + extern const char* MY_CMDS; + + constexpr auto MAX_MODELS = 512; + extern XModel** cached_models; + extern vec3_t* CorrectSolidDeltas; extern FastCriticalSection* db_hashCritSect; @@ -1092,6 +1120,8 @@ namespace Game void Sys_LockRead(FastCriticalSection* critSect); void Sys_UnlockRead(FastCriticalSection* critSect); + XModel* G_GetModel(int index); + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); void Menu_FreeItemMemory(Game::itemDef_s* item); void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); @@ -1120,8 +1150,8 @@ namespace Game void R_LoadSunThroughDvars(const char* mapname, sunflare_t* sun); void R_SetSunFromDvars(sunflare_t* sun); - void SV_KickClient(client_t* client, const char* reason); - void SV_KickClientError(client_t* client, const std::string& reason); + void SV_GameDropClient(int clientNum, const char* reason); + void SV_DropAllBots(); void SV_BotUserMove(client_t* client); void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 8c4e9523..e1561338 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -28,20 +28,20 @@ namespace Game unsigned __int16 classnum; }; - typedef void(__cdecl * xfunction_t)(); - typedef void(__cdecl * xmethod_t)(scr_entref_t); + typedef void(__cdecl * BuiltinFunction)(); + typedef void(__cdecl * BuiltinMethod)(scr_entref_t); struct BuiltinFunctionDef { const char* actionString; - xfunction_t actionFunc; + BuiltinFunction actionFunc; int type; }; struct BuiltinMethodDef { const char* actionString; - xmethod_t actionFunc; + BuiltinMethod actionFunc; int type; }; @@ -5576,15 +5576,25 @@ namespace Game CON_CONNECTED = 0x2 } clientConnected_t; + typedef enum + { + VISIONSET_NORMAL, + VISIONSET_NIGHT, + VISIONSET_MISSILECAM, + VISIONSET_THERMAL, + VISIONSET_PAIN, + VISIONSETCOUNT + } visionSetMode_t; + typedef struct gclient_s { playerState_s ps; sessionState_t sessionState; // 12572 - char pad0[40]; + unsigned char __pad0[40]; clientConnected_t connected; // 12616 - char pad1[144]; - unsigned int team; // 12764 - char pad2[436]; + unsigned char __pad1[144]; + team_t team; // 12764 + unsigned char __pad2[436]; int flags; // 13204 int spectatorClient; int lastCmdTime; @@ -5592,7 +5602,10 @@ namespace Game int oldbuttons; // 13220 int latched_buttons; // 13224 int buttonsSinceLastFrame; // 13228 - char pad3[700]; // 13232 + unsigned char __pad3[324]; // 13232 + int visionDuration[5]; + char visionName[5][64]; + unsigned char __pad4[36]; } gclient_t; static_assert(sizeof(gclient_t) == 13932);