diff options
Diffstat (limited to 'NorthstarDLL')
-rw-r--r-- | NorthstarDLL/NorthstarDLL.vcxproj | 2 | ||||
-rw-r--r-- | NorthstarDLL/NorthstarDLL.vcxproj.filters | 6 | ||||
-rw-r--r-- | NorthstarDLL/bansystem.cpp | 2 | ||||
-rw-r--r-- | NorthstarDLL/bots.cpp | 184 | ||||
-rw-r--r-- | NorthstarDLL/bots.h | 26 | ||||
-rw-r--r-- | NorthstarDLL/r2engine.h | 1 | ||||
-rw-r--r-- | NorthstarDLL/r2server.h | 2 | ||||
-rw-r--r-- | NorthstarDLL/serverauthentication.cpp | 13 |
8 files changed, 231 insertions, 5 deletions
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj b/NorthstarDLL/NorthstarDLL.vcxproj index 5e329f1f..7961ddf4 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj +++ b/NorthstarDLL/NorthstarDLL.vcxproj @@ -120,6 +120,7 @@ <ClInclude Include="bansystem.h" />
<ClInclude Include="bitbuf.h" />
<ClInclude Include="bits.h" />
+ <ClInclude Include="bots.h" />
<ClInclude Include="crashhandler.h" />
<ClInclude Include="keyvalues.h" />
<ClInclude Include="loghooks.h" />
@@ -569,6 +570,7 @@ <ClCompile Include="audio.cpp" />
<ClCompile Include="bansystem.cpp" />
<ClCompile Include="bits.cpp" />
+ <ClCompile Include="bots.cpp" />
<ClCompile Include="buildainfile.cpp" />
<ClCompile Include="chatcommand.cpp" />
<ClCompile Include="clientauthhooks.cpp" />
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj.filters b/NorthstarDLL/NorthstarDLL.vcxproj.filters index 14f8c265..4f5ccbc5 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj.filters +++ b/NorthstarDLL/NorthstarDLL.vcxproj.filters @@ -1503,6 +1503,9 @@ <ClInclude Include="squirrelclasstypes.h">
<Filter>Header Files\Squirrel</Filter>
</ClInclude>
+ <ClInclude Include="bots.h">
+ <Filter>Header Files\Server</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -1733,6 +1736,9 @@ <ClCompile Include="rejectconnectionfixes.cpp">
<Filter>Source Files\Client</Filter>
</ClCompile>
+ <ClCompile Include="bots.cpp">
+ <Filter>Source Files\Server</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="audio_asm.asm">
diff --git a/NorthstarDLL/bansystem.cpp b/NorthstarDLL/bansystem.cpp index 25c0e6bf..5ba24cf1 100644 --- a/NorthstarDLL/bansystem.cpp +++ b/NorthstarDLL/bansystem.cpp @@ -188,7 +188,7 @@ void ConCommand_ban(const CCommand& args) { R2::CBaseClient* player = &R2::g_pClientArray[i]; - if (!strcmp(player->m_Name, args.Arg(1)) || !strcmp(player->m_UID, args.Arg(1))) + if (player->m_Signon >= R2::eSignonState::CONNECTED && !strcmp(player->m_Name, args.Arg(1)) || !strcmp(player->m_UID, args.Arg(1))) { g_pBanSystem->BanUID(strtoull(player->m_UID, nullptr, 10)); R2::CBaseClient__Disconnect(player, 1, "Banned from server"); diff --git a/NorthstarDLL/bots.cpp b/NorthstarDLL/bots.cpp new file mode 100644 index 00000000..f8a37d26 --- /dev/null +++ b/NorthstarDLL/bots.cpp @@ -0,0 +1,184 @@ +#include "pch.h"
+#include "bots.h"
+
+#include "concommand.h"
+#include "r2engine.h"
+#include "r2server.h"
+#include "playlist.h"
+#include "maxplayers.h"
+#include "serverauthentication.h"
+
+AUTOHOOK_INIT()
+
+ServerBotManager* g_pBots;
+
+void* pServer;
+R2::CBaseClient* (*__fastcall CBaseServer__CreateFakeClient)(
+ void* self, const char* pName, const char* pUnk, const char* pDesiredPlaylist, int nDesiredTeam);
+
+void* pServerGameClients;
+void (*__fastcall ServerGameClients__ClientFullyConnect)(void* self, uint16_t edict, bool bRestore);
+
+void (*__fastcall CBasePlayer__RunNullCommand)(R2::CBasePlayer* self);
+
+const std::vector<const char*> BOT_NAMES = {
+ // normal titanfall names
+ "Jack",
+ "Cooper",
+ "BT-7274",
+ "FS-1041",
+ "Blisk",
+ "Marv",
+ "Marvin",
+ "Barker",
+ "Gates",
+ "Marder",
+ "Sarah",
+ "Briggs",
+ "Viper",
+ "Ash",
+ "Richter",
+ "Slone",
+ "Tai",
+ "Lastimosa",
+ "Davis",
+ "Droz",
+ "Bear",
+ "MacAllan",
+ "Bish",
+ "Spyglass",
+
+ // tf1 training/campaign npc names
+ "Rakowski",
+ "Alavi",
+ "Riggs",
+ "Bracken",
+ "Hainey",
+ "Vaughan",
+ "Dunnam",
+ "Riggins",
+ "Messerly",
+ "Heppe",
+ "Keating",
+ "Blanton",
+ "Emslie",
+ "Flagg",
+ "Hofner",
+
+ // deepcut references lol
+ "Iron",
+ "Starseeker",
+ "Hollow",
+ "Preacher",
+
+ // contributors/cool people
+ "BobTheBot",
+ "GeckoEidechsBot",
+ "TaskiBot",
+ "RoyalBot",
+ "EmmaB(ot)", // ok this one is shit to be honest but it's a hard name to put bot into
+ "bot0358",
+ // how the fuck do i turn amos into a bot name oh my god
+ "Botmos",
+ "Botscuit",
+ "Botty_RaVen",
+};
+
+// this is the root func from what usercmd running is called from
+AUTOHOOK(SomeRunUsercmdFunc, server.dll + 0x483A50,
+void, __fastcall, (char a1))
+{
+ g_pBots->SimulatePlayers();
+ SomeRunUsercmdFunc(a1);
+}
+
+void ConCommand_bot_add(const CCommand& arg)
+{
+ if (arg.ArgC() == 1)
+ g_pBots->AddBot();
+ else if (arg.ArgC() == 2)
+ g_pBots->AddBot(arg.Arg(1));
+ else if (arg.ArgC() == 2)
+ g_pBots->AddBot(arg.Arg(1), std::stoi(arg.Arg(2)));
+}
+
+ServerBotManager::ServerBotManager()
+{
+ //m_Cvar_bot_teams = new ConVar("")
+}
+
+
+// add a new bot player
+void ServerBotManager::AddBot(const char* pName, int iTeam)
+{
+ if (!*pName)
+ pName = BOT_NAMES[rand() % BOT_NAMES.size()];
+
+ if (iTeam == -1)
+ {
+ // pick team that needs players
+ // oops i cant be bothered just do imc for now
+ iTeam = 2;
+ }
+
+ const R2::CBaseClient* pPlayer = CBaseServer__CreateFakeClient(pServer, pName, "", "", iTeam);
+ ServerGameClients__ClientFullyConnect(pServerGameClients, pPlayer->edict, false); // this is normally done on eSignonState::FULL, but bots don't properly call it
+
+ spdlog::info("Created bot {}", pPlayer->m_Name);
+}
+
+
+// add bots at the start of a game
+void ServerBotManager::StartMatch()
+{
+ int nNumBots = Cvar_bot_quota->GetInt() - g_pServerAuthentication->m_PlayerAuthenticationData.size();
+ for (int i = nNumBots; i > 0; i--)
+ AddBot();
+}
+
+// setup bot after it connects
+void ServerBotManager::SetupPlayer(R2::CBaseClient* pPlayer)
+{
+ strncpy_s(pPlayer->m_ClanTag, Cvar_bot_clantag->GetString(), 15);
+}
+
+// every server frame, run bot usercmds
+void ServerBotManager::SimulatePlayers()
+{
+ for (int i = 0; i < R2::GetMaxPlayers(); i++)
+ {
+ R2::CBaseClient* pClient = &R2::g_pClientArray[i];
+ if (pClient->m_Signon == R2::eSignonState::FULL && pClient->m_bFakePlayer)
+ {
+ // todo: if we ever want actual moving bots, this would be where we'd nav, build usercmd, etc
+ CBasePlayer__RunNullCommand(R2::UTIL_PlayerByIndex(i + 1));
+ }
+ }
+}
+
+ON_DLL_LOAD_RELIESON("engine.dll", Bots, (ConVar, ConCommand), (CModule module))
+{
+ g_pBots = new ServerBotManager;
+ g_pBots->Cvar_bot_quota = new ConVar("bot_quota", "0", FCVAR_GAMEDLL, "Minimum number of players when filling game with bots");
+ g_pBots->Cvar_bot_clantag = new ConVar("bot_clantag", "BOT", FCVAR_GAMEDLL, "Clantag to give bots");
+
+ pServer = module.Offset(0x12A53D40).As<void*>();
+ pServerGameClients = module.Offset(0x13F0AAA8).As<void*>();
+
+ CBaseServer__CreateFakeClient =
+ module.Offset(0x114C60).As<R2::CBaseClient* (*__fastcall)(void*, const char*, const char*, const char*, int)>();
+
+ RegisterConCommand(
+ "bot_add",
+ ConCommand_bot_add,
+ "Add a bot, by default name and team are automatically chosen, they can be specified (bot_add name team)",
+ FCVAR_GAMEDLL);
+}
+
+ON_DLL_LOAD("server.dll", ServerBots, (CModule module))
+{
+ AUTOHOOK_DISPATCH_MODULE(server.dll)
+
+ ServerGameClients__ClientFullyConnect = module.Offset(0x153B70).As<void (*__fastcall)(void*, uint16_t, bool)>();
+ CBasePlayer__RunNullCommand = module.Offset(0x5A9FD0).As<void (*__fastcall)(R2::CBasePlayer*)>();
+}
diff --git a/NorthstarDLL/bots.h b/NorthstarDLL/bots.h new file mode 100644 index 00000000..5973983a --- /dev/null +++ b/NorthstarDLL/bots.h @@ -0,0 +1,26 @@ +#pragma once
+#include "convar.h"
+#include "r2engine.h"
+
+class ServerBotManager
+{
+
+ public:
+ ConVar* Cvar_bot_quota;
+ ConVar* Cvar_bot_teams;
+
+ ConVar* Cvar_bot_clantag;
+
+ public:
+ ServerBotManager();
+
+ void AddBot(const char* pName = "", int iTeam = -1);
+
+ // events we react to
+ void StartMatch();
+ void SetupPlayer(R2::CBaseClient* pPlayer);
+ void SimulatePlayers();
+
+};
+
+extern ServerBotManager* g_pBots;
diff --git a/NorthstarDLL/r2engine.h b/NorthstarDLL/r2engine.h index 1b1fc081..c816ec86 100644 --- a/NorthstarDLL/r2engine.h +++ b/NorthstarDLL/r2engine.h @@ -175,6 +175,7 @@ namespace R2 OFFSET_STRUCT(CBaseClient) { STRUCT_SIZE(0x2D728) + FIELD(0x14, uint16_t edict) FIELD(0x16, char m_Name[64]) FIELD(0x258, KeyValues* m_ConVars) FIELD(0x2A0, eSignonState m_Signon) diff --git a/NorthstarDLL/r2server.h b/NorthstarDLL/r2server.h index aadfdefe..5d69f53e 100644 --- a/NorthstarDLL/r2server.h +++ b/NorthstarDLL/r2server.h @@ -15,6 +15,8 @@ namespace R2 STRUCT_SIZE(0x1D02); FIELD(0x58, uint32_t m_nPlayerIndex) + FIELD(0x5E4, int m_nTeam) + FIELD(0x1C90, bool m_hasBadReputation) FIELD(0x1C91, char m_communityName[64]) FIELD(0x1CD1, char m_communityClanTag[16]) diff --git a/NorthstarDLL/serverauthentication.cpp b/NorthstarDLL/serverauthentication.cpp index 73b714ab..53892623 100644 --- a/NorthstarDLL/serverauthentication.cpp +++ b/NorthstarDLL/serverauthentication.cpp @@ -15,6 +15,7 @@ #include "r2engine.h" #include "r2client.h" #include "r2server.h" +#include "bots.h" #include "httplib.h" @@ -188,10 +189,6 @@ bool ServerAuthenticationManager::CheckAuthentication(R2::CBaseClient* pPlayer, void ServerAuthenticationManager::AuthenticatePlayer(R2::CBaseClient* pPlayer, uint64_t iUid, char* pAuthToken) { - // for bot players, generate a new uid - if (pPlayer->m_bFakePlayer) - iUid = 0; // is this a good way of doing things :clueless: - std::string sUid = std::to_string(iUid); // copy uuid @@ -316,7 +313,12 @@ bool,, (R2::CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, pAuthenticationFailure = "Authentication Failed."; } else // need to copy name for bots still + { + // generate uid and token for bot + iNextPlayerUid = 0; + pNextPlayerToken = (char*)""; strncpy_s(pVerifiedName, pName, 63); + } if (pAuthenticationFailure) { @@ -333,6 +335,9 @@ bool,, (R2::CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, // we already know this player's authentication data is legit, actually write it to them now g_pServerAuthentication->AuthenticatePlayer(self, iNextPlayerUid, pNextPlayerToken); + if (bFakePlayer) + g_pBots->SetupPlayer(self); + g_pServerAuthentication->AddPlayer(self, pNextPlayerToken); g_pServerLimits->AddPlayer(self); |