From d7a2b1aae7996677856f9972885400b92be89832 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Mon, 24 Jan 2022 02:00:30 +0000 Subject: [PATCH] Address more --- src/Components/Modules/Bots.cpp | 99 +++++++++++++++++++------------ src/Components/Modules/Bots.hpp | 6 +- src/Components/Modules/Script.cpp | 39 +++++++----- src/Components/Modules/Script.hpp | 2 + src/Game/Functions.cpp | 3 + src/Game/Functions.hpp | 5 ++ 6 files changed, 100 insertions(+), 54 deletions(-) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 9db5cc2f..991a18cd 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -3,8 +3,9 @@ namespace Components { std::vector Bots::BotNames; + Game::dvar_t* Bots::SVBotWarfare; - struct BotMovementInfo_t + struct BotMovementInfo { int buttons; // Actions int8_t forward; @@ -12,7 +13,7 @@ namespace Components uint16_t weapon; }; - static BotMovementInfo_t g_botai[18]; + static BotMovementInfo g_botai[18]; struct BotAction { @@ -187,7 +188,7 @@ namespace Components } const auto weapId = Game::G_GetWeaponIndexForName(weapon); - g_botai[entref.entnum].weapon = static_cast(weapId); + g_botai[entref.entnum].weapon = static_cast(weapId); }); Script::AddFunction("BotAction", [](Game::scr_entref_t entref) // Usage: BotAction(); @@ -253,6 +254,57 @@ namespace Components }); } + void Bots::BotAiAction() + { + for (auto i = 0; i < *Game::svs_numclients; ++i) + { + auto* client = &Game::svs_clients[i]; + + if (client->state < Game::CS_CONNECTED) + continue; + + if (!client->isBot) + continue; + + Game::usercmd_s ucmd = {0}; + + ucmd.serverTime = *Game::svs_time; + + ucmd.buttons = g_botai[i].buttons; + ucmd.forwardmove = g_botai[i].forward; + ucmd.rightmove = g_botai[i].right; + ucmd.weapon = g_botai[i].weapon; + + client->deltaMessage = client->netchan.outgoingSequence - 1; + + Game::SV_ClientThink(client, &ucmd); + } + } + + constexpr auto SV_UpdateBots = 0x626E50; + __declspec(naked) void Bots::SV_UpdateBots_Hk() + { + __asm + { + pushad + + call SV_UpdateBots + + // If bot warfare isn't being used let's keep + // test clients normal functionality + mov eax, Bots::SVBotWarfare + cmp byte ptr [eax + 0x10], 0; + + jz skip + + call Bots::BotAiAction + + skip: + popad + ret + } + } + Bots::Bots() { // Replace connect string @@ -261,48 +313,19 @@ namespace Components // Intercept sprintf for the connect string Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick(); - // Stop default behavour of bots spinning and shooting - Utils::Hook(0x627021, 0x4BB9B0, HOOK_CALL).install()->quick(); - Utils::Hook(0x627241, 0x4BB9B0, HOOK_CALL).install()->quick(); + Bots::SVBotWarfare = Game::Dvar_RegisterBool("sv_botWarfare", false, + Game::DVAR_FLAG_NONE, "Allow bot warfare mod to override default bot behaviour"); + + Utils::Hook(0x627021, SV_UpdateBots_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x627241, SV_UpdateBots_Hk, HOOK_CALL).install()->quick(); // Zero the bot command array for (auto i = 0u; i < std::extent_v; i++) { g_botai[i] = {0}; - g_botai[i].weapon = 1; // Prevent the bots from defaulting to the 'none' weapon + g_botai[i].weapon = 1; // Prevent the bots from defaulting to the 'none' weapon } - // Have the bots perform the command every server frame - Scheduler::OnFrame([]() - { - if (!Game::SV_Loaded()) - return; - - for (auto i = 0; i < *Game::svs_numclients; ++i) - { - auto* client = &Game::svs_clients[i]; - - if (client->state < Game::CS_CONNECTED) - continue; - - if (!client->isBot) - continue; - - Game::usercmd_s ucmd = {0}; - - ucmd.serverTime = *Game::svs_time; - - ucmd.buttons = g_botai[i].buttons; - ucmd.forwardmove = g_botai[i].forward; - ucmd.rightmove = g_botai[i].right; - ucmd.weapon = g_botai[i].weapon; - - client->deltaMessage = client->netchan.outgoingSequence - 1; - - Game::SV_ClientThink(client, &ucmd); - } - }); - Command::Add("spawnBot", [](Command::Params* params) { auto count = 1u; diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index f4d599ba..2546fe16 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -37,16 +37,20 @@ namespace Components NUM_8 = 0x1000000, NUM_9 = 0x2000000, - USE = 0x28, + USE = NUM_0 | NUM_1 }; private: static std::vector BotNames; + static Game::dvar_t* SVBotWarfare; static void BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port); static void Spawn(unsigned int count); static void AddMethods(); + + static void BotAiAction(); + static void SV_UpdateBots_Hk(); }; } diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 343d661e..d00fbf73 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -433,6 +433,30 @@ namespace Components return Game::Scr_GetNumParam(); } + // Allow printing to the console even when developer is 0 + void Script::PrintStub() + { + const auto g_no_script_spam = Dvar::Var("g_no_script_spam").get(); + + if (!g_no_script_spam) + return; + + const auto developer = Dvar::Var("developer").get(); + + for (auto i = 0u; i < Game::Scr_GetNumParam(); i++) + { + const auto str = (developer) ? Game::Scr_GetDebugString(i) : Game::Scr_GetString(i); + + if (str == nullptr) + { + Game::Scr_ParamError(i, "^1PrintConsole: Illegal parameters!\n"); + return; + } + + Logger::Print(*Game::level_scriptPrintChannel, "%s", str); + } + } + const char* Script::GetCodePosForParam(int index) { if (static_cast(index) >= Game::scrVmPub->outparamcount) @@ -582,20 +606,6 @@ namespace Components Game::Scr_AddInt(time.wMilliseconds); }); - // Print to console, even without being in 'developer 1'. - Script::AddFunction("PrintConsole", [](Game::scr_entref_t) // gsc: PrintConsole() - { - const auto* str = Game::Scr_GetString(0); - - if (str == nullptr) - { - Game::Scr_ParamError(0, "^1PrintConsole: Illegal parameters!\n"); - return; - } - - Logger::Print(0, "%s", str); - }); - // Executes command to the console Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec() { @@ -610,7 +620,6 @@ namespace Components Command::Execute(str, false); }); - // Script Storage Funcs Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(, ); { diff --git a/src/Components/Modules/Script.hpp b/src/Components/Modules/Script.hpp index ce514a37..4c7b5f50 100644 --- a/src/Components/Modules/Script.hpp +++ b/src/Components/Modules/Script.hpp @@ -73,6 +73,8 @@ namespace Components static unsigned int SetExpFogStub(); + static void PrintStub(); + static const char* GetCodePosForParam(int index); static void GetReplacedPos(const char* pos); static void SetReplacedPos(const char* what, const char* with); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 4f3cf29e..dd50dd9e 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -259,6 +259,7 @@ namespace Game Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0); Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900); + Scr_GetDebugString_t Scr_GetDebugString = Scr_GetDebugString_t(0x4EBF50); Scr_GetFloat_t Scr_GetFloat = Scr_GetFloat_t(0x443140); Scr_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0); Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100); @@ -431,6 +432,8 @@ namespace Game gentity_t* g_entities = reinterpret_cast(0x18835D8); + int* level_scriptPrintChannel = reinterpret_cast(0x1A860FC); + netadr_t* connectedHost = reinterpret_cast(0xA1E888); SOCKET* ip_socket = reinterpret_cast(0x64A3008); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 79a2bc8d..1515869f 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -663,6 +663,9 @@ namespace Game typedef const char*(__cdecl * Scr_GetString_t)(unsigned int); extern Scr_GetString_t Scr_GetString; + typedef const char*(__cdecl * Scr_GetDebugString_t)(unsigned int index); + extern Scr_GetDebugString_t Scr_GetDebugString; + typedef float(__cdecl * Scr_GetFloat_t)(unsigned int); extern Scr_GetFloat_t Scr_GetFloat; @@ -955,6 +958,8 @@ namespace Game constexpr auto MAX_GENTITIES = 2048u; extern gentity_t* g_entities; + extern int* level_scriptPrintChannel; + extern netadr_t* connectedHost; extern SOCKET* ip_socket;