[Bots]: Get additional names from Patreon (#771)
This commit is contained in:
parent
7189eab75c
commit
ffd7a59f5e
@ -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,72 +52,112 @@ namespace Components
|
|||||||
{ "activate", Game::CMD_BUTTON_ACTIVATE },
|
{ "activate", Game::CMD_BUTTON_ACTIVATE },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Bots::RandomizeBotNames()
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (i >= 18)
|
||||||
|
{
|
||||||
|
// Only parse 18 names from the file
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take into account for CR line endings
|
||||||
|
Utils::String::Replace(entry, "\r", "");
|
||||||
|
// Remove whitespace
|
||||||
|
Utils::String::Trim(entry);
|
||||||
|
|
||||||
|
if (entry.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string clanAbbrev;
|
||||||
|
|
||||||
|
// Check if there is a clan tag
|
||||||
|
if (const auto pos = entry.find(','); pos != std::string::npos)
|
||||||
|
{
|
||||||
|
// Only start copying over from non-null characters (otherwise it can be "<=")
|
||||||
|
if ((pos + 1) < entry.size())
|
||||||
|
{
|
||||||
|
clanAbbrev = entry.substr(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = entry.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
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 size_t botId = 0; // Loop over the BotNames vector
|
||||||
static bool loadedNames = false; // Load file only once
|
static bool loadedNames = false; // Load file only once
|
||||||
const char* botName;
|
std::string botName;
|
||||||
const char* clanName;
|
std::string clanName;
|
||||||
|
|
||||||
if (BotNames.empty() && !loadedNames)
|
if (!loadedNames)
|
||||||
{
|
{
|
||||||
FileSystem::File bots("bots.txt");
|
|
||||||
loadedNames = true;
|
loadedNames = true;
|
||||||
|
LoadBotNames();
|
||||||
if (bots.exists())
|
|
||||||
{
|
|
||||||
auto data = Utils::String::Split(bots.getBuffer(), '\n');
|
|
||||||
|
|
||||||
if (SVRandomBotNames.get<bool>())
|
|
||||||
{
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 gen(rd());
|
|
||||||
std::ranges::shuffle(data, gen);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& entry : data)
|
|
||||||
{
|
|
||||||
// Take into account for CR line endings
|
|
||||||
Utils::String::Replace(entry, "\r", "");
|
|
||||||
// Remove whitespace
|
|
||||||
Utils::String::Trim(entry);
|
|
||||||
|
|
||||||
if (!entry.empty())
|
|
||||||
{
|
|
||||||
std::string clanAbbrev;
|
|
||||||
|
|
||||||
// Check if there is a clan tag
|
|
||||||
if (const auto pos = entry.find(','); pos != std::string::npos)
|
|
||||||
{
|
|
||||||
// Only start copying over from non-null characters (otherwise it can be "<=")
|
|
||||||
if ((pos + 1) < entry.size())
|
|
||||||
{
|
|
||||||
clanAbbrev = entry.substr(pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = entry.substr(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
BotNames.emplace_back(std::make_pair(entry, clanAbbrev));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ namespace Game
|
|||||||
typedef bool(*NET_CompareAdr_t)(netadr_t a, netadr_t b);
|
typedef bool(*NET_CompareAdr_t)(netadr_t a, netadr_t b);
|
||||||
extern NET_CompareAdr_t NET_CompareAdr;
|
extern NET_CompareAdr_t NET_CompareAdr;
|
||||||
|
|
||||||
typedef void(*NET_DeferPacketToClient_t)(netadr_t *, msg_t *);
|
typedef void(*NET_DeferPacketToClient_t)(netadr_t*, msg_t*);
|
||||||
extern NET_DeferPacketToClient_t NET_DeferPacketToClient;
|
extern NET_DeferPacketToClient_t NET_DeferPacketToClient;
|
||||||
|
|
||||||
typedef const char* (*NET_ErrorString_t)();
|
typedef const char* (*NET_ErrorString_t)();
|
||||||
@ -284,19 +284,19 @@ namespace Game
|
|||||||
typedef bool(*NET_IsLocalAddress_t)(netadr_t adr);
|
typedef bool(*NET_IsLocalAddress_t)(netadr_t adr);
|
||||||
extern NET_IsLocalAddress_t NET_IsLocalAddress;
|
extern NET_IsLocalAddress_t NET_IsLocalAddress;
|
||||||
|
|
||||||
typedef int(*NET_StringToAdr_t)(const char *s, netadr_t *a);
|
typedef int(*NET_StringToAdr_t)(const char* s, netadr_t* a);
|
||||||
extern NET_StringToAdr_t NET_StringToAdr;
|
extern NET_StringToAdr_t NET_StringToAdr;
|
||||||
|
|
||||||
typedef void(*NET_OutOfBandPrint_t)(netsrc_t sock, netadr_t adr, const char *data);
|
typedef void(*NET_OutOfBandPrint_t)(netsrc_t sock, netadr_t adr, const char* data);
|
||||||
extern NET_OutOfBandPrint_t NET_OutOfBandPrint;
|
extern NET_OutOfBandPrint_t NET_OutOfBandPrint;
|
||||||
|
|
||||||
typedef void(*NET_OutOfBandData_t)(netsrc_t sock, netadr_t adr, const char *format, int len);
|
typedef void(*NET_OutOfBandData_t)(netsrc_t sock, netadr_t adr, const char* format, int len);
|
||||||
extern NET_OutOfBandData_t NET_OutOfBandData;
|
extern NET_OutOfBandData_t NET_OutOfBandData;
|
||||||
|
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user