diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 5f49f80f..2ae201b2 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -3,8 +3,9 @@ #include "command.hpp" -#include #include +#include +#include #include @@ -12,15 +13,61 @@ namespace bots { namespace { - const std::vector& get_bot_names() + 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::vector load_bots_names() + { + std::vector bot_names = + { + {"momo5502", "IW5x"}, + {"Maurice", "IW5x" }, + {"Jasmin", "<3"}, + }; + + 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& get_bot_names() { static const auto bot_names = [] { - std::vector names{ - "momo5502", - "Maurice", - "Jasmin", - }; + auto names = load_bots_names(); std::random_device rd; std::mt19937 gen(rd()); @@ -37,7 +84,26 @@ namespace bots const auto& names = get_bot_names(); current = (current + 1) % names.size(); - return names.at(current).data(); + return names.at(current).first.data(); + } + + int format_bot_string(char* buffer, [[maybe_unused]] const char* format, const char* name, const char* xuid, + const char* xnaddr, int protocol, int netfieldchk, const char* session_mode, int qport) + { + const auto find_name = [](const std::string& needle) -> const char* + { + for (const auto& entry : get_bot_names()) + { + if (entry.first == needle) + { + return entry.second.data(); + } + } + + return "3arc"; + }; + + return sprintf_s(buffer, 1024, bot_format_string, name, find_name(name), xuid, xnaddr, protocol, netfieldchk, session_mode, qport); } } @@ -46,10 +112,11 @@ namespace bots void post_unpack() override { utils::hook::jump(game::select(0x141653B70, 0x1402732E0), get_bot_name); + utils::hook::call(game::select(0x142249AF7, 0x14052E53A), format_bot_string); if (!game::is_server()) { - utils::hook::jump(0x141654280_g, get_bot_name); + utils::hook::jump(0x141654280_g, get_bot_name); // SV_ZombieNameRandom } command::add("spawnBot", [](const command::params& params) diff --git a/src/common/utils/string.cpp b/src/common/utils/string.cpp index d440c99e..64a1215e 100644 --- a/src/common/utils/string.cpp +++ b/src/common/utils/string.cpp @@ -175,6 +175,31 @@ namespace utils::string return str; } + std::string& ltrim(std::string& str) + { + str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const unsigned char input) + { + return !std::isspace(input); + })); + + return str; + } + + std::string& rtrim(std::string& str) + { + str.erase(std::find_if(str.rbegin(), str.rend(), [](const unsigned char input) + { + return !std::isspace(input); + }).base(), str.end()); + + return str; + } + + void trim(std::string& str) + { + ltrim(rtrim(str)); + } + void copy(char* dest, const size_t max_size, const char* src) { if (!max_size) diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index 6a2cdc76..d3d798dd 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -95,6 +95,8 @@ namespace utils::string std::string replace(std::string str, const std::string& from, const std::string& to); + void trim(std::string& str); + void copy(char* dest, size_t max_size, const char* src); template