[Bots]: Get additional names from Patreon (#771)

This commit is contained in:
Edo 2023-02-13 20:33:26 +00:00 committed by GitHub
parent 7189eab75c
commit ffd7a59f5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 60 deletions

View File

@ -1,5 +1,8 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include <Utils/InfoString.hpp>
#include "Bots.hpp" #include "Bots.hpp"
#include "ServerList.hpp"
#include "GSC/Script.hpp" #include "GSC/Script.hpp"
@ -11,7 +14,7 @@ namespace Components
{ {
std::vector<Bots::botData> Bots::BotNames; std::vector<Bots::botData> Bots::BotNames;
Dvar::Var Bots::SVRandomBotNames; Dvar::Var Bots::SVClanName;
struct BotMovementInfo struct BotMovementInfo
{ {
@ -49,38 +52,56 @@ namespace Components
{ "activate", Game::CMD_BUTTON_ACTIVATE }, { "activate", Game::CMD_BUTTON_ACTIVATE },
}; };
int Bots::BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port) void Bots::RandomizeBotNames()
{
static size_t botId = 0; // Loop over the BotNames vector
static bool loadedNames = false; // Load file only once
const char* botName;
const char* clanName;
if (BotNames.empty() && !loadedNames)
{
FileSystem::File bots("bots.txt");
loadedNames = true;
if (bots.exists())
{
auto data = Utils::String::Split(bots.getBuffer(), '\n');
if (SVRandomBotNames.get<bool>())
{ {
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
std::ranges::shuffle(data, gen); std::ranges::shuffle(BotNames, gen);
} }
void Bots::UpdateBotNames()
{
const auto masterPort = (*Game::com_masterPort)->current.integer;
const auto* masterServerName = (*Game::com_masterServerName)->current.string;
Game::netadr_t master;
if (ServerList::GetMasterServer(masterServerName, masterPort, master))
{
Logger::Print("Getting bots...\n");
Network::Send(master, "getbots");
}
}
void Bots::LoadBotNames()
{
FileSystem::File bots("bots.txt");
if (!bots.exists())
{
return;
}
auto data = Utils::String::Split(bots.getBuffer(), '\n');
auto i = 0;
for (auto& entry : data) for (auto& entry : data)
{ {
if (i >= 18)
{
// Only parse 18 names from the file
break;
}
// Take into account for CR line endings // Take into account for CR line endings
Utils::String::Replace(entry, "\r", ""); Utils::String::Replace(entry, "\r", "");
// Remove whitespace // Remove whitespace
Utils::String::Trim(entry); Utils::String::Trim(entry);
if (!entry.empty()) if (entry.empty())
{ {
continue;
}
std::string clanAbbrev; std::string clanAbbrev;
// Check if there is a clan tag // Check if there is a clan tag
@ -96,25 +117,47 @@ namespace Components
} }
BotNames.emplace_back(std::make_pair(entry, clanAbbrev)); BotNames.emplace_back(std::make_pair(entry, clanAbbrev));
++i;
}
if (i)
{
RandomizeBotNames();
} }
} }
}
int Bots::BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port)
{
static size_t botId = 0; // Loop over the BotNames vector
static bool loadedNames = false; // Load file only once
std::string botName;
std::string clanName;
if (!loadedNames)
{
loadedNames = true;
LoadBotNames();
} }
if (!BotNames.empty()) if (!BotNames.empty())
{ {
botId %= BotNames.size(); botId %= BotNames.size();
const auto index = botId++; const auto index = botId++;
botName = BotNames[index].first.data(); botName = BotNames[index].first;
clanName = BotNames[index].second.data(); clanName = BotNames[index].second;
} }
else else
{ {
botName = Utils::String::VA("bot%d", ++botId); botName = std::format("bot{}", ++botId);
clanName = "BOT"; clanName = "BOT"s;
} }
return _snprintf_s(buffer, 0x400, _TRUNCATE, connectString, num, botName, clanName, protocol, checksum, statVer, statStuff, port); if (const auto svClanName = SVClanName.get<std::string>(); !svClanName.empty())
{
clanName = svClanName;
}
return _snprintf_s(buffer, 0x400, _TRUNCATE, connectString, num, botName.data(), clanName.data(), protocol, checksum, statVer, statStuff, port);
} }
void Bots::Spawn(unsigned int count) void Bots::Spawn(unsigned int count)
@ -352,7 +395,30 @@ namespace Components
Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick();
SVRandomBotNames = Dvar::Register<bool>("sv_randomBotNames", false, Game::DVAR_NONE, "Randomize the bots' names"); Events::OnDvarInit([]
{
SVClanName = Dvar::Register<const char*>("sv_clanName", "", Game::DVAR_NONE, "The clan name for test clients");
});
Scheduler::OnGameInitialized(UpdateBotNames, Scheduler::Pipeline::MAIN);
Network::OnClientPacket("getbotsResponse", [](const Network::Address& address, const std::string& data)
{
const auto masterPort = (*Game::com_masterPort)->current.integer;
const auto* masterServerName = (*Game::com_masterServerName)->current.string;
Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort));
if (master == address)
{
auto botNames = Utils::String::Split(data, '\n');
for (const auto& entry : botNames)
{
BotNames.emplace_back(std::make_pair(entry, "BOT"));
}
RandomizeBotNames();
}
});
// Reset BotMovementInfo.active when client is dropped // Reset BotMovementInfo.active when client is dropped
Events::OnClientDisconnect([](const int clientNum) Events::OnClientDisconnect([](const int clientNum)

View File

@ -11,8 +11,11 @@ namespace Components
using botData = std::pair< std::string, std::string>; using botData = std::pair< std::string, std::string>;
static std::vector<botData> BotNames; static std::vector<botData> BotNames;
static Dvar::Var SVRandomBotNames; static Dvar::Var SVClanName;
static void RandomizeBotNames();
static void UpdateBotNames();
static void LoadBotNames();
static int BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port); static int 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 Spawn(unsigned int count);

View File

@ -165,8 +165,8 @@ namespace Components
return; return;
} }
auto masterPort = Dvar::Var("masterPort").get<int>(); const auto masterPort = (*Game::com_masterPort)->current.integer;
const auto* masterServerName = Dvar::Var("masterServerName").get<const char*>(); const auto* masterServerName = (*Game::com_masterServerName)->current.string;
Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort)); Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort));

View File

@ -299,8 +299,8 @@ namespace Components
} }
else if (IsOnlineList()) else if (IsOnlineList())
{ {
const auto masterPort = Dvar::Var("masterPort").get<int>(); const auto masterPort = (*Game::com_masterPort)->current.integer;
const auto masterServerName = Dvar::Var("masterServerName").get<const char*>(); const auto* masterServerName = (*Game::com_masterServerName)->current.string;
// Check if our dvars can properly convert to a address // Check if our dvars can properly convert to a address
Game::netadr_t masterServerAddr; Game::netadr_t masterServerAddr;

View File

@ -37,6 +37,8 @@ namespace Game
const dvar_t** com_timescale = reinterpret_cast<const dvar_t**>(0x1AD7920); const dvar_t** com_timescale = reinterpret_cast<const dvar_t**>(0x1AD7920);
const dvar_t** com_maxFrameTime = reinterpret_cast<const dvar_t**>(0x1AD78F4); const dvar_t** com_maxFrameTime = reinterpret_cast<const dvar_t**>(0x1AD78F4);
const dvar_t** com_sv_running = reinterpret_cast<const dvar_t**>(0x1AD7934); const dvar_t** com_sv_running = reinterpret_cast<const dvar_t**>(0x1AD7934);
const dvar_t** com_masterServerName = reinterpret_cast<const dvar_t**>(0x1AD8F48);
const dvar_t** com_masterPort = reinterpret_cast<const dvar_t**>(0x1AD8F30);
const dvar_t** dev_timescale = reinterpret_cast<const dvar_t**>(0x1AD8F20); const dvar_t** dev_timescale = reinterpret_cast<const dvar_t**>(0x1AD8F20);

View File

@ -89,6 +89,8 @@ namespace Game
extern const dvar_t** com_timescale; extern const dvar_t** com_timescale;
extern const dvar_t** com_maxFrameTime; extern const dvar_t** com_maxFrameTime;
extern const dvar_t** com_sv_running; extern const dvar_t** com_sv_running;
extern const dvar_t** com_masterServerName;
extern const dvar_t** com_masterPort;
extern const dvar_t** dev_timescale; extern const dvar_t** dev_timescale;

View File

@ -296,7 +296,7 @@ namespace Game
typedef int(*NET_OutOfBandVoiceData_t)(netsrc_t sock, netadr_t adr, unsigned char* format, int len, bool voiceData); typedef int(*NET_OutOfBandVoiceData_t)(netsrc_t sock, netadr_t adr, unsigned char* format, int len, bool voiceData);
extern NET_OutOfBandVoiceData_t NET_OutOfBandVoiceData; extern NET_OutOfBandVoiceData_t NET_OutOfBandVoiceData;
typedef void(*Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite); typedef void(*Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, int controllerIndex, bool fromGameInvite);
extern Live_MPAcceptInvite_t Live_MPAcceptInvite; extern Live_MPAcceptInvite_t Live_MPAcceptInvite;
typedef int(*Live_GetMapIndex_t)(const char* mapname); typedef int(*Live_GetMapIndex_t)(const char* mapname);