2022-11-20 11:44:08 -05:00
|
|
|
#include <std_include.hpp>
|
|
|
|
#include "loader/component_loader.hpp"
|
|
|
|
|
2022-12-31 06:18:09 -05:00
|
|
|
#include "command.hpp"
|
|
|
|
|
2022-11-20 11:44:08 -05:00
|
|
|
#include <utils/hook.hpp>
|
2023-02-16 17:29:24 -05:00
|
|
|
#include <utils/io.hpp>
|
|
|
|
#include <utils/string.hpp>
|
2022-11-20 11:44:08 -05:00
|
|
|
|
|
|
|
#include <game/game.hpp>
|
2023-02-27 06:32:29 -05:00
|
|
|
#include "getinfo.hpp"
|
2022-11-20 11:44:08 -05:00
|
|
|
|
|
|
|
namespace bots
|
|
|
|
{
|
|
|
|
namespace
|
|
|
|
{
|
2023-02-16 17:29:24 -05:00
|
|
|
constexpr auto* bot_format_string = "connect \"\\invited\\1\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\"
|
|
|
|
"5000\\name\\%s\\clanAbbrev\\%s\\xuid\\%s\\xnaddr\\%s\\natType\\2\\protocol\\%d\\netfieldchk\\%d\\sessionmode\\%s\\qport\\%d\"";
|
|
|
|
|
|
|
|
using bot_name = std::pair<std::string, std::string>;
|
|
|
|
|
|
|
|
std::vector<bot_name> load_bots_names()
|
|
|
|
{
|
|
|
|
std::vector<bot_name> bot_names =
|
|
|
|
{
|
|
|
|
{"momo5502", "IW5x"},
|
|
|
|
{"Jasmin", "<3"},
|
2023-02-17 05:51:47 -05:00
|
|
|
{"Dss0", "IW3x"},
|
|
|
|
{"FutureRave", "FR"},
|
|
|
|
{"Diamante", "IW2x"},
|
|
|
|
{"St0rm", "NN"},
|
|
|
|
{"Joel", "NN"},
|
|
|
|
{"Louve", "IW5x"},
|
2023-02-16 17:29:24 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
std::string buffer;
|
|
|
|
if (!utils::io::read_file("boiii_cfg/bots.txt", &buffer) || buffer.empty())
|
|
|
|
{
|
|
|
|
return bot_names;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto data = utils::string::split(buffer, '\n');
|
|
|
|
for (auto& entry : data)
|
|
|
|
{
|
|
|
|
utils::string::replace(entry, "\r", "");
|
|
|
|
utils::string::trim(entry);
|
|
|
|
|
|
|
|
if (entry.empty())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string clan_abbrev;
|
|
|
|
// 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())
|
|
|
|
{
|
|
|
|
clan_abbrev = entry.substr(pos + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
entry = entry.substr(0, pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
bot_names.emplace_back(std::make_pair(entry, clan_abbrev));
|
|
|
|
}
|
|
|
|
|
|
|
|
return bot_names;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<bot_name>& get_bot_names()
|
2022-11-20 11:44:08 -05:00
|
|
|
{
|
|
|
|
static const auto bot_names = []
|
|
|
|
{
|
2023-02-16 17:29:24 -05:00
|
|
|
auto names = load_bots_names();
|
2022-11-20 11:44:08 -05:00
|
|
|
|
|
|
|
std::random_device rd;
|
|
|
|
std::mt19937 gen(rd());
|
|
|
|
std::ranges::shuffle(names, gen);
|
|
|
|
return names;
|
|
|
|
}();
|
|
|
|
|
|
|
|
return bot_names;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* get_bot_name()
|
|
|
|
{
|
|
|
|
static size_t current = 0;
|
|
|
|
const auto& names = get_bot_names();
|
|
|
|
|
|
|
|
current = (current + 1) % names.size();
|
2023-02-16 17:29:24 -05:00
|
|
|
return names.at(current).first.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
int format_bot_string(char* buffer, [[maybe_unused]] const char* format, const char* name, const char* xuid,
|
2023-02-17 05:51:47 -05:00
|
|
|
const char* xnaddr, int protocol, int net_field_chk, const char* session_mode, int qport)
|
2023-02-16 17:29:24 -05:00
|
|
|
{
|
2023-02-16 17:32:05 -05:00
|
|
|
const auto find_name = [](const std::string& needle) -> const char*
|
2023-02-16 17:29:24 -05:00
|
|
|
{
|
|
|
|
for (const auto& entry : get_bot_names())
|
|
|
|
{
|
2023-02-16 17:32:05 -05:00
|
|
|
if (entry.first == needle)
|
2023-02-16 17:29:24 -05:00
|
|
|
{
|
|
|
|
return entry.second.data();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "3arc";
|
|
|
|
};
|
|
|
|
|
2023-02-17 05:51:47 -05:00
|
|
|
return sprintf_s(buffer, 1024, bot_format_string, name, find_name(name), xuid, xnaddr, protocol, net_field_chk, session_mode, qport);
|
2022-11-20 11:44:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-02 09:18:37 -05:00
|
|
|
struct component final : generic_component
|
2022-11-20 11:44:08 -05:00
|
|
|
{
|
|
|
|
void post_unpack() override
|
|
|
|
{
|
2023-01-02 09:18:37 -05:00
|
|
|
utils::hook::jump(game::select(0x141653B70, 0x1402732E0), get_bot_name);
|
2023-02-16 17:29:24 -05:00
|
|
|
utils::hook::call(game::select(0x142249AF7, 0x14052E53A), format_bot_string);
|
2023-01-02 09:18:37 -05:00
|
|
|
|
|
|
|
if (!game::is_server())
|
|
|
|
{
|
2023-02-16 17:29:24 -05:00
|
|
|
utils::hook::jump(0x141654280_g, get_bot_name); // SV_ZombieNameRandom
|
2023-01-02 09:18:37 -05:00
|
|
|
}
|
2022-12-31 06:18:09 -05:00
|
|
|
|
|
|
|
command::add("spawnBot", [](const command::params& params)
|
|
|
|
{
|
2023-02-27 06:32:29 -05:00
|
|
|
if (!getinfo::is_host())
|
2023-02-27 05:46:44 -05:00
|
|
|
{
|
2023-02-27 06:32:29 -05:00
|
|
|
return;
|
2023-02-27 05:46:44 -05:00
|
|
|
}
|
|
|
|
|
2022-12-31 06:18:09 -05:00
|
|
|
size_t count = 1;
|
|
|
|
if (params.size() > 1)
|
|
|
|
{
|
|
|
|
if (params[1] == "all"s)
|
|
|
|
{
|
|
|
|
count = 18;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = atoi(params[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
if (!game::SV_AddTestClient())
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2022-11-20 11:44:08 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_COMPONENT(bots::component)
|