From 1d5df7869214b44717aab69bac71ff2111932579 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 23 Apr 2017 13:31:48 +0200 Subject: [PATCH] [Bots] Add spawnBot command --- src/Components/Modules/Bots.cpp | 64 +++++++++++++++++++++++++++++ src/Components/Modules/Bots.hpp | 2 + src/Components/Modules/Renderer.cpp | 31 ++++++++++++++ src/Components/Modules/Renderer.hpp | 13 ++++++ src/Game/Functions.cpp | 5 +++ src/Game/Functions.hpp | 12 ++++++ src/Game/Structs.hpp | 3 +- 7 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index b97192e0..f4157b43 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -38,6 +38,40 @@ namespace Components strncpy_s(buffer, 0x400, Utils::String::VA(connectString, num, Bots::BotNames[botId++].data(), protocol, checksum, statVer, statStuff, port), 0x400); } + unsigned int Bots::Spawn(unsigned int count) + { + int error = 0; + std::vector entRefs; + + for (unsigned int i = 0; i < count; ++i) + { + std::this_thread::sleep_for(10ms); + + Game::gentity_t* entRef = Game::SV_AddTestClient(); + if (entRef) entRefs.push_back(entRef); + else if (++error == 3) break; + } + + for (auto& entRef : entRefs) + { + Renderer::OnDelay([entRef]() + { + Game::Scr_AddString("autoassign"); + Game::Scr_AddString("team_marinesopfor"); + Game::Scr_Notify(entRef, Game::SL_GetString("menuresponse", 0), 2); + + Renderer::OnDelay([entRef]() + { + Game::Scr_AddString(Utils::String::VA("class%d", Utils::Cryptography::Rand::GenerateInt() % 5)); + Game::Scr_AddString("changeclass"); + Game::Scr_Notify(entRef, Game::SL_GetString("menuresponse", 0), 2); + }, 1s); + }, 1s); + } + + return entRefs.size(); + } + Bots::Bots() { // Replace connect string @@ -45,6 +79,36 @@ namespace Components // Intercept sprintf for the connect string Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick(); + + Command::Add("spawnBot", [](Command::Params* params) + { + unsigned int count = 1; + + if (params->length() > 1) + { + if (params->get(1) == "all"s) count = static_cast(-1); + else count = atoi(params->get(1)); + } + + // Check if ingame and host + if (!Game::SV_Loaded()) + { + Toast::Show("cardicon_headshot", "^1Error", "You need to be host to spawn bots!", 3000); + Logger::Print("You need to be host to spawn bots!\n"); + } + + count = Bots::Spawn(count); + if (count) + { + Toast::Show("cardicon_headshot", "^2Success", Utils::String::VA("%d %s spawned", count, (count == 1 ? "bot" : "bots")), 3000); + Logger::Print("%d %s spawned successfully!\n", count, (count == 1 ? "bot" : "bots")); + } + else + { + Toast::Show("cardicon_headshot", "^1Error", "Unable to spawn new bots!", 3000); + Logger::Print("Unable to spawn new bots!"); + } + }); } Bots::~Bots() diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index 8d05ddb3..de625891 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -16,5 +16,7 @@ namespace Components static std::vector BotNames; static void BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port); + + static unsigned int Spawn(unsigned int count); }; } diff --git a/src/Components/Modules/Renderer.cpp b/src/Components/Modules/Renderer.cpp index f609de0a..83e278d6 100644 --- a/src/Components/Modules/Renderer.cpp +++ b/src/Components/Modules/Renderer.cpp @@ -9,6 +9,8 @@ namespace Components Utils::Signal Renderer::EndRecoverDeviceSignal; Utils::Signal Renderer::BeginRecoverDeviceSignal; + std::vector Renderer::DelayedSlots; + __declspec(naked) void Renderer::FrameStub() { __asm @@ -24,6 +26,7 @@ namespace Components void Renderer::FrameHandler() { + Renderer::DelaySignal(); Renderer::FrameSignal(); Utils::Signal copy(Renderer::FrameOnceSignal); @@ -84,6 +87,34 @@ namespace Components Renderer::BeginRecoverDeviceSignal.connect(callback); } + void Renderer::OnDelay(Utils::Slot callback, std::chrono::nanoseconds delay) + { + Renderer::DelayedSlot slot; + slot.callback = callback; + slot.delay = delay; + + Renderer::DelayedSlots.push_back(slot); + } + + void Renderer::DelaySignal() + { + Utils::Signal signal; + + for(auto i = Renderer::DelayedSlots.begin(); i != Renderer::DelayedSlots.end();) + { + if(i->interval.elapsed(i->delay)) + { + signal.connect(i->callback); + i = Renderer::DelayedSlots.erase(i); + continue; + } + + ++i; + } + + signal(); + } + int Renderer::Width() { return Utils::Hook::Get(0x66E1C68); diff --git a/src/Components/Modules/Renderer.hpp b/src/Components/Modules/Renderer.hpp index fedbe5c0..fcc28a56 100644 --- a/src/Components/Modules/Renderer.hpp +++ b/src/Components/Modules/Renderer.hpp @@ -21,17 +21,28 @@ namespace Components static void Once(Utils::Slot callback); static void OnFrame(Utils::Slot callback); static void OnBackendFrame(Utils::Slot callback); + static void OnDelay(Utils::Slot callback, std::chrono::nanoseconds delay); static void OnDeviceRecoveryEnd(Utils::Slot callback); static void OnDeviceRecoveryBegin(Utils::Slot callback); private: + class DelayedSlot + { + public: + std::chrono::nanoseconds delay; + Utils::Time::Interval interval; + Utils::Slot callback; + }; + static void FrameStub(); static void FrameHandler(); static void BackendFrameStub(); static void BackendFrameHandler(); + static void DelaySignal(); + static Utils::Signal FrameSignal; static Utils::Signal FrameOnceSignal; @@ -39,5 +50,7 @@ namespace Components static Utils::Signal BeginRecoverDeviceSignal; static Utils::Signal BackendFrameSignal; + + static std::vector DelayedSlots; }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index ef1ba1e3..af00516d 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -212,6 +212,9 @@ namespace Game Scr_ExecThread_t Scr_ExecThread = Scr_ExecThread_t(0x4AD0B0); Scr_FreeThread_t Scr_FreeThread = Scr_FreeThread_t(0x4BD320); + Scr_AddString_t Scr_AddString = Scr_AddString_t(0x412310); + Scr_Notify_t Scr_Notify = Scr_Notify_t(0x4A4750); + Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode = Scr_ShutdownAllocNode_t(0x441650); Script_Alloc_t Script_Alloc = Script_Alloc_t(0x422E70); @@ -238,12 +241,14 @@ namespace Game StringTable_Lookup_t StringTable_Lookup = StringTable_Lookup_t(0x42F0E0); + SV_AddTestClient_t SV_AddTestClient = SV_AddTestClient_t(0x48AD30); SV_GameClientNum_Score_t SV_GameClientNum_Score = SV_GameClientNum_Score_t(0x469AC0); SV_GameSendServerCommand_t SV_GameSendServerCommand = SV_GameSendServerCommand_t(0x4BC3A0); SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString = SV_Cmd_TokenizeString_t(0x4B5780); SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString = SV_Cmd_EndTokenizedString_t(0x464750); SV_DirectConnect_t SV_DirectConnect = SV_DirectConnect_t(0x460480); SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0); + SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0); Sys_Error_t Sys_Error = Sys_Error_t(0x4E0200); Sys_FreeFileList_t Sys_FreeFileList = Sys_FreeFileList_t(0x4D8580); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 79c480a4..6cd2f8b1 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -508,6 +508,9 @@ namespace Game typedef GfxWorld*(__cdecl * R_SortWorldSurfaces_t)(); extern R_SortWorldSurfaces_t R_SortWorldSurfaces; + typedef void(__cdecl * Scr_AddString_t)(const char* str); + extern Scr_AddString_t Scr_AddString; + typedef void(__cdecl * Scr_ShutdownAllocNode_t)(); extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode; @@ -532,6 +535,9 @@ namespace Game typedef int(__cdecl * Scr_FreeThread_t)(int); extern Scr_FreeThread_t Scr_FreeThread; + typedef void(__cdecl * Scr_Notify_t)(gentity_t *ent, unsigned __int16 stringValue, unsigned int paramcount); + extern Scr_Notify_t Scr_Notify; + typedef script_t* (__cdecl * Script_Alloc_t)(int length); extern Script_Alloc_t Script_Alloc; @@ -568,6 +574,9 @@ namespace Game typedef const char*(__cdecl * StringTable_Lookup_t)(StringTable *table, const int comparisonColumn, const char *value, const int valueColumn); extern StringTable_Lookup_t StringTable_Lookup; + typedef gentity_t*(__cdecl* SV_AddTestClient_t)(); + extern SV_AddTestClient_t SV_AddTestClient; + typedef int(__cdecl* SV_GameClientNum_Score_t)(int clientID); extern SV_GameClientNum_Score_t SV_GameClientNum_Score; @@ -586,6 +595,9 @@ namespace Game typedef void(__cdecl * SV_DirectConnect_t)(netadr_t adr); extern SV_DirectConnect_t SV_DirectConnect; + typedef bool(__cdecl * SV_Loaded_t)(); + extern SV_Loaded_t SV_Loaded; + typedef int(__cdecl * Sys_Error_t)(int, char *, ...); extern Sys_Error_t Sys_Error; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 2190c21d..7daacf14 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1194,7 +1194,8 @@ namespace Game typedef struct gentity_s { - unsigned char pad[312]; // 0 + int number; + unsigned char pad[308]; // 4 float origin[3]; // 312 float angles[3]; // 324 char pad2[8];