maint: January Update
Co-authored-by: Anomaly <jkohler@treyarch.com>
This commit is contained in:
parent
45907301ee
commit
199206ee5a
2
deps/gsc-tool
vendored
2
deps/gsc-tool
vendored
@ -1 +1 @@
|
||||
Subproject commit 9ff3b871ef59b14eb8b32d258bf18347e14a3e18
|
||||
Subproject commit e4cb6a7819726d9ea33cd6a52f0dcd9382258b47
|
@ -36,11 +36,8 @@ namespace auth
|
||||
auto hw_profile_path = (utils::properties::get_appdata_path() / "iw6-guid.dat").generic_string();
|
||||
if (utils::io::file_exists(hw_profile_path))
|
||||
{
|
||||
std::string hw_profile_info;
|
||||
if (utils::io::read_file(hw_profile_path, &hw_profile_info) && !hw_profile_info.empty())
|
||||
{
|
||||
return hw_profile_info;
|
||||
}
|
||||
// Migration
|
||||
utils::io::remove_file(hw_profile_path);
|
||||
}
|
||||
|
||||
HW_PROFILE_INFO info;
|
||||
@ -50,8 +47,6 @@ namespace auth
|
||||
}
|
||||
|
||||
auto hw_profile_info = std::string{ info.szHwProfileGuid, sizeof(info.szHwProfileGuid) };
|
||||
utils::io::write_file(hw_profile_path, hw_profile_info);
|
||||
|
||||
return hw_profile_info;
|
||||
}
|
||||
|
||||
@ -67,7 +62,7 @@ namespace auth
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto size = std::min(data_out.cbData, 52ul);
|
||||
const auto size = std::min<DWORD>(data_out.cbData, 52);
|
||||
std::string result{ reinterpret_cast<char*>(data_out.pbData), size };
|
||||
LocalFree(data_out.pbData);
|
||||
|
||||
@ -91,9 +86,72 @@ namespace auth
|
||||
return entropy;
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key& get_key()
|
||||
bool load_key(utils::cryptography::ecc::key& key)
|
||||
{
|
||||
static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
|
||||
std::string data{};
|
||||
|
||||
auto key_path = (utils::properties::get_appdata_path() / "iw6-private.key").generic_string();
|
||||
if (!utils::io::read_file(key_path, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
key.deserialize(data);
|
||||
if (!key.is_valid())
|
||||
{
|
||||
console::error("Loaded key is invalid!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key generate_key()
|
||||
{
|
||||
auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
|
||||
if (!key.is_valid())
|
||||
{
|
||||
throw std::runtime_error("Failed to generate cryptographic key!");
|
||||
}
|
||||
|
||||
auto key_path = (utils::properties::get_appdata_path() / "iw6-private.key").generic_string();
|
||||
if (!utils::io::write_file(key_path, key.serialize()))
|
||||
{
|
||||
console::error("Failed to write cryptographic key!\n");
|
||||
}
|
||||
|
||||
console::info("Generated cryptographic key: %llX\n", key.get_hash());
|
||||
return key;
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key load_or_generate_key()
|
||||
{
|
||||
utils::cryptography::ecc::key key{};
|
||||
if (load_key(key))
|
||||
{
|
||||
console::info("Loaded cryptographic key: %llX\n", key.get_hash());
|
||||
return key;
|
||||
}
|
||||
|
||||
return generate_key();
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key get_key_internal()
|
||||
{
|
||||
auto key = load_or_generate_key();
|
||||
|
||||
auto key_path = (utils::properties::get_appdata_path() / "iw6-public.key").generic_string();
|
||||
if (!utils::io::write_file(key_path, key.get_public_key()))
|
||||
{
|
||||
console::error("Failed to write public key!\n");
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
const utils::cryptography::ecc::key& get_key()
|
||||
{
|
||||
static auto key = get_key_internal();
|
||||
return key;
|
||||
}
|
||||
|
||||
@ -101,7 +159,7 @@ namespace auth
|
||||
{
|
||||
std::string connect_string(format, len);
|
||||
game::SV_Cmd_TokenizeString(connect_string.data());
|
||||
const auto _ = gsl::finally([]()
|
||||
const auto _0 = gsl::finally([]()
|
||||
{
|
||||
game::SV_Cmd_EndTokenizedString();
|
||||
});
|
||||
@ -124,7 +182,7 @@ namespace auth
|
||||
|
||||
proto::network::connect_info info;
|
||||
info.set_publickey(get_key().get_public_key());
|
||||
info.set_signature(sign_message(get_key(), challenge));
|
||||
info.set_signature(utils::cryptography::ecc::sign_message(get_key(), challenge));
|
||||
info.set_infostring(connect_string);
|
||||
|
||||
network::send(*adr, "connect", info.SerializeAsString());
|
||||
@ -165,14 +223,14 @@ namespace auth
|
||||
utils::cryptography::ecc::key key;
|
||||
key.set(info.publickey());
|
||||
|
||||
const auto xuid = strtoull(steam_id.data(), nullptr, 16);
|
||||
const auto xuid = std::strtoull(steam_id.data(), nullptr, 16);
|
||||
if (xuid != key.get_hash())
|
||||
{
|
||||
network::send(*from, "error", "XUID doesn't match the certificate!", '\n');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!key.is_valid() || !verify_message(key, challenge, info.signature()))
|
||||
if (!key.is_valid() || !utils::cryptography::ecc::verify_message(key, challenge, info.signature()))
|
||||
{
|
||||
network::send(*from, "error", "Challenge signature was invalid!", '\n');
|
||||
return;
|
||||
@ -232,7 +290,7 @@ namespace auth
|
||||
utils::hook::call(0x1402C4F8E, send_connect_data_stub);
|
||||
}
|
||||
|
||||
command::add("guid", []
|
||||
command::add("guid", []() -> void
|
||||
{
|
||||
console::info("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits);
|
||||
});
|
||||
|
@ -76,7 +76,16 @@ namespace colors
|
||||
|
||||
void com_clean_name_stub(const char* in, char* out, const int out_size)
|
||||
{
|
||||
strncpy_s(out, out_size, in, _TRUNCATE);
|
||||
// Check that the name is at least 3 char without colors
|
||||
char name[16]{};
|
||||
|
||||
game::I_strncpyz(out, in, std::min<int>(out_size, sizeof(name)));
|
||||
|
||||
utils::string::strip(out, name, std::strlen(out) + 1);
|
||||
if (std::strlen(name) < 3)
|
||||
{
|
||||
game::I_strncpyz(out, "UnnamedPlayer", std::min<int>(out_size, sizeof(name)));
|
||||
}
|
||||
}
|
||||
|
||||
char* i_clean_str_stub(char* string)
|
||||
@ -86,18 +95,31 @@ namespace colors
|
||||
return string;
|
||||
}
|
||||
|
||||
size_t get_client_name_stub(const int local_client_num, const int index, char* buf, const int size,
|
||||
const size_t unk, const size_t unk2)
|
||||
int cl_get_client_name_and_clan_tag_stub(const int local_client_num, const int index, char* name_buf, const int name_size, char* clan_tag_buf, int clan_tag_size)
|
||||
{
|
||||
// CL_GetClientName (CL_GetClientNameAndClantag?)
|
||||
const auto result = reinterpret_cast<size_t(*)(int, int, char*, int, size_t, size_t)>(0x1402CF790)(
|
||||
local_client_num, index, buf, size, unk, unk2);
|
||||
// CL_GetClientNameAndClanTag -> CL_GetClientNameAndClanTagColorize
|
||||
const auto result = utils::hook::invoke<int>(0x1402CF790, local_client_num, index, name_buf, name_size, clan_tag_buf, clan_tag_size);
|
||||
|
||||
utils::string::strip(buf, buf, size);
|
||||
utils::string::strip(name_buf, name_buf, name_size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int com_sprintf_stub(char* dest, int size, const char* fmt, const char* name)
|
||||
{
|
||||
const auto len = sprintf_s(dest, size, fmt, name);
|
||||
if (len < 0)
|
||||
{
|
||||
game::I_strncpyz(dest, "UnnamedAgent", size);
|
||||
return len;
|
||||
}
|
||||
|
||||
// This should inherit the name of the owner (a player) which already passed the length check in Com_CleanName
|
||||
utils::string::strip(dest, dest, len + 1);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void rb_lookup_color_stub(const char index, DWORD* color)
|
||||
{
|
||||
*color = RGB(255, 255, 255);
|
||||
@ -138,10 +160,15 @@ namespace colors
|
||||
if (!game::environment::is_sp())
|
||||
{
|
||||
// allows colored name in-game
|
||||
utils::hook::jump(0x1404F5FC0, com_clean_name_stub);
|
||||
utils::hook::call(0x1403881CF, com_clean_name_stub);
|
||||
utils::hook::call(0x140388224, com_clean_name_stub);
|
||||
|
||||
// don't apply colors to overhead names
|
||||
utils::hook::call(0x14025CE79, get_client_name_stub);
|
||||
utils::hook::call(0x14025CE79, cl_get_client_name_and_clan_tag_stub);
|
||||
|
||||
// don't apply colors to overhead names of agents (like dogs or juggernauts)
|
||||
// hook Com_sprintf in CL_GetAgentName
|
||||
utils::hook::call(0x1402CF760, com_sprintf_stub);
|
||||
|
||||
// patch I_CleanStr
|
||||
utils::hook::jump(0x1404F63C0, i_clean_str_stub);
|
||||
|
@ -56,8 +56,7 @@ namespace dedicated_info
|
||||
|
||||
std::string cleaned_hostname = sv_hostname->current.string;
|
||||
|
||||
utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(),
|
||||
cleaned_hostname.size() + 1);
|
||||
utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(), cleaned_hostname.size() + 1);
|
||||
|
||||
console::set_title(utils::string::va("%s on %s [%d/%d] (%d)", cleaned_hostname.data(),
|
||||
mapname->current.string, client_count,
|
||||
|
@ -99,7 +99,7 @@ namespace map_rotation
|
||||
console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation->name);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
console::info("dedicated_rotation size after parsing is '%llu'", dedicated_rotation.get_entries_size());
|
||||
console::info("dedicated_rotation size after parsing is '%llu'\n", dedicated_rotation.get_entries_size());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -53,23 +53,25 @@ namespace rcon
|
||||
const auto client = &game::mp::svs_clients[i];
|
||||
auto self = &game::mp::g_entities[i];
|
||||
|
||||
if (client->header.state == game::CS_FREE || !self || !self->client)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char clean_name[32]{};
|
||||
strncpy_s(clean_name, self->client->sess.cs.name, sizeof(clean_name));
|
||||
game::I_CleanStr(clean_name);
|
||||
|
||||
if (client->header.state > game::CS_FREE && self && self->client)
|
||||
{
|
||||
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
|
||||
i,
|
||||
self->client->sess.scores.score,
|
||||
game::SV_BotIsBot(i) ? "Yes" : "No",
|
||||
(client->header.state == game::CS_RECONNECTING) ? "CNCT" : (client->header.state == game::CS_ZOMBIE) ? "ZMBI" : utils::string::va("%4i", client->ping),
|
||||
game::SV_GetGuid(i),
|
||||
clean_name,
|
||||
network::net_adr_to_string(client->header.netchan.remoteAddress),
|
||||
client->header.netchan.remoteAddress.port)
|
||||
);
|
||||
}
|
||||
|
||||
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
|
||||
i,
|
||||
self->client->sess.scores.score,
|
||||
game::SV_BotIsBot(i) ? "Yes" : "No",
|
||||
(client->header.state == game::CS_RECONNECTING) ? "CNCT" : (client->header.state == game::CS_ZOMBIE) ? "ZMBI" : utils::string::va("%4i", client->ping),
|
||||
game::SV_GetGuid(i),
|
||||
clean_name,
|
||||
network::net_adr_to_string(client->header.netchan.remoteAddress),
|
||||
client->header.netchan.remoteAddress.port)
|
||||
);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
@ -10,6 +10,8 @@ namespace security
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour ui_replace_directive_hook;
|
||||
|
||||
void set_cached_playerdata_stub(const int localclient, const int index1, const int index2)
|
||||
{
|
||||
if (index1 >= 0 && index1 < 18 && index2 >= 0 && index2 < 42)
|
||||
@ -30,6 +32,35 @@ namespace security
|
||||
|
||||
utils::hook::invoke<void>(0x140472500, client, msg);
|
||||
}
|
||||
|
||||
void ui_replace_directive_stub(const int local_client_num, const char* src_string, char* dst_string, const int dst_buffer_size)
|
||||
{
|
||||
assert(src_string);
|
||||
if (!src_string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
assert(dst_string);
|
||||
if (!dst_string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
assert(dst_buffer_size > 0);
|
||||
if (dst_buffer_size <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr std::size_t MAX_HUDELEM_TEXT_LEN = 0x100;
|
||||
if (std::strlen(src_string) > MAX_HUDELEM_TEXT_LEN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ui_replace_directive_hook.invoke<void>(local_client_num, src_string, dst_string, dst_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -44,6 +75,8 @@ namespace security
|
||||
|
||||
// It is possible to make the server hang if left unchecked
|
||||
utils::hook::call(0x14047A29A, sv_execute_client_message_stub);
|
||||
|
||||
ui_replace_directive_hook.create(0x1404D8A00, ui_replace_directive_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace demonware
|
||||
uint64_t file_id;
|
||||
uint32_t create_time;
|
||||
uint32_t modified_time;
|
||||
bool priv;
|
||||
bool visibility;
|
||||
uint64_t owner_id;
|
||||
std::string filename;
|
||||
uint32_t file_size;
|
||||
@ -41,7 +41,7 @@ namespace demonware
|
||||
buffer->write_uint64(this->file_id);
|
||||
buffer->write_uint32(this->create_time);
|
||||
buffer->write_uint32(this->modified_time);
|
||||
buffer->write_bool(this->priv);
|
||||
buffer->write_bool(this->visibility);
|
||||
buffer->write_uint64(this->owner_id);
|
||||
buffer->write_string(this->filename);
|
||||
}
|
||||
@ -52,7 +52,7 @@ namespace demonware
|
||||
buffer->read_uint64(&this->file_id);
|
||||
buffer->read_uint32(&this->create_time);
|
||||
buffer->read_uint32(&this->modified_time);
|
||||
buffer->read_bool(&this->priv);
|
||||
buffer->read_bool(&this->visibility);
|
||||
buffer->read_uint64(&this->owner_id);
|
||||
buffer->read_string(&this->filename);
|
||||
}
|
||||
|
@ -10,19 +10,35 @@ namespace demonware
|
||||
this->register_service(4, &bdGroup::get_groups);
|
||||
}
|
||||
|
||||
void bdGroup::set_groups(i_server* server, byte_buffer* /*buffer*/) const
|
||||
void bdGroup::set_groups(i_server* server, byte_buffer* buffer)
|
||||
{
|
||||
//uint32_t groupCount;
|
||||
// TODO: Implement array reading
|
||||
uint32_t entries_count{};
|
||||
buffer->read_array_header(game::BD_BB_UNSIGNED_INTEGER32_TYPE, &entries_count);
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
|
||||
buffer->set_use_data_types(false);
|
||||
|
||||
for (uint32_t i = 0; i < entries_count; ++i)
|
||||
{
|
||||
uint32_t group_id{};
|
||||
buffer->read_uint32(&group_id);
|
||||
|
||||
if (group_id < ARRAYSIZE(this->groups))
|
||||
{
|
||||
this->groups[group_id] = 999;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->set_use_data_types(true);
|
||||
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdGroup::get_groups(i_server* server, byte_buffer* buffer)
|
||||
{
|
||||
uint32_t group_count;
|
||||
buffer->read_array_header(8, &group_count);
|
||||
buffer->read_array_header(game::BD_BB_UNSIGNED_INTEGER32_TYPE, &group_count);
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
|
||||
|
@ -9,7 +9,7 @@ namespace demonware
|
||||
bdGroup();
|
||||
|
||||
private:
|
||||
void set_groups(i_server* server, byte_buffer* buffer) const;
|
||||
void set_groups(i_server* server, byte_buffer* buffer);
|
||||
void get_groups(i_server* server, byte_buffer* buffer);
|
||||
|
||||
uint32_t groups[512]{};
|
||||
|
@ -119,11 +119,11 @@ namespace demonware
|
||||
|
||||
void bdStorage::set_legacy_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
bool priv;
|
||||
bool visibility;
|
||||
std::string filename, data;
|
||||
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_bool(&priv);
|
||||
buffer->read_bool(&visibility);
|
||||
buffer->read_blob(&data);
|
||||
|
||||
const auto id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
@ -139,11 +139,11 @@ namespace demonware
|
||||
|
||||
info->file_id = id;
|
||||
info->filename = filename;
|
||||
info->create_time = uint32_t(time(nullptr));
|
||||
info->create_time = static_cast<uint32_t>(std::time(nullptr));
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->file_size = static_cast<uint32_t>(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = priv;
|
||||
info->visibility = visibility;
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(info);
|
||||
@ -170,11 +170,11 @@ namespace demonware
|
||||
|
||||
info->file_id = id;
|
||||
info->filename = "<>";
|
||||
info->create_time = uint32_t(time(nullptr));
|
||||
info->create_time = static_cast<uint32_t>(std::time(nullptr));
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->file_size = static_cast<uint32_t>(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = false;
|
||||
info->visibility = false;
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(info);
|
||||
@ -207,12 +207,12 @@ namespace demonware
|
||||
|
||||
void bdStorage::list_legacy_user_files(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
uint64_t unk;
|
||||
uint64_t owner;
|
||||
uint32_t date;
|
||||
uint16_t num_results, offset;
|
||||
std::string filename, data;
|
||||
|
||||
buffer->read_uint64(&unk);
|
||||
buffer->read_uint64(&owner);
|
||||
buffer->read_uint32(&date);
|
||||
buffer->read_uint16(&num_results);
|
||||
buffer->read_uint16(&offset);
|
||||
@ -229,9 +229,9 @@ namespace demonware
|
||||
info->filename = filename;
|
||||
info->create_time = 0;
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = false;
|
||||
info->file_size = static_cast<uint32_t>(data.size());
|
||||
info->owner_id = owner;
|
||||
info->visibility = false;
|
||||
|
||||
reply->add(info);
|
||||
}
|
||||
@ -260,9 +260,9 @@ namespace demonware
|
||||
info->filename = filename;
|
||||
info->create_time = 0;
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->file_size = static_cast<uint32_t>(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = false;
|
||||
info->visibility = false;
|
||||
|
||||
reply->add(info);
|
||||
}
|
||||
@ -312,13 +312,13 @@ namespace demonware
|
||||
|
||||
void bdStorage::set_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
bool priv;
|
||||
bool visibility;
|
||||
uint64_t owner;
|
||||
std::string game, filename, data;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_bool(&priv);
|
||||
buffer->read_bool(&visibility);
|
||||
buffer->read_blob(&data);
|
||||
buffer->read_uint64(&owner);
|
||||
|
||||
@ -329,11 +329,11 @@ namespace demonware
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = uint32_t(time(nullptr));
|
||||
info->create_time = static_cast<uint32_t>(std::time(nullptr));
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->file_size = static_cast<uint32_t>(data.size());
|
||||
info->owner_id = owner;
|
||||
info->priv = priv;
|
||||
info->visibility = visibility;
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(info);
|
||||
|
@ -641,6 +641,33 @@ namespace game
|
||||
BD_MAX_ERROR_CODE = 0x27E2,
|
||||
};
|
||||
|
||||
enum bdBitBufferDataType
|
||||
{
|
||||
BD_BB_NO_TYPE = 0x0,
|
||||
BD_BB_BOOL_TYPE = 0x1,
|
||||
BD_BB_SIGNED_CHAR8_TYPE = 0x2,
|
||||
BD_BB_UNSIGNED_CHAR8_TYPE = 0x3,
|
||||
BD_BB_WCHAR16_TYPE = 0x4,
|
||||
BD_BB_SIGNED_INTEGER16_TYPE = 0x5,
|
||||
BD_BB_UNSIGNED_INTEGER16_TYPE = 0x6,
|
||||
BD_BB_SIGNED_INTEGER32_TYPE = 0x7,
|
||||
BD_BB_UNSIGNED_INTEGER32_TYPE = 0x8,
|
||||
BD_BB_SIGNED_INTEGER64_TYPE = 0x9,
|
||||
BD_BB_UNSIGNED_INTEGER64_TYPE = 0xA,
|
||||
BD_BB_RANGED_SIGNED_INTEGER32_TYPE = 0xB,
|
||||
BD_BB_RANGED_UNSIGNED_INTEGER32_TYPE = 0xC,
|
||||
BD_BB_FLOAT32_TYPE = 0xD,
|
||||
BD_BB_FLOAT64_TYPE = 0xE,
|
||||
BD_BB_RANGED_FLOAT32_TYPE = 0xF,
|
||||
BD_BB_SIGNED_CHAR8_STRING_TYPE = 0x10,
|
||||
BD_BB_UNSIGNED_CHAR8_STRING_TYPE = 0x11,
|
||||
BD_BB_MBSTRING_TYPE = 0x12,
|
||||
BD_BB_BLOB_TYPE = 0x13,
|
||||
BD_BB_NAN_TYPE = 0x14,
|
||||
BD_BB_FULL_TYPE = 0x15,
|
||||
BD_BB_MAX_TYPE = 0x20,
|
||||
};
|
||||
|
||||
enum bdNATType : uint8_t
|
||||
{
|
||||
BD_NAT_UNKNOWN = 0x0,
|
||||
|
@ -108,6 +108,7 @@ namespace game
|
||||
WEAK symbol<game_hudelem_s*(int clientNum, int teamNum)> HudElem_Alloc{0x0, 0x1403997E0};
|
||||
|
||||
WEAK symbol<char*(char* string)> I_CleanStr{0x140432460, 0x1404F63C0};
|
||||
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x140432810, 0x1404F67A0};
|
||||
|
||||
WEAK symbol<char*(GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
|
||||
uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const void* initData)>
|
||||
@ -243,6 +244,7 @@ namespace game
|
||||
|
||||
WEAK symbol<const char*(const char*)> UI_LocalizeMapname{0, 0x1404B96D0};
|
||||
WEAK symbol<const char*(const char*)> UI_LocalizeGametype{0, 0x1404B90F0};
|
||||
WEAK symbol<void(int localClientNum, const char* srcString, char* dstString, int dstBufferSize)> UI_ReplaceDirective{0x0, 0x1404D8A00};
|
||||
|
||||
WEAK symbol<DWOnlineStatus(int)> dwGetLogOnStatus{0, 0x140589490};
|
||||
|
||||
|
@ -115,13 +115,13 @@ namespace utils::string
|
||||
|
||||
void strip(const char* in, char* out, size_t max)
|
||||
{
|
||||
if (!in || !out) return;
|
||||
if (!in || !out || !max) return;
|
||||
|
||||
max--;
|
||||
auto current = 0u;
|
||||
while (*in != 0 && current < max)
|
||||
{
|
||||
const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48);
|
||||
const auto color_index = (static_cast<size_t>(*(in + 1) - 48)) >= 0xC ? 7 : (*(in + 1) - 48);
|
||||
|
||||
if (*in == '^' && (color_index != 7 || *(in + 1) == '7'))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user