From 724c7026ef64d22c1fc1a8fc023b3dd055e21ad5 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 3 Apr 2023 17:38:03 +0200 Subject: [PATCH 001/102] Prepare new authentication protocol --- src/client/component/auth.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index edac9e7b..2af779c1 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -2,6 +2,8 @@ #include "loader/component_loader.hpp" #include "auth.hpp" +#include "command.hpp" +#include "network.hpp" #include @@ -92,16 +94,32 @@ namespace auth return !is_first; } - int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, const int len) + int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, int len) { - /*const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; + std::string buffer{}; + + const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; if (is_connect_sequence) { - MessageBoxA(0, "CONNECT", 0, 0); - }*/ + buffer.append("connect "); + buffer.append(data, len); + + data = buffer.data(); + len = static_cast(buffer.size()); + } return reinterpret_cast(0x142173600_g)(sock, adr, data, len); } + + void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) + { + const std::string text(data.begin(), data.end()); + command::params_sv params(text); + + MessageBoxA(0, "Connecting", 0, 0); + + game::SV_DirectConnect(target); + } } uint64_t get_guid() @@ -123,6 +141,10 @@ namespace auth { void post_unpack() override { + // Skip connect handler + utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); + network::on("connect", handle_connect_packet); + // Patch steam id bit check std::vector> patches{}; const auto p = [&patches](const size_t a, const size_t b) From 27ab6193e51c37d1bdf26ef53504fb36767df302 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 3 Apr 2023 19:03:54 +0200 Subject: [PATCH 002/102] Prepare auth data --- src/client/component/auth.cpp | 23 ++++++-- src/client/component/network.cpp | 13 ++++- src/client/component/party.cpp | 12 ++++- src/client/game/structs.hpp | 2 +- src/common/utils/byte_buffer.cpp | 85 +++++++++++++++++++++++++++++ src/common/utils/byte_buffer.hpp | 91 ++++++++++++++++++++++++++++++++ 6 files changed, 217 insertions(+), 9 deletions(-) create mode 100644 src/common/utils/byte_buffer.cpp create mode 100644 src/common/utils/byte_buffer.hpp diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 2af779c1..4a76dddb 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -94,6 +95,14 @@ namespace auth return !is_first; } + std::string serialize_connect_data(const std::vector& data) + { + utils::byte_buffer buffer{}; + buffer.write_vector(data); + + return buffer.move_buffer(); + } + int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, int len) { std::string buffer{}; @@ -101,8 +110,12 @@ namespace auth const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; if (is_connect_sequence) { - buffer.append("connect "); - buffer.append(data, len); + std::vector connect_data{}; + connect_data.assign(data, data + len); + + buffer.append("connect"); + buffer.push_back(' '); + buffer.append(serialize_connect_data(connect_data)); data = buffer.data(); len = static_cast(buffer.size()); @@ -113,10 +126,10 @@ namespace auth void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) { - const std::string text(data.begin(), data.end()); - command::params_sv params(text); + utils::byte_buffer buffer(data); - MessageBoxA(0, "Connecting", 0, 0); + const auto text = buffer.read_vector(); + command::params_sv params(std::string(text.data(), text.size())); game::SV_DirectConnect(target); } diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 4dbe5f1a..9a722405 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -35,7 +35,18 @@ namespace network const std::basic_string_view data(message->data + offset, message->cursize - offset); - handler->second(*address, data); + try + { + handler->second(*address, data); + } + catch (const std::exception& e) + { + printf("Error: %s\n", e.what()); + } + catch (...) + { + } + return 0; } diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index bf5caebe..be598d14 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -36,7 +36,7 @@ namespace party } void connect_to_lobby(const game::netadr_t& addr, const std::string& mapname, const std::string& gamemode, - const std::string& pub_id) + const std::string& pub_id) { workshop::load_usermap_mod_if_needed(pub_id); @@ -55,7 +55,8 @@ namespace party } void connect_to_lobby_with_mode(const game::netadr_t& addr, const game::eModes mode, const std::string& mapname, - const std::string& gametype, const std::string& pub_id, const bool was_retried = false) + const std::string& gametype, const std::string& pub_id, + const bool was_retried = false) { if (game::Com_SessionMode_IsMode(mode)) { @@ -144,6 +145,13 @@ namespace party is_connecting_to_dedi = info.get("dedicated") == "1"; + if (atoi(info.get("protocol").data()) != PROTOCOL) + { + const auto str = "Invalid protocol."; + printf("%s\n", str); + return; + } + const auto gamename = info.get("gamename"); if (gamename != "T7"s) { diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index be6386f3..f48fb2eb 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1,6 +1,6 @@ #pragma once -#define PROTOCOL 1 +#define PROTOCOL 2 #ifdef __cplusplus namespace game diff --git a/src/common/utils/byte_buffer.cpp b/src/common/utils/byte_buffer.cpp new file mode 100644 index 00000000..c471858a --- /dev/null +++ b/src/common/utils/byte_buffer.cpp @@ -0,0 +1,85 @@ +#include "byte_buffer.hpp" + +#include +#include + +namespace utils +{ + byte_buffer::byte_buffer() + : writing_(true) + { + } + + byte_buffer::byte_buffer(std::string buffer) + : writing_(false) + , buffer_(std::move(buffer)) + { + } + + void byte_buffer::write(const void* buffer, const size_t length) + { + if (!writing_) + { + throw std::runtime_error("Writing to readable byte buffer"); + } + + buffer_.append(static_cast(buffer), length); + } + + void byte_buffer::read(void* data, const size_t length) + { + if (writing_) + { + throw std::runtime_error("Reading from writable byte buffer"); + } + + if (offset_ + length > buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } + + memcpy(data, buffer_.data() + offset_, length); + offset_ += length; + } + + std::string byte_buffer::read_string() + { + std::string result{}; + + while (true) + { + const auto b = read(); + if (!b) + { + break; + } + + result.push_back(b); + } + + return result; + } + + std::string byte_buffer::read_string(const size_t length) + { + std::string result{}; + result.reserve(length); + + for (size_t i = 0; i < length; ++i) + { + result.push_back(read()); + } + + return result; + } + + std::vector byte_buffer::read_data(const size_t length) + { + std::vector result{}; + result.resize(length); + + read(result.data(), result.size()); + + return result; + } +} diff --git a/src/common/utils/byte_buffer.hpp b/src/common/utils/byte_buffer.hpp new file mode 100644 index 00000000..662a5919 --- /dev/null +++ b/src/common/utils/byte_buffer.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include +#include + +namespace utils +{ + class byte_buffer + { + public: + byte_buffer(); + byte_buffer(std::string buffer); + + template + byte_buffer(const std::basic_string_view& buffer) + : byte_buffer(std::string(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T))) + { + } + + void write(const void* buffer, size_t length); + + void write(const std::string& string, const bool null_terminate = false) + { + const size_t addend = null_terminate ? 1 : 0; + write(string.data(), string.size() + addend); + } + + void write_string(const std::string& string) + { + write(string, true); + } + + template + void write(const T& object) + { + write(&object, sizeof(object)); + } + + template + void write(const std::vector& vec) + { + write(vec.data(), vec.size() * sizeof(T)); + } + + template + void write_vector(const std::vector& vec) + { + write(static_cast(vec.size())); + write(vec); + } + + const std::string& get_buffer() const + { + return buffer_; + } + + std::string move_buffer() + { + return std::move(buffer_); + } + + void read(void* data, size_t length); + + template + T read() + { + T object{}; + read(&object, sizeof(object)); + return object; + } + + template + std::vector read_vector() + { + std::vector result{}; + result.resize(read()); + read(result.data(), result.size() * sizeof(T)); + + return result; + } + + std::string read_string(); + std::string read_string(size_t length); + std::vector read_data(size_t length); + + private: + bool writing_{false}; + size_t offset_{0}; + std::string buffer_{}; + }; +} From 924abd0ed52317a523b10ce0ce7ae1834edb0cc8 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 3 Apr 2023 21:51:30 +0200 Subject: [PATCH 003/102] fix: forgot to * the array of clients --- src/client/component/dedicated_patches.cpp | 4 ++-- src/client/game/symbols.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 307f1095..b535a7be 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -70,7 +70,7 @@ namespace dedicated_patches uint64_t sv_get_player_xuid_stub(int client_num) { - return static_cast(game::svs_clients[client_num].xuid); + return static_cast((*game::svs_clients)[client_num].xuid); } int sv_get_guid(int client_num) @@ -80,7 +80,7 @@ namespace dedicated_patches return 0; } - return game::svs_clients[client_num].xuid; + return (*game::svs_clients)[client_num].xuid; } } diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 029c3d5f..c2fd5aec 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -190,7 +190,7 @@ namespace game WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; - WEAK symbol svs_clients{0x0, 0x14A178E98}; + WEAK symbol svs_clients{0x0, 0x14A178E98}; // Dvar variables WEAK symbol com_maxclients{0x0, 0x14948EE70}; From d29b40c618d2332deb23e301435f2606ba2e9cb9 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 3 Apr 2023 21:54:00 +0200 Subject: [PATCH 004/102] fix: this function did not need to be patched. Oops --- src/client/component/dedicated_patches.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index b535a7be..06c943ce 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -72,16 +72,6 @@ namespace dedicated_patches { return static_cast((*game::svs_clients)[client_num].xuid); } - - int sv_get_guid(int client_num) - { - if (client_num < 0 || client_num >= game::Dvar_GetInt(*game::com_maxclients)) - { - return 0; - } - - return (*game::svs_clients)[client_num].xuid; - } } struct component final : server_component @@ -109,7 +99,6 @@ namespace dedicated_patches utils::hook::jump(0x14052F0F5_g, 0x14052F139_g); utils::hook::call(0x1402853D7_g, sv_get_player_xuid_stub); // PlayerCmd_GetXuid - utils::hook::call(0x140283303_g, sv_get_guid); // PlayerCmd_GetGuid } }; } From b1cb80ba2ca597b228b246e03cfc6397b07ff9f2 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Mon, 3 Apr 2023 22:21:35 -0230 Subject: [PATCH 005/102] refresh custom maps list when entering mp/zm menu --- data/ui_scripts/stats/__init__.lua | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua index a20f2ea3..f861651d 100644 --- a/data/ui_scripts/stats/__init__.lua +++ b/data/ui_scripts/stats/__init__.lua @@ -423,6 +423,43 @@ end local MapVote = 0 +CoD.LobbyMenus.MPButtonsLAN = function( arg0, arg1, arg2 ) + if IsStarterPack() then + AddSmallButton( arg0, arg1, CoD.LobbyButtons.QUIT ) + return + end + if arg2 == 1 then + AddSmallButton( arg0, arg1, CoD.LobbyButtons.MP_CUSTOM_START_GAME ) + AddSmallButton( arg0, arg1, CoD.LobbyButtons.MP_CUSTOM_SETUP_GAME ) + AddSpacer( arg1 ) + end + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_CAC ) + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_SPECIALISTS ) + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_SCORESTREAKS ) + AddSpacer( arg1 ) + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_CODCASTER_SETTINGS ) + if Engine.DvarBool( nil, "inventory_test_button_visible" ) then + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_INVENTORY_TEST ) + end + Engine.Mods_Lists_UpdateUsermaps() +end + +CoD.LobbyMenus.MPButtonsMain = function ( arg0, arg1, arg2 ) + if arg2 == 1 then + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_PUBLIC_MATCH ) + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_ARENA ) + AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_CUSTOM_GAMES ) + AddLargeButton( arg0, arg1, CoD.LobbyButtons.THEATER_MP ) + end + AddSpacer( arg1 ) + if CoD.isPC then + AddLargeButton( arg0, arg1, CoD.LobbyButtons.STEAM_STORE ) + else + AddLargeButton( arg0, arg1, CoD.LobbyButtons.STORE ) + end + Engine.Mods_Lists_UpdateUsermaps() +end + CoD.LobbyMenus.MPButtonsOnline = function ( f26_arg0, f26_arg1, f26_arg2 ) if f26_arg2 == 1 then AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_FIND_MATCH ) @@ -510,6 +547,7 @@ CoD.LobbyMenus.ZMButtonsOnline = function ( f33_arg0, f33_arg1, f33_arg2 ) AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_BUILD_KITS ) AddSpacer( f33_arg1 ) AddSmallButton( f33_arg0, f33_arg1, CoD.LobbyButtons.MP_STATS ) + Engine.Mods_Lists_UpdateUsermaps() end local targetButtons = { From 55c340c68f8bba71449ffd2ac4fa1ca79b3eb919 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 4 Apr 2023 10:37:21 +0200 Subject: [PATCH 006/102] feat: implement sv_lanOnly & fix heart beat delay --- src/client/component/dedicated.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 6a5cde7f..9a66d959 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -15,6 +15,8 @@ namespace dedicated { namespace { + const game::dvar_t* sv_lan_only; + void sv_con_tell_f_stub(game::client_s* cl_0, game::svscmd_type type, [[maybe_unused]] const char* fmt, [[maybe_unused]] int c, char* text) { @@ -23,6 +25,11 @@ namespace dedicated void send_heartbeat_packet() { + if (sv_lan_only->current.value.enabled) + { + return; + } + game::netadr_t target{}; if (server_list::get_master_server(target)) { @@ -64,11 +71,14 @@ namespace dedicated // Fix tell command for IW4M utils::hook::call(0x14052A8CF_g, sv_con_tell_f_stub); + scheduler::once(send_heartbeat, scheduler::pipeline::main); scheduler::loop(send_heartbeat, scheduler::pipeline::main, 5min); command::add("heartbeat", send_heartbeat); // Hook GScr_ExitLevel utils::hook::jump(0x1402D1AA0_g, trigger_map_rotation); + + sv_lan_only = game::register_dvar_bool("sv_lanOnly", false, game::DVAR_NONE, "Don't send heartbeats"); } }; } From 34769f594d1545b941c0c798f814a21f481bcdb2 Mon Sep 17 00:00:00 2001 From: Sergio Brighenti Date: Tue, 4 Apr 2023 12:29:30 +0200 Subject: [PATCH 007/102] fix: restart button is never shown on online sessions --- data/ui_scripts/party/__init__.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/ui_scripts/party/__init__.lua b/data/ui_scripts/party/__init__.lua index b51b1fc0..741d9378 100644 --- a/data/ui_scripts/party/__init__.lua +++ b/data/ui_scripts/party/__init__.lua @@ -71,7 +71,7 @@ DataSources.StartMenuGameOptions = ListHelper_SetupDataSource("StartMenuGameOpti end elseif CoD.isZombie then table.insert(options, {models = {displayText = "MENU_RESUMEGAME_CAPS", action = StartMenuGoBack_ListElement}}) - if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) and (not not (Engine.SessionModeIsMode(CoD.SESSIONMODE_SYSTEMLINK) == true) or Engine.SessionModeIsMode(CoD.SESSIONMODE_OFFLINE) == true) then + if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) and (not Engine.SessionModeIsMode(CoD.SESSIONMODE_SYSTEMLINK) or Engine.SessionModeIsMode(CoD.SESSIONMODE_OFFLINE)) then table.insert(options, {models = {displayText = "MENU_RESTART_LEVEL_CAPS", action = RestartGame}}) end if Engine.IsLobbyHost(Enum.LobbyType.LOBBY_TYPE_GAME) == true then @@ -81,4 +81,4 @@ DataSources.StartMenuGameOptions = ListHelper_SetupDataSource("StartMenuGameOpti end end return options -end, true) \ No newline at end of file +end, true) From 077167e81baa6c434c7b622e149b60c75b78b09f Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Tue, 4 Apr 2023 18:23:10 +0200 Subject: [PATCH 008/102] Fix bytebuffer --- src/common/utils/byte_buffer.cpp | 1 - src/common/utils/byte_buffer.hpp | 10 ++++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/common/utils/byte_buffer.cpp b/src/common/utils/byte_buffer.cpp index c471858a..2ef0a3b0 100644 --- a/src/common/utils/byte_buffer.cpp +++ b/src/common/utils/byte_buffer.cpp @@ -1,7 +1,6 @@ #include "byte_buffer.hpp" #include -#include namespace utils { diff --git a/src/common/utils/byte_buffer.hpp b/src/common/utils/byte_buffer.hpp index 662a5919..6a801968 100644 --- a/src/common/utils/byte_buffer.hpp +++ b/src/common/utils/byte_buffer.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace utils { @@ -73,8 +74,13 @@ namespace utils std::vector read_vector() { std::vector result{}; - result.resize(read()); - read(result.data(), result.size() * sizeof(T)); + const auto size = read(); + if (offset_ + size > buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } + + read(result.data(), size); return result; } From 23c7228214d8442bc047d273d5c5d978c633f5ae Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 3 Apr 2023 19:14:45 +0200 Subject: [PATCH 009/102] fix getguid & getxuid --- src/client/component/bots.cpp | 2 ++ src/client/component/dedicated_patches.cpp | 20 ++++++++++++++++++++ src/client/game/structs.hpp | 4 ++++ src/client/game/symbols.hpp | 6 ++++++ 4 files changed, 32 insertions(+) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 2f334f62..0d06afd0 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -115,6 +115,8 @@ namespace bots struct component final : generic_component { + static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); + void post_unpack() override { utils::hook::jump(game::select(0x141653B70, 0x1402732E0), get_bot_name); diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 45a961c1..bb936719 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -67,10 +67,27 @@ namespace dedicated_patches spawn_server_hook.invoke(controllerIndex, server, preload, savegame); } + + uint64_t sv_get_player_xuid_stub(int client_num) + { + return game::svs_clients[client_num].xuid; + } + + int sv_get_guid(int client_num) + { + if (client_num < 0 || client_num >= game::Dvar_GetInt(*game::com_maxclients)) + { + return 0; + } + + return game::svs_clients[client_num].xuid; + } } struct component final : server_component { + static_assert(offsetof(game::client_s, xuid) == 0xBB354); + void post_unpack() override { // Fix infinite loop @@ -90,6 +107,9 @@ namespace dedicated_patches // Don't count server as client utils::hook::jump(0x14052F0F5_g, 0x14052F139_g); + + utils::hook::call(0x1402853D7_g, sv_get_player_xuid_stub); // PlayerCmd_GetXuid + utils::hook::call(0x140283303_g, sv_get_guid); // PlayerCmd_GetGuid } }; } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index f48fb2eb..6ba49856 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1544,6 +1544,10 @@ namespace game struct client_s { + char __pad0[0xBB354]; + int xuid; + char __pad1[0x8]; + bool bIsTestClient; }; enum scriptInstance_t diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 4e325035..029c3d5f 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -104,6 +104,7 @@ namespace game WEAK symbol Dvar_GetString{0x1422BF590, 0x140575E30}; WEAK symbol Dvar_DisplayableValue{0x1422BC080}; WEAK symbol Dvar_GetBool{0x1422BCED0}; + WEAK symbol Dvar_GetInt{0x0, 0x140575C20}; WEAK symbol Dvar_RegisterBool{ 0x1422D0900, 0x14057B500 @@ -189,6 +190,11 @@ namespace game WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; + WEAK symbol svs_clients{0x0, 0x14A178E98}; + + // Dvar variables + WEAK symbol com_maxclients{0x0, 0x14948EE70}; + namespace s_wcd { WEAK symbol codLogo{0x157E75A50, 0x14A640BC0}; From fcec2f9b89d6873fe6a7d42864891f976a074274 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 3 Apr 2023 19:18:37 +0200 Subject: [PATCH 010/102] forgot to fill out rest of struct --- src/client/game/structs.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 6ba49856..9e6cd35a 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1548,8 +1548,11 @@ namespace game int xuid; char __pad1[0x8]; bool bIsTestClient; + char __pad2[0x29DAC]; }; + static_assert(sizeof(client_s) == 0xE5110); + enum scriptInstance_t { SCRIPTINSTANCE_SERVER = 0x0, From 4e713355f2cd4321dbb4b389852a76aba6e869be Mon Sep 17 00:00:00 2001 From: Edo Date: Mon, 3 Apr 2023 19:54:45 +0200 Subject: [PATCH 011/102] dedicated_patche: handle conversion to unsigned --- src/client/component/dedicated_patches.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index bb936719..307f1095 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -70,7 +70,7 @@ namespace dedicated_patches uint64_t sv_get_player_xuid_stub(int client_num) { - return game::svs_clients[client_num].xuid; + return static_cast(game::svs_clients[client_num].xuid); } int sv_get_guid(int client_num) From 5ca61c83530f6e3f1f7dd77d216543c8f58b6d5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 18:03:23 +0000 Subject: [PATCH 012/102] Bump deps/libtommath from `886126c` to `53fdf5f` Bumps [deps/libtommath](https://github.com/libtom/libtommath) from `886126c` to `53fdf5f`. - [Release notes](https://github.com/libtom/libtommath/releases) - [Commits](https://github.com/libtom/libtommath/compare/886126cb45bac67da77f4238bef6ffb843e9e26f...53fdf5f9c73cb4fde599dd07e54bac8264f7b236) --- updated-dependencies: - dependency-name: deps/libtommath dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/libtommath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/libtommath b/deps/libtommath index 886126cb..53fdf5f9 160000 --- a/deps/libtommath +++ b/deps/libtommath @@ -1 +1 @@ -Subproject commit 886126cb45bac67da77f4238bef6ffb843e9e26f +Subproject commit 53fdf5f9c73cb4fde599dd07e54bac8264f7b236 From 6686f9f2ea3e79c14bc83d8ee4b36cce2ba448f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 18:03:29 +0000 Subject: [PATCH 013/102] Bump deps/curl from `3797f1a` to `a13ef31` Bumps [deps/curl](https://github.com/curl/curl) from `3797f1a` to `a13ef31`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/3797f1a4ca8fbd1c73a93ea973a3a6931b6e689b...a13ef31d0fbbf98120b711746bd8802acaba6b0a) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 3797f1a4..a13ef31d 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 3797f1a4ca8fbd1c73a93ea973a3a6931b6e689b +Subproject commit a13ef31d0fbbf98120b711746bd8802acaba6b0a From 9ffb5d62445d92daf1c2f3e91928fccc18a7f50c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 18:03:48 +0000 Subject: [PATCH 014/102] Bump deps/libtomcrypt from `05f9407` to `fae62af` Bumps [deps/libtomcrypt](https://github.com/libtom/libtomcrypt) from `05f9407` to `fae62af`. - [Release notes](https://github.com/libtom/libtomcrypt/releases) - [Commits](https://github.com/libtom/libtomcrypt/compare/05f94077cc0aa42f550e85d2785a92b668117ada...fae62af0ab16f469c2512ec04575dd60ca018657) --- updated-dependencies: - dependency-name: deps/libtomcrypt dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/libtomcrypt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/libtomcrypt b/deps/libtomcrypt index 05f94077..fae62af0 160000 --- a/deps/libtomcrypt +++ b/deps/libtomcrypt @@ -1 +1 @@ -Subproject commit 05f94077cc0aa42f550e85d2785a92b668117ada +Subproject commit fae62af0ab16f469c2512ec04575dd60ca018657 From 45b1462dca41c6e85262cb391256a05f67a06fb1 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 3 Apr 2023 21:51:30 +0200 Subject: [PATCH 015/102] fix: forgot to * the array of clients --- src/client/component/dedicated_patches.cpp | 4 ++-- src/client/game/symbols.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 307f1095..b535a7be 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -70,7 +70,7 @@ namespace dedicated_patches uint64_t sv_get_player_xuid_stub(int client_num) { - return static_cast(game::svs_clients[client_num].xuid); + return static_cast((*game::svs_clients)[client_num].xuid); } int sv_get_guid(int client_num) @@ -80,7 +80,7 @@ namespace dedicated_patches return 0; } - return game::svs_clients[client_num].xuid; + return (*game::svs_clients)[client_num].xuid; } } diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 029c3d5f..c2fd5aec 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -190,7 +190,7 @@ namespace game WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; - WEAK symbol svs_clients{0x0, 0x14A178E98}; + WEAK symbol svs_clients{0x0, 0x14A178E98}; // Dvar variables WEAK symbol com_maxclients{0x0, 0x14948EE70}; From 04ad73f5ea5611fccce42d74b406a7d36c68b578 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 3 Apr 2023 21:54:00 +0200 Subject: [PATCH 016/102] fix: this function did not need to be patched. Oops --- src/client/component/dedicated_patches.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index b535a7be..06c943ce 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -72,16 +72,6 @@ namespace dedicated_patches { return static_cast((*game::svs_clients)[client_num].xuid); } - - int sv_get_guid(int client_num) - { - if (client_num < 0 || client_num >= game::Dvar_GetInt(*game::com_maxclients)) - { - return 0; - } - - return (*game::svs_clients)[client_num].xuid; - } } struct component final : server_component @@ -109,7 +99,6 @@ namespace dedicated_patches utils::hook::jump(0x14052F0F5_g, 0x14052F139_g); utils::hook::call(0x1402853D7_g, sv_get_player_xuid_stub); // PlayerCmd_GetXuid - utils::hook::call(0x140283303_g, sv_get_guid); // PlayerCmd_GetGuid } }; } From 34eca16e16cf58f25f7557038b0e99c5420e3af9 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 4 Apr 2023 10:37:21 +0200 Subject: [PATCH 017/102] feat: implement sv_lanOnly & fix heart beat delay --- src/client/component/dedicated.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 6a5cde7f..9a66d959 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -15,6 +15,8 @@ namespace dedicated { namespace { + const game::dvar_t* sv_lan_only; + void sv_con_tell_f_stub(game::client_s* cl_0, game::svscmd_type type, [[maybe_unused]] const char* fmt, [[maybe_unused]] int c, char* text) { @@ -23,6 +25,11 @@ namespace dedicated void send_heartbeat_packet() { + if (sv_lan_only->current.value.enabled) + { + return; + } + game::netadr_t target{}; if (server_list::get_master_server(target)) { @@ -64,11 +71,14 @@ namespace dedicated // Fix tell command for IW4M utils::hook::call(0x14052A8CF_g, sv_con_tell_f_stub); + scheduler::once(send_heartbeat, scheduler::pipeline::main); scheduler::loop(send_heartbeat, scheduler::pipeline::main, 5min); command::add("heartbeat", send_heartbeat); // Hook GScr_ExitLevel utils::hook::jump(0x1402D1AA0_g, trigger_map_rotation); + + sv_lan_only = game::register_dvar_bool("sv_lanOnly", false, game::DVAR_NONE, "Don't send heartbeats"); } }; } From 3c4642303f37d67266d97c52fde73490fab5f995 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 18:01:59 +0000 Subject: [PATCH 018/102] Bump deps/curl from `a13ef31` to `4399a53` Bumps [deps/curl](https://github.com/curl/curl) from `a13ef31` to `4399a53`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/a13ef31d0fbbf98120b711746bd8802acaba6b0a...4399a532e9b7f340a3c8a573f3c2d36d2032bbc0) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index a13ef31d..4399a532 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit a13ef31d0fbbf98120b711746bd8802acaba6b0a +Subproject commit 4399a532e9b7f340a3c8a573f3c2d36d2032bbc0 From fcd41ddca8160b376478335e8494b8c41ff0c3f8 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Tue, 4 Apr 2023 20:40:20 +0200 Subject: [PATCH 019/102] Temporarily disable hooks --- src/client/component/auth.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 4a76dddb..fba96ad8 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -155,8 +155,8 @@ namespace auth void post_unpack() override { // Skip connect handler - utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); - network::on("connect", handle_connect_packet); + //utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); + //network::on("connect", handle_connect_packet); // Patch steam id bit check std::vector> patches{}; @@ -203,7 +203,7 @@ namespace auth p(0x141EB5992_g, 0x141EB59D5_g); p(0x141EB74D2_g, 0x141EB7515_g); // ? - utils::hook::call(0x14134BF7D_g, send_connect_data_stub); + //utils::hook::call(0x14134BF7D_g, send_connect_data_stub); } for (const auto& patch : patches) From 163f9c53b871c233c0be1bf13b2a3031e705d713 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Tue, 4 Apr 2023 20:40:48 +0200 Subject: [PATCH 020/102] Some cleanup and svs_clients --- src/client/component/command.cpp | 19 +++++----- src/client/component/dedicated_patches.cpp | 43 ++++++++++++---------- src/client/component/getinfo.cpp | 23 ++++++++---- src/client/game/structs.hpp | 25 +++++++++++-- src/client/game/symbols.hpp | 2 + 5 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index 0ac70162..07a2a241 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace command { @@ -66,15 +67,6 @@ namespace command } } - struct component final : generic_component - { - void post_unpack() override - { - // Disable whitelist - utils::hook::jump(game::select(0x1420EE860, 0x1404F9CD0), update_whitelist_stub); - } - }; - params::params() : nesting_(get_cmd_args()->nesting) { @@ -227,6 +219,15 @@ namespace command game::Cmd_AddServerCommandInternal(cmd_string, execute_custom_sv_command, allocator.allocate()); } + + struct component final : generic_component + { + void post_unpack() override + { + // Disable whitelist + utils::hook::jump(game::select(0x1420EE860, 0x1404F9CD0), update_whitelist_stub); + } + }; } REGISTER_COMPONENT(command::component) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 06c943ce..48ed8326 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -36,22 +36,22 @@ namespace dedicated_patches { const std::vector is_mod_loaded_addresses = { - { 0x14019CFC4_g }, - { 0x14024D4A0_g }, - { 0x14024D669_g }, - { 0x14024D939_g }, - { 0x14024DC64_g }, - { 0x14024E13A_g }, - { 0x14024E5A3_g }, - { 0x14024FFB9_g }, - { 0x140251E9E_g }, - { 0x140253680_g }, - { 0x140257BF6_g }, - { 0x1402D296D_g }, - { 0x1402D58E9_g }, - { 0x140468374_g }, - { 0x14046B796_g }, - { 0x14048003D_g }, + {0x14019CFC4_g}, + {0x14024D4A0_g}, + {0x14024D669_g}, + {0x14024D939_g}, + {0x14024DC64_g}, + {0x14024E13A_g}, + {0x14024E5A3_g}, + {0x14024FFB9_g}, + {0x140251E9E_g}, + {0x140253680_g}, + {0x140257BF6_g}, + {0x1402D296D_g}, + {0x1402D58E9_g}, + {0x140468374_g}, + {0x14046B796_g}, + {0x14048003D_g}, }; for (const auto& address : is_mod_loaded_addresses) @@ -68,15 +68,20 @@ namespace dedicated_patches spawn_server_hook.invoke(controllerIndex, server, preload, savegame); } - uint64_t sv_get_player_xuid_stub(int client_num) + uint64_t sv_get_player_xuid_stub(const int client_num) { - return static_cast((*game::svs_clients)[client_num].xuid); + const auto* clients = *game::svs_clients; + if (!clients) + { + return 0; + } + + return static_cast(clients[client_num].guid); } } struct component final : server_component { - static_assert(offsetof(game::client_s, xuid) == 0xBB354); void post_unpack() override { diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index 1deb6826..9e770266 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -21,21 +21,18 @@ namespace getinfo return game::get_dvar_int("com_maxclients"); } - int get_client_count() + template + int get_client_count(T* client_states) { - int count = 0; - const auto client_states = *reinterpret_cast(game::select(0x1576F9318, 0x14A178E98)); if (!client_states) { return 0; } - const auto object_length = game::is_server() ? 0xE5110 : 0xE5170; - + int count = 0; for (int i = 0; i < get_max_client_count(); ++i) { - const auto client_state = *reinterpret_cast(client_states + (i * object_length)); - if (client_state > 0) + if (client_states[i].client_state > 0) { ++count; } @@ -44,9 +41,19 @@ namespace getinfo return count; } + int get_client_count() + { + if (game::is_server()) + { + return get_client_count(*game::svs_clients); + } + + return get_client_count(*game::svs_clients_cl); + } + int get_bot_count() { - const auto client_states = *reinterpret_cast(game::select(0x1576F9318, 0x14A178E98)); + const auto client_states = game::is_server() ? *game::svs_clients : *game::svs_clients_cl; if (!client_states) { return 0; diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 9e6cd35a..9e35f729 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1544,15 +1544,32 @@ namespace game struct client_s { - char __pad0[0xBB354]; - int xuid; - char __pad1[0x8]; + int client_state; + char __pad0[0x28]; + netadr_t address; + char __pad1[0xBB318]; + int guid; + char __pad2[0x8]; bool bIsTestClient; - char __pad2[0x29DAC]; + char __pad3[0x25818]; + uint64_t xuid; + char __pad4[0x4588]; }; static_assert(sizeof(client_s) == 0xE5110); + static_assert(offsetof(game::client_s, address) == 0x2C); + static_assert(offsetof(game::client_s, guid) == 0xBB354); + static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); + static_assert(offsetof(game::client_s, xuid) == 0xE0B80); + + struct client_s_cl : client_s + { + char __pad1_0[0x60]; + }; + + static_assert(sizeof(client_s_cl) == 0xE5170); + enum scriptInstance_t { SCRIPTINSTANCE_SERVER = 0x0, diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index c2fd5aec..6abf5b32 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -190,6 +190,8 @@ namespace game WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; + // Client and dedi struct size differs :( + WEAK symbol svs_clients_cl{0x1576F9318, 0}; WEAK symbol svs_clients{0x0, 0x14A178E98}; // Dvar variables From fe59e621803afbbe25a730415dbffd2193288160 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 18:01:06 +0000 Subject: [PATCH 021/102] Bump deps/libtommath from `53fdf5f` to `37bd262` Bumps [deps/libtommath](https://github.com/libtom/libtommath) from `53fdf5f` to `37bd262`. - [Release notes](https://github.com/libtom/libtommath/releases) - [Commits](https://github.com/libtom/libtommath/compare/53fdf5f9c73cb4fde599dd07e54bac8264f7b236...37bd262cc22aeffaac5b9528ade3bf07fe8ea424) --- updated-dependencies: - dependency-name: deps/libtommath dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/libtommath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/libtommath b/deps/libtommath index 53fdf5f9..37bd262c 160000 --- a/deps/libtommath +++ b/deps/libtommath @@ -1 +1 @@ -Subproject commit 53fdf5f9c73cb4fde599dd07e54bac8264f7b236 +Subproject commit 37bd262cc22aeffaac5b9528ade3bf07fe8ea424 From 6f2607b91be63e70b889719c5badd96fc3eba2d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 18:01:10 +0000 Subject: [PATCH 022/102] Bump deps/curl from `4399a53` to `98fac31` Bumps [deps/curl](https://github.com/curl/curl) from `4399a53` to `98fac31`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/4399a532e9b7f340a3c8a573f3c2d36d2032bbc0...98fac31b0613fc8cb88709a78c816d38d715fe11) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 4399a532..98fac31b 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 4399a532e9b7f340a3c8a573f3c2d36d2032bbc0 +Subproject commit 98fac31b0613fc8cb88709a78c816d38d715fe11 From 08a1d6c744d02e3d89c842b16638abcb45983071 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:22:14 +0000 Subject: [PATCH 023/102] Bump deps/curl from `98fac31` to `356dd0b` Bumps [deps/curl](https://github.com/curl/curl) from `98fac31` to `356dd0b`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/98fac31b0613fc8cb88709a78c816d38d715fe11...356dd0b73a75ed6d56682c818b73145862881989) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 98fac31b..356dd0b7 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 98fac31b0613fc8cb88709a78c816d38d715fe11 +Subproject commit 356dd0b73a75ed6d56682c818b73145862881989 From 24bfcd9f32ce3c7903ed1d91afa50152a1498cd5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:22:18 +0000 Subject: [PATCH 024/102] Bump deps/libtommath from `37bd262` to `3f10a28` Bumps [deps/libtommath](https://github.com/libtom/libtommath) from `37bd262` to `3f10a28`. - [Release notes](https://github.com/libtom/libtommath/releases) - [Commits](https://github.com/libtom/libtommath/compare/37bd262cc22aeffaac5b9528ade3bf07fe8ea424...3f10a28885601256c8b5261be3b15c926c93393d) --- updated-dependencies: - dependency-name: deps/libtommath dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/libtommath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/libtommath b/deps/libtommath index 37bd262c..3f10a288 160000 --- a/deps/libtommath +++ b/deps/libtommath @@ -1 +1 @@ -Subproject commit 37bd262cc22aeffaac5b9528ade3bf07fe8ea424 +Subproject commit 3f10a28885601256c8b5261be3b15c926c93393d From 70ea07fd905c986000b32435207b3267f8dd8b9e Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 6 Apr 2023 21:16:42 +0200 Subject: [PATCH 025/102] Fix bytebuffer --- src/client/component/auth.cpp | 6 +++--- src/common/utils/byte_buffer.cpp | 18 +++++++++--------- src/common/utils/byte_buffer.hpp | 25 ++++++++++++++----------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index fba96ad8..4a76dddb 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -155,8 +155,8 @@ namespace auth void post_unpack() override { // Skip connect handler - //utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); - //network::on("connect", handle_connect_packet); + utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); + network::on("connect", handle_connect_packet); // Patch steam id bit check std::vector> patches{}; @@ -203,7 +203,7 @@ namespace auth p(0x141EB5992_g, 0x141EB59D5_g); p(0x141EB74D2_g, 0x141EB7515_g); // ? - //utils::hook::call(0x14134BF7D_g, send_connect_data_stub); + utils::hook::call(0x14134BF7D_g, send_connect_data_stub); } for (const auto& patch : patches) diff --git a/src/common/utils/byte_buffer.cpp b/src/common/utils/byte_buffer.cpp index 2ef0a3b0..76e02a00 100644 --- a/src/common/utils/byte_buffer.cpp +++ b/src/common/utils/byte_buffer.cpp @@ -17,28 +17,28 @@ namespace utils void byte_buffer::write(const void* buffer, const size_t length) { - if (!writing_) + if (!this->writing_) { throw std::runtime_error("Writing to readable byte buffer"); } - buffer_.append(static_cast(buffer), length); + this->buffer_.append(static_cast(buffer), length); } void byte_buffer::read(void* data, const size_t length) { - if (writing_) + if (this->writing_) { throw std::runtime_error("Reading from writable byte buffer"); } - if (offset_ + length > buffer_.size()) + if (this->offset_ + length > this->buffer_.size()) { throw std::runtime_error("Out of bounds read from byte buffer"); } - memcpy(data, buffer_.data() + offset_, length); - offset_ += length; + memcpy(data, this->buffer_.data() + this->offset_, length); + this->offset_ += length; } std::string byte_buffer::read_string() @@ -47,7 +47,7 @@ namespace utils while (true) { - const auto b = read(); + const auto b = this->read(); if (!b) { break; @@ -66,7 +66,7 @@ namespace utils for (size_t i = 0; i < length; ++i) { - result.push_back(read()); + result.push_back(this->read()); } return result; @@ -77,7 +77,7 @@ namespace utils std::vector result{}; result.resize(length); - read(result.data(), result.size()); + this->read(result.data(), result.size()); return result; } diff --git a/src/common/utils/byte_buffer.hpp b/src/common/utils/byte_buffer.hpp index 6a801968..8989cbbd 100644 --- a/src/common/utils/byte_buffer.hpp +++ b/src/common/utils/byte_buffer.hpp @@ -23,41 +23,41 @@ namespace utils void write(const std::string& string, const bool null_terminate = false) { const size_t addend = null_terminate ? 1 : 0; - write(string.data(), string.size() + addend); + this->write(string.data(), string.size() + addend); } void write_string(const std::string& string) { - write(string, true); + this->write(string, true); } template void write(const T& object) { - write(&object, sizeof(object)); + this->write(&object, sizeof(object)); } template void write(const std::vector& vec) { - write(vec.data(), vec.size() * sizeof(T)); + this->write(vec.data(), vec.size() * sizeof(T)); } template void write_vector(const std::vector& vec) { - write(static_cast(vec.size())); - write(vec); + this->write(static_cast(vec.size())); + this->write(vec); } const std::string& get_buffer() const { - return buffer_; + return this->buffer_; } std::string move_buffer() { - return std::move(buffer_); + return std::move(this->buffer_); } void read(void* data, size_t length); @@ -66,7 +66,7 @@ namespace utils T read() { T object{}; - read(&object, sizeof(object)); + this->read(&object, sizeof(object)); return object; } @@ -75,12 +75,15 @@ namespace utils { std::vector result{}; const auto size = read(); - if (offset_ + size > buffer_.size()) + const auto totalSize = size * sizeof(T); + + if (this->offset_ + totalSize > this->buffer_.size()) { throw std::runtime_error("Out of bounds read from byte buffer"); } - read(result.data(), size); + result.resize(size); + this->read(result.data(), totalSize); return result; } From c569ed5d8dc23a3222f7c5eb7db8e2f64fe6d194 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 6 Apr 2023 22:04:20 +0200 Subject: [PATCH 026/102] Prepare profile info distribution --- src/client/component/auth.cpp | 31 ++++++++++----- src/client/component/profile_infos.cpp | 55 +++++++++++++++++++++----- src/client/component/profile_infos.hpp | 14 ++++++- src/common/utils/byte_buffer.cpp | 31 --------------- src/common/utils/byte_buffer.hpp | 37 ++++++++++++----- src/common/utils/info_string.cpp | 5 +++ src/common/utils/info_string.hpp | 5 ++- 7 files changed, 116 insertions(+), 62 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 4a76dddb..22086bce 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -4,6 +4,7 @@ #include "auth.hpp" #include "command.hpp" #include "network.hpp" +#include "profile_infos.hpp" #include @@ -15,6 +16,7 @@ #include #include + namespace auth { namespace @@ -95,10 +97,10 @@ namespace auth return !is_first; } - std::string serialize_connect_data(const std::vector& data) + std::string serialize_connect_data(const char* data, const int length) { utils::byte_buffer buffer{}; - buffer.write_vector(data); + buffer.write_string(data, static_cast(length)); return buffer.move_buffer(); } @@ -110,12 +112,9 @@ namespace auth const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; if (is_connect_sequence) { - std::vector connect_data{}; - connect_data.assign(data, data + len); - buffer.append("connect"); buffer.push_back(' '); - buffer.append(serialize_connect_data(connect_data)); + buffer.append(serialize_connect_data(data, len)); data = buffer.data(); len = static_cast(buffer.size()); @@ -126,10 +125,24 @@ namespace auth void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) { - utils::byte_buffer buffer(data); + // TODO: SV running? - const auto text = buffer.read_vector(); - command::params_sv params(std::string(text.data(), text.size())); + utils::byte_buffer buffer(data); + profile_infos::profile_info info(buffer); + + const auto connect_data = buffer.read_string(); + const command::params_sv params(connect_data); + + if (params.size() != 2) + { + return; + } + + const utils::info_string info_string(params[1]); + const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 10); + + profile_infos::add_profile_info(xuid, std::move(info)); + profile_infos::distribute_profile_infos(); game::SV_DirectConnect(target); } diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index d03ccc49..10ea2ad9 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -3,6 +3,7 @@ #include "profile_infos.hpp" #include "network.hpp" +#include "party.hpp" #include #include @@ -29,7 +30,7 @@ namespace profile_infos profile_info info{}; constexpr auto version_size = sizeof(info.version); - if(data.size() < sizeof(version_size)) + if (data.size() < sizeof(version_size)) { return {}; } @@ -37,10 +38,40 @@ namespace profile_infos memcpy(&info.version, data.data(), version_size); info.ddl.assign(data.begin() + version_size, data.end()); - return { std::move(info) }; + return {std::move(info)}; } } + profile_info::profile_info(utils::byte_buffer& buffer) + { + this->version = buffer.read(); + this->ddl = buffer.read_string(); + } + + void profile_info::serialize(utils::byte_buffer& buffer) const + { + buffer.write(this->version); + buffer.write_string(this->ddl); + } + + void add_profile_info(const uint64_t user_id, profile_info info) + { + if (user_id == steam::SteamUser()->GetSteamID().bits) + { + return; + } + + profile_mapping.access([&](profile_map& profiles) + { + profiles[user_id] = std::move(info); + }); + } + + void distribute_profile_infos() + { + // TODO + } + std::optional get_profile_info(uint64_t user_id) { if (user_id == steam::SteamUser()->GetSteamID().bits) @@ -73,17 +104,23 @@ namespace profile_infos utils::io::write_file("players/user/profile_info", data); } - struct component final : generic_component + struct component final : client_component { - void post_load() override - { - } - void post_unpack() override { - /*network::on("profileInfo", [](const game::netadr_t& server, const network::data_view& data) + network::on("profileInfo", [](const game::netadr_t& server, const network::data_view& data) { - });*/ + if (party::get_connected_server() != server) + { + return; + } + + utils::byte_buffer buffer(data); + const auto user_id = buffer.read(); + const profile_info info(buffer); + + add_profile_info(user_id, info); + }); } }; } diff --git a/src/client/component/profile_infos.hpp b/src/client/component/profile_infos.hpp index e0f8cf5d..f875bf67 100644 --- a/src/client/component/profile_infos.hpp +++ b/src/client/component/profile_infos.hpp @@ -1,13 +1,23 @@ #pragma once +#include + namespace profile_infos { struct profile_info { - int32_t version; - std::string ddl; + int32_t version{3}; + std::string ddl{}; + + profile_info() = default; + profile_info(utils::byte_buffer& buffer); + void serialize(utils::byte_buffer& buffer) const; }; + void add_profile_info(uint64_t user_id, profile_info info); + + void distribute_profile_infos(); + std::optional get_profile_info(uint64_t user_id); void update_profile_info(const profile_info& info); } diff --git a/src/common/utils/byte_buffer.cpp b/src/common/utils/byte_buffer.cpp index 76e02a00..7a3d5b94 100644 --- a/src/common/utils/byte_buffer.cpp +++ b/src/common/utils/byte_buffer.cpp @@ -41,37 +41,6 @@ namespace utils this->offset_ += length; } - std::string byte_buffer::read_string() - { - std::string result{}; - - while (true) - { - const auto b = this->read(); - if (!b) - { - break; - } - - result.push_back(b); - } - - return result; - } - - std::string byte_buffer::read_string(const size_t length) - { - std::string result{}; - result.reserve(length); - - for (size_t i = 0; i < length; ++i) - { - result.push_back(this->read()); - } - - return result; - } - std::vector byte_buffer::read_data(const size_t length) { std::vector result{}; diff --git a/src/common/utils/byte_buffer.hpp b/src/common/utils/byte_buffer.hpp index 8989cbbd..c4c33ec7 100644 --- a/src/common/utils/byte_buffer.hpp +++ b/src/common/utils/byte_buffer.hpp @@ -20,15 +20,20 @@ namespace utils void write(const void* buffer, size_t length); - void write(const std::string& string, const bool null_terminate = false) + void write_string(const char* str, const size_t length) { - const size_t addend = null_terminate ? 1 : 0; - this->write(string.data(), string.size() + addend); + this->write(static_cast(length)); + this->write(str, length); } - void write_string(const std::string& string) + void write_string(const std::string& str) { - this->write(string, true); + this->write_string(str.data(), str.size()); + } + + void write_string(const char* str) + { + this->write_string(str, strlen(str)); } template @@ -46,7 +51,7 @@ namespace utils template void write_vector(const std::vector& vec) { - this->write(static_cast(vec.size())); + this->write(static_cast(vec.size())); this->write(vec); } @@ -74,7 +79,7 @@ namespace utils std::vector read_vector() { std::vector result{}; - const auto size = read(); + const auto size = this->read(); const auto totalSize = size * sizeof(T); if (this->offset_ + totalSize > this->buffer_.size()) @@ -88,8 +93,22 @@ namespace utils return result; } - std::string read_string(); - std::string read_string(size_t length); + std::string read_string() + { + std::string result{}; + const auto size = this->read(); + + if (this->offset_ + size > this->buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } + + result.resize(size); + this->read(result.data(), size); + + return result; + } + std::vector read_data(size_t length); private: diff --git a/src/common/utils/info_string.cpp b/src/common/utils/info_string.cpp index bdb3ad1f..d6f401ea 100644 --- a/src/common/utils/info_string.cpp +++ b/src/common/utils/info_string.cpp @@ -8,6 +8,11 @@ namespace utils this->parse(buffer); } + info_string::info_string(const char* buffer) + : info_string(std::string{buffer}) + { + } + info_string::info_string(const std::string_view& buffer) : info_string(std::string{buffer}) { diff --git a/src/common/utils/info_string.hpp b/src/common/utils/info_string.hpp index 776739ab..4e3e4bc9 100644 --- a/src/common/utils/info_string.hpp +++ b/src/common/utils/info_string.hpp @@ -9,8 +9,9 @@ namespace utils { public: info_string() = default; - info_string(const std::string& buffer); - info_string(const std::string_view& buffer); + explicit info_string(const std::string& buffer); + explicit info_string(const char* buffer); + explicit info_string(const std::string_view& buffer); info_string(const std::basic_string_view& buffer); void set(const std::string& key, const std::string& value); From a939a536f37c595bb13c11ffeff7d1519239e037 Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Thu, 6 Apr 2023 23:55:10 +0200 Subject: [PATCH 027/102] Workaround out-of-gobblegums --- src/client/component/script.cpp | 8 ++++++++ src/client/game/symbols.hpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/client/component/script.cpp b/src/client/component/script.cpp index f840f406..4a9e3eb6 100644 --- a/src/client/component/script.cpp +++ b/src/client/component/script.cpp @@ -13,6 +13,8 @@ namespace script namespace { utils::hook::detour db_findxassetheader_hook; + utils::hook::detour gscr_get_bgb_remaining_hook; + std::unordered_map loaded_scripts; game::RawFile* get_loaded_script(const std::string& name) @@ -110,6 +112,11 @@ namespace script return asset_header; } + + void gscr_get_bgb_remaining_stub(game::scriptInstance_t inst, void* entref) + { + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, 255); + } } struct component final : generic_component @@ -126,6 +133,7 @@ namespace script } db_findxassetheader_hook.create(game::select(0x141420ED0, 0x1401D5FB0), db_findxassetheader_stub); + gscr_get_bgb_remaining_hook.create(game::select(0x141A8CAB0, 0x1402D2310), gscr_get_bgb_remaining_stub); } }; }; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index c2fd5aec..7d41fc0e 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -139,7 +139,7 @@ namespace game WEAK symbol CL_CheckKeepDrawingConnectScreen{0x1413CCAE0}; // Scr - WEAK symbol Scr_AddInt{0x0, 0x14016F160}; + WEAK symbol Scr_AddInt{0x1412E9870, 0x14016F160}; WEAK symbol Scr_AddString{0x0, 0x14016F320}; WEAK symbol Scr_GetString{0x0, 0x140171490}; WEAK symbol Scr_Notify_Canon{ From 26a56b0602114a5d787329be65311c78cd11982d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 09:01:36 +0200 Subject: [PATCH 028/102] More profile info progress --- src/client/component/auth.cpp | 3 +- src/client/component/party.cpp | 7 ++ src/client/component/party.hpp | 2 + src/client/component/profile_infos.cpp | 94 ++++++++++++++++++++++++-- src/client/component/profile_infos.hpp | 7 +- 5 files changed, 101 insertions(+), 12 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 22086bce..cc909f66 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -141,8 +141,7 @@ namespace auth const utils::info_string info_string(params[1]); const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 10); - profile_infos::add_profile_info(xuid, std::move(info)); - profile_infos::distribute_profile_infos(); + profile_infos::add_and_distribute_profile_info(target, xuid, info); game::SV_DirectConnect(target); } diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index be598d14..7a80a301 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -6,6 +6,7 @@ #include "network.hpp" #include "scheduler.hpp" #include "workshop.hpp" +#include "profile_infos.hpp" #include #include @@ -211,6 +212,7 @@ namespace party connect_host = target; } + profile_infos::clear_profile_infos(); query_server(connect_host, handle_connect_query_response); } @@ -314,6 +316,11 @@ namespace party return *reinterpret_cast(address); } + bool is_host(const game::netadr_t& addr) + { + return get_connected_server() == addr || connect_host == addr; + } + struct component final : client_component { void post_unpack() override diff --git a/src/client/component/party.hpp b/src/client/component/party.hpp index 4bca8966..f682a14e 100644 --- a/src/client/component/party.hpp +++ b/src/client/component/party.hpp @@ -9,4 +9,6 @@ namespace party void query_server(const game::netadr_t& host, query_callback callback); game::netadr_t get_connected_server(); + + bool is_host(const game::netadr_t& addr); } diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 10ea2ad9..576217b1 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -12,12 +12,14 @@ #include "../steam/steam.hpp" #include +#include "game/utils.hpp" + namespace profile_infos { namespace { using profile_map = std::unordered_map; - utils::concurrency::container profile_mapping; + utils::concurrency::container profile_mapping{}; std::optional load_profile_info() { @@ -40,6 +42,49 @@ namespace profile_infos return {std::move(info)}; } + + int get_max_client_count() + { + return game::get_dvar_int("com_maxclients"); + } + + void send_profile_info(const game::netadr_t& address, const std::string& buffer) + { + network::send(address, "profileInfo", buffer); + } + + template + void distribute_profile_info(T* client_states, const std::string& buffer) + { + if (!client_states) + { + return; + } + + for (int i = 0; i < get_max_client_count(); ++i) + { + if (client_states[i].client_state > 0) + { + send_profile_info(client_states[i].address, buffer); + } + } + } + + void distribute_profile_info(const uint64_t user_id, const profile_info& info) + { + utils::byte_buffer buffer{}; + buffer.write(user_id); + info.serialize(buffer); + + if (game::is_server()) + { + distribute_profile_info(*game::svs_clients, buffer.get_buffer()); + } + else + { + distribute_profile_info(*game::svs_clients_cl, buffer.get_buffer()); + } + } } profile_info::profile_info(utils::byte_buffer& buffer) @@ -54,26 +99,61 @@ namespace profile_infos buffer.write_string(this->ddl); } - void add_profile_info(const uint64_t user_id, profile_info info) + void add_profile_info(const uint64_t user_id, const profile_info& info) { if (user_id == steam::SteamUser()->GetSteamID().bits) { return; } + printf("Adding profile info: %llX\n", user_id); + profile_mapping.access([&](profile_map& profiles) { - profiles[user_id] = std::move(info); + profiles[user_id] = info; }); } - void distribute_profile_infos() + void distribute_profile_info_to_user(const game::netadr_t& addr, const uint64_t user_id, const profile_info& info) { - // TODO + utils::byte_buffer buffer{}; + buffer.write(user_id); + info.serialize(buffer); + + send_profile_info(addr, buffer.get_buffer()); } - std::optional get_profile_info(uint64_t user_id) + void distribute_profile_infos_to_user(const game::netadr_t& addr) { + profile_mapping.access([&](const profile_map& profiles) + { + for (const auto& entry : profiles) + { + distribute_profile_info_to_user(addr, entry.first, entry.second); + } + }); + } + + void add_and_distribute_profile_info(const game::netadr_t& addr, const uint64_t user_id, const profile_info& info) + { + distribute_profile_infos_to_user(addr); + + add_profile_info(user_id, info); + distribute_profile_info(user_id, info); + } + + void clear_profile_infos() + { + profile_mapping.access([&](profile_map& profiles) + { + profiles = {}; + }); + } + + std::optional get_profile_info(const uint64_t user_id) + { + printf("Requesting profile info: %llX\n", user_id); + if (user_id == steam::SteamUser()->GetSteamID().bits) { return load_profile_info(); @@ -110,7 +190,7 @@ namespace profile_infos { network::on("profileInfo", [](const game::netadr_t& server, const network::data_view& data) { - if (party::get_connected_server() != server) + if (!party::is_host(server)) { return; } diff --git a/src/client/component/profile_infos.hpp b/src/client/component/profile_infos.hpp index f875bf67..a417a545 100644 --- a/src/client/component/profile_infos.hpp +++ b/src/client/component/profile_infos.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include namespace profile_infos @@ -14,9 +15,9 @@ namespace profile_infos void serialize(utils::byte_buffer& buffer) const; }; - void add_profile_info(uint64_t user_id, profile_info info); - - void distribute_profile_infos(); + void add_profile_info(uint64_t user_id, const profile_info& info); + void add_and_distribute_profile_info(const game::netadr_t& addr, uint64_t user_id, const profile_info& info); + void clear_profile_infos(); std::optional get_profile_info(uint64_t user_id); void update_profile_info(const profile_info& info); From 2f5eebebd0ec475bd74879e62b54ba8ffbf82a6c Mon Sep 17 00:00:00 2001 From: Diavolo Date: Fri, 7 Apr 2023 10:41:22 +0200 Subject: [PATCH 029/102] getinfo: add sv_running & more utils --- src/client/component/getinfo.cpp | 2 +- src/client/game/symbols.hpp | 5 +++++ src/client/game/utils.cpp | 13 +++++++++++++ src/client/game/utils.hpp | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index 1deb6826..496db001 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -109,7 +109,7 @@ namespace getinfo info.set("protocol", utils::string::va("%i", PROTOCOL)); info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode())); info.set("gamemode", utils::string::va("%i", Com_SessionMode_GetGameMode())); - //info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running"))); + info.set("sv_running", utils::string::va("%i", game::get_dvar_bool("sv_running"))); info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0)); info.set("shortversion", SHORTVERSION); diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 7d41fc0e..94887b58 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -105,10 +105,15 @@ namespace game WEAK symbol Dvar_DisplayableValue{0x1422BC080}; WEAK symbol Dvar_GetBool{0x1422BCED0}; WEAK symbol Dvar_GetInt{0x0, 0x140575C20}; + WEAK symbol Dvar_GetFLoat{0x0, 0x140575B20}; WEAK symbol Dvar_RegisterBool{ 0x1422D0900, 0x14057B500 }; + WEAK symbol Dvar_RegisterFloat{ + 0x0, 0x14057B6B0 + }; WEAK symbol Dvar_SessionModeRegisterBool{ 0x1422D0D40, 0x14057BAA0 diff --git a/src/client/game/utils.cpp b/src/client/game/utils.cpp index b33c08ef..74c650f1 100644 --- a/src/client/game/utils.cpp +++ b/src/client/game/utils.cpp @@ -83,6 +83,19 @@ namespace game return registered_dvar; } + const dvar_t* register_dvar_float(const char* dvar_name, float value, float min, float max, const int flags, const char* description) + { + const auto hash = Dvar_GenerateHash(dvar_name); + auto* registered_dvar = Dvar_RegisterFloat(hash, dvar_name, value, min, max, flags, description); + + if (registered_dvar) + { + registered_dvar->debugName = dvar_name; + } + + return registered_dvar; + } + const dvar_t* register_dvar_string(const char* dvar_name, const char* value, const int flags, const char* description) { const auto hash = Dvar_GenerateHash(dvar_name); diff --git a/src/client/game/utils.hpp b/src/client/game/utils.hpp index c59bbfc7..e08b9417 100644 --- a/src/client/game/utils.hpp +++ b/src/client/game/utils.hpp @@ -9,6 +9,7 @@ namespace game bool get_dvar_bool(const char* dvar_name); const dvar_t* register_dvar_bool(const char* dvar_name, bool value, int flags, const char* description); + const dvar_t* register_dvar_float(const char* dvar_name, float value, float min, float max, const int flags, const char* description); const dvar_t* register_sessionmode_dvar_bool(const char* dvar_name, bool value, int flags, const char* description, eModes mode = MODE_COUNT); const dvar_t* register_dvar_string(const char* dvar_name, const char* value, int flags, const char* description); void dvar_add_flags(const char* dvar, dvarFlags_e flags); From bee66b1e910cfa75b43f8ec129779d7ff49cc909 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 10:46:09 +0200 Subject: [PATCH 030/102] Finish profile infos --- src/client/component/auth.cpp | 8 +++++--- src/client/component/profile_infos.cpp | 21 ++++++++++++++++++++- src/client/component/profile_infos.hpp | 2 ++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index cc909f66..a8bfd8eb 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -100,6 +100,8 @@ namespace auth std::string serialize_connect_data(const char* data, const int length) { utils::byte_buffer buffer{}; + profile_infos::get_profile_info().value_or(profile_infos::profile_info{}).serialize(buffer); + buffer.write_string(data, static_cast(length)); return buffer.move_buffer(); @@ -128,18 +130,18 @@ namespace auth // TODO: SV running? utils::byte_buffer buffer(data); - profile_infos::profile_info info(buffer); + const profile_infos::profile_info info(buffer); const auto connect_data = buffer.read_string(); const command::params_sv params(connect_data); - if (params.size() != 2) + if (params.size() < 2) { return; } const utils::info_string info_string(params[1]); - const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 10); + const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 16); profile_infos::add_and_distribute_profile_info(target, xuid, info); diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 576217b1..24c9ba68 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -72,6 +72,11 @@ namespace profile_infos void distribute_profile_info(const uint64_t user_id, const profile_info& info) { + if (user_id == steam::SteamUser()->GetSteamID().bits) + { + return; + } + utils::byte_buffer buffer{}; buffer.write(user_id); info.serialize(buffer); @@ -132,6 +137,15 @@ namespace profile_infos distribute_profile_info_to_user(addr, entry.first, entry.second); } }); + + if (!game::is_server()) + { + const auto info = get_profile_info(); + if (info) + { + distribute_profile_info_to_user(addr, steam::SteamUser()->GetSteamID().bits, *info); + } + } } void add_and_distribute_profile_info(const game::netadr_t& addr, const uint64_t user_id, const profile_info& info) @@ -150,13 +164,18 @@ namespace profile_infos }); } + std::optional get_profile_info() + { + return load_profile_info(); + } + std::optional get_profile_info(const uint64_t user_id) { printf("Requesting profile info: %llX\n", user_id); if (user_id == steam::SteamUser()->GetSteamID().bits) { - return load_profile_info(); + return get_profile_info(); } return profile_mapping.access>([user_id](const profile_map& profiles) diff --git a/src/client/component/profile_infos.hpp b/src/client/component/profile_infos.hpp index a417a545..c1cfd1f8 100644 --- a/src/client/component/profile_infos.hpp +++ b/src/client/component/profile_infos.hpp @@ -19,6 +19,8 @@ namespace profile_infos void add_and_distribute_profile_info(const game::netadr_t& addr, uint64_t user_id, const profile_info& info); void clear_profile_infos(); + + std::optional get_profile_info(); std::optional get_profile_info(uint64_t user_id); void update_profile_info(const profile_info& info); } From 363f8cb01a070795101ac07fdae43e26aec9d885 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 12:12:19 +0200 Subject: [PATCH 031/102] Trigger pcache updates --- src/client/component/auth.cpp | 7 +++- src/client/component/profile_infos.cpp | 55 ++++++++++++++++++++------ src/client/game/symbols.hpp | 3 ++ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index a8bfd8eb..7385be95 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -7,6 +7,7 @@ #include "profile_infos.hpp" #include +#include #include #include @@ -16,7 +17,6 @@ #include #include - namespace auth { namespace @@ -127,7 +127,10 @@ namespace auth void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) { - // TODO: SV running? + if (!game::get_dvar_bool("sv_running")) + { + return; + } utils::byte_buffer buffer(data); const profile_infos::profile_info info(buffer); diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 24c9ba68..46fa2c6d 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -4,6 +4,7 @@ #include "profile_infos.hpp" #include "network.hpp" #include "party.hpp" +#include "scheduler.hpp" #include #include @@ -90,6 +91,31 @@ namespace profile_infos distribute_profile_info(*game::svs_clients_cl, buffer.get_buffer()); } } + + void schedule_pcache_update() + { + static std::atomic_bool update_triggered{false}; + if (game::is_server() || update_triggered.exchange(true)) + { + return; + } + + scheduler::once([] + { + game::PCache_DeleteEntries(game::CONTROLLER_INDEX_FIRST); + update_triggered = false; + }, scheduler::main, 5s); + } + + void clean_cached_profile_infos() + { + if (!game::get_dvar_bool("sv_running")) + { + return; + } + + // TODO + } } profile_info::profile_info(utils::byte_buffer& buffer) @@ -111,12 +137,12 @@ namespace profile_infos return; } - printf("Adding profile info: %llX\n", user_id); - profile_mapping.access([&](profile_map& profiles) { profiles[user_id] = info; }); + + schedule_pcache_update(); } void distribute_profile_info_to_user(const game::netadr_t& addr, const uint64_t user_id, const profile_info& info) @@ -203,23 +229,28 @@ namespace profile_infos utils::io::write_file("players/user/profile_info", data); } - struct component final : client_component + struct component final : generic_component { void post_unpack() override { - network::on("profileInfo", [](const game::netadr_t& server, const network::data_view& data) + scheduler::loop(clean_cached_profile_infos, scheduler::main, 5s); + + if (game::is_client()) { - if (!party::is_host(server)) + network::on("profileInfo", [](const game::netadr_t& server, const network::data_view& data) { - return; - } + if (!party::is_host(server)) + { + return; + } - utils::byte_buffer buffer(data); - const auto user_id = buffer.read(); - const profile_info info(buffer); + utils::byte_buffer buffer(data); + const auto user_id = buffer.read(); + const profile_info info(buffer); - add_profile_info(user_id, info); - }); + add_profile_info(user_id, info); + }); + } } }; } diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 6abf5b32..4f666024 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -157,6 +157,9 @@ namespace game 0x141CD98D0 }; + // PCache + WEAK symbol PCache_DeleteEntries{0x141E8D710}; + // SV WEAK symbol SV_Loaded{0x142252250, 0x140535460}; WEAK symbol SV_AddTestClient{0x142248F40, 0x14052E3E0}; From 9e7a567acb123ba6c1e6f1abbc70a8f2bcce005d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 13:55:43 +0200 Subject: [PATCH 032/102] Fix xuid offset --- src/client/component/bots.cpp | 2 -- src/client/component/dedicated_patches.cpp | 2 +- src/client/game/structs.hpp | 16 ++++++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 0d06afd0..2f334f62 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -115,8 +115,6 @@ namespace bots struct component final : generic_component { - static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); - void post_unpack() override { utils::hook::jump(game::select(0x141653B70, 0x1402732E0), get_bot_name); diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 48ed8326..6e7f249e 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -76,7 +76,7 @@ namespace dedicated_patches return 0; } - return static_cast(clients[client_num].guid); + return clients[client_num].xuid; } } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 9e35f729..1e852b6c 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1547,21 +1547,21 @@ namespace game int client_state; char __pad0[0x28]; netadr_t address; - char __pad1[0xBB318]; - int guid; - char __pad2[0x8]; - bool bIsTestClient; - char __pad3[0x25818]; + char __pad1[0x5588]; uint64_t xuid; - char __pad4[0x4588]; + char __pad2[0xB5D84]; + int guid; + char __pad3[0x8]; + bool bIsTestClient; + char __pad4[0x29DAC]; }; - static_assert(sizeof(client_s) == 0xE5110); + static_assert(sizeof(client_s) <= 0xE5110); static_assert(offsetof(game::client_s, address) == 0x2C); + static_assert(offsetof(game::client_s, xuid) == 0x55C8); static_assert(offsetof(game::client_s, guid) == 0xBB354); static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); - static_assert(offsetof(game::client_s, xuid) == 0xE0B80); struct client_s_cl : client_s { From fd8460349f61d3698fe7759b5d1b34feb1c56f38 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 14:25:56 +0200 Subject: [PATCH 033/102] Cleanup cached profile infos --- src/client/component/auth.cpp | 2 +- src/client/component/chat.cpp | 4 +- src/client/component/dedicated_info.cpp | 4 +- src/client/component/getinfo.cpp | 33 +++++------- src/client/component/getinfo.hpp | 5 +- src/client/component/profile_infos.cpp | 66 ++++++++++++----------- src/client/game/utils.cpp | 69 ++++++++++++++++++++++++- src/client/game/utils.hpp | 10 ++++ 8 files changed, 133 insertions(+), 60 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 7385be95..d5e2d4f6 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -127,7 +127,7 @@ namespace auth void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) { - if (!game::get_dvar_bool("sv_running")) + if (!game::is_server_running()) { return; } diff --git a/src/client/component/chat.cpp b/src/client/component/chat.cpp index 7bb8a52e..41b1b44a 100644 --- a/src/client/component/chat.cpp +++ b/src/client/component/chat.cpp @@ -122,7 +122,7 @@ namespace chat // Overwrite say command utils::hook::jump(0x14052A6C0_g, +[] { - if (!game::get_dvar_bool("sv_running")) + if (!game::is_server_running()) { printf("Server is not running\n"); return; @@ -138,7 +138,7 @@ namespace chat // Overwrite tell command utils::hook::jump(0x14052A7E0_g, +[] { - if (!game::get_dvar_bool("sv_running")) + if (!game::is_server_running()) { printf("Server is not running\n"); return; diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp index c950a247..95089a2d 100644 --- a/src/client/component/dedicated_info.cpp +++ b/src/client/component/dedicated_info.cpp @@ -27,11 +27,11 @@ namespace dedicated_info const auto mapname = game::get_dvar_string("mapname"); - const std::string window_text = utils::string::va("%s on %s [%d/%d] (%d)", + const std::string window_text = utils::string::va("%s on %s [%zu/%zu] (%zu)", clean_server_name, mapname.data(), getinfo::get_client_count(), - getinfo::get_max_client_count(), + game::get_max_client_count(), getinfo::get_bot_count()); console::set_title(window_text); diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index 9e770266..17901992 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -41,33 +41,28 @@ namespace getinfo return count; } - int get_client_count() + size_t get_client_count() { - if (game::is_server()) + size_t count = 0; + game::foreach_connected_client([&count](const game::client_s&) { - return get_client_count(*game::svs_clients); - } + ++count; + }); - return get_client_count(*game::svs_clients_cl); + return count; } - int get_bot_count() + size_t get_bot_count() { - const auto client_states = game::is_server() ? *game::svs_clients : *game::svs_clients_cl; - if (!client_states) - { - return 0; - } + size_t count = 0; - int count = 0; - - for (int i = 0; i < get_max_client_count(); ++i) + game::foreach_connected_client([&count](const game::client_s&, const size_t index) { - if (game::SV_IsTestClient(i)) + if (game::SV_IsTestClient(static_cast(index))) { ++count; } - } + }); return count; } @@ -110,9 +105,9 @@ namespace getinfo info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); info.set("mapname", game::get_dvar_string("mapname")); info.set("isPrivate", game::get_dvar_string("g_password").empty() ? "0" : "1"); - info.set("clients", utils::string::va("%i", get_client_count())); - info.set("bots", utils::string::va("%i", get_bot_count())); - info.set("sv_maxclients", utils::string::va("%i", get_max_client_count())); + info.set("clients", utils::string::va("%zu", get_client_count())); + info.set("bots", utils::string::va("%zu", get_bot_count())); + info.set("sv_maxclients", utils::string::va("%zu", get_max_client_count())); info.set("protocol", utils::string::va("%i", PROTOCOL)); info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode())); info.set("gamemode", utils::string::va("%i", Com_SessionMode_GetGameMode())); diff --git a/src/client/component/getinfo.hpp b/src/client/component/getinfo.hpp index 5d9d14be..0bf43b4d 100644 --- a/src/client/component/getinfo.hpp +++ b/src/client/component/getinfo.hpp @@ -2,8 +2,7 @@ namespace getinfo { - int get_max_client_count(); - int get_client_count(); - int get_bot_count(); + size_t get_client_count(); + size_t get_bot_count(); bool is_host(); } diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 46fa2c6d..b72d192f 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -44,33 +44,11 @@ namespace profile_infos return {std::move(info)}; } - int get_max_client_count() - { - return game::get_dvar_int("com_maxclients"); - } - void send_profile_info(const game::netadr_t& address, const std::string& buffer) { network::send(address, "profileInfo", buffer); } - template - void distribute_profile_info(T* client_states, const std::string& buffer) - { - if (!client_states) - { - return; - } - - for (int i = 0; i < get_max_client_count(); ++i) - { - if (client_states[i].client_state > 0) - { - send_profile_info(client_states[i].address, buffer); - } - } - } - void distribute_profile_info(const uint64_t user_id, const profile_info& info) { if (user_id == steam::SteamUser()->GetSteamID().bits) @@ -82,14 +60,12 @@ namespace profile_infos buffer.write(user_id); info.serialize(buffer); - if (game::is_server()) + const std::string data = buffer.move_buffer(); + + game::foreach_connected_client([&](const game::client_s& client) { - distribute_profile_info(*game::svs_clients, buffer.get_buffer()); - } - else - { - distribute_profile_info(*game::svs_clients_cl, buffer.get_buffer()); - } + send_profile_info(client.address, data); + }); } void schedule_pcache_update() @@ -107,14 +83,42 @@ namespace profile_infos }, scheduler::main, 5s); } + std::unordered_set get_connected_client_xuids() + { + std::unordered_set connected_clients{}; + connected_clients.reserve(game::get_max_client_count()); + + game::foreach_connected_client([&](const game::client_s& client) + { + connected_clients.emplace(client.xuid); + }); + + return connected_clients; + } + void clean_cached_profile_infos() { - if (!game::get_dvar_bool("sv_running")) + if (!game::is_server_running()) { return; } - // TODO + const auto xuids = get_connected_client_xuids(); + + profile_mapping.access([&](profile_map& profiles) + { + for (auto i = profiles.begin(); i != profiles.end();) + { + if (xuids.contains(i->first)) + { + ++i; + } + else + { + i = profiles.erase(i); + } + } + }); } } diff --git a/src/client/game/utils.cpp b/src/client/game/utils.cpp index b33c08ef..051b3352 100644 --- a/src/client/game/utils.cpp +++ b/src/client/game/utils.cpp @@ -45,7 +45,8 @@ namespace game return dvar->current.value.enabled; } - const dvar_t* register_sessionmode_dvar_bool(const char* dvar_name, const bool value, const int flags, const char* description, const eModes mode) + const dvar_t* register_sessionmode_dvar_bool(const char* dvar_name, const bool value, const int flags, + const char* description, const eModes mode) { const auto hash = Dvar_GenerateHash(dvar_name); auto* registered_dvar = Dvar_SessionModeRegisterBool(hash, dvar_name, value, flags, description); @@ -83,7 +84,8 @@ namespace game return registered_dvar; } - const dvar_t* register_dvar_string(const char* dvar_name, const char* value, const int flags, const char* description) + const dvar_t* register_dvar_string(const char* dvar_name, const char* value, const int flags, + const char* description) { const auto hash = Dvar_GenerateHash(dvar_name); auto* registered_dvar = Dvar_RegisterString(hash, dvar_name, value, flags, description); @@ -135,4 +137,67 @@ namespace game dvar_to_change->flags = flags; } + + bool is_server_running() + { + return get_dvar_bool("sv_running"); + } + + size_t get_max_client_count() + { + return static_cast(get_dvar_int("com_maxclients")); + } + + template + static void foreach_client(T* client_states, const std::function& callback) + { + if (!client_states || !callback) + { + return; + } + + for (size_t i = 0; i < get_max_client_count(); ++i) + { + callback(client_states[i], i); + } + } + + void foreach_client(const std::function& callback) + { + if (is_server()) + { + foreach_client(*svs_clients, callback); + } + else + { + foreach_client(*svs_clients_cl, callback); + } + } + + void foreach_client(const std::function& callback) + { + foreach_client([&](client_s& client, size_t) + { + callback(client); + }); + } + + void foreach_connected_client(const std::function& callback) + { + foreach_client([&](client_s& client, const size_t index) + { + if (client.client_state > 0) + { + callback(client, index); + } + }); + } + + void foreach_connected_client(const std::function& callback) + { + foreach_connected_client([&](client_s& client, size_t) + { + callback(client); + }); + } } diff --git a/src/client/game/utils.hpp b/src/client/game/utils.hpp index c59bbfc7..a4e4de16 100644 --- a/src/client/game/utils.hpp +++ b/src/client/game/utils.hpp @@ -11,6 +11,16 @@ namespace game const dvar_t* register_dvar_bool(const char* dvar_name, bool value, int flags, const char* description); const dvar_t* register_sessionmode_dvar_bool(const char* dvar_name, bool value, int flags, const char* description, eModes mode = MODE_COUNT); const dvar_t* register_dvar_string(const char* dvar_name, const char* value, int flags, const char* description); + void dvar_add_flags(const char* dvar, dvarFlags_e flags); void dvar_set_flags(const char* dvar_name, dvarFlags_e flags); + + bool is_server_running(); + size_t get_max_client_count(); + + void foreach_client(const std::function& callback); + void foreach_client(const std::function& callback); + + void foreach_connected_client(const std::function& callback); + void foreach_connected_client(const std::function& callback); } From 5ed2a1355eff8649588a67ba6078bd8856ec06ba Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 14:33:23 +0200 Subject: [PATCH 034/102] Use new util --- src/client/component/getinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index e0d8a6a7..ee848f15 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -111,7 +111,7 @@ namespace getinfo info.set("protocol", utils::string::va("%i", PROTOCOL)); info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode())); info.set("gamemode", utils::string::va("%i", Com_SessionMode_GetGameMode())); - info.set("sv_running", utils::string::va("%i", game::get_dvar_bool("sv_running"))); + info.set("sv_running", utils::string::va("%i", game::is_server_running())); info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0)); info.set("shortversion", SHORTVERSION); From a28235df267f7c379129344e5b8a6d413750237f Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 14:37:34 +0200 Subject: [PATCH 035/102] Temporarily diable new protocol to merge changes --- src/client/component/auth.cpp | 8 +++++--- src/client/game/structs.hpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index d5e2d4f6..45405af4 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -172,8 +172,9 @@ namespace auth void post_unpack() override { // Skip connect handler - utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); - network::on("connect", handle_connect_packet); + //utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); + //network::on("connect", handle_connect_packet); + (void)&handle_connect_packet; // Patch steam id bit check std::vector> patches{}; @@ -220,7 +221,8 @@ namespace auth p(0x141EB5992_g, 0x141EB59D5_g); p(0x141EB74D2_g, 0x141EB7515_g); // ? - utils::hook::call(0x14134BF7D_g, send_connect_data_stub); + //utils::hook::call(0x14134BF7D_g, send_connect_data_stub); + (void)&send_connect_data_stub; } for (const auto& patch : patches) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 1e852b6c..a54fddbf 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1,6 +1,6 @@ #pragma once -#define PROTOCOL 2 +#define PROTOCOL 1 #ifdef __cplusplus namespace game From 4661b261274cdbe0340afab0c78b8cf7a9efb882 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 14:51:16 +0200 Subject: [PATCH 036/102] Revert "Temporarily diable new protocol to merge changes" This reverts commit 6d0d3510646121acf41f3164e283b60201fa2d81. --- src/client/component/auth.cpp | 8 +++----- src/client/game/structs.hpp | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 45405af4..d5e2d4f6 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -172,9 +172,8 @@ namespace auth void post_unpack() override { // Skip connect handler - //utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); - //network::on("connect", handle_connect_packet); - (void)&handle_connect_packet; + utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); + network::on("connect", handle_connect_packet); // Patch steam id bit check std::vector> patches{}; @@ -221,8 +220,7 @@ namespace auth p(0x141EB5992_g, 0x141EB59D5_g); p(0x141EB74D2_g, 0x141EB7515_g); // ? - //utils::hook::call(0x14134BF7D_g, send_connect_data_stub); - (void)&send_connect_data_stub; + utils::hook::call(0x14134BF7D_g, send_connect_data_stub); } for (const auto& patch : patches) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index a54fddbf..1e852b6c 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1,6 +1,6 @@ #pragma once -#define PROTOCOL 1 +#define PROTOCOL 2 #ifdef __cplusplus namespace game From f019f7f30a644da94694ecd4b4d643cf89c308ea Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 14:52:08 +0200 Subject: [PATCH 037/102] Remove debug print --- src/client/component/profile_infos.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index b72d192f..2badc361 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -201,8 +201,6 @@ namespace profile_infos std::optional get_profile_info(const uint64_t user_id) { - printf("Requesting profile info: %llX\n", user_id); - if (user_id == steam::SteamUser()->GetSteamID().bits) { return get_profile_info(); From 54519cdc0aba1ce1db050014a0e4975d7e8a148b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 14:52:39 +0200 Subject: [PATCH 038/102] Fix static assert --- src/client/game/structs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 1e852b6c..54dde0c0 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1556,7 +1556,7 @@ namespace game char __pad4[0x29DAC]; }; - static_assert(sizeof(client_s) <= 0xE5110); + static_assert(sizeof(client_s) == 0xE5110); static_assert(offsetof(game::client_s, address) == 0x2C); static_assert(offsetof(game::client_s, xuid) == 0x55C8); From c096712dae72e4aad197e0a479fca59059dbfae8 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 15:53:36 +0200 Subject: [PATCH 039/102] Fix Scr_AddInt --- src/client/game/symbols.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 22638c6d..f754090f 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -144,7 +144,7 @@ namespace game WEAK symbol CL_CheckKeepDrawingConnectScreen{0x1413CCAE0}; // Scr - WEAK symbol Scr_AddInt{0x0, 0x14016F160}; + WEAK symbol Scr_AddInt{0x1412E9870, 0x14016F160}; WEAK symbol Scr_AddString{0x0, 0x14016F320}; WEAK symbol Scr_GetString{0x0, 0x140171490}; WEAK symbol Scr_Notify_Canon{ From b2214c40e2ee15bb87f5b6d19489d67c926c59e0 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Fri, 7 Apr 2023 18:30:04 +0200 Subject: [PATCH 040/102] feat #367: added Engine.IsBoiii to lua state --- src/client/component/ui_scripting.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index a414c427..51dc4eaa 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -20,6 +20,7 @@ namespace ui_scripting std::unordered_map> converted_functions; + utils::hook::detour ui_init_hook; utils::hook::detour ui_cod_init_hook; utils::hook::detour ui_cod_lobbyui_init_hook; utils::hook::detour cl_first_snapshot_hook; @@ -192,7 +193,7 @@ namespace ui_scripting state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_SECURE; } - void start() + void setup_lua_globals() { globals = {}; @@ -204,6 +205,12 @@ namespace ui_scripting lua["print"] = function(reinterpret_cast(0x141D30290_g)); // hks::base_print lua["table"]["unpack"] = lua["unpack"]; lua["luiglobals"] = lua; + lua["Engine"]["IsBOIII"] = true; + } + + void start() + { + setup_lua_globals(); const utils::nt::library host{}; const auto folder = game::is_server() ? "lobby_scripts/" : "ui_scripts/"; @@ -223,6 +230,13 @@ namespace ui_scripting } } + void ui_init_stub(void* allocFunction, void* outOfMemoryFunction) + { + ui_init_hook.invoke(allocFunction, outOfMemoryFunction); + + setup_lua_globals(); + } + bool doneFirstSnapshot = false; void ui_cod_init_stub(const bool frontend) @@ -467,6 +481,7 @@ namespace ui_scripting return; } + ui_init_hook.create(0x142704FF0_g, ui_init_stub); cl_first_snapshot_hook.create(0x141320E60_g, cl_first_snapshot_stub); scheduler::once([]() From 544acc44724c91a79584502f5abd9631a2795700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Apr 2023 18:00:56 +0000 Subject: [PATCH 041/102] Bump deps/curl from `356dd0b` to `4033642` Bumps [deps/curl](https://github.com/curl/curl) from `356dd0b` to `4033642`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/356dd0b73a75ed6d56682c818b73145862881989...403364293005ed54ef6230a214acee43e867995d) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 356dd0b7..40336429 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 356dd0b73a75ed6d56682c818b73145862881989 +Subproject commit 403364293005ed54ef6230a214acee43e867995d From 06916ac8801ccb66780dc33c337b26f4bf098d33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Apr 2023 18:01:02 +0000 Subject: [PATCH 042/102] Bump deps/rapidjson from `083f359` to `949c771` Bumps [deps/rapidjson](https://github.com/Tencent/rapidjson) from `083f359` to `949c771`. - [Release notes](https://github.com/Tencent/rapidjson/releases) - [Commits](https://github.com/Tencent/rapidjson/compare/083f359f5c36198accc2b9360ce1e32a333231d9...949c771b03de448bdedea80c44a4a5f65284bfeb) --- updated-dependencies: - dependency-name: deps/rapidjson dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/rapidjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rapidjson b/deps/rapidjson index 083f359f..949c771b 160000 --- a/deps/rapidjson +++ b/deps/rapidjson @@ -1 +1 @@ -Subproject commit 083f359f5c36198accc2b9360ce1e32a333231d9 +Subproject commit 949c771b03de448bdedea80c44a4a5f65284bfeb From fb57f0d55fb7e38d9db74a622d014c0ac60cfca5 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 7 Apr 2023 20:25:43 +0200 Subject: [PATCH 043/102] Fix profile info distribution --- src/client/component/auth.cpp | 10 +++++++++ src/client/component/profile_infos.cpp | 30 ++++++++------------------ src/client/component/profile_infos.hpp | 1 + src/common/utils/concurrency.hpp | 5 +++++ 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index d5e2d4f6..e870dfc5 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -143,12 +143,22 @@ namespace auth return; } + const auto _ = profile_infos::acquire_profile_lock(); + const utils::info_string info_string(params[1]); const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 16); profile_infos::add_and_distribute_profile_info(target, xuid, info); game::SV_DirectConnect(target); + + game::foreach_connected_client([&](game::client_s& client) + { + if (client.address == target) + { + client.xuid = xuid; + } + }); } } diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 2badc361..597be96a 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -20,7 +20,7 @@ namespace profile_infos namespace { using profile_map = std::unordered_map; - utils::concurrency::container profile_mapping{}; + utils::concurrency::container profile_mapping{}; std::optional load_profile_info() { @@ -68,21 +68,6 @@ namespace profile_infos }); } - void schedule_pcache_update() - { - static std::atomic_bool update_triggered{false}; - if (game::is_server() || update_triggered.exchange(true)) - { - return; - } - - scheduler::once([] - { - game::PCache_DeleteEntries(game::CONTROLLER_INDEX_FIRST); - update_triggered = false; - }, scheduler::main, 5s); - } - std::unordered_set get_connected_client_xuids() { std::unordered_set connected_clients{}; @@ -103,10 +88,10 @@ namespace profile_infos return; } - const auto xuids = get_connected_client_xuids(); - - profile_mapping.access([&](profile_map& profiles) + profile_mapping.access([](profile_map& profiles) { + const auto xuids = get_connected_client_xuids(); + for (auto i = profiles.begin(); i != profiles.end();) { if (xuids.contains(i->first)) @@ -145,8 +130,6 @@ namespace profile_infos { profiles[user_id] = info; }); - - schedule_pcache_update(); } void distribute_profile_info_to_user(const game::netadr_t& addr, const uint64_t user_id, const profile_info& info) @@ -194,6 +177,11 @@ namespace profile_infos }); } + std::unique_lock acquire_profile_lock() + { + return profile_mapping.acquire_lock(); + } + std::optional get_profile_info() { return load_profile_info(); diff --git a/src/client/component/profile_infos.hpp b/src/client/component/profile_infos.hpp index c1cfd1f8..611ba422 100644 --- a/src/client/component/profile_infos.hpp +++ b/src/client/component/profile_infos.hpp @@ -19,6 +19,7 @@ namespace profile_infos void add_and_distribute_profile_info(const game::netadr_t& addr, uint64_t user_id, const profile_info& info); void clear_profile_infos(); + std::unique_lock acquire_profile_lock(); std::optional get_profile_info(); std::optional get_profile_info(uint64_t user_id); diff --git a/src/common/utils/concurrency.hpp b/src/common/utils/concurrency.hpp index 75967525..e8be0db0 100644 --- a/src/common/utils/concurrency.hpp +++ b/src/common/utils/concurrency.hpp @@ -45,6 +45,11 @@ namespace utils::concurrency return object_; } + std::unique_lock acquire_lock() + { + return std::unique_lock{mutex_}; + } + private: mutable MutexType mutex_{}; T object_{}; From d8a8fee67e5341478dea6c6478125b1394cf17d2 Mon Sep 17 00:00:00 2001 From: Vlad Loktionov Date: Sat, 8 Apr 2023 00:35:41 +0300 Subject: [PATCH 044/102] Make launcher window use dark mode --- src/client/launcher/window.cpp | 8 ++++++++ src/client/launcher/window.hpp | 1 + src/client/std_include.hpp | 1 + 3 files changed, 10 insertions(+) diff --git a/src/client/launcher/window.cpp b/src/client/launcher/window.cpp index 1b6dc4a7..75564319 100644 --- a/src/client/launcher/window.cpp +++ b/src/client/launcher/window.cpp @@ -1,6 +1,10 @@ #include #include "window.hpp" +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + namespace { thread_local uint32_t window_count = 0; @@ -34,6 +38,10 @@ window::window(const std::string& title, const int width, const int height, this->handle_ = CreateWindowExA(NULL, this->wc_.lpszClassName, title.data(), flags, x, y, width, height, nullptr, nullptr, this->wc_.hInstance, this); + BOOL value = TRUE; + DwmSetWindowAttribute(this->handle_, + DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); + SendMessageA(this->handle_, WM_DPICHANGED, 0, 0); ShowWindow(this->handle_, SW_SHOW); SetForegroundWindow(this->handle_); diff --git a/src/client/launcher/window.hpp b/src/client/launcher/window.hpp index 9b840759..17808c4e 100644 --- a/src/client/launcher/window.hpp +++ b/src/client/launcher/window.hpp @@ -1,4 +1,5 @@ #pragma once +#pragma comment (lib, "dwmapi.lib") class window { diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index e64b1b8c..59b83a41 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include From 6e4b61c0f5777edd47038686288ceffe2199959a Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Sun, 9 Apr 2023 00:33:43 +0200 Subject: [PATCH 045/102] fix: changed new frontend buttons system so mods with custom buttons work, improved code --- data/ui_scripts/frontend_menus/__init__.lua | 121 ++++ data/ui_scripts/frontend_menus/utils.lua | 129 ++++ data/ui_scripts/stats/__init__.lua | 678 ++++++-------------- 3 files changed, 443 insertions(+), 485 deletions(-) create mode 100644 data/ui_scripts/frontend_menus/__init__.lua create mode 100644 data/ui_scripts/frontend_menus/utils.lua diff --git a/data/ui_scripts/frontend_menus/__init__.lua b/data/ui_scripts/frontend_menus/__init__.lua new file mode 100644 index 00000000..adf81bbb --- /dev/null +++ b/data/ui_scripts/frontend_menus/__init__.lua @@ -0,0 +1,121 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +local utils = require("utils") + +CoD.LobbyButtons.MP_STATS = { + stringRef = "STATS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "BoiiiStatsMenu", controller) + end, + customId = "btnMPStats" +} + +CoD.LobbyButtons.MP_START_GAME = { + stringRef = "MENU_START_GAME_CAPS", + action = function(self, element, controller, param, menu) + Engine.SetDvar("party_minplayers", 1) + Engine.Exec(nil, "launchgame") + end, + customId = "btnStartGame" +} + +CoD.LobbyButtons.SETTING_UP_BOTS = { + stringRef = "MENU_SETUP_BOTS_CAPS", + action = function(self, element, controller, param, menu) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", true) + OpenPopup(menu, "GameSettings_Bots", controller) + end, + customId = "btnSettingUpBots" +} + +CoD.LobbyButtons.MP_CUSTOM_SETUP_GAME = { + stringRef = "MPUI_SETUP_GAME_CAPS", + action = OpenSetupGameMP, + customId = "btnSetupGame", +} + +local shouldShowMapVote = false +local addCustomButtons = function(controller, menuId, buttonTable, isLeader) + if menuId == LobbyData.UITargets.UI_MPLOBBYONLINE.id or menuId == LobbyData.UITargets.UI_ZMLOBBYONLINE.id then + utils.AddSpacer(buttonTable) + utils.AddSmallButton(controller, buttonTable, CoD.LobbyButtons.MP_STATS) + end + + if menuId == LobbyData.UITargets.UI_MPLOBBYONLINE.id or menuId == LobbyData.UITargets.UI_ZMLOBBYONLINE.id or menuId == LobbyData.UITargets.UI_MPLOBBYMAIN.id or menuId == LobbyData.UITargets.UI_MPLOBBYLANGAME.id then + Engine.Mods_Lists_UpdateUsermaps() + end + + if menuId == LobbyData.UITargets.UI_MPLOBBYONLINE.id then + shouldShowMapVote = true + elseif menuId == LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id then + if shouldShowMapVote == true then + shouldShowMapVote = false + Engine.Exec(nil, "LobbyStopDemo") -- Enable map vote at start lobby + end + utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.MP_START_GAME, 1) --Launch match button + utils.AddSpacer(buttonTable, 1) + + utils.AddSpacer(buttonTable) + utils.AddSmallButton(controller, buttonTable, CoD.LobbyButtons.MP_CUSTOM_SETUP_GAME) --Setup game in public lobby + elseif menuId == LobbyData.UITargets.UI_MPLOBBYONLINEARENAGAME.id then + utils.AddSpacer(buttonTable) + utils.AddSmallButton(controller, buttonTable, CoD.LobbyButtons.SETTING_UP_BOTS) --Bot setting button in public lobby + end +end + +local targetButtons = { + [LobbyData.UITargets.UI_MAIN.id] = CoD.LobbyMenus.ModeSelect, + [LobbyData.UITargets.UI_MODESELECT.id] = CoD.LobbyMenus.ModeSelect, + [LobbyData.UITargets.UI_CPLOBBYLANGAME.id] = CoD.LobbyMenus.CPButtonsLAN, + [LobbyData.UITargets.UI_CPLOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM, + [LobbyData.UITargets.UI_CPLOBBYONLINE.id] = CoD.LobbyMenus.CPButtonsOnline, + [LobbyData.UITargets.UI_CPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPButtonsPublicGame, + [LobbyData.UITargets.UI_CPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame, + [LobbyData.UITargets.UI_CP2LOBBYLANGAME.id] = CoD.LobbyMenus.CPZMButtonsLAN, + [LobbyData.UITargets.UI_CP2LOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM, + [LobbyData.UITargets.UI_CP2LOBBYONLINE.id] = CoD.LobbyMenus.CPZMButtonsOnline, + [LobbyData.UITargets.UI_CP2LOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPZMButtonsPublicGame, + [LobbyData.UITargets.UI_CP2LOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame, + [LobbyData.UITargets.UI_DOALOBBYLANGAME.id] = CoD.LobbyMenus.DOAButtonsLAN, + [LobbyData.UITargets.UI_DOALOBBYONLINE.id] = CoD.LobbyMenus.DOAButtonsOnline, + [LobbyData.UITargets.UI_DOALOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.DOAButtonsPublicGame, + [LobbyData.UITargets.UI_MPLOBBYLANGAME.id] = CoD.LobbyMenus.MPButtonsLAN, + [LobbyData.UITargets.UI_MPLOBBYMAIN.id] = CoD.LobbyMenus.MPButtonsMain, + [LobbyData.UITargets.UI_MPLOBBYONLINE.id] = CoD.LobbyMenus.MPButtonsOnline, + [LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.MPButtonsOnlinePublic, + [LobbyData.UITargets.UI_MPLOBBYONLINEMODGAME.id] = CoD.LobbyMenus.MPButtonsModGame, + [LobbyData.UITargets.UI_MPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.MPButtonsCustomGame, + [LobbyData.UITargets.UI_MPLOBBYONLINEARENA.id] = CoD.LobbyMenus.MPButtonsArena, + [LobbyData.UITargets.UI_MPLOBBYONLINEARENAGAME.id] = CoD.LobbyMenus.MPButtonsArenaGame, + [LobbyData.UITargets.UI_FRLOBBYONLINEGAME.id] = CoD.LobbyMenus.FRButtonsOnlineGame, + [LobbyData.UITargets.UI_FRLOBBYLANGAME.id] = CoD.LobbyMenus.FRButtonsLANGame, + [LobbyData.UITargets.UI_ZMLOBBYLANGAME.id] = CoD.LobbyMenus.ZMButtonsLAN, + [LobbyData.UITargets.UI_ZMLOBBYONLINE.id] = CoD.LobbyMenus.ZMButtonsOnline, + [LobbyData.UITargets.UI_ZMLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.ZMButtonsPublicGame, + [LobbyData.UITargets.UI_ZMLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.ZMButtonsCustomGame, + [LobbyData.UITargets.UI_MPLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame, + [LobbyData.UITargets.UI_ZMLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame +} + +CoD.LobbyMenus.AddButtonsForTarget = function(controller, id) + local buttonFunc = targetButtons[id] + local model = nil + if Engine.IsLobbyActive(Enum.LobbyType.LOBBY_TYPE_GAME) then + model = Engine.GetModel(DataSources.LobbyRoot.getModel(controller), "gameClient.isHost") + else + model = Engine.GetModel(DataSources.LobbyRoot.getModel(controller), "privateClient.isHost") + end + local isLeader = nil + if model ~= nil then + isLeader = Engine.GetModelValue(model) + else + isLeader = 1 + end + local result = {} + buttonFunc(controller, result, isLeader) + addCustomButtons(controller, id, result, isLeader) + return result +end diff --git a/data/ui_scripts/frontend_menus/utils.lua b/data/ui_scripts/frontend_menus/utils.lua new file mode 100644 index 00000000..d8190895 --- /dev/null +++ b/data/ui_scripts/frontend_menus/utils.lua @@ -0,0 +1,129 @@ +local IsGamescomDemo = function() + return Dvar.ui_execdemo_gamescom:get() +end + +local IsBetaDemo = function() + return Dvar.ui_execdemo_beta:get() +end + +local SetButtonState = function(button, state) + if state == nil then + return + elseif state == CoD.LobbyButtons.DISABLED then + button.disabled = true + elseif state == CoD.LobbyButtons.HIDDEN then + button.hidden = true + end +end + +local AddButton = function(controller, options, button, isLargeButton, index) + if button == nil then + return + end + + button.disabled = false + button.hidden = false + button.selected = false + button.warning = false + if button.defaultState ~= nil then + if button.defaultState == CoD.LobbyButtons.DISABLED then + button.disabled = true + elseif button.defaultState == CoD.LobbyButtons.HIDDEN then + button.hidden = true + end + end + if button.disabledFunc ~= nil then + button.disabled = button.disabledFunc(controller) + end + if button.visibleFunc ~= nil then + button.hidden = not button.visibleFunc(controller) + end + if IsBetaDemo() then + SetButtonState(button, button.demo_beta) + elseif IsGamescomDemo() then + SetButtonState(button, button.demo_gamescom) + end + if button.hidden then + return + end + local lobbyNav = LobbyData.GetLobbyNav() + if button.selectedFunc ~= nil then + button.selected = button.selectedFunc(button.selectedParam) + elseif CoD.LobbyMenus.History[lobbyNav] ~= nil then + button.selected = CoD.LobbyMenus.History[lobbyNav] == button.customId + end + if button.newBreadcrumbFunc then + local f8_local1 = button.newBreadcrumbFunc + if type(f8_local1) == "string" then + f8_local1 = LUI.getTableFromPath(f8_local1) + end + if f8_local1 then + button.isBreadcrumbNew = f8_local1(controller) + end + end + if button.warningFunc ~= nil then + button.warning = button.warningFunc(controller) + end + if button.starterPack == CoD.LobbyButtons.STARTERPACK_UPGRADE then + button.starterPackUpgrade = true + if IsStarterPack() then + button.disabled = false + end + end + if index ~= nil then + table.insert(options, index, { + optionDisplay = button.stringRef, + action = button.action, + param = button.param, + customId = button.customId, + isLargeButton = isLargeButton, + isLastButtonInGroup = false, + disabled = button.disabled, + selected = button.selected, + isBreadcrumbNew = button.isBreadcrumbNew, + warning = button.warning, + requiredChunk = button.selectedParam, + starterPackUpgrade = button.starterPackUpgrade, + unloadMod = button.unloadMod + }) + else + table.insert(options, { + optionDisplay = button.stringRef, + action = button.action, + param = button.param, + customId = button.customId, + isLargeButton = isLargeButton, + isLastButtonInGroup = false, + disabled = button.disabled, + selected = button.selected, + isBreadcrumbNew = button.isBreadcrumbNew, + warning = button.warning, + requiredChunk = button.selectedParam, + starterPackUpgrade = button.starterPackUpgrade, + unloadMod = button.unloadMod + }) + end +end + +local AddLargeButton = function(controller, options, button, index) + AddButton(controller, options, button, true, index) +end + +local AddSmallButton = function(controller, options, button, index) + AddButton(controller, options, button, false, index) +end + +local AddSpacer = function(options, index) + if index ~= nil then + options[index].isLastButtonInGroup = true + elseif 0 < #options then + options[#options].isLastButtonInGroup = true + end +end + +return { + AddButton = AddButton, + AddLargeButton = AddLargeButton, + AddSmallButton = AddSmallButton, + AddSpacer = AddSpacer +} diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua index f861651d..5ac66426 100644 --- a/data/ui_scripts/stats/__init__.lua +++ b/data/ui_scripts/stats/__init__.lua @@ -2,90 +2,107 @@ if Engine.GetCurrentMap() ~= "core_frontend" then return end -DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", function ( controller ) - local optionsTable = {} +DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", function(controller) + local optionsTable = {} local updateDvar = function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) - local oldValue = Engine.DvarInt( nil, dvarName ) - local newValue = f1_arg1.value - UpdateInfoModels( f1_arg1 ) - if oldValue == newValue then - return - end - Engine.SetDvar( dvarName, f1_arg1.value ) - if dvarName == "cg_unlockall_loot" then - Engine.SetDvar( "ui_enableAllHeroes", f1_arg1.value ) + local oldValue = Engine.DvarInt(nil, dvarName) + local newValue = f1_arg1.value + UpdateInfoModels(f1_arg1) + if oldValue == newValue then + return end - end + Engine.SetDvar(dvarName, f1_arg1.value) + if dvarName == "cg_unlockall_loot" then + Engine.SetDvar("ui_enableAllHeroes", f1_arg1.value) + end + end - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock All Loot", "Whether loot should be locked based on the player's stats or always unlocked.", "MPStatsSettings_unlock_loot", "cg_unlockall_loot", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar )) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Loot", + "Whether loot should be locked based on the player's stats or always unlocked.", "MPStatsSettings_unlock_loot", + "cg_unlockall_loot", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock All Purchases", "All items that need to be purchased with unlock tokens are unlocked.", "MPStatsSettings_purchase_all", "cg_unlockall_purchases", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar )) - end - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock All Attachments", "All attachments on weapons are unlocked.", "MPStatsSettings_unlockall_attachments", "cg_unlockall_attachments", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar )) - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock all Camos and Reticles", "All camos and reticles on weapons are unlocked.", "MPStatsSettings_unlockall_camos_and_reticles", "cg_unlockall_camos_and_reticles", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar )) - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock all Calling Cards", "All calling cards are unlocked.", "MPStatsSettings_unlockall_calling_cards", "cg_unlockall_calling_cards", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar )) - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock all Specialists Outfits", "All specialists outfits are unlocked.", "MPStatsSettings_unlockall_specialists_outfits", "cg_unlockall_specialists_outfits", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar )) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Purchases", + "All items that need to be purchased with unlock tokens are unlocked.", "MPStatsSettings_purchase_all", + "cg_unlockall_purchases", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + end + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock All Attachments", + "All attachments on weapons are unlocked.", + "MPStatsSettings_unlockall_attachments", "cg_unlockall_attachments", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Camos and Reticles", + "All camos and reticles on weapons are unlocked.", "MPStatsSettings_unlockall_camos_and_reticles", + "cg_unlockall_camos_and_reticles", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Calling Cards", "All calling cards are unlocked.", + "MPStatsSettings_unlockall_calling_cards", "cg_unlockall_calling_cards", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Specialists Outfits", + "All specialists outfits are unlocked.", "MPStatsSettings_unlockall_specialists_outfits", + "cg_unlockall_specialists_outfits", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) local rankLevels = {} if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then @@ -95,9 +112,9 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", fu end local rankObjs = {} local hasDefault = false - local currentRank = CoD.BlackMarketUtility.GetCurrentRank( controller ) + 1 + local currentRank = CoD.BlackMarketUtility.GetCurrentRank(controller) + 1 for index, value in ipairs(rankLevels) do - table.insert( rankObjs, { + table.insert(rankObjs, { name = value, value = value - 1, default = value == currentRank, @@ -110,7 +127,7 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", fu end if not hasDefault then - table.insert( rankObjs, { + table.insert(rankObjs, { name = currentRank, value = currentRank - 1, default = true, @@ -121,23 +138,23 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", fu local prestigeTable = {} for i = 0, 10 do - table.insert( prestigeTable, { + table.insert(prestigeTable, { name = i == 0 and "None" or i, value = i, - default = i == CoD.PrestigeUtility.GetCurrentPLevel( controller ), + default = i == CoD.PrestigeUtility.GetCurrentPLevel(controller), title = "Prestige", desc = "" }) end - local createSettingsDatasource = function ( controller, datasourceName, optionsTable, currentValue, loopEdges, action ) + local createSettingsDatasource = function(controller, datasourceName, optionsTable, currentValue, loopEdges, action) if currentValue == nil then currentValue = 0 end - DataSources[datasourceName] = DataSourceHelpers.ListSetup( datasourceName, function ( f47_arg0 ) + DataSources[datasourceName] = DataSourceHelpers.ListSetup(datasourceName, function(f47_arg0) local f47_local0 = {} - for f47_local4, f47_local5 in ipairs( optionsTable ) do - table.insert( f47_local0, { + for f47_local4, f47_local5 in ipairs(optionsTable) do + table.insert(f47_local0, { models = { text = optionsTable[f47_local4].name }, @@ -150,456 +167,147 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", fu action = action, selectIndex = optionsTable[f47_local4].value == currentValue, loopEdges = loopEdges, - showChangeIndicator = function ( f48_arg0, f48_arg1, f48_arg2 ) + showChangeIndicator = function(f48_arg0, f48_arg1, f48_arg2) return f48_arg0.default ~= true end } - } ) + }) end f47_local0[1].properties.first = true f47_local0[#optionsTable].properties.last = true return f47_local0 - end, nil, nil, nil ) + end, nil, nil, nil) return datasourceName end - - table.insert( optionsTable, { + + table.insert(optionsTable, { models = { name = "Rank Level", desc = "", image = nil, - optionsDatasource = createSettingsDatasource( controller, "MPStatsSettings_rank_level", rankObjs, CoD.BlackMarketUtility.GetCurrentRank( controller ), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) - UpdateInfoModels( f1_arg1 ) - local rankTable = nil - if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then - rankTable = "gamedata/tables/mp/mp_ranktable.csv" - elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then - rankTable = "gamedata/tables/zm/zm_ranktable.csv" - end - local skipLines = Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER and 3 or 2 - local maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, f1_arg1.value + skipLines, 7)) - if maxXp == nil then - maxXp = 9999999999 - end - Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp - 1) - Engine.ExecNow(f1_arg0, "statsetbyname rank " .. f1_arg1.value) - Engine.Exec( f1_arg0, "uploadstats " .. tostring( Engine.CurrentSessionMode() ) ) - end ) + optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_level", rankObjs, + CoD.BlackMarketUtility.GetCurrentRank(controller), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + UpdateInfoModels(f1_arg1) + local rankTable = nil + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + rankTable = "gamedata/tables/mp/mp_ranktable.csv" + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + rankTable = "gamedata/tables/zm/zm_ranktable.csv" + end + local skipLines = Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER and 3 or 2 + local maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, f1_arg1.value + skipLines, 7)) + if maxXp == nil then + maxXp = 9999999999 + end + Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp - 1) + Engine.ExecNow(f1_arg0, "statsetbyname rank " .. f1_arg1.value) + Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + end) }, properties = { - revert = function ( f50_arg0 ) end + revert = function(f50_arg0) + end } }) - table.insert( optionsTable, { + table.insert(optionsTable, { models = { name = "Prestige", desc = "", image = nil, - optionsDatasource = createSettingsDatasource( controller, "MPStatsSettings_rank_prestige", prestigeTable, CoD.PrestigeUtility.GetCurrentPLevel( controller ), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) - UpdateInfoModels( f1_arg1 ) - local newPrestige = f1_arg1.value - Engine.ExecNow(f1_arg0, "statsetbyname plevel " .. newPrestige) - Engine.ExecNow(f1_arg0, "statsetbyname hasprestiged " .. (newPrestige > 0 and 1 or 0)) - Engine.Exec( f1_arg0, "uploadstats " .. tostring( Engine.CurrentSessionMode() ) ) - end ) + optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_prestige", prestigeTable, + CoD.PrestigeUtility.GetCurrentPLevel(controller), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + UpdateInfoModels(f1_arg1) + local newPrestige = f1_arg1.value + Engine.ExecNow(f1_arg0, "statsetbyname plevel " .. newPrestige) + Engine.ExecNow(f1_arg0, "statsetbyname hasprestiged " .. (newPrestige > 0 and 1 or 0)) + Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + end) }, properties = { - revert = function ( f50_arg0 ) end + revert = function(f50_arg0) + end } }) - - return optionsTable + + return optionsTable end) if Dvar.cg_unlockall_loot:get() == true then - Engine.SetDvar( "ui_enableAllHeroes", 1 ) + Engine.SetDvar("ui_enableAllHeroes", 1) end -LUI.createMenu.BoiiiStatsMenu = function ( controller ) - local self = CoD.Menu.NewForUIEditor( "BoiiiStatsMenu" ) +LUI.createMenu.BoiiiStatsMenu = function(controller) + local self = CoD.Menu.NewForUIEditor("BoiiiStatsMenu") if PreLoadFunc then - PreLoadFunc( self, controller ) + PreLoadFunc(self, controller) end self.soundSet = "ChooseDecal" - self:setOwner( controller ) - self:setLeftRight( true, true, 0, 0 ) - self:setTopBottom( true, true, 0, 0 ) - self:playSound( "menu_open", controller ) - self.buttonModel = Engine.CreateModel( Engine.GetModelForController( controller ), "BoiiiStatsMenu.buttonPrompts" ) + self:setOwner(controller) + self:setLeftRight(true, true, 0, 0) + self:setTopBottom(true, true, 0, 0) + self:playSound("menu_open", controller) + self.buttonModel = Engine.CreateModel(Engine.GetModelForController(controller), "BoiiiStatsMenu.buttonPrompts") self.anyChildUsesUpdateState = true - local GameSettingsBackground = CoD.GameSettings_Background.new( self, controller ) - GameSettingsBackground:setLeftRight( true, true, 0, 0 ) - GameSettingsBackground:setTopBottom( true, true, 0, 0 ) - GameSettingsBackground.MenuFrame.titleLabel:setText( Engine.Localize( "STATS SETTINGS" ) ) - GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText( Engine.Localize( "STATS SETTINGS" ) ) - GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeInfo:setAlpha( 0 ) - GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeName:setAlpha( 0 ) - self:addElement( GameSettingsBackground ) + local GameSettingsBackground = CoD.GameSettings_Background.new(self, controller) + GameSettingsBackground:setLeftRight(true, true, 0, 0) + GameSettingsBackground:setTopBottom(true, true, 0, 0) + GameSettingsBackground.MenuFrame.titleLabel:setText(Engine.Localize("STATS SETTINGS")) + GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText(Engine + .Localize("STATS SETTINGS")) + GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeInfo:setAlpha(0) + GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeName:setAlpha(0) + self:addElement(GameSettingsBackground) self.GameSettingsBackground = GameSettingsBackground - local Options = CoD.Competitive_SettingsList.new( self, controller ) - Options:setLeftRight( true, false, 26, 741 ) - Options:setTopBottom( true, false, 135, 720 ) - Options.Title.DescTitle:setText( Engine.Localize( "Stats" ) ) - Options.ButtonList:setVerticalCount( 15 ) - Options.ButtonList:setDataSource( "MPStatsSettings" ) - self:addElement( Options ) + local Options = CoD.Competitive_SettingsList.new(self, controller) + Options:setLeftRight(true, false, 26, 741) + Options:setTopBottom(true, false, 135, 720) + Options.Title.DescTitle:setText(Engine.Localize("Stats")) + Options.ButtonList:setVerticalCount(15) + Options.ButtonList:setDataSource("MPStatsSettings") + self:addElement(Options) self.Options = Options - self:AddButtonCallbackFunction( self, controller, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, nil, function ( element, menu, controller, model ) - GoBack( self, controller ) - SetPerControllerTableProperty( controller, "disableGameSettingsOptions", nil ) - return true - end, function ( element, menu, controller ) - CoD.Menu.SetButtonLabel( menu, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, "MENU_BACK" ) - return true - end, false ) + self:AddButtonCallbackFunction(self, controller, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, nil, + function(element, menu, controller, model) + GoBack(self, controller) + SetPerControllerTableProperty(controller, "disableGameSettingsOptions", nil) + return true + end, function(element, menu, controller) + CoD.Menu.SetButtonLabel(menu, Enum.LUIButton.LUI_KEY_XBB_PSCIRCLE, "MENU_BACK") + return true + end, false) - GameSettingsBackground.MenuFrame:setModel( self.buttonModel, controller ) - Options.id = "Options" + GameSettingsBackground.MenuFrame:setModel(self.buttonModel, controller) + Options.id = "Options" - self:processEvent( { + self:processEvent({ name = "menu_loaded", controller = controller - } ) - self:processEvent( { + }) + self:processEvent({ name = "update_state", menu = self - } ) - if not self:restoreState() then - self.Options:processEvent( { + }) + if not self:restoreState() then + self.Options:processEvent({ name = "gain_focus", controller = controller - } ) + }) end - LUI.OverrideFunction_CallOriginalSecond( self, "close", function ( element ) + LUI.OverrideFunction_CallOriginalSecond(self, "close", function(element) element.GameSettingsBackground:close() element.Options:close() - Engine.UnsubscribeAndFreeModel( Engine.GetModel( Engine.GetModelForController( controller ), "BoiiiStatsMenu.buttonPrompts" ) ) - end ) + Engine.UnsubscribeAndFreeModel(Engine.GetModel(Engine.GetModelForController(controller), + "BoiiiStatsMenu.buttonPrompts")) + end) - if PostLoadFunc then - PostLoadFunc( self, controller ) + if PostLoadFunc then + PostLoadFunc(self, controller) end - return self + return self end - -CoD.LobbyButtons.MP_STATS = { - stringRef = "STATS", - action = function ( self, element, controller, param, menu ) - SetPerControllerTableProperty( controller, "disableGameSettingsOptions", true ) - OpenPopup( menu, "BoiiiStatsMenu", controller ) - end, - customId = "btnMPStats" -} - -CoD.LobbyButtons.MP_START_GAME = { - stringRef = "MENU_START_GAME_CAPS", - action = function ( self, element, controller, param, menu ) - --Engine.SetDvar( "bot_difficulty", 3 ) - Engine.SetDvar( "party_minplayers", 1 ) - Engine.Exec( nil, "launchgame" ) - end, - customId = "btnStartGame" -} - -CoD.LobbyButtons.SETTING_UP_BOTS = { - stringRef = "MENU_SETUP_BOTS_CAPS", - action = function ( self, element, controller, param, menu ) - SetPerControllerTableProperty( controller, "disableGameSettingsOptions", true ) - OpenPopup( menu, "GameSettings_Bots", controller ) - end, - customId = "btnSettingUpBots" -} - -CoD.LobbyButtons.MP_CUSTOM_SETUP_GAME = { - stringRef = "MPUI_SETUP_GAME_CAPS", - action = OpenSetupGameMP, - customId = "btnSetupGame", -} - -local IsGamescomDemo = function () - return Dvar.ui_execdemo_gamescom:get() -end - -local IsBetaDemo = function () - return Dvar.ui_execdemo_beta:get() -end - -local SetButtonState = function ( button, state ) - if state == nil then - return - elseif state == CoD.LobbyButtons.DISABLED then - button.disabled = true - elseif state == CoD.LobbyButtons.HIDDEN then - button.hidden = true - end -end - -local AddButton = function ( controller, options, button, isLargeButton ) - button.disabled = false - button.hidden = false - button.selected = false - button.warning = false - if button.defaultState ~= nil then - if button.defaultState == CoD.LobbyButtons.DISABLED then - button.disabled = true - elseif button.defaultState == CoD.LobbyButtons.HIDDEN then - button.hidden = true - end - end - if button.disabledFunc ~= nil then - button.disabled = button.disabledFunc( controller ) - end - if button.visibleFunc ~= nil then - button.hidden = not button.visibleFunc( controller ) - end - if IsBetaDemo() then - SetButtonState( button, button.demo_beta ) - elseif IsGamescomDemo() then - SetButtonState( button, button.demo_gamescom ) - end - if button.hidden then - return - end - local lobbyNav = LobbyData.GetLobbyNav() - if button.selectedFunc ~= nil then - button.selected = button.selectedFunc( button.selectedParam ) - elseif CoD.LobbyMenus.History[lobbyNav] ~= nil then - button.selected = CoD.LobbyMenus.History[lobbyNav] == button.customId - end - if button.newBreadcrumbFunc then - local f8_local1 = button.newBreadcrumbFunc - if type( f8_local1 ) == "string" then - f8_local1 = LUI.getTableFromPath( f8_local1 ) - end - if f8_local1 then - button.isBreadcrumbNew = f8_local1( controller ) - end - end - if button.warningFunc ~= nil then - button.warning = button.warningFunc( controller ) - end - if button.starterPack == CoD.LobbyButtons.STARTERPACK_UPGRADE then - button.starterPackUpgrade = true - if IsStarterPack() then - button.disabled = false - end - end - table.insert( options, { - optionDisplay = button.stringRef, - action = button.action, - param = button.param, - customId = button.customId, - isLargeButton = isLargeButton, - isLastButtonInGroup = false, - disabled = button.disabled, - selected = button.selected, - isBreadcrumbNew = button.isBreadcrumbNew, - warning = button.warning, - requiredChunk = button.selectedParam, - starterPackUpgrade = button.starterPackUpgrade, - unloadMod = button.unloadMod - } ) -end - -local AddLargeButton = function ( controller, options, button ) - AddButton( controller, options, button, true ) -end - -local AddSmallButton = function ( controller, options, button ) - AddButton( controller, options, button, false ) -end - -local AddSpacer = function ( options ) - if 0 < #options then - options[#options].isLastButtonInGroup = true - end -end - -local MapVote = 0 - -CoD.LobbyMenus.MPButtonsLAN = function( arg0, arg1, arg2 ) - if IsStarterPack() then - AddSmallButton( arg0, arg1, CoD.LobbyButtons.QUIT ) - return - end - if arg2 == 1 then - AddSmallButton( arg0, arg1, CoD.LobbyButtons.MP_CUSTOM_START_GAME ) - AddSmallButton( arg0, arg1, CoD.LobbyButtons.MP_CUSTOM_SETUP_GAME ) - AddSpacer( arg1 ) - end - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_CAC ) - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_SPECIALISTS ) - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_SCORESTREAKS ) - AddSpacer( arg1 ) - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_CODCASTER_SETTINGS ) - if Engine.DvarBool( nil, "inventory_test_button_visible" ) then - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_INVENTORY_TEST ) - end - Engine.Mods_Lists_UpdateUsermaps() -end - -CoD.LobbyMenus.MPButtonsMain = function ( arg0, arg1, arg2 ) - if arg2 == 1 then - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_PUBLIC_MATCH ) - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_ARENA ) - AddLargeButton( arg0, arg1, CoD.LobbyButtons.MP_CUSTOM_GAMES ) - AddLargeButton( arg0, arg1, CoD.LobbyButtons.THEATER_MP ) - end - AddSpacer( arg1 ) - if CoD.isPC then - AddLargeButton( arg0, arg1, CoD.LobbyButtons.STEAM_STORE ) - else - AddLargeButton( arg0, arg1, CoD.LobbyButtons.STORE ) - end - Engine.Mods_Lists_UpdateUsermaps() -end - -CoD.LobbyMenus.MPButtonsOnline = function ( f26_arg0, f26_arg1, f26_arg2 ) - if f26_arg2 == 1 then - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_FIND_MATCH ) - AddSpacer( f26_arg1 ) - end - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_CAC_NO_WARNING ) - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_SPECIALISTS_NO_WARNING ) - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_SCORESTREAKS ) - if (Dvar.ui_execdemo_beta:get() or IsStarterPack()) and IsStoreAvailable() then - if CoD.isPC then - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.STEAM_STORE ) - else - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.STORE ) - end - end - if Engine.DvarBool( nil, "inventory_test_button_visible" ) then - AddLargeButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_INVENTORY_TEST ) - end - AddSpacer( f26_arg1 ) - if not DisableBlackMarket() then - AddSmallButton( f26_arg0, f26_arg1, CoD.LobbyButtons.BLACK_MARKET ) - end - AddSpacer( f26_arg1 ) - AddSmallButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_STATS ) - MapVote = 1 -end - -CoD.LobbyMenus.MPButtonsOnlinePublic = function ( f27_arg0, f27_arg1, f27_arg2 ) - if MapVote == 1 then - Engine.Exec(nil, "LobbyStopDemo") -- Enable map vote at start lobby - MapVote = 0 - end - AddLargeButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_START_GAME ) --Launch match button - AddSpacer( f27_arg1 ) - AddLargeButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_CAC ) - AddLargeButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_SPECIALISTS ) - AddLargeButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_SCORESTREAKS ) - if Engine.DvarBool( nil, "inventory_test_button_visible" ) then - AddLargeButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_INVENTORY_TEST ) - end ---[[local f27_local0 = Engine.GetPlaylistInfoByID( Engine.GetPlaylistID() ) - if f27_local0 then - local f27_local1 = f27_local0.playlist.category - if f27_local1 == Engine.GetPlaylistCategoryIdByName( "core" ) or f27_local1 == Engine.GetPlaylistCategoryIdByName( "hardcore" ) then - AddSpacer( f27_arg1 ) - AddSmallButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_PUBLIC_LOBBY_LEADERBOARD ) - end - end -]] if not DisableBlackMarket() then - AddSpacer( f27_arg1 ) - AddLargeButton( f27_arg0, f27_arg1, CoD.LobbyButtons.BLACK_MARKET ) - end - AddSpacer( f27_arg1 ) - AddSmallButton( f27_arg0, f27_arg1, CoD.LobbyButtons.MP_CUSTOM_SETUP_GAME ) --Setup game in public lobby -end - -CoD.LobbyMenus.MPButtonsArenaGame = function ( f31_arg0, f31_arg1, f31_arg2 ) - AddLargeButton( f31_arg0, f31_arg1, CoD.LobbyButtons.MP_START_GAME ) --Launch match button - AddSpacer( f31_arg1 ) - AddLargeButton( f31_arg0, f31_arg1, CoD.LobbyButtons.MP_CAC ) - AddLargeButton( f31_arg0, f31_arg1, CoD.LobbyButtons.MP_SPECIALISTS ) - AddLargeButton( f31_arg0, f31_arg1, CoD.LobbyButtons.MP_SCORESTREAKS ) - if not DisableBlackMarket() then - AddSpacer( f31_arg1 ) - AddLargeButton( f31_arg0, f31_arg1, CoD.LobbyButtons.BLACK_MARKET ) - end - AddSpacer( f31_arg1 ) - AddSmallButton( f31_arg0, f31_arg1, CoD.LobbyButtons.SETTING_UP_BOTS ) --Bot setting button in public lobby -end - -CoD.LobbyMenus.ZMButtonsOnline = function ( f33_arg0, f33_arg1, f33_arg2 ) - if IsStarterPack() then - AddSmallButton( f33_arg0, f33_arg1, CoD.LobbyButtons.QUIT ) - return - elseif f33_arg2 == 1 then - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_SOLO_GAME ) - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_FIND_MATCH ) - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_CUSTOM_GAMES ) - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.THEATER_ZM ) - AddSpacer( f33_arg1 ) - end - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_BUBBLEGUM_BUFFS ) - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_MEGACHEW_FACTORY ) - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_GOBBLEGUM_RECIPES ) - AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_BUILD_KITS ) - AddSpacer( f33_arg1 ) - AddSmallButton( f33_arg0, f33_arg1, CoD.LobbyButtons.MP_STATS ) - Engine.Mods_Lists_UpdateUsermaps() -end - -local targetButtons = { - [LobbyData.UITargets.UI_MAIN.id] = CoD.LobbyMenus.ModeSelect, - [LobbyData.UITargets.UI_MODESELECT.id] = CoD.LobbyMenus.ModeSelect, - [LobbyData.UITargets.UI_CPLOBBYLANGAME.id] = CoD.LobbyMenus.CPButtonsLAN, - [LobbyData.UITargets.UI_CPLOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM, - [LobbyData.UITargets.UI_CPLOBBYONLINE.id] = CoD.LobbyMenus.CPButtonsOnline, - [LobbyData.UITargets.UI_CPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPButtonsPublicGame, - [LobbyData.UITargets.UI_CPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame, - [LobbyData.UITargets.UI_CP2LOBBYLANGAME.id] = CoD.LobbyMenus.CPZMButtonsLAN, - [LobbyData.UITargets.UI_CP2LOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM, - [LobbyData.UITargets.UI_CP2LOBBYONLINE.id] = CoD.LobbyMenus.CPZMButtonsOnline, - [LobbyData.UITargets.UI_CP2LOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPZMButtonsPublicGame, - [LobbyData.UITargets.UI_CP2LOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame, - [LobbyData.UITargets.UI_DOALOBBYLANGAME.id] = CoD.LobbyMenus.DOAButtonsLAN, - [LobbyData.UITargets.UI_DOALOBBYONLINE.id] = CoD.LobbyMenus.DOAButtonsOnline, - [LobbyData.UITargets.UI_DOALOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.DOAButtonsPublicGame, - [LobbyData.UITargets.UI_MPLOBBYLANGAME.id] = CoD.LobbyMenus.MPButtonsLAN, - [LobbyData.UITargets.UI_MPLOBBYMAIN.id] = CoD.LobbyMenus.MPButtonsMain, - [LobbyData.UITargets.UI_MPLOBBYONLINE.id] = CoD.LobbyMenus.MPButtonsOnline, - [LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.MPButtonsOnlinePublic, - [LobbyData.UITargets.UI_MPLOBBYONLINEMODGAME.id] = CoD.LobbyMenus.MPButtonsModGame, - [LobbyData.UITargets.UI_MPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.MPButtonsCustomGame, - [LobbyData.UITargets.UI_MPLOBBYONLINEARENA.id] = CoD.LobbyMenus.MPButtonsArena, - [LobbyData.UITargets.UI_MPLOBBYONLINEARENAGAME.id] = CoD.LobbyMenus.MPButtonsArenaGame, - [LobbyData.UITargets.UI_FRLOBBYONLINEGAME.id] = CoD.LobbyMenus.FRButtonsOnlineGame, - [LobbyData.UITargets.UI_FRLOBBYLANGAME.id] = CoD.LobbyMenus.FRButtonsLANGame, - [LobbyData.UITargets.UI_ZMLOBBYLANGAME.id] = CoD.LobbyMenus.ZMButtonsLAN, - [LobbyData.UITargets.UI_ZMLOBBYONLINE.id] = CoD.LobbyMenus.ZMButtonsOnline, - [LobbyData.UITargets.UI_ZMLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.ZMButtonsPublicGame, - [LobbyData.UITargets.UI_ZMLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.ZMButtonsCustomGame, - [LobbyData.UITargets.UI_MPLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame, - [LobbyData.UITargets.UI_ZMLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame -} - -CoD.LobbyMenus.AddButtonsForTarget = function ( controller, id ) - local buttonFunc = targetButtons[id] - local model = nil - if Engine.IsLobbyActive( Enum.LobbyType.LOBBY_TYPE_GAME ) then - model = Engine.GetModel( DataSources.LobbyRoot.getModel( controller ), "gameClient.isHost" ) - else - model = Engine.GetModel( DataSources.LobbyRoot.getModel( controller ), "privateClient.isHost" ) - end - local isLeader = nil - if model ~= nil then - isLeader = Engine.GetModelValue( model ) - else - isLeader = 1 - end - local result = {} - buttonFunc( controller, result, isLeader ) - return result -end - From 2f3feade70374f1c2c98f1494117ea44cf2251a3 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Sun, 9 Apr 2023 01:09:02 +0200 Subject: [PATCH 046/102] fix: added call to original AddButtonsForTarget incase mod uses different lobbymenu names --- data/ui_scripts/frontend_menus/__init__.lua | 46 +++------------------ 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/data/ui_scripts/frontend_menus/__init__.lua b/data/ui_scripts/frontend_menus/__init__.lua index adf81bbb..836045e8 100644 --- a/data/ui_scripts/frontend_menus/__init__.lua +++ b/data/ui_scripts/frontend_menus/__init__.lua @@ -1,5 +1,5 @@ if Engine.GetCurrentMap() ~= "core_frontend" then - return + return end local utils = require("utils") @@ -53,9 +53,10 @@ local addCustomButtons = function(controller, menuId, buttonTable, isLeader) elseif menuId == LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id then if shouldShowMapVote == true then shouldShowMapVote = false - Engine.Exec(nil, "LobbyStopDemo") -- Enable map vote at start lobby + --Enable map vote at start lobby + Engine.Exec(nil, "LobbyStopDemo") end - utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.MP_START_GAME, 1) --Launch match button + utils.AddLargeButton(controller, buttonTable, CoD.LobbyButtons.MP_START_GAME, 1) --Launch match button utils.AddSpacer(buttonTable, 1) utils.AddSpacer(buttonTable) @@ -66,42 +67,8 @@ local addCustomButtons = function(controller, menuId, buttonTable, isLeader) end end -local targetButtons = { - [LobbyData.UITargets.UI_MAIN.id] = CoD.LobbyMenus.ModeSelect, - [LobbyData.UITargets.UI_MODESELECT.id] = CoD.LobbyMenus.ModeSelect, - [LobbyData.UITargets.UI_CPLOBBYLANGAME.id] = CoD.LobbyMenus.CPButtonsLAN, - [LobbyData.UITargets.UI_CPLOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM, - [LobbyData.UITargets.UI_CPLOBBYONLINE.id] = CoD.LobbyMenus.CPButtonsOnline, - [LobbyData.UITargets.UI_CPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPButtonsPublicGame, - [LobbyData.UITargets.UI_CPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame, - [LobbyData.UITargets.UI_CP2LOBBYLANGAME.id] = CoD.LobbyMenus.CPZMButtonsLAN, - [LobbyData.UITargets.UI_CP2LOBBYLANCUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsLANCUSTOM, - [LobbyData.UITargets.UI_CP2LOBBYONLINE.id] = CoD.LobbyMenus.CPZMButtonsOnline, - [LobbyData.UITargets.UI_CP2LOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.CPZMButtonsPublicGame, - [LobbyData.UITargets.UI_CP2LOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.CPButtonsCustomGame, - [LobbyData.UITargets.UI_DOALOBBYLANGAME.id] = CoD.LobbyMenus.DOAButtonsLAN, - [LobbyData.UITargets.UI_DOALOBBYONLINE.id] = CoD.LobbyMenus.DOAButtonsOnline, - [LobbyData.UITargets.UI_DOALOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.DOAButtonsPublicGame, - [LobbyData.UITargets.UI_MPLOBBYLANGAME.id] = CoD.LobbyMenus.MPButtonsLAN, - [LobbyData.UITargets.UI_MPLOBBYMAIN.id] = CoD.LobbyMenus.MPButtonsMain, - [LobbyData.UITargets.UI_MPLOBBYONLINE.id] = CoD.LobbyMenus.MPButtonsOnline, - [LobbyData.UITargets.UI_MPLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.MPButtonsOnlinePublic, - [LobbyData.UITargets.UI_MPLOBBYONLINEMODGAME.id] = CoD.LobbyMenus.MPButtonsModGame, - [LobbyData.UITargets.UI_MPLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.MPButtonsCustomGame, - [LobbyData.UITargets.UI_MPLOBBYONLINEARENA.id] = CoD.LobbyMenus.MPButtonsArena, - [LobbyData.UITargets.UI_MPLOBBYONLINEARENAGAME.id] = CoD.LobbyMenus.MPButtonsArenaGame, - [LobbyData.UITargets.UI_FRLOBBYONLINEGAME.id] = CoD.LobbyMenus.FRButtonsOnlineGame, - [LobbyData.UITargets.UI_FRLOBBYLANGAME.id] = CoD.LobbyMenus.FRButtonsLANGame, - [LobbyData.UITargets.UI_ZMLOBBYLANGAME.id] = CoD.LobbyMenus.ZMButtonsLAN, - [LobbyData.UITargets.UI_ZMLOBBYONLINE.id] = CoD.LobbyMenus.ZMButtonsOnline, - [LobbyData.UITargets.UI_ZMLOBBYONLINEPUBLICGAME.id] = CoD.LobbyMenus.ZMButtonsPublicGame, - [LobbyData.UITargets.UI_ZMLOBBYONLINECUSTOMGAME.id] = CoD.LobbyMenus.ZMButtonsCustomGame, - [LobbyData.UITargets.UI_MPLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame, - [LobbyData.UITargets.UI_ZMLOBBYONLINETHEATER.id] = CoD.LobbyMenus.ButtonsTheaterGame -} - +local oldAddButtonsForTarget = CoD.LobbyMenus.AddButtonsForTarget CoD.LobbyMenus.AddButtonsForTarget = function(controller, id) - local buttonFunc = targetButtons[id] local model = nil if Engine.IsLobbyActive(Enum.LobbyType.LOBBY_TYPE_GAME) then model = Engine.GetModel(DataSources.LobbyRoot.getModel(controller), "gameClient.isHost") @@ -114,8 +81,7 @@ CoD.LobbyMenus.AddButtonsForTarget = function(controller, id) else isLeader = 1 end - local result = {} - buttonFunc(controller, result, isLeader) + local result = oldAddButtonsForTarget(controller, id) addCustomButtons(controller, id, result, isLeader) return result end From aef16d1e0c25e5040695f7110f95bced6c7f8bda Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:57:06 +0200 Subject: [PATCH 047/102] Allow custom gamesettings to be loaded from disk --- src/client/component/gamesettings.cpp | 135 ++++++++++++++++++++++++++ src/client/game/symbols.hpp | 6 ++ 2 files changed, 141 insertions(+) create mode 100644 src/client/component/gamesettings.cpp diff --git a/src/client/component/gamesettings.cpp b/src/client/component/gamesettings.cpp new file mode 100644 index 00000000..9d672b76 --- /dev/null +++ b/src/client/component/gamesettings.cpp @@ -0,0 +1,135 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "scheduler.hpp" + +#include +#include +#include + +namespace gamesettings +{ + namespace + { + // + std::unordered_map gamesettings_files; + + const std::string get_gamesettings_name(const std::vector& sub_strings) + { + if (sub_strings.size() > 2) + { + return sub_strings[sub_strings.size() - 2] + '/' + sub_strings[sub_strings.size() - 1]; + } + + return ""; + } + + const std::string get_gamesettings_path(const std::string& name) + { + const auto itr = gamesettings_files.find(name); + return (itr == gamesettings_files.end()) ? "" : itr->second; + } + + void search_gamesettings_folder(const std::string& gamesettings_dir) + { + if (!utils::io::directory_exists(gamesettings_dir)) + { + return; + } + + const auto files = utils::io::list_files(gamesettings_dir, true); + + for (const auto& path : files) + { + if (!std::filesystem::is_directory(path)) + { + auto sub_strings = utils::string::split(path.generic_string(), '/'); + gamesettings_files.insert_or_assign(get_gamesettings_name(sub_strings), path.generic_string()); + } + } + } + + bool has_gamesettings_file_on_disk(const char* path) + { + if (!path) + { + return false; + } + + auto sub_strings = utils::string::split(path, '/'); + auto gamesettings_name = get_gamesettings_name(sub_strings); + + return get_gamesettings_path(gamesettings_name) != ""; + } + + void cmd_exec_stub(utils::hook::assembler& a) + { + const auto exec_from_fastfile = a.newLabel(); + const auto exec_from_disk = a.newLabel(); + + a.pushad64(); + + a.mov(rcx, r10); + a.call_aligned(has_gamesettings_file_on_disk); + a.cmp(rax, 1); +; + a.popad64(); + + a.jnz(exec_from_fastfile); + + a.bind(exec_from_disk); + a.jmp(game::select(0x1420ED087, 0x1404F855E)); + + a.bind(exec_from_fastfile); + a.lea(rdx, ptr(rsp, (game::is_server() ? 0x30 : 0x40))); + a.jmp(game::select(0x1420ED007, 0x1404F853F)); + } + + int read_file_stub(const char* qpath, void** buffer) + { + auto sub_strings = utils::string::split(qpath, '/'); + auto game_settings_name = get_gamesettings_name(sub_strings); + + std::string gamesettings_data; + utils::io::read_file(get_gamesettings_path(game_settings_name), &gamesettings_data); + + if (!gamesettings_data.empty()) + { + ++(*game::fs_loadStack); + + auto len = static_cast(gamesettings_data.length()); + auto buf = game::FS_AllocMem(len + 1); + + *buffer = buf; + gamesettings_data.copy(reinterpret_cast(*buffer), len); + buf[len] = '\0'; + + return len; + } + + return utils::hook::invoke(game::select(0x1422A48D0, 0x140564F70), qpath, buffer); + } + + void search_gamesettings_files_on_disk() + { + const utils::nt::library host{}; + + search_gamesettings_folder((host.get_folder() / "boiii/gamesettings").string()); + search_gamesettings_folder((game::get_appdata_path() / "data/gamesettings").string()); + } + } + + struct component final : generic_component + { + void post_unpack() override + { + search_gamesettings_files_on_disk(); + + utils::hook::call(game::select(0x1420ED0A1, 0x1404F857D), read_file_stub); + utils::hook::jump(game::select(0x1420ED002, 0x1404F853A), utils::hook::assemble(cmd_exec_stub)); + } + }; +}; + +REGISTER_COMPONENT(gamesettings::component) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index f754090f..422a74c3 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -35,6 +35,7 @@ namespace game WEAK symbol Com_SwitchMode{ 0x14214A4D0 }; + WEAK symbol Com_LoadRawTextFile{0x1420F61B0}; WEAK symbol Cbuf_AddText{0x1420EC010, 0x1404F75B0}; WEAK symbol Cbuf_ExecuteBuffer{ @@ -180,6 +181,9 @@ namespace game WEAK symbol SV_Cmd_TokenizeString{0x1420EF130, 0x1404FA6C0}; WEAK symbol SV_Cmd_EndTokenizedString{0x1420EF0E0, 0x1404FA670}; + // FS + WEAK symbol FS_AllocMem{0x1422AC9F0, 0x14056C340}; + // Utils WEAK symbol I_CleanStr{0x1422E9050, 0x140580E80}; @@ -198,6 +202,8 @@ namespace game WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; + WEAK symbol fs_loadStack{0x157A65310, 0x14A39C650}; + // Client and dedi struct size differs :( WEAK symbol svs_clients_cl{0x1576F9318, 0}; WEAK symbol svs_clients{0x0, 0x14A178E98}; From 825fc9f6f081926ef279bc3401ea42811e468eae Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:59:08 +0200 Subject: [PATCH 048/102] Stop executing default steam config files Since we're setting up our config files differently for dedicated servers this is no longer necessary. --- src/client/component/dedicated_patches.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 6e7f249e..80a0245c 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -104,6 +104,9 @@ namespace dedicated_patches utils::hook::jump(0x14052F0F5_g, 0x14052F139_g); utils::hook::call(0x1402853D7_g, sv_get_player_xuid_stub); // PlayerCmd_GetXuid + + // Stop executing default_dedicated.cfg & language_settings.cfg + utils::hook::set(0x1405063C0_g, 0xC3); } }; } From 6c1cb108d0e80bb476cc8cd78e37f6c5c76e6256 Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:59:58 +0200 Subject: [PATCH 049/102] Fix typo in gamesettings_escort.cfg --- data/gamesettings/mp/gamesettings_escort.cfg | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 data/gamesettings/mp/gamesettings_escort.cfg diff --git a/data/gamesettings/mp/gamesettings_escort.cfg b/data/gamesettings/mp/gamesettings_escort.cfg new file mode 100644 index 00000000..5b713e17 --- /dev/null +++ b/data/gamesettings/mp/gamesettings_escort.cfg @@ -0,0 +1,26 @@ +gametype_setting timelimit 5 +gametype_setting scorelimit 0 +gametype_setting roundscorelimit 1 +gametype_setting roundwinlimit 2 +gametype_setting roundlimit 2 +gametype_setting preroundperiod 10 +gametype_setting teamCount 2 + +gametype_setting shutdownDamage 3 +gametype_setting bootTime 5 +gametype_setting rebootTime 15 +gametype_setting rebootPlayers 0 +gametype_setting movePlayers 1 +gametype_setting robotSpeed 1 +gametype_setting robotShield 0 + + +gametype_setting scoreHeroPowerGainFactor 0.788 //Score earned towards Hero Weapons and Abilities are multiplied by this factor +gametype_setting scoreHeroPowerTimeFactor 0.788 + +gametype_setting spawntraptriggertime 5 + +gametype_setting disableVehicleSpawners 1 + +gametype_setting gameAdvertisementRuleTimeLeft 3.5 +gametype_setting gameAdvertisementRuleRound 3 From bd7355bf094e328d5c4d7db73f0eb171008ca115 Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:22:52 +0200 Subject: [PATCH 050/102] Give priority too boiii folder in root directory --- src/client/component/gamesettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/gamesettings.cpp b/src/client/component/gamesettings.cpp index 9d672b76..713a2a0b 100644 --- a/src/client/component/gamesettings.cpp +++ b/src/client/component/gamesettings.cpp @@ -115,8 +115,8 @@ namespace gamesettings { const utils::nt::library host{}; - search_gamesettings_folder((host.get_folder() / "boiii/gamesettings").string()); search_gamesettings_folder((game::get_appdata_path() / "data/gamesettings").string()); + search_gamesettings_folder((host.get_folder() / "boiii/gamesettings").string()); } } From 229beb1bb708e1d9104c22983b1b15019f4c57e9 Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:48:17 +0200 Subject: [PATCH 051/102] Remove unused include --- src/client/component/gamesettings.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client/component/gamesettings.cpp b/src/client/component/gamesettings.cpp index 713a2a0b..c511ef5c 100644 --- a/src/client/component/gamesettings.cpp +++ b/src/client/component/gamesettings.cpp @@ -2,8 +2,6 @@ #include "loader/component_loader.hpp" #include "game/game.hpp" -#include "scheduler.hpp" - #include #include #include From 9326405be31cbb24f611137bf9268b74387026a3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Apr 2023 09:02:07 +0200 Subject: [PATCH 052/102] Add profile info logging --- src/client/component/profile_infos.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 597be96a..16bd8dbc 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -100,6 +100,10 @@ namespace profile_infos } else { +#ifdef DEV_BUILD + printf("Erasing profile info: %llX\n", i->first); +#endif + i = profiles.erase(i); } } @@ -126,6 +130,10 @@ namespace profile_infos return; } +#ifdef DEV_BUILD + printf("Adding profile info: %llX\n", user_id); +#endif + profile_mapping.access([&](profile_map& profiles) { profiles[user_id] = info; @@ -202,7 +210,17 @@ namespace profile_infos if (profile_entry != profiles.end()) { result = profile_entry->second; + +#ifdef DEV_BUILD + printf("Requesting profile info: %llX - good\n", user_id); +#endif } +#ifdef DEV_BUILD + else + { + printf("Requesting profile info: %llX - bad\n", user_id); + } +#endif return result; }); From 008790b1ba223e9eddb85196a587d91f0624b59f Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Apr 2023 10:10:22 +0200 Subject: [PATCH 053/102] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c75df1e0..821ee1a3 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,11 @@ # BOIII ☄️ -Reverse engineering and analysis of Call of Duty: Black Ops 3. +An attempt at reverse engineering and analyzing of Call of Duty: Black Ops 3. -## Roadmap +## Technical Features - [x] Steam API Emulation - [x] Steam Integrity Bypass @@ -24,6 +24,8 @@ Reverse engineering and analysis of Call of Duty: Black Ops 3. - [x] P2P multiplayer - [x] Dedicated Servers +Check out the closed issues for more gameplay related features and fixes that have been added! + ## Writeups & Articles - Reverse engineering integrity checks in Black Ops 3 From 27c197e95e75f4d9d37acf6d7a835904a9555907 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Mon, 10 Apr 2023 10:13:14 +0200 Subject: [PATCH 054/102] cleanup game settings --- .../{gamesettings.cpp => game_settings.cpp} | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) rename src/client/component/{gamesettings.cpp => game_settings.cpp} (60%) diff --git a/src/client/component/gamesettings.cpp b/src/client/component/game_settings.cpp similarity index 60% rename from src/client/component/gamesettings.cpp rename to src/client/component/game_settings.cpp index c511ef5c..85680f6e 100644 --- a/src/client/component/gamesettings.cpp +++ b/src/client/component/game_settings.cpp @@ -11,54 +11,54 @@ namespace gamesettings namespace { // - std::unordered_map gamesettings_files; + std::unordered_map game_settings_files; - const std::string get_gamesettings_name(const std::vector& sub_strings) + std::string get_game_settings_name(const std::vector& sub_strings) { if (sub_strings.size() > 2) { return sub_strings[sub_strings.size() - 2] + '/' + sub_strings[sub_strings.size() - 1]; } - return ""; + return std::string(); } - const std::string get_gamesettings_path(const std::string& name) + std::string get_game_settings_path(const std::string& name) { - const auto itr = gamesettings_files.find(name); - return (itr == gamesettings_files.end()) ? "" : itr->second; + const auto itr = game_settings_files.find(name); + return (itr == game_settings_files.end()) ? std::string() : itr->second; } - void search_gamesettings_folder(const std::string& gamesettings_dir) + void search_game_settings_folder(const std::string& game_settings_dir) { - if (!utils::io::directory_exists(gamesettings_dir)) + if (!utils::io::directory_exists(game_settings_dir)) { return; } - const auto files = utils::io::list_files(gamesettings_dir, true); + const auto files = utils::io::list_files(game_settings_dir, true); for (const auto& path : files) { if (!std::filesystem::is_directory(path)) { auto sub_strings = utils::string::split(path.generic_string(), '/'); - gamesettings_files.insert_or_assign(get_gamesettings_name(sub_strings), path.generic_string()); + game_settings_files.insert_or_assign(get_game_settings_name(sub_strings), path.generic_string()); } } } - bool has_gamesettings_file_on_disk(const char* path) + bool has_game_settings_file_on_disk(const char* path) { if (!path) { return false; } - auto sub_strings = utils::string::split(path, '/'); - auto gamesettings_name = get_gamesettings_name(sub_strings); + const auto sub_strings = utils::string::split(path, '/'); + const auto game_settings_name = get_game_settings_name(sub_strings); - return get_gamesettings_path(gamesettings_name) != ""; + return !get_game_settings_path(game_settings_name).empty(); } void cmd_exec_stub(utils::hook::assembler& a) @@ -69,7 +69,7 @@ namespace gamesettings a.pushad64(); a.mov(rcx, r10); - a.call_aligned(has_gamesettings_file_on_disk); + a.call_aligned(has_game_settings_file_on_disk); a.cmp(rax, 1); ; a.popad64(); @@ -86,11 +86,11 @@ namespace gamesettings int read_file_stub(const char* qpath, void** buffer) { - auto sub_strings = utils::string::split(qpath, '/'); - auto game_settings_name = get_gamesettings_name(sub_strings); + const auto sub_strings = utils::string::split(qpath, '/'); + const auto game_settings_name = get_game_settings_name(sub_strings); std::string gamesettings_data; - utils::io::read_file(get_gamesettings_path(game_settings_name), &gamesettings_data); + utils::io::read_file(get_game_settings_path(game_settings_name), &gamesettings_data); if (!gamesettings_data.empty()) { @@ -113,8 +113,8 @@ namespace gamesettings { const utils::nt::library host{}; - search_gamesettings_folder((game::get_appdata_path() / "data/gamesettings").string()); - search_gamesettings_folder((host.get_folder() / "boiii/gamesettings").string()); + search_game_settings_folder((game::get_appdata_path() / "data/gamesettings").string()); + search_game_settings_folder((host.get_folder() / "boiii/gamesettings").string()); } } From 481e892351abc73b98d9a34570184e6c2e6bf4a5 Mon Sep 17 00:00:00 2001 From: Edo Date: Mon, 10 Apr 2023 10:20:48 +0200 Subject: [PATCH 055/102] use brace'd initializer --- src/client/component/game_settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/game_settings.cpp b/src/client/component/game_settings.cpp index 85680f6e..0572f0b8 100644 --- a/src/client/component/game_settings.cpp +++ b/src/client/component/game_settings.cpp @@ -20,7 +20,7 @@ namespace gamesettings return sub_strings[sub_strings.size() - 2] + '/' + sub_strings[sub_strings.size() - 1]; } - return std::string(); + return {}; } std::string get_game_settings_path(const std::string& name) From a44675aa68d7df7ab3180bdb8644021f01da7dc2 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Apr 2023 11:59:05 +0200 Subject: [PATCH 056/102] Print errors in connect stub --- src/client/component/auth.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index e870dfc5..959d6e57 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -109,20 +109,29 @@ namespace auth int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, int len) { - std::string buffer{}; - - const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; - if (is_connect_sequence) + try { - buffer.append("connect"); - buffer.push_back(' '); - buffer.append(serialize_connect_data(data, len)); + std::string buffer{}; - data = buffer.data(); - len = static_cast(buffer.size()); + const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; + if (is_connect_sequence) + { + buffer.append("connect"); + buffer.push_back(' '); + buffer.append(serialize_connect_data(data, len)); + + data = buffer.data(); + len = static_cast(buffer.size()); + } + + return reinterpret_cast(0x142173600_g)(sock, adr, data, len); + } + catch (std::exception& e) + { + printf("Error: %s\n", e.what()); } - return reinterpret_cast(0x142173600_g)(sock, adr, data, len); + return 0; } void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) From 282d5e97a37ac732b560c0582b665954bdb527e5 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Apr 2023 15:05:11 +0200 Subject: [PATCH 057/102] Struct fixes --- src/client/game/structs.hpp | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 54dde0c0..ca9b7904 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -689,6 +689,7 @@ namespace game byte color[4]; const dvar_t* indirect[3]; } value; + uint64_t encryptedValue; }; @@ -699,26 +700,31 @@ namespace game int stringCount; const char** strings; } enumeration; + struct { int min; int max; } integer; + struct { int64_t min; int64_t max; } integer64; + struct { uint64_t min; uint64_t max; } unsignedInt64; + struct { float min; float max; } value; + struct { vec_t min; @@ -1028,7 +1034,7 @@ namespace game JoinResult joinResult; }; - +#ifdef __cplusplus namespace hks { struct lua_State; @@ -1051,7 +1057,7 @@ namespace game typedef size_t hksSize; typedef void* (*lua_Alloc)(void*, void*, size_t, size_t); - typedef hksInt32(*lua_CFunction)(lua_State*); + typedef hksInt32 (*lua_CFunction)(lua_State*); struct GenericChunkHeader { @@ -1108,11 +1114,14 @@ namespace game TNUMBER = 0x3, TSTRING = 0x4, TTABLE = 0x5, - TFUNCTION = 0x6, // idk + TFUNCTION = 0x6, + // idk TUSERDATA = 0x7, TTHREAD = 0x8, - TIFUNCTION = 0x9, // Lua function - TCFUNCTION = 0xA, // C function + TIFUNCTION = 0x9, + // Lua function + TCFUNCTION = 0xA, + // C function TUI64 = 0xB, TSTRUCT = 0xC, NUM_TYPE_OBJECTS = 0xE, @@ -1294,7 +1303,7 @@ namespace game int _m_isHksGlobalMemoTestingMode; HksCompilerSettings_BytecodeSharingFormat m_bytecodeSharingFormat; HksCompilerSettings_IntLiteralOptions m_enableIntLiterals; - int(*m_debugMap)(const char*, int); + int (*m_debugMap)(const char*, int); }; enum HksBytecodeSharingMode : __int64 @@ -1504,7 +1513,7 @@ namespace game void* m_profiler; RuntimeProfileData m_runProfilerData; HksCompilerSettings m_compilerSettings; - int(*m_panicFunction)(lua_State*); + int (*m_panicFunction)(lua_State*); void* m_luaplusObjectList; int m_heapAssertionFrequency; int m_heapAssertionCount; @@ -1533,6 +1542,7 @@ namespace game HksError m_error; }; } +#endif typedef uint32_t ScrVarCanonicalName_t; @@ -1556,19 +1566,23 @@ namespace game char __pad4[0x29DAC]; }; +#ifdef __cplusplus static_assert(sizeof(client_s) == 0xE5110); static_assert(offsetof(game::client_s, address) == 0x2C); static_assert(offsetof(game::client_s, xuid) == 0x55C8); static_assert(offsetof(game::client_s, guid) == 0xBB354); static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); +#endif struct client_s_cl : client_s { char __pad1_0[0x60]; }; +#ifdef __cplusplus static_assert(sizeof(client_s_cl) == 0xE5170); +#endif enum scriptInstance_t { @@ -1598,7 +1612,9 @@ namespace game unsigned char __pad1[0x2A0]; }; +#ifdef __cplusplus static_assert(sizeof(gentity_s) == 0x4F8); +#endif enum workshop_type { @@ -1623,7 +1639,9 @@ namespace game workshop_type type; }; +#ifdef __cplusplus static_assert(sizeof(workshop_data) == 0x4C8); +#endif struct DDLMember { @@ -1695,7 +1713,7 @@ namespace game }; struct DDLContext; - typedef void(* DDLWriteCB)(DDLContext*, void*); + typedef void (* DDLWriteCB)(DDLContext*, void*); struct DDLContext { From 601be011e18098dcda1306eeacb02fe4d3eee9ba Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Apr 2023 15:05:23 +0200 Subject: [PATCH 058/102] Prepare sendpacket fixes --- src/client/component/network.cpp | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 9a722405..c517e862 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -256,6 +256,38 @@ namespace network return a.port == b.port && a.addr == b.addr; } + int net_sendpacket_stub(const game::netsrc_t sock, const int length, const char* data, const game::netadr_t* to) + { + printf("Sending packet of size: %X\n", length); + + if (to->type != game::NA_RAWIP) + { + printf("NET_SendPacket: bad address type\n"); + return 0; + } + + const auto s = *game::ip_socket; + if (!s || sock > game::NS_MAXCLIENTS) + { + return 0; + } + + sockaddr_in address{}; + address.sin_family = AF_INET; + address.sin_port = htons(to->port); + address.sin_addr.s_addr = htonl(((to->ipv4.c | ((to->ipv4.b | (to->ipv4.a << 8)) << 8)) << 8) | to->ipv4.d); + + const auto size = static_cast(length); + + std::vector buffer{}; + buffer.resize(size + 1); + buffer[0] = static_cast((static_cast(sock) & 0xF) | ((to->localNetID & 0xF) << 4)); + memcpy(buffer.data() + 1, data, size); + + return sendto(s, buffer.data(), static_cast(buffer.size()), 0, reinterpret_cast(&address), + sizeof(address)); + } + struct component final : generic_component { void post_unpack() override @@ -268,6 +300,9 @@ namespace network // skip checksum verification utils::hook::set(game::select(0x14233249E, 0x140596F2E), 0); // don't add checksum to packet + // Recreate NET_SendPacket to increase max packet size + utils::hook::jump(game::select(0x1423323B0, 0x140596E40), net_sendpacket_stub); + utils::hook::set(game::select(0x14134C6E0, 0x14018E574), 5); // set initial connection state to challenging From 4a5b6d43d0d931c27903dae552fde46b766ec336 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Mon, 10 Apr 2023 15:15:12 +0200 Subject: [PATCH 059/102] feat: added bots column on server browser --- data/ui_scripts/server_browser/__init__.lua | 371 ++++++++++++++++++ .../server_browser_button/__init__.lua | 3 - src/client/component/server_list.cpp | 18 +- src/client/game/symbols.hpp | 8 +- .../steam/interfaces/matchmaking_servers.cpp | 5 +- 5 files changed, 397 insertions(+), 8 deletions(-) create mode 100644 data/ui_scripts/server_browser/__init__.lua delete mode 100644 data/ui_scripts/server_browser_button/__init__.lua diff --git a/data/ui_scripts/server_browser/__init__.lua b/data/ui_scripts/server_browser/__init__.lua new file mode 100644 index 00000000..d53055de --- /dev/null +++ b/data/ui_scripts/server_browser/__init__.lua @@ -0,0 +1,371 @@ +if Engine.GetCurrentMap() ~= "core_frontend" then + return +end + +function IsServerBrowserEnabled() + return true +end + +DataSources.LobbyServer = { + prepare = function ( controller, list, filter ) + list.numElementsInList = list.vCount + list.controller = controller + list.serverBrowserRootModel = Engine.CreateModel( Engine.GetGlobalModel(), "serverBrowser" ) + local serverListCountModel = Engine.GetModel( list.serverBrowserRootModel, "serverListCount" ) + if serverListCountModel then + list.serverCount = Engine.GetModelValue( serverListCountModel ) + else + list.serverCount = 0 + end + list.servers = {} + local serversModel = Engine.CreateModel( list.serverBrowserRootModel, "servers" ) + for i = 1, list.numElementsInList, 1 do + list.servers[i] = {} + list.servers[i].root = Engine.CreateModel( serversModel, "server_" .. i ) + list.servers[i].model = Engine.CreateModel( list.servers[i].root, "model" ) + end + list.updateModels = function ( controller, list, offset ) + local serverInfo = Engine.SteamServerBrowser_GetServerInfo( offset ) + if serverInfo then + local SetModelValue = function ( model, key, value ) + local model = Engine.CreateModel( model, key ) + if model then + Engine.SetModelValue( model, value ) + end + end + + local elementIndex = offset % list.numElementsInList + 1 + local serverModel = list.servers[elementIndex].model + SetModelValue( serverModel, "serverIndex", serverInfo.serverIndex ) + SetModelValue( serverModel, "connectAddr", serverInfo.connectAddr ) + SetModelValue( serverModel, "ping", serverInfo.ping ) + SetModelValue( serverModel, "modName", serverInfo.modName ) + SetModelValue( serverModel, "mapName", serverInfo.map ) + SetModelValue( serverModel, "desc", serverInfo.desc ) + -- Changed the client count to be the actual player count + local clientCount = serverInfo.playerCount - serverInfo.botCount + SetModelValue( serverModel, "clientCount", clientCount ) + SetModelValue( serverModel, "maxClients", serverInfo.maxPlayers ) + SetModelValue( serverModel, "passwordProtected", serverInfo.password ) + SetModelValue( serverModel, "secure", serverInfo.secure ) + SetModelValue( serverModel, "name", serverInfo.name ) + SetModelValue( serverModel, "gameType", serverInfo.gametype ) + SetModelValue( serverModel, "dedicated", serverInfo.dedicated ) + SetModelValue( serverModel, "ranked", serverInfo.ranked ) + SetModelValue( serverModel, "hardcore", serverInfo.hardcore ) + -- Added the bot count + SetModelValue( serverModel, "botCount", serverInfo.botCount ) + return serverModel + else + return nil + end + end + + if list.serverListUpdateSubscription then + list:removeSubscription( list.serverListUpdateSubscription ) + end + local serverListUpdateModel = Engine.CreateModel( list.serverBrowserRootModel, "serverListCount" ) + list.serverListUpdateSubscription = list:subscribeToModel( serverListUpdateModel, function ( model ) + list:updateDataSource( false, false ) + end, false ) + if list.serverListSortTypeSubscription then + list:removeSubscription( list.serverListSortTypeSubscription ) + end + local serverListSortTypeModel = Engine.CreateModel( list.serverBrowserRootModel, "serverListSortType" ) + list.serverListSortTypeSubscription = list:subscribeToModel( serverListSortTypeModel, function ( model ) + list:updateDataSource( false, false ) + end, false ) + end, + getCount = function ( list ) + return list.serverCount + end, + getItem = function ( controller, list, index ) + local offset = index - 1 + return list.updateModels( controller, list, offset ) + end, + cleanup = function ( list ) + if list.serverBrowserRootModel then + Engine.UnsubscribeAndFreeModel( list.serverBrowserRootModel ) + list.serverBrowserRootModel = nil + end + end +} + +CoD.ServerBrowserRowInternal.new = function ( menu, controller ) + local self = LUI.UIHorizontalList.new( { + left = 0, + top = 0, + right = 0, + bottom = 0, + leftAnchor = true, + topAnchor = true, + rightAnchor = true, + bottomAnchor = true, + spacing = 2 + } ) + self:setAlignment( LUI.Alignment.Left ) + if PreLoadFunc then + PreLoadFunc( self, controller ) + end + self:setUseStencil( false ) + self:setClass( CoD.ServerBrowserRowInternal ) + self.id = "ServerBrowserRowInternal" + self.soundSet = "default" + self:setLeftRight( true, false, 0, 700 ) + self:setTopBottom( true, false, 0, 22 ) + self:makeFocusable() + self.onlyChildrenFocusable = true + self.anyChildUsesUpdateState = true + + local passwordFlag = CoD.ServerBrowserFlag.new( menu, controller ) + passwordFlag:setLeftRight( true, false, 0, 28 ) + passwordFlag:setTopBottom( true, true, 0, 0 ) + passwordFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_protected" ) ) + passwordFlag:linkToElementModel( self, nil, false, function ( model ) + passwordFlag:setModel( model, controller ) + end ) + passwordFlag:mergeStateConditions( { + { + stateName = "FlagOn", + condition = function ( menu, element, event ) + return IsSelfModelValueTrue( element, controller, "passwordProtected" ) + end + } + } ) + passwordFlag:linkToElementModel( passwordFlag, "passwordProtected", true, function ( model ) + menu:updateElementState( passwordFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue( model ), + modelName = "passwordProtected" + } ) + end ) + self:addElement( passwordFlag ) + self.passwordFlag = passwordFlag + + local dedicatedFlag = CoD.ServerBrowserFlag.new( menu, controller ) + dedicatedFlag:setLeftRight( true, false, 30, 58 ) + dedicatedFlag:setTopBottom( true, true, 0, 0 ) + dedicatedFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_dedicated" ) ) + dedicatedFlag:linkToElementModel( self, nil, false, function ( model ) + dedicatedFlag:setModel( model, controller ) + end ) + dedicatedFlag:mergeStateConditions( { + { + stateName = "FlagOn", + condition = function ( menu, element, event ) + return IsSelfModelValueTrue( element, controller, "dedicated" ) + end + } + } ) + dedicatedFlag:linkToElementModel( dedicatedFlag, "dedicated", true, function ( model ) + menu:updateElementState( dedicatedFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue( model ), + modelName = "dedicated" + } ) + end ) + self:addElement( dedicatedFlag ) + self.dedicatedFlag = dedicatedFlag + + local rankedFlag = CoD.ServerBrowserFlag.new( menu, controller ) + rankedFlag:setLeftRight( true, false, 60, 88 ) + rankedFlag:setTopBottom( true, true, 0, 0 ) + rankedFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_ranked" ) ) + rankedFlag:linkToElementModel( self, nil, false, function ( model ) + rankedFlag:setModel( model, controller ) + end ) + rankedFlag:mergeStateConditions( { + { + stateName = "FlagOn", + condition = function ( menu, element, event ) + return IsSelfModelValueTrue( element, controller, "ranked" ) + end + } + } ) + rankedFlag:linkToElementModel( rankedFlag, "ranked", true, function ( model ) + menu:updateElementState( rankedFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue( model ), + modelName = "ranked" + } ) + end ) + self:addElement( rankedFlag ) + self.rankedFlag = rankedFlag + + local name = CoD.horizontalScrollingTextBox_18pt.new( menu, controller ) + name:setLeftRight( true, false, 90, 330 ) + name:setTopBottom( true, false, 2, 20 ) + name.textBox:setTTF( "fonts/default.ttf" ) + name.textBox:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) + name:linkToElementModel( self, "name", true, function ( model ) + local _name = Engine.GetModelValue( model ) + if _name then + name.textBox:setText( Engine.Localize( _name ) ) + end + end ) + self:addElement( name ) + self.name = name + + local spacer = LUI.UIFrame.new( menu, controller, 0, 0, false ) + spacer:setLeftRight( true, false, 332, 339 ) + spacer:setTopBottom( true, false, 0, 22 ) + spacer:setAlpha( 0 ) + self:addElement( spacer ) + self.spacer = spacer + + local map = CoD.horizontalScrollingTextBox_18pt.new( menu, controller ) + map:setLeftRight( true, false, 341, 446 ) + map:setTopBottom( true, false, 2, 20 ) + map.textBox:setTTF( "fonts/default.ttf" ) + map.textBox:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) + map:linkToElementModel( self, "mapName", true, function ( model ) + local mapName = Engine.GetModelValue( model ) + if mapName then + map.textBox:setText( MapNameToLocalizedMapName( mapName ) ) + end + end ) + self:addElement( map ) + self.map = map + + local hardcoreFlag = CoD.ServerBrowserFlag.new( menu, controller ) + hardcoreFlag:setLeftRight( true, false, 448, 470 ) + hardcoreFlag:setTopBottom( true, true, 0, 0 ) + hardcoreFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_skull" ) ) + hardcoreFlag:linkToElementModel( self, nil, false, function ( model ) + hardcoreFlag:setModel( model, controller ) + end ) + hardcoreFlag:mergeStateConditions( { + { + stateName = "FlagOn", + condition = function ( menu, element, event ) + return IsSelfModelValueTrue( element, controller, "hardcore" ) + end + } + } ) + hardcoreFlag:linkToElementModel( hardcoreFlag, "hardcore", true, function ( model ) + menu:updateElementState( hardcoreFlag, { + name = "model_validation", + menu = menu, + modelValue = Engine.GetModelValue( model ), + modelName = "hardcore" + } ) + end ) + self:addElement( hardcoreFlag ) + self.hardcoreFlag = hardcoreFlag + + local gametype = LUI.UIText.new() + gametype:setLeftRight( true, false, 472, 576 ) + gametype:setTopBottom( true, false, 2, 20 ) + gametype:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) + gametype:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) + gametype:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) + gametype:linkToElementModel( self, "gameType", true, function ( model ) + local gameType = Engine.GetModelValue( model ) + if gameType then + gametype:setText( Engine.Localize( GetGameTypeDisplayString( gameType ) ) ) + end + end ) + self:addElement( gametype ) + self.gametype = gametype + + local playerCount = LUI.UIText.new() + playerCount:setLeftRight( true, false, 593, 613 ) + playerCount:setTopBottom( true, false, 2, 20 ) + playerCount:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) + playerCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_RIGHT ) + playerCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) + playerCount:linkToElementModel( self, "clientCount", true, function ( model ) + local clientCount = Engine.GetModelValue( model ) + if clientCount then + playerCount:setText( Engine.Localize( clientCount ) ) + end + end ) + self:addElement( playerCount ) + self.playerCount = playerCount + + local slash = LUI.UIText.new() + slash:setLeftRight( true, false, 615, 624 ) + slash:setTopBottom( true, false, 2, 20 ) + slash:setText( Engine.Localize( "/" ) ) + slash:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) + slash:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) + slash:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) + self:addElement( slash ) + self.slash = slash + + local maxPlayers = LUI.UIText.new() + maxPlayers:setLeftRight( true, false, 626, 645 ) + maxPlayers:setTopBottom( true, false, 2, 20 ) + maxPlayers:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) + maxPlayers:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) + maxPlayers:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) + maxPlayers:linkToElementModel( self, "maxClients", true, function ( model ) + local maxClients = Engine.GetModelValue( model ) + if maxClients then + maxPlayers:setText( Engine.Localize( maxClients ) ) + end + end ) + self:addElement( maxPlayers ) + self.maxPlayers = maxPlayers + + local botCount = LUI.UIText.new() + botCount:setLeftRight( true, false, 637, 659 ) + botCount:setTopBottom( true, false, 2, 20 ) + botCount:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) + botCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) + botCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) + botCount:linkToElementModel( self, "botCount", true, function ( model ) + local _botCount = Engine.GetModelValue( model ) + if _botCount then + botCount:setText( "[".. Engine.Localize( _botCount ) .."]" ) + end + end ) + self:addElement( botCount ) + self.botCount = botCount + + local ping = LUI.UIText.new() + ping:setLeftRight( true, false, 661, 699.37 ) + ping:setTopBottom( true, false, 2, 20 ) + ping:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) + ping:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_CENTER ) + ping:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) + ping:linkToElementModel( self, "ping", true, function ( model ) + local _ping = Engine.GetModelValue( model ) + if _ping then + ping:setText( Engine.Localize( _ping ) ) + end + end ) + self:addElement( ping ) + self.ping = ping + + spacer.id = "spacer" + self:registerEventHandler( "gain_focus", function ( self, event ) + if self.m_focusable and self.spacer:processEvent( event ) then + return true + else + return LUI.UIElement.gainFocus( self, event ) + end + end ) + LUI.OverrideFunction_CallOriginalSecond( self, "close", function ( element ) + element.passwordFlag:close() + element.dedicatedFlag:close() + element.rankedFlag:close() + element.name:close() + element.map:close() + element.hardcoreFlag:close() + element.gametype:close() + element.playerCount:close() + element.maxPlayers:close() + element.ping:close() + end ) + + if PostLoadFunc then + PostLoadFunc( self, controller, menu ) + end + + return self +end + diff --git a/data/ui_scripts/server_browser_button/__init__.lua b/data/ui_scripts/server_browser_button/__init__.lua deleted file mode 100644 index affb1588..00000000 --- a/data/ui_scripts/server_browser_button/__init__.lua +++ /dev/null @@ -1,3 +0,0 @@ -function IsServerBrowserEnabled() - return true -end \ No newline at end of file diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp index 7bcff98e..ab0d291f 100644 --- a/src/client/component/server_list.cpp +++ b/src/client/component/server_list.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "network.hpp" #include "scheduler.hpp" @@ -14,6 +15,8 @@ namespace server_list { namespace { + utils::hook::detour lua_gameitem_to_table_hook; + struct state { game::netadr_t address{}; @@ -72,6 +75,17 @@ namespace server_list } callback(true, result); + } + + void lua_gameitem_to_table_stub(game::hks::lua_State* state, __int64 gameItem, int index) + { + lua_gameitem_to_table_hook.invoke(state, gameItem, index); + + if (state) + { + auto botCount = atoi(game::Info_ValueForKey(gameItem + 276, "bots")); + game::Lua_SetTableInt("botCount", botCount, state); + } } } @@ -131,7 +145,9 @@ namespace server_list s.callback(false, {}); s.callback = {}; }); - }, scheduler::async, 200ms); + }, scheduler::async, 200ms); + + lua_gameitem_to_table_hook.create(0x141F1FD10_g, lua_gameitem_to_table_stub); } void pre_destroy() override diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index f754090f..0fe15b80 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -72,7 +72,10 @@ namespace game WEAK symbol DB_ReleaseXAssets{0x1414247C0}; // Live - WEAK symbol Live_GetConnectivityInformation{0x141E0C380}; + WEAK symbol Live_GetConnectivityInformation{0x141E0C380}; + + // Info + WEAK symbol Info_ValueForKey{ 0x1422E87B0 }; // MSG WEAK symbol MSG_ReadByte{0x142155450, 0x14050D1B0}; @@ -141,7 +144,8 @@ namespace game WEAK symbol UI_CoD_GetRootNameForController{0x141F28940, 0x0}; WEAK symbol Lua_CoD_LoadLuaFile{0x141F11A20, 0x0}; WEAK symbol CG_LUIHUDRestart{0x140F7E970}; - WEAK symbol CL_CheckKeepDrawingConnectScreen{0x1413CCAE0}; + WEAK symbol CL_CheckKeepDrawingConnectScreen{0x1413CCAE0}; + WEAK symbol Lua_SetTableInt{ 0x141F066E0 }; // Scr WEAK symbol Scr_AddInt{0x1412E9870, 0x14016F160}; diff --git a/src/client/steam/interfaces/matchmaking_servers.cpp b/src/client/steam/interfaces/matchmaking_servers.cpp index 8f772b65..13d25e84 100644 --- a/src/client/steam/interfaces/matchmaking_servers.cpp +++ b/src/client/steam/interfaces/matchmaking_servers.cpp @@ -55,10 +55,11 @@ namespace steam const auto mode = game::eModes(std::atoi(playmode.data())); const auto* tags = ::utils::string::va( - R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\false\zombies\%s\modName\\playerCount\%d)", + R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\false\zombies\%s\modName\\playerCount\%d\bots\%d\)", info.get("gametype").data(), info.get("dedicated") == "1" ? "true" : "false", - mode == game::MODE_ZOMBIES ? "true" : "false", server.m_nPlayers); + mode == game::MODE_ZOMBIES ? "true" : "false", + server.m_nPlayers, atoi(info.get("bots").data())); ::utils::string::copy(server.m_szGameTags, tags); server.m_steamID.bits = strtoull(info.get("xuid").data(), nullptr, 16); From d31fe6e8557967de1d95d3feee54af00bd228779 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Mon, 10 Apr 2023 15:57:46 +0200 Subject: [PATCH 060/102] fix: improved lua formatting --- data/ui_scripts/server_browser/__init__.lua | 455 ++++++++++---------- 1 file changed, 227 insertions(+), 228 deletions(-) diff --git a/data/ui_scripts/server_browser/__init__.lua b/data/ui_scripts/server_browser/__init__.lua index d53055de..c29af165 100644 --- a/data/ui_scripts/server_browser/__init__.lua +++ b/data/ui_scripts/server_browser/__init__.lua @@ -7,92 +7,92 @@ function IsServerBrowserEnabled() end DataSources.LobbyServer = { - prepare = function ( controller, list, filter ) + prepare = function(controller, list, filter) list.numElementsInList = list.vCount list.controller = controller - list.serverBrowserRootModel = Engine.CreateModel( Engine.GetGlobalModel(), "serverBrowser" ) - local serverListCountModel = Engine.GetModel( list.serverBrowserRootModel, "serverListCount" ) + list.serverBrowserRootModel = Engine.CreateModel(Engine.GetGlobalModel(), "serverBrowser") + local serverListCountModel = Engine.GetModel(list.serverBrowserRootModel, "serverListCount") if serverListCountModel then - list.serverCount = Engine.GetModelValue( serverListCountModel ) + list.serverCount = Engine.GetModelValue(serverListCountModel) else list.serverCount = 0 end list.servers = {} - local serversModel = Engine.CreateModel( list.serverBrowserRootModel, "servers" ) + local serversModel = Engine.CreateModel(list.serverBrowserRootModel, "servers") for i = 1, list.numElementsInList, 1 do list.servers[i] = {} - list.servers[i].root = Engine.CreateModel( serversModel, "server_" .. i ) - list.servers[i].model = Engine.CreateModel( list.servers[i].root, "model" ) + list.servers[i].root = Engine.CreateModel(serversModel, "server_" .. i) + list.servers[i].model = Engine.CreateModel(list.servers[i].root, "model") end - list.updateModels = function ( controller, list, offset ) - local serverInfo = Engine.SteamServerBrowser_GetServerInfo( offset ) + list.updateModels = function(controller, list, offset) + local serverInfo = Engine.SteamServerBrowser_GetServerInfo(offset) if serverInfo then - local SetModelValue = function ( model, key, value ) - local model = Engine.CreateModel( model, key ) + local SetModelValue = function(model, key, value) + local model = Engine.CreateModel(model, key) if model then - Engine.SetModelValue( model, value ) + Engine.SetModelValue(model, value) end end - + local elementIndex = offset % list.numElementsInList + 1 local serverModel = list.servers[elementIndex].model - SetModelValue( serverModel, "serverIndex", serverInfo.serverIndex ) - SetModelValue( serverModel, "connectAddr", serverInfo.connectAddr ) - SetModelValue( serverModel, "ping", serverInfo.ping ) - SetModelValue( serverModel, "modName", serverInfo.modName ) - SetModelValue( serverModel, "mapName", serverInfo.map ) - SetModelValue( serverModel, "desc", serverInfo.desc ) + SetModelValue(serverModel, "serverIndex", serverInfo.serverIndex) + SetModelValue(serverModel, "connectAddr", serverInfo.connectAddr) + SetModelValue(serverModel, "ping", serverInfo.ping) + SetModelValue(serverModel, "modName", serverInfo.modName) + SetModelValue(serverModel, "mapName", serverInfo.map) + SetModelValue(serverModel, "desc", serverInfo.desc) -- Changed the client count to be the actual player count local clientCount = serverInfo.playerCount - serverInfo.botCount - SetModelValue( serverModel, "clientCount", clientCount ) - SetModelValue( serverModel, "maxClients", serverInfo.maxPlayers ) - SetModelValue( serverModel, "passwordProtected", serverInfo.password ) - SetModelValue( serverModel, "secure", serverInfo.secure ) - SetModelValue( serverModel, "name", serverInfo.name ) - SetModelValue( serverModel, "gameType", serverInfo.gametype ) - SetModelValue( serverModel, "dedicated", serverInfo.dedicated ) - SetModelValue( serverModel, "ranked", serverInfo.ranked ) - SetModelValue( serverModel, "hardcore", serverInfo.hardcore ) + SetModelValue(serverModel, "clientCount", clientCount) + SetModelValue(serverModel, "maxClients", serverInfo.maxPlayers) + SetModelValue(serverModel, "passwordProtected", serverInfo.password) + SetModelValue(serverModel, "secure", serverInfo.secure) + SetModelValue(serverModel, "name", serverInfo.name) + SetModelValue(serverModel, "gameType", serverInfo.gametype) + SetModelValue(serverModel, "dedicated", serverInfo.dedicated) + SetModelValue(serverModel, "ranked", serverInfo.ranked) + SetModelValue(serverModel, "hardcore", serverInfo.hardcore) -- Added the bot count - SetModelValue( serverModel, "botCount", serverInfo.botCount ) + SetModelValue(serverModel, "botCount", serverInfo.botCount) return serverModel else return nil end end - + if list.serverListUpdateSubscription then - list:removeSubscription( list.serverListUpdateSubscription ) + list:removeSubscription(list.serverListUpdateSubscription) end - local serverListUpdateModel = Engine.CreateModel( list.serverBrowserRootModel, "serverListCount" ) - list.serverListUpdateSubscription = list:subscribeToModel( serverListUpdateModel, function ( model ) - list:updateDataSource( false, false ) - end, false ) + local serverListUpdateModel = Engine.CreateModel(list.serverBrowserRootModel, "serverListCount") + list.serverListUpdateSubscription = list:subscribeToModel(serverListUpdateModel, function(model) + list:updateDataSource(false, false) + end, false) if list.serverListSortTypeSubscription then - list:removeSubscription( list.serverListSortTypeSubscription ) + list:removeSubscription(list.serverListSortTypeSubscription) end - local serverListSortTypeModel = Engine.CreateModel( list.serverBrowserRootModel, "serverListSortType" ) - list.serverListSortTypeSubscription = list:subscribeToModel( serverListSortTypeModel, function ( model ) - list:updateDataSource( false, false ) - end, false ) + local serverListSortTypeModel = Engine.CreateModel(list.serverBrowserRootModel, "serverListSortType") + list.serverListSortTypeSubscription = list:subscribeToModel(serverListSortTypeModel, function(model) + list:updateDataSource(false, false) + end, false) end, - getCount = function ( list ) + getCount = function(list) return list.serverCount end, - getItem = function ( controller, list, index ) + getItem = function(controller, list, index) local offset = index - 1 - return list.updateModels( controller, list, offset ) + return list.updateModels(controller, list, offset) end, - cleanup = function ( list ) + cleanup = function(list) if list.serverBrowserRootModel then - Engine.UnsubscribeAndFreeModel( list.serverBrowserRootModel ) + Engine.UnsubscribeAndFreeModel(list.serverBrowserRootModel) list.serverBrowserRootModel = nil end end } -CoD.ServerBrowserRowInternal.new = function ( menu, controller ) - local self = LUI.UIHorizontalList.new( { +CoD.ServerBrowserRowInternal.new = function(menu, controller) + local self = LUI.UIHorizontalList.new({ left = 0, top = 0, right = 0, @@ -102,254 +102,254 @@ CoD.ServerBrowserRowInternal.new = function ( menu, controller ) rightAnchor = true, bottomAnchor = true, spacing = 2 - } ) - self:setAlignment( LUI.Alignment.Left ) + }) + self:setAlignment(LUI.Alignment.Left) if PreLoadFunc then - PreLoadFunc( self, controller ) + PreLoadFunc(self, controller) end - self:setUseStencil( false ) - self:setClass( CoD.ServerBrowserRowInternal ) + self:setUseStencil(false) + self:setClass(CoD.ServerBrowserRowInternal) self.id = "ServerBrowserRowInternal" self.soundSet = "default" - self:setLeftRight( true, false, 0, 700 ) - self:setTopBottom( true, false, 0, 22 ) + self:setLeftRight(true, false, 0, 700) + self:setTopBottom(true, false, 0, 22) self:makeFocusable() self.onlyChildrenFocusable = true self.anyChildUsesUpdateState = true - - local passwordFlag = CoD.ServerBrowserFlag.new( menu, controller ) - passwordFlag:setLeftRight( true, false, 0, 28 ) - passwordFlag:setTopBottom( true, true, 0, 0 ) - passwordFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_protected" ) ) - passwordFlag:linkToElementModel( self, nil, false, function ( model ) - passwordFlag:setModel( model, controller ) - end ) - passwordFlag:mergeStateConditions( { + + local passwordFlag = CoD.ServerBrowserFlag.new(menu, controller) + passwordFlag:setLeftRight(true, false, 0, 28) + passwordFlag:setTopBottom(true, true, 0, 0) + passwordFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_protected")) + passwordFlag:linkToElementModel(self, nil, false, function(model) + passwordFlag:setModel(model, controller) + end) + passwordFlag:mergeStateConditions({ { stateName = "FlagOn", - condition = function ( menu, element, event ) - return IsSelfModelValueTrue( element, controller, "passwordProtected" ) + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "passwordProtected") end } - } ) - passwordFlag:linkToElementModel( passwordFlag, "passwordProtected", true, function ( model ) - menu:updateElementState( passwordFlag, { + }) + passwordFlag:linkToElementModel(passwordFlag, "passwordProtected", true, function(model) + menu:updateElementState(passwordFlag, { name = "model_validation", menu = menu, - modelValue = Engine.GetModelValue( model ), + modelValue = Engine.GetModelValue(model), modelName = "passwordProtected" - } ) - end ) - self:addElement( passwordFlag ) + }) + end) + self:addElement(passwordFlag) self.passwordFlag = passwordFlag - - local dedicatedFlag = CoD.ServerBrowserFlag.new( menu, controller ) - dedicatedFlag:setLeftRight( true, false, 30, 58 ) - dedicatedFlag:setTopBottom( true, true, 0, 0 ) - dedicatedFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_dedicated" ) ) - dedicatedFlag:linkToElementModel( self, nil, false, function ( model ) - dedicatedFlag:setModel( model, controller ) - end ) - dedicatedFlag:mergeStateConditions( { + + local dedicatedFlag = CoD.ServerBrowserFlag.new(menu, controller) + dedicatedFlag:setLeftRight(true, false, 30, 58) + dedicatedFlag:setTopBottom(true, true, 0, 0) + dedicatedFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_dedicated")) + dedicatedFlag:linkToElementModel(self, nil, false, function(model) + dedicatedFlag:setModel(model, controller) + end) + dedicatedFlag:mergeStateConditions({ { stateName = "FlagOn", - condition = function ( menu, element, event ) - return IsSelfModelValueTrue( element, controller, "dedicated" ) + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "dedicated") end } - } ) - dedicatedFlag:linkToElementModel( dedicatedFlag, "dedicated", true, function ( model ) - menu:updateElementState( dedicatedFlag, { + }) + dedicatedFlag:linkToElementModel(dedicatedFlag, "dedicated", true, function(model) + menu:updateElementState(dedicatedFlag, { name = "model_validation", menu = menu, - modelValue = Engine.GetModelValue( model ), + modelValue = Engine.GetModelValue(model), modelName = "dedicated" - } ) - end ) - self:addElement( dedicatedFlag ) + }) + end) + self:addElement(dedicatedFlag) self.dedicatedFlag = dedicatedFlag - - local rankedFlag = CoD.ServerBrowserFlag.new( menu, controller ) - rankedFlag:setLeftRight( true, false, 60, 88 ) - rankedFlag:setTopBottom( true, true, 0, 0 ) - rankedFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_ranked" ) ) - rankedFlag:linkToElementModel( self, nil, false, function ( model ) - rankedFlag:setModel( model, controller ) - end ) - rankedFlag:mergeStateConditions( { + + local rankedFlag = CoD.ServerBrowserFlag.new(menu, controller) + rankedFlag:setLeftRight(true, false, 60, 88) + rankedFlag:setTopBottom(true, true, 0, 0) + rankedFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_ranked")) + rankedFlag:linkToElementModel(self, nil, false, function(model) + rankedFlag:setModel(model, controller) + end) + rankedFlag:mergeStateConditions({ { stateName = "FlagOn", - condition = function ( menu, element, event ) - return IsSelfModelValueTrue( element, controller, "ranked" ) + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "ranked") end } - } ) - rankedFlag:linkToElementModel( rankedFlag, "ranked", true, function ( model ) - menu:updateElementState( rankedFlag, { + }) + rankedFlag:linkToElementModel(rankedFlag, "ranked", true, function(model) + menu:updateElementState(rankedFlag, { name = "model_validation", menu = menu, - modelValue = Engine.GetModelValue( model ), + modelValue = Engine.GetModelValue(model), modelName = "ranked" - } ) - end ) - self:addElement( rankedFlag ) + }) + end) + self:addElement(rankedFlag) self.rankedFlag = rankedFlag - - local name = CoD.horizontalScrollingTextBox_18pt.new( menu, controller ) - name:setLeftRight( true, false, 90, 330 ) - name:setTopBottom( true, false, 2, 20 ) - name.textBox:setTTF( "fonts/default.ttf" ) - name.textBox:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) - name:linkToElementModel( self, "name", true, function ( model ) - local _name = Engine.GetModelValue( model ) + + local name = CoD.horizontalScrollingTextBox_18pt.new(menu, controller) + name:setLeftRight(true, false, 90, 330) + name:setTopBottom(true, false, 2, 20) + name.textBox:setTTF("fonts/default.ttf") + name.textBox:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + name:linkToElementModel(self, "name", true, function(model) + local _name = Engine.GetModelValue(model) if _name then - name.textBox:setText( Engine.Localize( _name ) ) + name.textBox:setText(Engine.Localize(_name)) end - end ) - self:addElement( name ) + end) + self:addElement(name) self.name = name - - local spacer = LUI.UIFrame.new( menu, controller, 0, 0, false ) - spacer:setLeftRight( true, false, 332, 339 ) - spacer:setTopBottom( true, false, 0, 22 ) - spacer:setAlpha( 0 ) - self:addElement( spacer ) + + local spacer = LUI.UIFrame.new(menu, controller, 0, 0, false) + spacer:setLeftRight(true, false, 332, 339) + spacer:setTopBottom(true, false, 0, 22) + spacer:setAlpha(0) + self:addElement(spacer) self.spacer = spacer - - local map = CoD.horizontalScrollingTextBox_18pt.new( menu, controller ) - map:setLeftRight( true, false, 341, 446 ) - map:setTopBottom( true, false, 2, 20 ) - map.textBox:setTTF( "fonts/default.ttf" ) - map.textBox:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) - map:linkToElementModel( self, "mapName", true, function ( model ) - local mapName = Engine.GetModelValue( model ) + + local map = CoD.horizontalScrollingTextBox_18pt.new(menu, controller) + map:setLeftRight(true, false, 341, 446) + map:setTopBottom(true, false, 2, 20) + map.textBox:setTTF("fonts/default.ttf") + map.textBox:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + map:linkToElementModel(self, "mapName", true, function(model) + local mapName = Engine.GetModelValue(model) if mapName then - map.textBox:setText( MapNameToLocalizedMapName( mapName ) ) + map.textBox:setText(MapNameToLocalizedMapName(mapName)) end - end ) - self:addElement( map ) + end) + self:addElement(map) self.map = map - - local hardcoreFlag = CoD.ServerBrowserFlag.new( menu, controller ) - hardcoreFlag:setLeftRight( true, false, 448, 470 ) - hardcoreFlag:setTopBottom( true, true, 0, 0 ) - hardcoreFlag.icon:setImage( RegisterImage( "uie_t7_icon_serverbrowser_skull" ) ) - hardcoreFlag:linkToElementModel( self, nil, false, function ( model ) - hardcoreFlag:setModel( model, controller ) - end ) - hardcoreFlag:mergeStateConditions( { + + local hardcoreFlag = CoD.ServerBrowserFlag.new(menu, controller) + hardcoreFlag:setLeftRight(true, false, 448, 470) + hardcoreFlag:setTopBottom(true, true, 0, 0) + hardcoreFlag.icon:setImage(RegisterImage("uie_t7_icon_serverbrowser_skull")) + hardcoreFlag:linkToElementModel(self, nil, false, function(model) + hardcoreFlag:setModel(model, controller) + end) + hardcoreFlag:mergeStateConditions({ { stateName = "FlagOn", - condition = function ( menu, element, event ) - return IsSelfModelValueTrue( element, controller, "hardcore" ) + condition = function(menu, element, event) + return IsSelfModelValueTrue(element, controller, "hardcore") end } - } ) - hardcoreFlag:linkToElementModel( hardcoreFlag, "hardcore", true, function ( model ) - menu:updateElementState( hardcoreFlag, { + }) + hardcoreFlag:linkToElementModel(hardcoreFlag, "hardcore", true, function(model) + menu:updateElementState(hardcoreFlag, { name = "model_validation", menu = menu, - modelValue = Engine.GetModelValue( model ), + modelValue = Engine.GetModelValue(model), modelName = "hardcore" - } ) - end ) - self:addElement( hardcoreFlag ) + }) + end) + self:addElement(hardcoreFlag) self.hardcoreFlag = hardcoreFlag - + local gametype = LUI.UIText.new() - gametype:setLeftRight( true, false, 472, 576 ) - gametype:setTopBottom( true, false, 2, 20 ) - gametype:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) - gametype:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) - gametype:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) - gametype:linkToElementModel( self, "gameType", true, function ( model ) - local gameType = Engine.GetModelValue( model ) + gametype:setLeftRight(true, false, 472, 576) + gametype:setTopBottom(true, false, 2, 20) + gametype:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + gametype:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + gametype:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + gametype:linkToElementModel(self, "gameType", true, function(model) + local gameType = Engine.GetModelValue(model) if gameType then - gametype:setText( Engine.Localize( GetGameTypeDisplayString( gameType ) ) ) + gametype:setText(Engine.Localize(GetGameTypeDisplayString(gameType))) end - end ) - self:addElement( gametype ) + end) + self:addElement(gametype) self.gametype = gametype - + local playerCount = LUI.UIText.new() - playerCount:setLeftRight( true, false, 593, 613 ) - playerCount:setTopBottom( true, false, 2, 20 ) - playerCount:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) - playerCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_RIGHT ) - playerCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) - playerCount:linkToElementModel( self, "clientCount", true, function ( model ) - local clientCount = Engine.GetModelValue( model ) + playerCount:setLeftRight(true, false, 593, 613) + playerCount:setTopBottom(true, false, 2, 20) + playerCount:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + playerCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_RIGHT) + playerCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + playerCount:linkToElementModel(self, "clientCount", true, function(model) + local clientCount = Engine.GetModelValue(model) if clientCount then - playerCount:setText( Engine.Localize( clientCount ) ) + playerCount:setText(Engine.Localize(clientCount)) end - end ) - self:addElement( playerCount ) + end) + self:addElement(playerCount) self.playerCount = playerCount - + local slash = LUI.UIText.new() - slash:setLeftRight( true, false, 615, 624 ) - slash:setTopBottom( true, false, 2, 20 ) - slash:setText( Engine.Localize( "/" ) ) - slash:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) - slash:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) - slash:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) - self:addElement( slash ) + slash:setLeftRight(true, false, 615, 624) + slash:setTopBottom(true, false, 2, 20) + slash:setText(Engine.Localize("/")) + slash:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + slash:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + slash:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + self:addElement(slash) self.slash = slash - + local maxPlayers = LUI.UIText.new() - maxPlayers:setLeftRight( true, false, 626, 645 ) - maxPlayers:setTopBottom( true, false, 2, 20 ) - maxPlayers:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) - maxPlayers:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) - maxPlayers:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) - maxPlayers:linkToElementModel( self, "maxClients", true, function ( model ) - local maxClients = Engine.GetModelValue( model ) + maxPlayers:setLeftRight(true, false, 626, 645) + maxPlayers:setTopBottom(true, false, 2, 20) + maxPlayers:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + maxPlayers:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + maxPlayers:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + maxPlayers:linkToElementModel(self, "maxClients", true, function(model) + local maxClients = Engine.GetModelValue(model) if maxClients then - maxPlayers:setText( Engine.Localize( maxClients ) ) + maxPlayers:setText(Engine.Localize(maxClients)) end - end ) - self:addElement( maxPlayers ) + end) + self:addElement(maxPlayers) self.maxPlayers = maxPlayers - + local botCount = LUI.UIText.new() - botCount:setLeftRight( true, false, 637, 659 ) - botCount:setTopBottom( true, false, 2, 20 ) - botCount:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) - botCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_LEFT ) - botCount:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) - botCount:linkToElementModel( self, "botCount", true, function ( model ) - local _botCount = Engine.GetModelValue( model ) + botCount:setLeftRight(true, false, 637, 659) + botCount:setTopBottom(true, false, 2, 20) + botCount:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + botCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_LEFT) + botCount:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + botCount:linkToElementModel(self, "botCount", true, function(model) + local _botCount = Engine.GetModelValue(model) if _botCount then - botCount:setText( "[".. Engine.Localize( _botCount ) .."]" ) + botCount:setText("[" .. Engine.Localize(_botCount) .. "]") end - end ) - self:addElement( botCount ) + end) + self:addElement(botCount) self.botCount = botCount - + local ping = LUI.UIText.new() - ping:setLeftRight( true, false, 661, 699.37 ) - ping:setTopBottom( true, false, 2, 20 ) - ping:setTTF( "fonts/RefrigeratorDeluxe-Regular.ttf" ) - ping:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_CENTER ) - ping:setAlignment( Enum.LUIAlignment.LUI_ALIGNMENT_TOP ) - ping:linkToElementModel( self, "ping", true, function ( model ) - local _ping = Engine.GetModelValue( model ) + ping:setLeftRight(true, false, 661, 699.37) + ping:setTopBottom(true, false, 2, 20) + ping:setTTF("fonts/RefrigeratorDeluxe-Regular.ttf") + ping:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_CENTER) + ping:setAlignment(Enum.LUIAlignment.LUI_ALIGNMENT_TOP) + ping:linkToElementModel(self, "ping", true, function(model) + local _ping = Engine.GetModelValue(model) if _ping then - ping:setText( Engine.Localize( _ping ) ) + ping:setText(Engine.Localize(_ping)) end - end ) - self:addElement( ping ) + end) + self:addElement(ping) self.ping = ping - + spacer.id = "spacer" - self:registerEventHandler( "gain_focus", function ( self, event ) - if self.m_focusable and self.spacer:processEvent( event ) then + self:registerEventHandler("gain_focus", function(self, event) + if self.m_focusable and self.spacer:processEvent(event) then return true else - return LUI.UIElement.gainFocus( self, event ) + return LUI.UIElement.gainFocus(self, event) end - end ) - LUI.OverrideFunction_CallOriginalSecond( self, "close", function ( element ) + end) + LUI.OverrideFunction_CallOriginalSecond(self, "close", function(element) element.passwordFlag:close() element.dedicatedFlag:close() element.rankedFlag:close() @@ -360,12 +360,11 @@ CoD.ServerBrowserRowInternal.new = function ( menu, controller ) element.playerCount:close() element.maxPlayers:close() element.ping:close() - end ) - + end) + if PostLoadFunc then - PostLoadFunc( self, controller, menu ) + PostLoadFunc(self, controller, menu) end - + return self end - From 51582936c4f853adf7e418ea9c29818d69e52ef1 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Mon, 10 Apr 2023 16:37:32 +0200 Subject: [PATCH 061/102] fix: added serverinfo struct --- src/client/component/server_list.cpp | 10 +++++----- src/client/game/structs.hpp | 26 ++++++++++++++++++++++++++ src/client/game/symbols.hpp | 2 +- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp index ab0d291f..7c0ca6ad 100644 --- a/src/client/component/server_list.cpp +++ b/src/client/component/server_list.cpp @@ -15,7 +15,7 @@ namespace server_list { namespace { - utils::hook::detour lua_gameitem_to_table_hook; + utils::hook::detour lua_serverinfo_to_table_hook; struct state { @@ -77,13 +77,13 @@ namespace server_list callback(true, result); } - void lua_gameitem_to_table_stub(game::hks::lua_State* state, __int64 gameItem, int index) + void lua_serverinfo_to_table_stub(game::hks::lua_State* state, game::ServerInfo serverInfo, int index) { - lua_gameitem_to_table_hook.invoke(state, gameItem, index); + lua_serverinfo_to_table_hook.invoke(state, serverInfo, index); if (state) { - auto botCount = atoi(game::Info_ValueForKey(gameItem + 276, "bots")); + auto botCount = atoi(game::Info_ValueForKey(serverInfo.tags, "bots")); game::Lua_SetTableInt("botCount", botCount, state); } } @@ -147,7 +147,7 @@ namespace server_list }); }, scheduler::async, 200ms); - lua_gameitem_to_table_hook.create(0x141F1FD10_g, lua_gameitem_to_table_stub); + lua_serverinfo_to_table_hook.create(0x141F1FD10_g, lua_serverinfo_to_table_stub); } void pre_destroy() override diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index ca9b7904..57d38e2c 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1032,6 +1032,32 @@ namespace game Agreement debugAgreement; JoinType joinType; JoinResult joinResult; + }; + + struct ServerInfo + { + uint16_t m_usConnectionPort; + uint16_t m_usQueryPort; + uint32_t m_unIP; + int m_nPing; + byte unk[0x22]; + char mapname[32]; + char description[64]; + char gamemode[16]; + char modname[32]; + int playerCount; + int maxPlayers; + int unk2; + int unk3; + int unk4; + bool dedicated; + bool ranked; + bool hardcore; + bool zombies; + char servername[64]; + char tags[128]; + int unk5; + int unk6; }; #ifdef __cplusplus diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 820d68c6..205c0348 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -76,7 +76,7 @@ namespace game WEAK symbol Live_GetConnectivityInformation{0x141E0C380}; // Info - WEAK symbol Info_ValueForKey{ 0x1422E87B0 }; + WEAK symbol Info_ValueForKey{ 0x1422E87B0 }; // MSG WEAK symbol MSG_ReadByte{0x142155450, 0x14050D1B0}; From 3f97e5d4e6b8b6988d3d6e613e60b3eabd85212a Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Mon, 10 Apr 2023 16:46:55 +0200 Subject: [PATCH 062/102] fix: only have bot count on multiplayer servers --- data/ui_scripts/server_browser/__init__.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/ui_scripts/server_browser/__init__.lua b/data/ui_scripts/server_browser/__init__.lua index c29af165..493795a4 100644 --- a/data/ui_scripts/server_browser/__init__.lua +++ b/data/ui_scripts/server_browser/__init__.lua @@ -53,6 +53,7 @@ DataSources.LobbyServer = { SetModelValue(serverModel, "dedicated", serverInfo.dedicated) SetModelValue(serverModel, "ranked", serverInfo.ranked) SetModelValue(serverModel, "hardcore", serverInfo.hardcore) + SetModelValue(serverModel, "zombies", serverInfo.zombies) -- Added the bot count SetModelValue(serverModel, "botCount", serverInfo.botCount) return serverModel @@ -323,6 +324,12 @@ CoD.ServerBrowserRowInternal.new = function(menu, controller) botCount:setText("[" .. Engine.Localize(_botCount) .. "]") end end) + botCount:linkToElementModel(self, "zombies", true, function(model) + local zombies = Engine.GetModelValue(model) + if zombies ~= nil then + botCount:setAlpha(zombies and 0 or 1) + end + end) self:addElement(botCount) self.botCount = botCount @@ -359,6 +366,7 @@ CoD.ServerBrowserRowInternal.new = function(menu, controller) element.gametype:close() element.playerCount:close() element.maxPlayers:close() + element.botCount:close() element.ping:close() end) From 7f17d1b280a5822acf668cebab4372a77ad57ea0 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Apr 2023 17:14:16 +0200 Subject: [PATCH 063/102] Add some logging --- src/client/component/auth.cpp | 5 +++++ src/client/component/network.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 959d6e57..6d5ad34d 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -104,6 +104,8 @@ namespace auth buffer.write_string(data, static_cast(length)); + printf("Serialized with size: %llX\n", buffer.get_buffer().size()); + return buffer.move_buffer(); } @@ -141,6 +143,9 @@ namespace auth return; } + + printf("Deserialized with size: %llX\n", data.size()); + utils::byte_buffer buffer(data); const profile_infos::profile_info info(buffer); diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index c517e862..da384f16 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -258,7 +258,7 @@ namespace network int net_sendpacket_stub(const game::netsrc_t sock, const int length, const char* data, const game::netadr_t* to) { - printf("Sending packet of size: %X\n", length); + //printf("Sending packet of size: %X\n", length); if (to->type != game::NA_RAWIP) { From 1ae4cf0d86f5eada30ac618f8f35d239e6099194 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Apr 2023 17:43:36 +0200 Subject: [PATCH 064/102] Don't send profile infos Temporary workaround for #480 --- src/client/component/auth.cpp | 5 ++++- src/client/component/network.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 6d5ad34d..9ec2a241 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -100,7 +100,10 @@ namespace auth std::string serialize_connect_data(const char* data, const int length) { utils::byte_buffer buffer{}; - profile_infos::get_profile_info().value_or(profile_infos::profile_info{}).serialize(buffer); + profile_infos::profile_info info{}; + info.version = 4; // invalid + info.serialize(buffer); + //profile_infos::get_profile_info().value_or(profile_infos::profile_info{}).serialize(buffer); buffer.write_string(data, static_cast(length)); diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index da384f16..7abe2663 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -301,7 +301,7 @@ namespace network utils::hook::set(game::select(0x14233249E, 0x140596F2E), 0); // don't add checksum to packet // Recreate NET_SendPacket to increase max packet size - utils::hook::jump(game::select(0x1423323B0, 0x140596E40), net_sendpacket_stub); + //utils::hook::jump(game::select(0x1423323B0, 0x140596E40), net_sendpacket_stub); utils::hook::set(game::select(0x14134C6E0, 0x14018E574), 5); // set initial connection state to challenging From b047ac227299314ebe05b15f0b0e64f6fcab98e7 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Apr 2023 18:32:05 +0200 Subject: [PATCH 065/102] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 821ee1a3..92e89dc2 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ # BOIII ☄️ -An attempt at reverse engineering and analyzing of Call of Duty: Black Ops 3. +An attempt at reverse engineering and analyzing Call of Duty: Black Ops 3. From c2082bb2e0e4ac382d27d1cebf63c870b9ece7b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 18:12:56 +0000 Subject: [PATCH 066/102] Bump deps/curl from `4033642` to `826e801` Bumps [deps/curl](https://github.com/curl/curl) from `4033642` to `826e801`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/403364293005ed54ef6230a214acee43e867995d...826e8011d5417504fcd4b7c2769bf47e97768788) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 40336429..826e8011 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 403364293005ed54ef6230a214acee43e867995d +Subproject commit 826e8011d5417504fcd4b7c2769bf47e97768788 From d4f91ef3a61b4933881a55384f950ede15455260 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Tue, 11 Apr 2023 00:27:21 +0200 Subject: [PATCH 067/102] fix: support for hardcore on the serverbrowser --- src/client/component/getinfo.cpp | 5 +++-- src/client/game/symbols.hpp | 1 + src/client/steam/interfaces/matchmaking_servers.cpp | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index ee848f15..26903d1f 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -103,7 +103,7 @@ namespace getinfo info.set("description", game::is_server() ? game::get_dvar_string("live_steam_server_description") : ""); info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); - info.set("mapname", game::get_dvar_string("mapname")); + info.set("mapname", game::get_dvar_string("mapname")); info.set("isPrivate", game::get_dvar_string("g_password").empty() ? "0" : "1"); info.set("clients", utils::string::va("%zu", get_client_count())); info.set("bots", utils::string::va("%zu", get_bot_count())); @@ -112,7 +112,8 @@ namespace getinfo info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode())); info.set("gamemode", utils::string::va("%i", Com_SessionMode_GetGameMode())); info.set("sv_running", utils::string::va("%i", game::is_server_running())); - info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0)); + info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0)); + info.set("hc", utils::string::va("%i", game::Com_GametypeSettings_GetUInt("hardcoremode", false))); info.set("shortversion", SHORTVERSION); network::send(target, "infoResponse", info.build(), '\n'); diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 205c0348..38090235 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -31,6 +31,7 @@ namespace game WEAK symbol Com_GametypeSettings_SetGametype{ 0x1420F5980 }; + WEAK symbol Com_GametypeSettings_GetUInt{0x1420F4E00, 0x1404FE5C0}; WEAK symbol Com_IsRunningUILevel{0x142148350}; WEAK symbol Com_SwitchMode{ 0x14214A4D0 diff --git a/src/client/steam/interfaces/matchmaking_servers.cpp b/src/client/steam/interfaces/matchmaking_servers.cpp index 13d25e84..79f0f784 100644 --- a/src/client/steam/interfaces/matchmaking_servers.cpp +++ b/src/client/steam/interfaces/matchmaking_servers.cpp @@ -55,9 +55,10 @@ namespace steam const auto mode = game::eModes(std::atoi(playmode.data())); const auto* tags = ::utils::string::va( - R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\false\zombies\%s\modName\\playerCount\%d\bots\%d\)", + R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\modName\\playerCount\%d\bots\%d\)", info.get("gametype").data(), - info.get("dedicated") == "1" ? "true" : "false", + info.get("dedicated") == "1" ? "true" : "false", + info.get("hc") == "1" ? "true" : "false", mode == game::MODE_ZOMBIES ? "true" : "false", server.m_nPlayers, atoi(info.get("bots").data())); From f60528895477b36c1868ef3b4cd8fce8f49f3c74 Mon Sep 17 00:00:00 2001 From: Jari van der Kaap Date: Tue, 11 Apr 2023 00:38:45 +0200 Subject: [PATCH 068/102] changed string literal to %u --- src/client/component/getinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index 26903d1f..67c8f3b6 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -113,7 +113,7 @@ namespace getinfo info.set("gamemode", utils::string::va("%i", Com_SessionMode_GetGameMode())); info.set("sv_running", utils::string::va("%i", game::is_server_running())); info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0)); - info.set("hc", utils::string::va("%i", game::Com_GametypeSettings_GetUInt("hardcoremode", false))); + info.set("hc", utils::string::va("%u", game::Com_GametypeSettings_GetUInt("hardcoremode", false))); info.set("shortversion", SHORTVERSION); network::send(target, "infoResponse", info.build(), '\n'); From d973dba010c09ed35b1191933a6a5954c0c8fef0 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Tue, 11 Apr 2023 08:21:06 +0200 Subject: [PATCH 069/102] Update window.cpp --- src/client/launcher/window.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/client/launcher/window.cpp b/src/client/launcher/window.cpp index 75564319..b9c36563 100644 --- a/src/client/launcher/window.cpp +++ b/src/client/launcher/window.cpp @@ -1,6 +1,8 @@ #include #include "window.hpp" +#include + #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif @@ -8,6 +10,19 @@ namespace { thread_local uint32_t window_count = 0; + + uint32_t get_dpi_for_window(const HWND window) + { + const utils::nt::library user32{"user32.dll"}; + const auto get_dpi = user32 ? user32.get_proc("GetDpiForWindow") : nullptr; + + if (!get_dpi) + { + return USER_DEFAULT_SCREEN_DPI; + } + + return get_dpi(window); + } } window::window(const std::string& title, const int width, const int height, @@ -75,7 +90,7 @@ LRESULT window::processor(const UINT message, const WPARAM w_param, const LPARAM { if (message == WM_DPICHANGED) { - const auto dpi = GetDpiForWindow(*this); + const auto dpi = get_dpi_for_window(*this); if (dpi != this->last_dpi_) { RECT rect; From 8bee19fa23a23414d058805ccc457fbe1c873f30 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 11 Apr 2023 12:07:03 +0200 Subject: [PATCH 070/102] getinfo: use std::to_string where possible --- src/client/component/getinfo.cpp | 248 +++++++++++++++---------------- 1 file changed, 124 insertions(+), 124 deletions(-) diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index 67c8f3b6..83d8209b 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -1,125 +1,125 @@ -#include -#include "loader/component_loader.hpp" - -#include "game/game.hpp" -#include "steam/steam.hpp" - -#include "network.hpp" - -#include -#include -#include - -#include - -#include "game/utils.hpp" - -namespace getinfo -{ - int get_max_client_count() - { - return game::get_dvar_int("com_maxclients"); - } - - template - int get_client_count(T* client_states) - { - if (!client_states) - { - return 0; - } - - int count = 0; - for (int i = 0; i < get_max_client_count(); ++i) - { - if (client_states[i].client_state > 0) - { - ++count; - } - } - - return count; - } - - size_t get_client_count() - { - size_t count = 0; - game::foreach_connected_client([&count](const game::client_s&) - { - ++count; - }); - - return count; - } - - size_t get_bot_count() - { - size_t count = 0; - - game::foreach_connected_client([&count](const game::client_s&, const size_t index) - { - if (game::SV_IsTestClient(static_cast(index))) - { - ++count; - } - }); - - return count; - } - - namespace - { - int Com_SessionMode_GetGameMode() - { - return *reinterpret_cast(game::select(0x1568ED7F4, 0x14948DB04)) << 14 >> 28; - } - } - - int get_assigned_team() - { - return (rand() % 2) + 1; - } - - bool is_host() - { - return game::SV_Loaded() && (game::is_server() || !game::Com_IsRunningUILevel()); - } - - struct component final : generic_component - { - void post_unpack() override - { - //utils::hook::jump(game::select(0x142254EF0, 0x140537730), get_assigned_team); - - network::on("getInfo", [](const game::netadr_t& target, const network::data_view& data) - { - utils::info_string info{}; - info.set("challenge", std::string(data.begin(), data.end())); - info.set("gamename", "T7"); - info.set("hostname", - game::get_dvar_string(game::is_server() ? "live_steam_server_name" : "sv_hostname")); - info.set("gametype", game::get_dvar_string("g_gametype")); - //info.set("sv_motd", get_dvar_string("sv_motd")); - info.set("description", - game::is_server() ? game::get_dvar_string("live_steam_server_description") : ""); - info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "steam/steam.hpp" + +#include "network.hpp" + +#include +#include +#include + +#include + +#include "game/utils.hpp" + +namespace getinfo +{ + int get_max_client_count() + { + return game::get_dvar_int("com_maxclients"); + } + + template + int get_client_count(T* client_states) + { + if (!client_states) + { + return 0; + } + + int count = 0; + for (int i = 0; i < get_max_client_count(); ++i) + { + if (client_states[i].client_state > 0) + { + ++count; + } + } + + return count; + } + + size_t get_client_count() + { + size_t count = 0; + game::foreach_connected_client([&count](const game::client_s&) + { + ++count; + }); + + return count; + } + + size_t get_bot_count() + { + size_t count = 0; + + game::foreach_connected_client([&count](const game::client_s&, const size_t index) + { + if (game::SV_IsTestClient(static_cast(index))) + { + ++count; + } + }); + + return count; + } + + namespace + { + int Com_SessionMode_GetGameMode() + { + return *reinterpret_cast(game::select(0x1568ED7F4, 0x14948DB04)) << 14 >> 28; + } + } + + int get_assigned_team() + { + return (rand() % 2) + 1; + } + + bool is_host() + { + return game::SV_Loaded() && (game::is_server() || !game::Com_IsRunningUILevel()); + } + + struct component final : generic_component + { + void post_unpack() override + { + //utils::hook::jump(game::select(0x142254EF0, 0x140537730), get_assigned_team); + + network::on("getInfo", [](const game::netadr_t& target, const network::data_view& data) + { + utils::info_string info{}; + info.set("challenge", std::string{ data.begin(), data.end() }); + info.set("gamename", "T7"); + info.set("hostname", + game::get_dvar_string(game::is_server() ? "live_steam_server_name" : "sv_hostname")); + info.set("gametype", game::get_dvar_string("g_gametype")); + //info.set("sv_motd", get_dvar_string("sv_motd")); + info.set("description", + game::is_server() ? game::get_dvar_string("live_steam_server_description") : ""); + info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); info.set("mapname", game::get_dvar_string("mapname")); - info.set("isPrivate", game::get_dvar_string("g_password").empty() ? "0" : "1"); - info.set("clients", utils::string::va("%zu", get_client_count())); - info.set("bots", utils::string::va("%zu", get_bot_count())); - info.set("sv_maxclients", utils::string::va("%zu", get_max_client_count())); - info.set("protocol", utils::string::va("%i", PROTOCOL)); - info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode())); - info.set("gamemode", utils::string::va("%i", Com_SessionMode_GetGameMode())); - info.set("sv_running", utils::string::va("%i", game::is_server_running())); - info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0)); - info.set("hc", utils::string::va("%u", game::Com_GametypeSettings_GetUInt("hardcoremode", false))); - info.set("shortversion", SHORTVERSION); - - network::send(target, "infoResponse", info.build(), '\n'); - }); - } - }; -} - -REGISTER_COMPONENT(getinfo::component) + info.set("isPrivate", game::get_dvar_string("g_password").empty() ? "0" : "1"); + info.set("clients", std::to_string(get_client_count())); + info.set("bots", std::to_string(get_bot_count())); + info.set("sv_maxclients", std::to_string(get_max_client_count())); + info.set("protocol", std::to_string(PROTOCOL)); + info.set("playmode", std::to_string(game::Com_SessionMode_GetMode())); + info.set("gamemode", std::to_string(Com_SessionMode_GetGameMode())); + info.set("sv_running", std::to_string(game::is_server_running())); + info.set("dedicated", game::is_server() ? "1" : "0"); + info.set("hc", std::to_string(game::Com_GametypeSettings_GetUInt("hardcoremode", false))); + info.set("shortversion", SHORTVERSION); + + network::send(target, "infoResponse", info.build(), '\n'); + }); + } + }; +} + +REGISTER_COMPONENT(getinfo::component) From 11ce8989c24bcff0eb117d8b640f21ff9d45a41c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 18:01:06 +0000 Subject: [PATCH 071/102] Bump deps/curl from `826e801` to `dc18b40` Bumps [deps/curl](https://github.com/curl/curl) from `826e801` to `dc18b40`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/826e8011d5417504fcd4b7c2769bf47e97768788...dc18b40b406e9946a2198d66b6edb62575660faf) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 826e8011..dc18b40b 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 826e8011d5417504fcd4b7c2769bf47e97768788 +Subproject commit dc18b40b406e9946a2198d66b6edb62575660faf From 9323dec8a01fd1994da6693d406b0266fcd287a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 18:01:08 +0000 Subject: [PATCH 072/102] Bump deps/libtommath from `3f10a28` to `0df542c` Bumps [deps/libtommath](https://github.com/libtom/libtommath) from `3f10a28` to `0df542c`. - [Release notes](https://github.com/libtom/libtommath/releases) - [Commits](https://github.com/libtom/libtommath/compare/3f10a28885601256c8b5261be3b15c926c93393d...0df542cb70f621bbeec207be1949832fb1442479) --- updated-dependencies: - dependency-name: deps/libtommath dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/libtommath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/libtommath b/deps/libtommath index 3f10a288..0df542cb 160000 --- a/deps/libtommath +++ b/deps/libtommath @@ -1 +1 @@ -Subproject commit 3f10a28885601256c8b5261be3b15c926c93393d +Subproject commit 0df542cb70f621bbeec207be1949832fb1442479 From 4bffc7920d48578d250f856e9def09358c2dc0da Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Tue, 11 Apr 2023 20:48:14 +0200 Subject: [PATCH 073/102] Support packet fragmentation --- src/client/component/auth.cpp | 72 +- src/client/component/network.cpp | 4 + src/client/component/profile_infos.cpp | 21 +- src/client/game/fragment_handler.cpp | 155 + src/client/game/fragment_handler.hpp | 17 + src/client/game/structs.hpp | 3716 ++++++++++++------------ src/client/game/symbols.hpp | 533 ++-- src/common/utils/byte_buffer.cpp | 4 +- src/common/utils/byte_buffer.hpp | 24 +- 9 files changed, 2389 insertions(+), 2157 deletions(-) create mode 100644 src/client/game/fragment_handler.cpp create mode 100644 src/client/game/fragment_handler.hpp diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 9ec2a241..57346b8f 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -4,6 +4,7 @@ #include "auth.hpp" #include "command.hpp" #include "network.hpp" +#include "scheduler.hpp" #include "profile_infos.hpp" #include @@ -17,6 +18,8 @@ #include #include +#include + namespace auth { namespace @@ -100,10 +103,7 @@ namespace auth std::string serialize_connect_data(const char* data, const int length) { utils::byte_buffer buffer{}; - profile_infos::profile_info info{}; - info.version = 4; // invalid - info.serialize(buffer); - //profile_infos::get_profile_info().value_or(profile_infos::profile_info{}).serialize(buffer); + profile_infos::get_profile_info().value_or(profile_infos::profile_info{}).serialize(buffer); buffer.write_string(data, static_cast(length)); @@ -112,24 +112,38 @@ namespace auth return buffer.move_buffer(); } - int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, int len) + void send_fragmented_connect_packet(const game::netsrc_t sock, game::netadr_t* adr, const char* data, + const int length) + { + const auto connect_data = serialize_connect_data(data, length); + game::fragment_handler::fragment_data // + (connect_data.data(), connect_data.size(), [&](const utils::byte_buffer& buffer) + { + utils::byte_buffer packet_buffer{}; + packet_buffer.write("connect"); + packet_buffer.write(" "); + packet_buffer.write(buffer); + + const auto& fragment_packet = packet_buffer.get_buffer(); + + game::NET_OutOfBandData( + sock, adr, fragment_packet.data(), + static_cast(fragment_packet.size())); + }); + } + + int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, const int len) { try { - std::string buffer{}; - const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; - if (is_connect_sequence) + if (!is_connect_sequence) { - buffer.append("connect"); - buffer.push_back(' '); - buffer.append(serialize_connect_data(data, len)); - - data = buffer.data(); - len = static_cast(buffer.size()); + return game::NET_OutOfBandData(sock, adr, data, len); } - return reinterpret_cast(0x142173600_g)(sock, adr, data, len); + send_fragmented_connect_packet(sock, adr, data, len); + return true; } catch (std::exception& e) { @@ -139,16 +153,8 @@ namespace auth return 0; } - void handle_connect_packet(const game::netadr_t& target, const network::data_view& data) + void dispatch_connect_packet(const game::netadr_t& target, const std::string& data) { - if (!game::is_server_running()) - { - return; - } - - - printf("Deserialized with size: %llX\n", data.size()); - utils::byte_buffer buffer(data); const profile_infos::profile_info info(buffer); @@ -177,6 +183,22 @@ namespace auth } }); } + + void handle_connect_packet_fragment(const game::netadr_t& target, const network::data_view& data) + { + if (!game::is_server_running()) + { + return; + } + + utils::byte_buffer buffer(data); + + std::string final_packet{}; + if (game::fragment_handler::handle(target, buffer, final_packet)) + { + dispatch_connect_packet(target, final_packet); + } + } } uint64_t get_guid() @@ -200,7 +222,7 @@ namespace auth { // Skip connect handler utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); - network::on("connect", handle_connect_packet); + network::on("connect", handle_connect_packet_fragment); // Patch steam id bit check std::vector> patches{}; diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 7abe2663..546d5a1f 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -10,6 +10,8 @@ #include "network.hpp" +#include "game/fragment_handler.hpp" + namespace network { namespace @@ -292,6 +294,8 @@ namespace network { void post_unpack() override { + scheduler::loop(game::fragment_handler::clean, scheduler::async, 5s); + utils::hook::nop(game::select(0x1423322B6, 0x140596DF6), 4); // don't increment data pointer to optionally skip socket byte utils::hook::call(game::select(0x142332283, 0x140596DC3), read_socket_byte_stub); diff --git a/src/client/component/profile_infos.cpp b/src/client/component/profile_infos.cpp index 16bd8dbc..e1faf09e 100644 --- a/src/client/component/profile_infos.cpp +++ b/src/client/component/profile_infos.cpp @@ -6,7 +6,6 @@ #include "party.hpp" #include "scheduler.hpp" -#include #include #include @@ -14,6 +13,7 @@ #include #include "game/utils.hpp" +#include "game/fragment_handler.hpp" namespace profile_infos { @@ -44,9 +44,12 @@ namespace profile_infos return {std::move(info)}; } - void send_profile_info(const game::netadr_t& address, const std::string& buffer) + void send_profile_info(const game::netadr_t& address, const std::string& data) { - network::send(address, "profileInfo", buffer); + game::fragment_handler::fragment_data(data.data(), data.size(), [&address](const utils::byte_buffer& buffer) + { + network::send(address, "profileInfo", buffer.get_buffer()); + }); } void distribute_profile_info(const uint64_t user_id, const profile_info& info) @@ -253,10 +256,16 @@ namespace profile_infos } utils::byte_buffer buffer(data); - const auto user_id = buffer.read(); - const profile_info info(buffer); - add_profile_info(user_id, info); + std::string final_packet{}; + if (game::fragment_handler::handle(server, buffer, final_packet)) + { + buffer = utils::byte_buffer(final_packet); + const auto user_id = buffer.read(); + const profile_info info(buffer); + + add_profile_info(user_id, info); + } }); } } diff --git a/src/client/game/fragment_handler.cpp b/src/client/game/fragment_handler.cpp new file mode 100644 index 00000000..f3771d5c --- /dev/null +++ b/src/client/game/fragment_handler.cpp @@ -0,0 +1,155 @@ +#include +#include "fragment_handler.hpp" + +namespace game::fragment_handler +{ + namespace + { + constexpr size_t MAX_FRAGMENTS = 100; + + using fragments = std::unordered_map; + + struct fragmented_packet + { + size_t fragment_count{0}; + fragments fragments{}; + std::chrono::high_resolution_clock::time_point insertion_time = std::chrono::high_resolution_clock::now(); + }; + + using id_fragment_map = std::unordered_map; + using address_fragment_map = std::unordered_map; + + utils::concurrency::container global_map{}; + + std::vector construct_fragments(const void* data, const size_t length) + { + std::vector fragments{}; + + constexpr size_t max_fragment_size = 0x400; + + for (size_t i = 0; i < length; i += max_fragment_size) + { + const auto current_fragment_size = std::min(length - i, max_fragment_size); + + std::string fragment(static_cast(data) + i, current_fragment_size); + fragments.push_back(std::move(fragment)); + } + + return fragments; + } + } + + bool handle(const netadr_t& target, utils::byte_buffer& buffer, std::string& final_packet) + { + const auto fragment_id = buffer.read(); + const size_t fragment_count = buffer.read(); + const size_t fragment_index = buffer.read(); + + auto fragment_data = buffer.get_remaining_data(); + + if (fragment_index > fragment_count || !fragment_count || fragment_count > MAX_FRAGMENTS) + { + return false; + } + + return global_map.access([&](address_fragment_map& map) + { + auto& user_map = map[target]; + if (!user_map.contains(fragment_id) && user_map.size() > MAX_FRAGMENTS) + { + return false; + } + + auto& packet_queue = user_map[fragment_id]; + + if (packet_queue.fragment_count == 0) + { + packet_queue.fragment_count = fragment_count; + } + + if (packet_queue.fragment_count != fragment_count) + { + return false; + } + + if (packet_queue.fragments.size() + 1 < fragment_count) + { + packet_queue.fragments[fragment_index] = std::move(fragment_data); + return false; + } + + final_packet.clear(); + + for (size_t i = 0; i < fragment_count; ++i) + { + if (i == fragment_index) + { + final_packet.append(fragment_data); + } + else + { + final_packet.append(packet_queue.fragments.at(i)); + } + } + + return true; + }); + } + + void clean() + { + global_map.access([](address_fragment_map& map) + { + for (auto i = map.begin(); i != map.end();) + { + auto& user_map = i->second; + + for (auto j = user_map.begin(); j != user_map.end();) + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - j->second.insertion_time; + + if (diff > 5s) + { + j = user_map.erase(j); + } + else + { + ++j; + } + } + + if (user_map.empty()) + { + i = map.erase(i); + } + else + { + ++i; + } + } + }); + } + + void fragment_handler::fragment_data(const void* data, const size_t size, + const std::function& callback) + { + static std::atomic_uint64_t current_id{0}; + const auto id = current_id++; + + const auto fragments = construct_fragments(data, size); + + for (size_t i = 0; i < fragments.size(); ++i) + { + utils::byte_buffer buffer{}; + buffer.write(id); + buffer.write(static_cast(fragments.size())); + buffer.write(static_cast(i)); + + auto& fragment = fragments.at(i); + buffer.write(fragment.data(), fragment.size()); + + callback(buffer); + } + } +} diff --git a/src/client/game/fragment_handler.hpp b/src/client/game/fragment_handler.hpp new file mode 100644 index 00000000..8bbfff42 --- /dev/null +++ b/src/client/game/fragment_handler.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "../component/network.hpp" + +namespace game::fragment_handler +{ + bool handle(const netadr_t& target, utils::byte_buffer& buffer, + std::string& final_packet); + + void clean(); + + void fragment_data(const void* data, const size_t size, + const std::function& callback); +} diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 57d38e2c..424c59ac 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1,1043 +1,1043 @@ -#pragma once - -#define PROTOCOL 2 - -#ifdef __cplusplus -namespace game -{ -#endif - - enum ControllerIndex_t - { - INVALID_CONTROLLER_PORT = 0xFFFFFFFF, - CONTROLLER_INDEX_FIRST = 0x0, - CONTROLLER_INDEX_0 = 0x0, - CONTROLLER_INDEX_1 = 0x1, - CONTROLLER_INDEX_2 = 0x2, - CONTROLLER_INDEX_3 = 0x3, - CONTROLLER_INDEX_COUNT = 0x4, - }; - - enum eGameModes - { - MODE_GAME_MATCHMAKING_PLAYLIST = 0x0, - MODE_GAME_MATCHMAKING_MANUAL = 0x1, - MODE_GAME_DEFAULT = 0x2, - MODE_GAME_LEAGUE = 0x3, - MODE_GAME_THEATER = 0x4, - MODE_GAME_COUNT = 0x5, - MODE_GAME_INVALID = 0x5, - }; - - enum eModes - { - MODE_ZOMBIES = 0x0, - MODE_MULTIPLAYER = 0x1, - MODE_CAMPAIGN = 0x2, - MODE_COUNT = 0x3, - MODE_INVALID = 0x3, - MODE_FIRST = 0x0, - }; - - enum eNetworkModes - { - MODE_NETWORK_OFFLINE = 0x0, - MODE_NETWORK_SYSTEMLINK = 0x1, - MODE_NETWORK_ONLINE = 0x2, - MODE_NETWORK_COUNT = 0x3, - MODE_NETWORK_INVALID = 0x3, - }; - - enum MapPreload - { - MAP_PRELOAD_NONE = 0x0, - MAP_PRELOAD_FRONTEND = 0x1, - MAP_PRELOAD_IN_GAME = 0x2, - }; - - enum bdLobbyErrorCode - { - BD_NO_ERROR = 0x0, - BD_TOO_MANY_TASKS = 0x1, - BD_NOT_CONNECTED = 0x2, - BD_SEND_FAILED = 0x3, - BD_HANDLE_TASK_FAILED = 0x4, - BD_START_TASK_FAILED = 0x5, - BD_RESULT_EXCEEDS_BUFFER_SIZE = 0x64, - BD_ACCESS_DENIED = 0x65, - BD_EXCEPTION_IN_DB = 0x66, - BD_MALFORMED_TASK_HEADER = 0x67, - BD_INVALID_ROW = 0x68, - BD_EMPTY_ARG_LIST = 0x69, - BD_PARAM_PARSE_ERROR = 0x6A, - BD_PARAM_MISMATCHED_TYPE = 0x6B, - BD_SERVICE_NOT_AVAILABLE = 0x6C, - BD_CONNECTION_RESET = 0x6D, - BD_INVALID_USER_ID = 0x6E, - BD_LOBBY_PROTOCOL_VERSION_FAILURE = 0x6F, - BD_LOBBY_INTERNAL_FAILURE = 0x70, - BD_LOBBY_PROTOCOL_ERROR = 0x71, - BD_LOBBY_FAILED_TO_DECODE_UTF8 = 0x72, - BD_LOBBY_ASCII_EXPECTED = 0x73, - BD_ASYNCHRONOUS_ERROR = 0xC8, - BD_STREAMING_COMPLETE = 0xC9, - BD_MEMBER_NO_PROPOSAL = 0x12C, - BD_TEAMNAME_ALREADY_EXISTS = 0x12D, - BD_MAX_TEAM_MEMBERSHIPS_LIMITED = 0x12E, - BD_MAX_TEAM_OWNERSHIPS_LIMITED = 0x12F, - BD_NOT_A_TEAM_MEMBER = 0x130, - BD_INVALID_TEAM_ID = 0x131, - BD_INVALID_TEAM_NAME = 0x132, - BD_NOT_A_TEAM_OWNER = 0x133, - BD_NOT_AN_ADMIN_OR_OWNER = 0x134, - BD_MEMBER_PROPOSAL_EXISTS = 0x135, - BD_MEMBER_EXISTS = 0x136, - BD_TEAM_FULL = 0x137, - BD_VULGAR_TEAM_NAME = 0x138, - BD_TEAM_USERID_BANNED = 0x139, - BD_TEAM_EMPTY = 0x13A, - BD_INVALID_TEAM_PROFILE_QUERY_ID = 0x13B, - BD_TEAMNAME_TOO_SHORT = 0x13C, - BD_UNIQUE_PROFILE_DATA_EXISTS_ALREADY = 0x13D, - BD_INVALID_LEADERBOARD_ID = 0x190, - BD_INVALID_STATS_SET = 0x191, - BD_EMPTY_STATS_SET_IGNORED = 0x193, - BD_NO_DIRECT_ACCESS_TO_ARBITRATED_LBS = 0x194, - BD_STATS_WRITE_PERMISSION_DENIED = 0x195, - BD_STATS_WRITE_TYPE_DATA_TYPE_MISMATCH = 0x196, - BD_NO_STATS_FOR_USER = 0x197, - BD_INVALID_ACCESS_TO_UNRANKED_LB = 0x198, - BD_INVALID_EXTERNAL_TITLE_ID = 0x199, - BD_DIFFERENT_LEADERBOARD_SCHEMAS = 0x19A, - BD_TOO_MANY_LEADERBOARDS_REQUESTED = 0x19B, - BD_ENTITLEMENTS_ERROR = 0x19C, - BD_ENTITLEMENTS_INVALID_TITLEID = 0x19D, - BD_ENTITLEMENTS_INVALID_LEADERBOARDID = 0x19E, - BD_ENTITLEMENTS_INVALID_GET_MODE_FOR_TITLE = 0x19F, - BD_ENTITLEMENTS_URL_CONNECTION_ERROR = 0x1A0, - BD_ENTITLEMENTS_CONFIG_ERROR = 0x1A1, - BD_ENTITLEMENTS_NAMED_PARENT_ERROR = 0x1A2, - BD_ENTITLEMENTS_NAMED_KEY_ERROR = 0x1A3, - BD_TOO_MANY_ENTITY_IDS_REQUESTED = 0x1A4, - BD_STATS_READ_FAILED = 0x1A5, - BD_INVALID_TITLE_ID = 0x1F4, - BD_MESSAGING_INVALID_MAIL_ID = 0x258, - BD_SELF_BLOCK_NOT_ALLOWED = 0x259, - BD_GLOBAL_MESSAGE_ACCESS_DENIED = 0x25A, - BD_GLOBAL_MESSAGES_USER_LIMIT_EXCEEDED = 0x25B, - BD_MESSAGING_SENDER_DOES_NOT_EXIST = 0x25C, - BD_AUTH_NO_ERROR = 0x2BC, - BD_AUTH_BAD_REQUEST = 0x2BD, - BD_AUTH_SERVER_CONFIG_ERROR = 0x2BE, - BD_AUTH_BAD_TITLE_ID = 0x2BF, - BD_AUTH_BAD_ACCOUNT = 0x2C0, - BD_AUTH_ILLEGAL_OPERATION = 0x2C1, - BD_AUTH_INCORRECT_LICENSE_CODE = 0x2C2, - BD_AUTH_CREATE_USERNAME_EXISTS = 0x2C3, - BD_AUTH_CREATE_USERNAME_ILLEGAL = 0x2C4, - BD_AUTH_CREATE_USERNAME_VULGAR = 0x2C5, - BD_AUTH_CREATE_MAX_ACC_EXCEEDED = 0x2C6, - BD_AUTH_MIGRATE_NOT_SUPPORTED = 0x2C7, - BD_AUTH_TITLE_DISABLED = 0x2C8, - BD_AUTH_ACCOUNT_EXPIRED = 0x2C9, - BD_AUTH_ACCOUNT_LOCKED = 0x2CA, - BD_AUTH_UNKNOWN_ERROR = 0x2CB, - BD_AUTH_INCORRECT_PASSWORD = 0x2CC, - BD_AUTH_IP_NOT_IN_ALLOWED_RANGE = 0x2CD, - BD_AUTH_WII_TOKEN_VERIFICATION_FAILED = 0x2CE, - BD_AUTH_WII_AUTHENTICATION_FAILED = 0x2CF, - BD_AUTH_IP_KEY_LIMIT_REACHED = 0x2D0, - BD_AUTH_INVALID_GSPID = 0x2D1, - BD_AUTH_INVALID_IP_RANGE_ID = 0x2D2, - BD_AUTH_3DS_TOKEN_VERIFICATION_FAILED = 0x2D1, - BD_AUTH_3DS_AUTHENTICATION_FAILED = 0x2D2, - BD_AUTH_STEAM_APP_ID_MISMATCH = 0x2D3, - BD_AUTH_ABACCOUNTS_APP_ID_MISMATCH = 0x2D4, - BD_AUTH_CODO_USERNAME_NOT_SET = 0x2D5, - BD_AUTH_WIIU_TOKEN_VERIFICATION_FAILED = 0x2D6, - BD_AUTH_WIIU_AUTHENTICATION_FAILED = 0x2D7, - BD_AUTH_CODO_USERNAME_NOT_BASE64 = 0x2D8, - BD_AUTH_CODO_USERNAME_NOT_UTF8 = 0x2D9, - BD_AUTH_TENCENT_TICKET_EXPIRED = 0x2DA, - BD_AUTH_PS3_SERVICE_ID_MISMATCH = 0x2DB, - BD_AUTH_CODOID_NOT_WHITELISTED = 0x2DC, - BD_AUTH_PLATFORM_TOKEN_ERROR = 0x2DD, - BD_AUTH_JSON_FORMAT_ERROR = 0x2DE, - BD_AUTH_REPLY_CONTENT_ERROR = 0x2DF, - BD_AUTH_THIRD_PARTY_TOKEN_EXPIRED = 0x2E0, - BD_AUTH_CONTINUING = 0x2E1, - BD_AUTH_PLATFORM_DEVICE_ID_ERROR = 0x2E4, - BD_NO_PROFILE_INFO_EXISTS = 0x320, - BD_FRIENDSHIP_NOT_REQUSTED = 0x384, - BD_NOT_A_FRIEND = 0x385, - BD_SELF_FRIENDSHIP_NOT_ALLOWED = 0x387, - BD_FRIENDSHIP_EXISTS = 0x388, - BD_PENDING_FRIENDSHIP_EXISTS = 0x389, - BD_USERID_BANNED = 0x38A, - BD_FRIENDS_FULL = 0x38C, - BD_FRIENDS_NO_RICH_PRESENCE = 0x38D, - BD_RICH_PRESENCE_TOO_LARGE = 0x38E, - BD_NO_FILE = 0x3E8, - BD_PERMISSION_DENIED = 0x3E9, - BD_FILESIZE_LIMIT_EXCEEDED = 0x3EA, - BD_FILENAME_MAX_LENGTH_EXCEEDED = 0x3EB, - BD_EXTERNAL_STORAGE_SERVICE_ERROR = 0x3EC, - BD_CHANNEL_DOES_NOT_EXIST = 0x44D, - BD_CHANNEL_ALREADY_SUBSCRIBED = 0x44E, - BD_CHANNEL_NOT_SUBSCRIBED = 0x44F, - BD_CHANNEL_FULL = 0x450, - BD_CHANNEL_SUBSCRIPTIONS_FULL = 0x451, - BD_CHANNEL_NO_SELF_WHISPERING = 0x452, - BD_CHANNEL_ADMIN_REQUIRED = 0x453, - BD_CHANNEL_TARGET_NOT_SUBSCRIBED = 0x454, - BD_CHANNEL_REQUIRES_PASSWORD = 0x455, - BD_CHANNEL_TARGET_IS_SELF = 0x456, - BD_CHANNEL_PUBLIC_BAN_NOT_ALLOWED = 0x457, - BD_CHANNEL_USER_BANNED = 0x458, - BD_CHANNEL_PUBLIC_PASSWORD_NOT_ALLOWED = 0x459, - BD_CHANNEL_PUBLIC_KICK_NOT_ALLOWED = 0x45A, - BD_CHANNEL_MUTED = 0x45B, - BD_EVENT_DESC_TRUNCATED = 0x4B0, - BD_CONTENT_UNLOCK_UNKNOWN_ERROR = 0x514, - BD_UNLOCK_KEY_INVALID = 0x515, - BD_UNLOCK_KEY_ALREADY_USED_UP = 0x516, - BD_SHARED_UNLOCK_LIMIT_REACHED = 0x517, - BD_DIFFERENT_HARDWARE_ID = 0x518, - BD_INVALID_CONTENT_OWNER = 0x519, - BD_CONTENT_UNLOCK_INVALID_USER = 0x51A, - BD_CONTENT_UNLOCK_INVALID_CATEGORY = 0x51B, - BD_KEY_ARCHIVE_INVALID_WRITE_TYPE = 0x5DC, - BD_KEY_ARCHIVE_EXCEEDED_MAX_IDS_PER_REQUEST = 0x5DD, - BD_BANDWIDTH_TEST_TRY_AGAIN = 0x712, - BD_BANDWIDTH_TEST_STILL_IN_PROGRESS = 0x713, - BD_BANDWIDTH_TEST_NOT_PROGRESS = 0x714, - BD_BANDWIDTH_TEST_SOCKET_ERROR = 0x715, - BD_INVALID_SESSION_NONCE = 0x76D, - BD_ARBITRATION_FAILURE = 0x76F, - BD_ARBITRATION_USER_NOT_REGISTERED = 0x771, - BD_ARBITRATION_NOT_CONFIGURED = 0x772, - BD_CONTENTSTREAMING_FILE_NOT_AVAILABLE = 0x7D0, - BD_CONTENTSTREAMING_STORAGE_SPACE_EXCEEDED = 0x7D1, - BD_CONTENTSTREAMING_NUM_FILES_EXCEEDED = 0x7D2, - BD_CONTENTSTREAMING_UPLOAD_BANDWIDTH_EXCEEDED = 0x7D3, - BD_CONTENTSTREAMING_FILENAME_MAX_LENGTH_EXCEEDED = 0x7D4, - BD_CONTENTSTREAMING_MAX_THUMB_DATA_SIZE_EXCEEDED = 0x7D5, - BD_CONTENTSTREAMING_DOWNLOAD_BANDWIDTH_EXCEEDED = 0x7D6, - BD_CONTENTSTREAMING_NOT_ENOUGH_DOWNLOAD_BUFFER_SPACE = 0x7D7, - BD_CONTENTSTREAMING_SERVER_NOT_CONFIGURED = 0x7D8, - BD_CONTENTSTREAMING_INVALID_APPLE_RECEIPT = 0x7DA, - BD_CONTENTSTREAMING_APPLE_STORE_NOT_AVAILABLE = 0x7DB, - BD_CONTENTSTREAMING_APPLE_RECEIPT_FILENAME_MISMATCH = 0x7DC, - BD_CONTENTSTREAMING_HTTP_ERROR = 0x7E4, - BD_CONTENTSTREAMING_FAILED_TO_START_HTTP = 0x7E5, - BD_CONTENTSTREAMING_LOCALE_INVALID = 0x7E6, - BD_CONTENTSTREAMING_LOCALE_MISSING = 0x7E7, - BD_VOTERANK_ERROR_EMPTY_RATING_SUBMISSION = 0x7EE, - BD_VOTERANK_ERROR_MAX_VOTES_EXCEEDED = 0x7EF, - BD_VOTERANK_ERROR_INVALID_RATING = 0x7F0, - BD_MAX_NUM_TAGS_EXCEEDED = 0x82A, - BD_TAGGED_COLLECTION_DOES_NOT_EXIST = 0x82B, - BD_EMPTY_TAG_ARRAY = 0x82C, - BD_INVALID_QUERY_ID = 0x834, - BD_NO_ENTRY_TO_UPDATE = 0x835, - BD_SESSION_INVITE_EXISTS = 0x836, - BD_INVALID_SESSION_ID = 0x837, - BD_ATTACHMENT_TOO_LARGE = 0x838, - BD_INVALID_GROUP_ID = 0xAF0, - BD_MAIL_INVALID_MAIL_ID_ERROR = 0xB55, - BD_UCD_SERVICE_ERROR = 0xC80, - BD_UCD_SERVICE_DISABLED = 0xC81, - BD_UCD_UNINTIALIZED_ERROR = 0xC82, - BD_UCD_ACCOUNT_ALREADY_REGISTERED = 0xC83, - BD_UCD_ACCOUNT_NOT_REGISTERED = 0xC84, - BD_UCD_AUTH_ATTEMPT_FAILED = 0xC85, - BD_UCD_ACCOUNT_LINKING_ERROR = 0xC86, - BD_UCD_ENCRYPTION_ERROR = 0xC87, - BD_UCD_ACCOUNT_DATA_INVALID = 0xC88, - BD_UCD_ACCOUNT_DATA_INVALID_FIRSTNAME = 0xC89, - BD_UCD_ACCOUNT_DATA_INVALID_LASTNAME = 0xC8A, - BD_UCD_ACCOUNT_DATA_INVALID_DOB = 0xC8B, - BD_UCD_ACCOUNT_DATA_INVALID_EMAIL = 0xC8C, - BD_UCD_ACCOUNT_DATA_INVALID_COUNTRY = 0xC8D, - BD_UCD_ACCOUNT_DATA_INVALID_POSTCODE = 0xC8E, - BD_UCD_ACCOUNT_DATA_INVALID_PASSWORD = 0xC8F, - BD_UCD_ACCOUNT_NAME_ALREADY_RESISTERED = 0xC94, - BD_UCD_ACCOUNT_EMAIL_ALREADY_RESISTERED = 0xC95, - BD_UCD_GUEST_ACCOUNT_AUTH_CONFLICT = 0xC96, - BD_TWITCH_SERVICE_ERROR = 0xC1D, - BD_TWITCH_ACCOUNT_ALREADY_LINKED = 0xC1E, - BD_TWITCH_NO_LINKED_ACCOUNT = 0xC1F, - BD_YOUTUBE_SERVICE_ERROR = 0xCE5, - BD_YOUTUBE_SERVICE_COMMUNICATION_ERROR = 0xCE6, - BD_YOUTUBE_USER_DENIED_AUTHORIZATION = 0xCE7, - BD_YOUTUBE_AUTH_MAX_TIME_EXCEEDED = 0xCE8, - BD_YOUTUBE_USER_UNAUTHORIZED = 0xCE9, - BD_YOUTUBE_UPLOAD_MAX_TIME_EXCEEDED = 0xCEA, - BD_YOUTUBE_DUPLICATE_UPLOAD = 0xCEB, - BD_YOUTUBE_FAILED_UPLOAD = 0xCEC, - BD_YOUTUBE_ACCOUNT_ALREADY_REGISTERED = 0xCED, - BD_YOUTUBE_ACCOUNT_NOT_REGISTERED = 0xCEE, - BD_YOUTUBE_CONTENT_SERVER_ERROR = 0xCEF, - BD_YOUTUBE_UPLOAD_DOES_NOT_EXIST = 0xCF0, - BD_YOUTUBE_NO_LINKED_ACCOUNT = 0xCF1, - BD_YOUTUBE_DEVELOPER_TAGS_INVALID = 0xCF2, - BD_TWITTER_AUTH_ATTEMPT_FAILED = 0xDAD, - BD_TWITTER_AUTH_TOKEN_INVALID = 0xDAE, - BD_TWITTER_UPDATE_LIMIT_REACHED = 0xDAF, - BD_TWITTER_UNAVAILABLE = 0xDB0, - BD_TWITTER_ERROR = 0xDB1, - BD_TWITTER_TIMED_OUT = 0xDB2, - BD_TWITTER_DISABLED_FOR_USER = 0xDB3, - BD_TWITTER_ACCOUNT_AMBIGUOUS = 0xDB4, - BD_TWITTER_MAXIMUM_ACCOUNTS_REACHED = 0xDB5, - BD_TWITTER_ACCOUNT_NOT_REGISTERED = 0xDB6, - BD_TWITTER_DUPLICATE_STATUS = 0xDB7, - BD_TWITTER_ACCOUNT_ALREADY_REGISTERED = 0xE1C, - BD_FACEBOOK_AUTH_ATTEMPT_FAILED = 0xE11, - BD_FACEBOOK_AUTH_TOKEN_INVALID = 0xE12, - BD_FACEBOOK_PHOTO_DOES_NOT_EXIST = 0xE13, - BD_FACEBOOK_PHOTO_INVALID = 0xE14, - BD_FACEBOOK_PHOTO_ALBUM_FULL = 0xE15, - BD_FACEBOOK_UNAVAILABLE = 0xE16, - BD_FACEBOOK_ERROR = 0xE17, - BD_FACEBOOK_TIMED_OUT = 0xE18, - BD_FACEBOOK_DISABLED_FOR_USER = 0xE19, - BD_FACEBOOK_ACCOUNT_AMBIGUOUS = 0xE1A, - BD_FACEBOOK_MAXIMUM_ACCOUNTS_REACHED = 0xE1B, - BD_FACEBOOK_INVALID_NUM_PICTURES_REQUESTED = 0xE1C, - BD_FACEBOOK_VIDEO_DOES_NOT_EXIST = 0xE1D, - BD_FACEBOOK_ACCOUNT_ALREADY_REGISTERED = 0xE1E, - BD_APNS_INVALID_PAYLOAD = 0xE74, - BD_APNS_INVALID_TOKEN_LENGTH_ERROR = 0xE76, - BD_MAX_CONSOLEID_LENGTH_EXCEEDED = 0xEE1, - BD_MAX_WHITELIST_LENGTH_EXCEEDED = 0xEE2, - BD_USERGROUP_NAME_ALREADY_EXISTS = 0x1770, - BD_INVALID_USERGROUP_ID = 0x1771, - BD_USER_ALREADY_IN_USERGROUP = 0x1772, - BD_USER_NOT_IN_USERGROUP = 0x1773, - BD_INVALID_USERGROUP_MEMBER_TYPE = 0x1774, - BD_TOO_MANY_MEMBERS_REQUESTED = 0x1775, - BD_USERGROUP_NAME_TOO_SHORT = 0x1776, - BD_RICH_PRESENCE_DATA_TOO_LARGE = 0x1A90, - BD_RICH_PRESENCE_TOO_MANY_USERS = 0x1A91, - BD_PRESENCE_DATA_TOO_LARGE = 0x283C, - BD_PRESENCE_TOO_MANY_USERS = 0x283D, - BD_USER_LOGGED_IN_OTHER_TITLE = 0x283E, - BD_USER_NOT_LOGGED_IN = 0x283F, - BD_SUBSCRIPTION_TOO_MANY_USERS = 0x1B58, - BD_SUBSCRIPTION_TICKET_PARSE_ERROR = 0x1B59, - BD_CODO_ID_INVALID_DATA = 0x1BBC, - BD_INVALID_MESSAGE_FORMAT = 0x1BBD, - BD_TLOG_TOO_MANY_MESSAGES = 0x1BBE, - BD_CODO_ID_NOT_IN_WHITELIST = 0x1BBF, - BD_TLOG_MESSAGE_TRANSFORMATION_ERROR = 0x1BC0, - BD_REWARDS_NOT_ENABLED = 0x1BC1, - BD_MARKETPLACE_ERROR = 0x1F40, - BD_MARKETPLACE_RESOURCE_NOT_FOUND = 0x1F41, - BD_MARKETPLACE_INVALID_CURRENCY = 0x1F42, - BD_MARKETPLACE_INVALID_PARAMETER = 0x1F43, - BD_MARKETPLACE_RESOURCE_CONFLICT = 0x1F44, - BD_MARKETPLACE_STORAGE_ERROR = 0x1F45, - BD_MARKETPLACE_INTEGRITY_ERROR = 0x1F46, - BD_MARKETPLACE_INSUFFICIENT_FUNDS_ERROR = 0x1F47, - BD_MARKETPLACE_MMP_SERVICE_ERROR = 0x1F48, - BD_MARKETPLACE_PRECONDITION_REQUIRED = 0x1F49, - BD_MARKETPLACE_ITEM_MULTIPLE_PURCHASE_ERROR = 0x1F4A, - BD_MARKETPLACE_MISSING_REQUIRED_ENTITLEMENT = 0x1F4B, - BD_MARKETPLACE_VALIDATION_ERROR = 0x1F4C, - BD_MARKETPLACE_TENCENT_PAYMENT_ERROR = 0x1F4D, - BD_MARKETPLACE_SKU_NOT_COUPON_ENABLED_ERROR = 0x1F4E, - BD_LEAGUE_INVALID_TEAM_SIZE = 0x1FA4, - BD_LEAGUE_INVALID_TEAM = 0x1FA5, - BD_LEAGUE_INVALID_SUBDIVISION = 0x1FA6, - BD_LEAGUE_INVALID_LEAGUE = 0x1FA7, - BD_LEAGUE_TOO_MANY_RESULTS_REQUESTED = 0x1FA8, - BD_LEAGUE_METADATA_TOO_LARGE = 0x1FA9, - BD_LEAGUE_TEAM_ICON_TOO_LARGE = 0x1FAA, - BD_LEAGUE_TEAM_NAME_TOO_LONG = 0x1FAB, - BD_LEAGUE_ARRAY_SIZE_MISMATCH = 0x1FAC, - BD_LEAGUE_SUBDIVISION_MISMATCH = 0x2008, - BD_LEAGUE_INVALID_WRITE_TYPE = 0x2009, - BD_LEAGUE_INVALID_STATS_DATA = 0x200A, - BD_LEAGUE_SUBDIVISION_UNRANKED = 0x200B, - BD_LEAGUE_CROSS_TEAM_STATS_WRITE_PREVENTED = 0x200C, - BD_LEAGUE_INVALID_STATS_SEASON = 0x200D, - BD_COMMERCE_ERROR = 0x206C, - BD_COMMERCE_RESOURCE_NOT_FOUND = 0x206D, - BD_COMMERCE_STORAGE_INVALID_PARAMETER = 0x206E, - BD_COMMERCE_APPLICATION_INVALID_PARAMETER = 0x206F, - BD_COMMERCE_RESOURCE_CONFLICT = 0x2070, - BD_COMMERCE_STORAGE_ERROR = 0x2071, - BD_COMMERCE_INTEGRITY_ERROR = 0x2072, - BD_COMMERCE_MMP_SERVICE_ERROR = 0x2073, - BD_COMMERCE_PERMISSION_DENIED = 0x2074, - BD_COMMERCE_INSUFFICIENT_FUNDS_ERROR = 0x2075, - BD_COMMERCE_UNKNOWN_CURRENCY = 0x2076, - BD_COMMERCE_INVALID_RECEIPT = 0x2077, - BD_COMMERCE_RECEIPT_USED = 0x2078, - BD_COMMERCE_TRANSACTION_ALREADY_APPLIED = 0x2079, - BD_COMMERCE_INVALID_CURRENCY_TYPE = 0x207A, - BD_CONNECTION_COUNTER_ERROR = 0x20D0, - BD_LINKED_ACCOUNTS_INVALID_CONTEXT = 0x2198, - BD_LINKED_ACCOUNTS_INVALID_PLATFORM = 0x2199, - BD_LINKED_ACCOUNTS_LINKED_ACCOUNTS_FETCH_ERROR = 0x219A, - BD_LINKED_ACCOUNTS_INVALID_ACCOUNT = 0x219B, - BD_GMSG_INVALID_CATEGORY_ID = 0x27D8, - BD_GMSG_CATEGORY_MEMBERSHIPS_LIMIT = 0x27D9, - BD_GMSG_NONMEMBER_POST_DISALLOWED = 0x27DA, - BD_GMSG_CATEGORY_DISALLOWS_CLIENT_TYPE = 0x27DB, - BD_GMSG_PAYLOAD_TOO_BIG = 0x27DC, - BD_GMSG_MEMBER_POST_DISALLOWED = 0x27DD, - BD_GMSG_OVERLOADED = 0x27DE, - BD_GMSG_USER_PERCATEGORY_POST_RATE_EXCEEDED = 0x27DF, - BD_GMSG_USER_GLOBAL_POST_RATE_EXCEEDED = 0x27E0, - BD_GMSG_GROUP_POST_RATE_EXCEEDED = 0x27E1, - BD_MAX_ERROR_CODE = 0x27E2, - }; - - enum bdNATType : uint8_t - { - BD_NAT_UNKNOWN = 0x0, - BD_NAT_OPEN = 0x1, - BD_NAT_MODERATE = 0x2, - BD_NAT_STRICT = 0x3, - }; - - enum itemTextStyle - { - ITEM_TEXTSTYLE_NORMAL = 0, - ITEM_TEXTSTYLE_SHADOWED = 3, - ITEM_TEXTSTYLE_SHADOWEDMORE = 6, - ITEM_TEXTSTYLE_BORDERED = 7, - ITEM_TEXTSTYLE_BORDEREDMORE = 8, - ITEM_TEXTSTYLE_MONOSPACE = 128, - ITEM_TEXTSTYLE_MONOSPACESHADOWED = 132, - }; - - enum errorParm - { - ERR_FATAL = 0, - ERR_DROP = 1, - ERR_SERVERDISCONNECT = 2, - ERR_DISCONNECT = 3, - ERR_SCRIPT = 4, - ERR_SCRIPT_DROP = 5, - ERR_LOCALIZATION = 6, - ERR_MAPLOADERRORSUMMARY = 7, - }; - - enum errorCode - { - ERROR_NONE = 0x0, - ERROR_FATAL = 0x1, - ERROR_DROP = 0x2, - ERROR_FROM_STARTUP = 0x4, - ERROR_SERVERDISCONNECT = 0x8, - ERROR_DISCONNECT = 0x10, - ERROR_SCRIPT = 0x20, - ERROR_SCRIPT_DROP = 0x40, - ERROR_LOCALIZATION = 0x80, - ERROR_UI = 0x100, - ERROR_LUA = 0x200, - ERROR_SOFTRESTART = 0x400, - ERROR_SOFTRESTART_KEEPDW = 0x800, - }; - - enum XAssetType - { - ASSET_TYPE_PHYSPRESET = 0x0, - ASSET_TYPE_PHYSCONSTRAINTS = 0x1, - ASSET_TYPE_DESTRUCTIBLEDEF = 0x2, - ASSET_TYPE_XANIMPARTS = 0x3, - ASSET_TYPE_XMODEL = 0x4, - ASSET_TYPE_XMODELMESH = 0x5, - ASSET_TYPE_MATERIAL = 0x6, - ASSET_TYPE_COMPUTE_SHADER_SET = 0x7, - ASSET_TYPE_TECHNIQUE_SET = 0x8, - ASSET_TYPE_IMAGE = 0x9, - ASSET_TYPE_SOUND = 0xA, - ASSET_TYPE_SOUND_PATCH = 0xB, - ASSET_TYPE_CLIPMAP = 0xC, - ASSET_TYPE_COMWORLD = 0xD, - ASSET_TYPE_GAMEWORLD = 0xE, - ASSET_TYPE_MAP_ENTS = 0xF, - ASSET_TYPE_GFXWORLD = 0x10, - ASSET_TYPE_LIGHT_DEF = 0x11, - ASSET_TYPE_LENSFLARE_DEF = 0x12, - ASSET_TYPE_UI_MAP = 0x13, - ASSET_TYPE_FONT = 0x14, - ASSET_TYPE_FONTICON = 0x15, - ASSET_TYPE_LOCALIZE_ENTRY = 0x16, - ASSET_TYPE_WEAPON = 0x17, - ASSET_TYPE_WEAPONDEF = 0x18, - ASSET_TYPE_WEAPON_VARIANT = 0x19, - ASSET_TYPE_WEAPON_FULL = 0x1A, - ASSET_TYPE_CGMEDIA = 0x1B, - ASSET_TYPE_PLAYERSOUNDS = 0x1C, - ASSET_TYPE_PLAYERFX = 0x1D, - ASSET_TYPE_SHAREDWEAPONSOUNDS = 0x1E, - ASSET_TYPE_ATTACHMENT = 0x1F, - ASSET_TYPE_ATTACHMENT_UNIQUE = 0x20, - ASSET_TYPE_WEAPON_CAMO = 0x21, - ASSET_TYPE_CUSTOMIZATION_TABLE = 0x22, - ASSET_TYPE_CUSTOMIZATION_TABLE_FE_IMAGES = 0x23, - ASSET_TYPE_CUSTOMIZATION_TABLE_COLOR = 0x24, - ASSET_TYPE_SNDDRIVER_GLOBALS = 0x25, - ASSET_TYPE_FX = 0x26, - ASSET_TYPE_TAGFX = 0x27, - ASSET_TYPE_NEW_LENSFLARE_DEF = 0x28, - ASSET_TYPE_IMPACT_FX = 0x29, - ASSET_TYPE_IMPACT_SOUND = 0x2A, - ASSET_TYPE_PLAYER_CHARACTER = 0x2B, - ASSET_TYPE_AITYPE = 0x2C, - ASSET_TYPE_CHARACTER = 0x2D, - ASSET_TYPE_XMODELALIAS = 0x2E, - ASSET_TYPE_RAWFILE = 0x2F, - ASSET_TYPE_STRINGTABLE = 0x30, - ASSET_TYPE_STRUCTURED_TABLE = 0x31, - ASSET_TYPE_LEADERBOARD = 0x32, - ASSET_TYPE_DDL = 0x33, - ASSET_TYPE_GLASSES = 0x34, - ASSET_TYPE_TEXTURELIST = 0x35, - ASSET_TYPE_SCRIPTPARSETREE = 0x36, - ASSET_TYPE_KEYVALUEPAIRS = 0x37, - ASSET_TYPE_VEHICLEDEF = 0x38, - ASSET_TYPE_ADDON_MAP_ENTS = 0x39, - ASSET_TYPE_TRACER = 0x3A, - ASSET_TYPE_SLUG = 0x3B, - ASSET_TYPE_SURFACEFX_TABLE = 0x3C, - ASSET_TYPE_SURFACESOUNDDEF = 0x3D, - ASSET_TYPE_FOOTSTEP_TABLE = 0x3E, - ASSET_TYPE_ENTITYFXIMPACTS = 0x3F, - ASSET_TYPE_ENTITYSOUNDIMPACTS = 0x40, - ASSET_TYPE_ZBARRIER = 0x41, - ASSET_TYPE_VEHICLEFXDEF = 0x42, - ASSET_TYPE_VEHICLESOUNDDEF = 0x43, - ASSET_TYPE_TYPEINFO = 0x44, - ASSET_TYPE_SCRIPTBUNDLE = 0x45, - ASSET_TYPE_SCRIPTBUNDLELIST = 0x46, - ASSET_TYPE_RUMBLE = 0x47, - ASSET_TYPE_BULLETPENETRATION = 0x48, - ASSET_TYPE_LOCDMGTABLE = 0x49, - ASSET_TYPE_AIMTABLE = 0x4A, - ASSET_TYPE_ANIMSELECTORTABLESET = 0x4B, - ASSET_TYPE_ANIMMAPPINGTABLE = 0x4C, - ASSET_TYPE_ANIMSTATEMACHINE = 0x4D, - ASSET_TYPE_BEHAVIORTREE = 0x4E, - ASSET_TYPE_BEHAVIORSTATEMACHINE = 0x4F, - ASSET_TYPE_TTF = 0x50, - ASSET_TYPE_SANIM = 0x51, - ASSET_TYPE_LIGHT_DESCRIPTION = 0x52, - ASSET_TYPE_SHELLSHOCK = 0x53, - ASSET_TYPE_XCAM = 0x54, - ASSET_TYPE_BG_CACHE = 0x55, - ASSET_TYPE_TEXTURE_COMBO = 0x56, - ASSET_TYPE_FLAMETABLE = 0x57, - ASSET_TYPE_BITFIELD = 0x58, - ASSET_TYPE_ATTACHMENT_COSMETIC_VARIANT = 0x59, - ASSET_TYPE_MAPTABLE = 0x5A, - ASSET_TYPE_MAPTABLE_LOADING_IMAGES = 0x5B, - ASSET_TYPE_MEDAL = 0x5C, - ASSET_TYPE_MEDALTABLE = 0x5D, - ASSET_TYPE_OBJECTIVE = 0x5E, - ASSET_TYPE_OBJECTIVE_LIST = 0x5F, - ASSET_TYPE_UMBRA_TOME = 0x60, - ASSET_TYPE_NAVMESH = 0x61, - ASSET_TYPE_NAVVOLUME = 0x62, - ASSET_TYPE_BINARYHTML = 0x63, - ASSET_TYPE_LASER = 0x64, - ASSET_TYPE_BEAM = 0x65, - ASSET_TYPE_STREAMER_HINT = 0x66, - ASSET_TYPE_COUNT = 0x67, - ASSET_TYPE_STRING = 0x68, - ASSET_TYPE_ASSETLIST = 0x69, - ASSET_TYPE_REPORT = 0x6A, - ASSET_TYPE_DEPEND = 0x68, - ASSET_TYPE_FULL_COUNT = 0x6C, - }; - - struct RawFile - { - const char* name; - int len; - const char* buffer; - }; - - struct XZoneBuffer - { - const void* data; - size_t dataSize; - }; - - struct XZoneInfo - { - const char* name; - int allocFlags; - int freeFlags; - int allocSlot; - int freeSlot; - XZoneBuffer fileBuffer; - }; - - typedef void (*xcommand_t)(); - - struct cmd_function_s - { - cmd_function_s* next; - const char* name; - const char* autoCompleteDir; - const char* autoCompleteExt; - xcommand_t function; - int autoComplete; - }; - - struct CmdArgs - { - int nesting; - int localClientNum[8]; - int controllerIndex[8]; - int argshift[8]; - int argc[8]; - const char** argv[8]; - char textPool[8192]; - const char* argvPool[512]; - int usedTextPool[8]; - int totalUsedArgvPool; - int totalUsedTextPool; - }; - - struct va_info_t - { - char va_string[4][1024]; - int index; - }; - - struct TLSData - { - va_info_t* vaInfo; - jmp_buf* errorJmpBuf; - void* traceInfo; - CmdArgs* cmdArgs; - void* errorData; - }; - - typedef uint32_t dvarStrHash_t; - - enum dvarType_t - { - DVAR_TYPE_INVALID = 0x0, - DVAR_TYPE_BOOL = 0x1, - DVAR_TYPE_FLOAT = 0x2, - DVAR_TYPE_FLOAT_2 = 0x3, - DVAR_TYPE_FLOAT_3 = 0x4, - DVAR_TYPE_FLOAT_4 = 0x5, - DVAR_TYPE_INT = 0x6, - DVAR_TYPE_ENUM = 0x7, - DVAR_TYPE_STRING = 0x8, - DVAR_TYPE_COLOR = 0x9, - DVAR_TYPE_INT64 = 0xA, - DVAR_TYPE_UINT64 = 0xB, - DVAR_TYPE_LINEAR_COLOR_RGB = 0xC, - DVAR_TYPE_COLOR_XYZ = 0xD, - DVAR_TYPE_COLOR_LAB = 0xE, - DVAR_TYPE_SESSIONMODE_BASE_DVAR = 0xF, - DVAR_TYPE_COUNT = 0x10, - }; - - enum dvarFlags_e - { - DVAR_NONE = 0, - DVAR_ARCHIVE = 1 << 0, - DVAR_USERINFO = 1 << 1, - DVAR_SERVERINFO = 1 << 2, - DVAR_SYSTEMINFO = 1 << 3, - DVAR_LATCH = 1 << 4, - DVAR_ROM = 1 << 5, - DVAR_SAVED = 1 << 6, - DVAR_INIT = 1 << 7, - DVAR_CHEAT = 1 << 8, - //DVAR_UNKNOWN = 1 << 9, - DVAR_EXTERNAL = 1 << 10, - //DVAR_UNKNOWN3x = 1 << 11-13, - DVAR_SESSIONMODE = 1 << 15 - }; - - typedef float vec_t; - - union vec4_t - { - vec_t v[4]; - //vec4_t::$E8049E02A67BEF20C2B48C1E90A72E45 _anon_0; - //vec4_t::$65A5F67E76558B5B186374890F5F7384 _anon_1; - //vec3_t xyz; - }; - - struct dvar_t; - - struct DvarValue - { - union - { - bool enabled; - int integer; - uint32_t unsignedInt; - int64_t integer64; - uint64_t unsignedInt64; - float value; - vec4_t vector; - const char* string; - byte color[4]; - const dvar_t* indirect[3]; - } value; - - uint64_t encryptedValue; - }; - - union DvarLimits - { - struct - { - int stringCount; - const char** strings; - } enumeration; - - struct - { - int min; - int max; - } integer; - - struct - { - int64_t min; - int64_t max; - } integer64; - - struct - { - uint64_t min; - uint64_t max; - } unsignedInt64; - - struct - { - float min; - float max; - } value; - - struct - { - vec_t min; - vec_t max; - } vector; - }; - - struct dvar_t - { - dvarStrHash_t name; - const char* debugName; - const char* description; - unsigned int flags; - dvarType_t type; - bool modified; - DvarValue current; - DvarValue latched; - DvarValue reset; - DvarLimits domain; - dvar_t* hashNext; - }; - - struct netipv4_t - { - byte a; - byte b; - byte c; - byte d; - }; - - enum netadrtype_t - { - NA_BOT = 0x0, - NA_BAD = 0x1, - NA_LOOPBACK = 0x2, - NA_RAWIP = 0x3, - NA_IP = 0x4, - }; - - enum netsrc_t - { - NS_NULL = -1, - NS_CLIENT1 = 0x0, - NS_CLIENT2 = 0x1, - NS_CLIENT3 = 0x2, - NS_CLIENT4 = 0x3, - NS_SERVER = 0x4, - NS_MAXCLIENTS = 0x4, - NS_PACKET = 0x5, - }; - - struct netadr_t - { - union - { - netipv4_t ipv4; - uint32_t addr; - }; - - uint16_t port; - netadrtype_t type; - netsrc_t localNetID; - }; - - struct XNADDR - { - byte addrBuff[37]; - }; - - struct bdSecurityID - { - byte ab[8]; - }; - - typedef bdSecurityID XNKID; - - struct bdSecurityKey - { - byte ab[16]; - }; - - typedef bdSecurityKey XNKEY; - - typedef uint64_t XUID; - - struct SerializedAdr - { - byte valid; - byte addrBuff[37]; - }; - - struct XSESSION_INFO - { - XNKID sessionID; - XNADDR hostAddress; - XNKEY keyExchangeKey; - }; - - typedef int qboolean; - - enum PacketModeList - { - PACKETDATA_FIRST = 0x0, - PACKETDATA_UNDEFINED = 0x0, - PACKETDATA_HEADER = 0x1, - PACKETDATA_OVERHEAD = 0x2, - PACKETDATA_DATA = 0x3, - PACKETDATA_RELIABLEDATA = 0x4, - PACKETDATA_ZEROFLOAT = 0x5, - PACKETDATA_SMALLFLOAT = 0x6, - PACKETDATA_LARGEFLOAT = 0x7, - PACKETDATA_ZEROINT = 0x8, - PACKETDATA_SMALLANGLE = 0x9, - PACKETDATA_ZEROANGLE = 0xA, - PACKETDATA_TIMEDELTA = 0xB, - PACKETDATA_TIME = 0xC, - PACKETDATA_24BITFLAGINDEX = 0xD, - PACKETDATA_GROUNDENTITY = 0xE, - PACKETDATA_ENTITYNUM = 0xF, - PACKETDATA_LASTFIELDCHANGED = 0x10, - PACKETDATA_NOTNETWORKDATA = 0x11, - PACKETDATA_ORIGINDELTA = 0x12, - PACKETDATA_ORIGIN = 0x13, - NUM_PACKETDATA_MODES = 0x14, - }; - - struct PacketMode - { - unsigned int start; - PacketModeList mode; - }; - - struct msg_t - { - qboolean overflowed; - qboolean readOnly; - byte* data; - byte* splitData; - int maxsize; - int cursize; - int splitSize; - int readcount; - int bit; - int lastEntityRef; - qboolean flush; - netsrc_t targetLocalNetID; - //PacketMode analysis; - }; - - typedef void* bdCommonAddrRef; - - struct HostInfo - { - uint64_t xuid; - char name[32]; - netadr_t netAdr; - SerializedAdr serializedAdr; - bdSecurityID secId; - bdSecurityKey secKey; - uint32_t serverLocation; - }; - - enum LobbyType - { - LOBBY_TYPE_INVALID = 0xFFFFFFFF, - LOBBY_TYPE_PRIVATE = 0x0, - LOBBY_TYPE_GAME = 0x1, - LOBBY_TYPE_TRANSITION = 0x2, - LOBBY_TYPE_COUNT = 0x3, - LOBBY_TYPE_FIRST = 0x0, - LOBBY_TYPE_LAST = 0x2, - LOBBY_TYPE_AUTO = 0x3, - }; - - enum LobbyNetworkMode - { - LOBBY_NETWORKMODE_INVALID = 0xFFFFFFFF, - LOBBY_NETWORKMODE_LOCAL = 0x0, - LOBBY_NETWORKMODE_LAN = 0x1, - LOBBY_NETWORKMODE_LIVE = 0x2, - LOBBY_NETWORKMODE_COUNT = 0x3, - }; - - enum LobbyMainMode - { - LOBBY_MAINMODE_INVALID = 0xFFFFFFFF, - LOBBY_MAINMODE_CP = 0x0, - LOBBY_MAINMODE_MP = 0x1, - LOBBY_MAINMODE_ZM = 0x2, - LOBBY_MAINMODE_COUNT = 0x3, - }; - - struct LobbyParams - { - LobbyNetworkMode networkMode; - LobbyMainMode mainMode; - }; - - enum JoinType - { - JOIN_TYPE_NORMAL = 0x0, - JOIN_TYPE_PLAYLIST = 0x1, - JOIN_TYPE_FRIEND = 0x2, - JOIN_TYPE_INVITE = 0x3, - JOIN_TYPE_PARTY = 0x4, - JOIN_TYPE_COUNT = 0x5, - }; - - struct JoinHost - { - HostInfo info; - LobbyType lobbyType; - LobbyParams lobbyParams; - uint64_t reservationKey; - int retryTime; - int retryCount; - }; - - enum JoinSourceState - { - JOIN_SOURCE_STATE_IDLE = 0x0, - JOIN_SOURCE_STATE_CONNECT_TO_NEXT_HOST = 0x1, - JOIN_SOURCE_STATE_ASSOCIATING = 0x2, - JOIN_SOURCE_STATE_HANDSHAKING = 0x3, - JOIN_SOURCE_STATE_WAITING_FOR_AGREEMENT = 0x4, - JOIN_SOURCE_STATE_CONNECTION_FAILED = 0x5, - JOIN_SOURCE_STATE_CONNECTION_SUCCESS = 0x6, - JOIN_SOURCE_STATE_ENDING_HOST = 0x7, - JOIN_SOURCE_STATE_CLEANUP = 0x8, - JOIN_SOURCE_STATE_COUNT = 0x9, - }; - - enum JoinResult - { - JOIN_RESULT_INVALID = 0x0, - JOIN_RESULT_SUCCESS = 0x1, - JOIN_RESULT_CONNECT_TO_HOST_FAILURE = 0x2, - JOIN_RESULT_PROBE_SEND_FAILURE = 0x3, - JOIN_RESULT_PROBE_TIMEOUT = 0x4, - JOIN_RESULT_PROBE_INVALID_LOBBY = 0x5, - JOIN_RESULT_PROBE_INVALID_INFO = 0x6, - JOIN_RESULT_PROBE_RESULT_INVALID = 0x7, - JOIN_RESULT_INVALID_LOBBY = 0x8, - JOIN_RESULT_SEND_AGREEMENT_REQUEST_FAILED = 0x9, - JOIN_RESULT_HANDSHAKE_WINDOW_EXPIRED = 0xA, - JOIN_RESULT_AGREEMENT_WINDOW_EXPIRED = 0xB, - JOIN_RESULT_JOIN_DISABLED = 0xC, - JOIN_RESULT_JOIN_ALREADY_IN_PROGRESS = 0xD, - JOIN_RESULT_NOT_JOINABLE_NOT_HOSTING = 0xE, - JOIN_RESULT_NOT_JOINABLE_NOT_IDLE = 0xF, - JOIN_RESULT_NOT_JOINABLE_CLOSED = 0x10, - JOIN_RESULT_NOT_JOINABLE_INVITE_ONLY = 0x11, - JOIN_RESULT_NOT_JOINABLE_FRIENDS_ONLY = 0x12, - JOIN_RESULT_LOBBY_FULL = 0x13, - JOIN_RESULT_NETWORK_MODE_MISMATCH = 0x14, - JOIN_RESULT_MISMATCH_PLAYLISTID = 0x15, - JOIN_RESULT_MISMATCH_PLAYLIST_VERSION_TO_NEW = 0x16, - JOIN_RESULT_MISMATCH_PLAYLIST_VERSION_TO_OLD = 0x17, - JOIN_RESULT_MISMATCH_PROTOCOL_VERSION = 0x18, - JOIN_RESULT_MISMATCH_NETFIELD_CHECKSUM = 0x19, - JOIN_RESULT_MISMATCH_FFOTD_VERSION_TO_NEW = 0x1A, - JOIN_RESULT_MISMATCH_FFOTD_VERSION_TO_OLD = 0x1B, - JOIN_RESULT_MIGRATE_IN_PROGRESS = 0x1C, - JOIN_RESULT_COULD_NOT_RESERVE = 0x1D, - JOIN_RESPONSE_COUNT = 0x1E, - }; - - typedef void (*joinCompleteCallback)(int, JoinResult); - - struct AgreementStatus - { - XUID xuid; - char name[32]; - bool responded; - bool agrees; - int startTime; - int responseTime; - }; - - struct Agreement - { - int nonce; - AgreementStatus status[18]; - int requestCount; - int responseCount; - int agreeCount; - }; - - struct Join - { - JoinSourceState state; - int actionId; - int startTime; - int duration; - ControllerIndex_t controllerIndex; - LobbyType sourceLobbyType; - LobbyType targetLobbyType; - joinCompleteCallback joinComplete; - JoinHost hostList[50]; - int hostCount; - int processedCount; - bool isFinalized; - JoinHost potentialHost; - Agreement agreement; - Agreement debugAgreement; - JoinType joinType; - JoinResult joinResult; +#pragma once + +#define PROTOCOL 3 + +#ifdef __cplusplus +namespace game +{ +#endif + + enum ControllerIndex_t + { + INVALID_CONTROLLER_PORT = 0xFFFFFFFF, + CONTROLLER_INDEX_FIRST = 0x0, + CONTROLLER_INDEX_0 = 0x0, + CONTROLLER_INDEX_1 = 0x1, + CONTROLLER_INDEX_2 = 0x2, + CONTROLLER_INDEX_3 = 0x3, + CONTROLLER_INDEX_COUNT = 0x4, + }; + + enum eGameModes + { + MODE_GAME_MATCHMAKING_PLAYLIST = 0x0, + MODE_GAME_MATCHMAKING_MANUAL = 0x1, + MODE_GAME_DEFAULT = 0x2, + MODE_GAME_LEAGUE = 0x3, + MODE_GAME_THEATER = 0x4, + MODE_GAME_COUNT = 0x5, + MODE_GAME_INVALID = 0x5, + }; + + enum eModes + { + MODE_ZOMBIES = 0x0, + MODE_MULTIPLAYER = 0x1, + MODE_CAMPAIGN = 0x2, + MODE_COUNT = 0x3, + MODE_INVALID = 0x3, + MODE_FIRST = 0x0, + }; + + enum eNetworkModes + { + MODE_NETWORK_OFFLINE = 0x0, + MODE_NETWORK_SYSTEMLINK = 0x1, + MODE_NETWORK_ONLINE = 0x2, + MODE_NETWORK_COUNT = 0x3, + MODE_NETWORK_INVALID = 0x3, + }; + + enum MapPreload + { + MAP_PRELOAD_NONE = 0x0, + MAP_PRELOAD_FRONTEND = 0x1, + MAP_PRELOAD_IN_GAME = 0x2, + }; + + enum bdLobbyErrorCode + { + BD_NO_ERROR = 0x0, + BD_TOO_MANY_TASKS = 0x1, + BD_NOT_CONNECTED = 0x2, + BD_SEND_FAILED = 0x3, + BD_HANDLE_TASK_FAILED = 0x4, + BD_START_TASK_FAILED = 0x5, + BD_RESULT_EXCEEDS_BUFFER_SIZE = 0x64, + BD_ACCESS_DENIED = 0x65, + BD_EXCEPTION_IN_DB = 0x66, + BD_MALFORMED_TASK_HEADER = 0x67, + BD_INVALID_ROW = 0x68, + BD_EMPTY_ARG_LIST = 0x69, + BD_PARAM_PARSE_ERROR = 0x6A, + BD_PARAM_MISMATCHED_TYPE = 0x6B, + BD_SERVICE_NOT_AVAILABLE = 0x6C, + BD_CONNECTION_RESET = 0x6D, + BD_INVALID_USER_ID = 0x6E, + BD_LOBBY_PROTOCOL_VERSION_FAILURE = 0x6F, + BD_LOBBY_INTERNAL_FAILURE = 0x70, + BD_LOBBY_PROTOCOL_ERROR = 0x71, + BD_LOBBY_FAILED_TO_DECODE_UTF8 = 0x72, + BD_LOBBY_ASCII_EXPECTED = 0x73, + BD_ASYNCHRONOUS_ERROR = 0xC8, + BD_STREAMING_COMPLETE = 0xC9, + BD_MEMBER_NO_PROPOSAL = 0x12C, + BD_TEAMNAME_ALREADY_EXISTS = 0x12D, + BD_MAX_TEAM_MEMBERSHIPS_LIMITED = 0x12E, + BD_MAX_TEAM_OWNERSHIPS_LIMITED = 0x12F, + BD_NOT_A_TEAM_MEMBER = 0x130, + BD_INVALID_TEAM_ID = 0x131, + BD_INVALID_TEAM_NAME = 0x132, + BD_NOT_A_TEAM_OWNER = 0x133, + BD_NOT_AN_ADMIN_OR_OWNER = 0x134, + BD_MEMBER_PROPOSAL_EXISTS = 0x135, + BD_MEMBER_EXISTS = 0x136, + BD_TEAM_FULL = 0x137, + BD_VULGAR_TEAM_NAME = 0x138, + BD_TEAM_USERID_BANNED = 0x139, + BD_TEAM_EMPTY = 0x13A, + BD_INVALID_TEAM_PROFILE_QUERY_ID = 0x13B, + BD_TEAMNAME_TOO_SHORT = 0x13C, + BD_UNIQUE_PROFILE_DATA_EXISTS_ALREADY = 0x13D, + BD_INVALID_LEADERBOARD_ID = 0x190, + BD_INVALID_STATS_SET = 0x191, + BD_EMPTY_STATS_SET_IGNORED = 0x193, + BD_NO_DIRECT_ACCESS_TO_ARBITRATED_LBS = 0x194, + BD_STATS_WRITE_PERMISSION_DENIED = 0x195, + BD_STATS_WRITE_TYPE_DATA_TYPE_MISMATCH = 0x196, + BD_NO_STATS_FOR_USER = 0x197, + BD_INVALID_ACCESS_TO_UNRANKED_LB = 0x198, + BD_INVALID_EXTERNAL_TITLE_ID = 0x199, + BD_DIFFERENT_LEADERBOARD_SCHEMAS = 0x19A, + BD_TOO_MANY_LEADERBOARDS_REQUESTED = 0x19B, + BD_ENTITLEMENTS_ERROR = 0x19C, + BD_ENTITLEMENTS_INVALID_TITLEID = 0x19D, + BD_ENTITLEMENTS_INVALID_LEADERBOARDID = 0x19E, + BD_ENTITLEMENTS_INVALID_GET_MODE_FOR_TITLE = 0x19F, + BD_ENTITLEMENTS_URL_CONNECTION_ERROR = 0x1A0, + BD_ENTITLEMENTS_CONFIG_ERROR = 0x1A1, + BD_ENTITLEMENTS_NAMED_PARENT_ERROR = 0x1A2, + BD_ENTITLEMENTS_NAMED_KEY_ERROR = 0x1A3, + BD_TOO_MANY_ENTITY_IDS_REQUESTED = 0x1A4, + BD_STATS_READ_FAILED = 0x1A5, + BD_INVALID_TITLE_ID = 0x1F4, + BD_MESSAGING_INVALID_MAIL_ID = 0x258, + BD_SELF_BLOCK_NOT_ALLOWED = 0x259, + BD_GLOBAL_MESSAGE_ACCESS_DENIED = 0x25A, + BD_GLOBAL_MESSAGES_USER_LIMIT_EXCEEDED = 0x25B, + BD_MESSAGING_SENDER_DOES_NOT_EXIST = 0x25C, + BD_AUTH_NO_ERROR = 0x2BC, + BD_AUTH_BAD_REQUEST = 0x2BD, + BD_AUTH_SERVER_CONFIG_ERROR = 0x2BE, + BD_AUTH_BAD_TITLE_ID = 0x2BF, + BD_AUTH_BAD_ACCOUNT = 0x2C0, + BD_AUTH_ILLEGAL_OPERATION = 0x2C1, + BD_AUTH_INCORRECT_LICENSE_CODE = 0x2C2, + BD_AUTH_CREATE_USERNAME_EXISTS = 0x2C3, + BD_AUTH_CREATE_USERNAME_ILLEGAL = 0x2C4, + BD_AUTH_CREATE_USERNAME_VULGAR = 0x2C5, + BD_AUTH_CREATE_MAX_ACC_EXCEEDED = 0x2C6, + BD_AUTH_MIGRATE_NOT_SUPPORTED = 0x2C7, + BD_AUTH_TITLE_DISABLED = 0x2C8, + BD_AUTH_ACCOUNT_EXPIRED = 0x2C9, + BD_AUTH_ACCOUNT_LOCKED = 0x2CA, + BD_AUTH_UNKNOWN_ERROR = 0x2CB, + BD_AUTH_INCORRECT_PASSWORD = 0x2CC, + BD_AUTH_IP_NOT_IN_ALLOWED_RANGE = 0x2CD, + BD_AUTH_WII_TOKEN_VERIFICATION_FAILED = 0x2CE, + BD_AUTH_WII_AUTHENTICATION_FAILED = 0x2CF, + BD_AUTH_IP_KEY_LIMIT_REACHED = 0x2D0, + BD_AUTH_INVALID_GSPID = 0x2D1, + BD_AUTH_INVALID_IP_RANGE_ID = 0x2D2, + BD_AUTH_3DS_TOKEN_VERIFICATION_FAILED = 0x2D1, + BD_AUTH_3DS_AUTHENTICATION_FAILED = 0x2D2, + BD_AUTH_STEAM_APP_ID_MISMATCH = 0x2D3, + BD_AUTH_ABACCOUNTS_APP_ID_MISMATCH = 0x2D4, + BD_AUTH_CODO_USERNAME_NOT_SET = 0x2D5, + BD_AUTH_WIIU_TOKEN_VERIFICATION_FAILED = 0x2D6, + BD_AUTH_WIIU_AUTHENTICATION_FAILED = 0x2D7, + BD_AUTH_CODO_USERNAME_NOT_BASE64 = 0x2D8, + BD_AUTH_CODO_USERNAME_NOT_UTF8 = 0x2D9, + BD_AUTH_TENCENT_TICKET_EXPIRED = 0x2DA, + BD_AUTH_PS3_SERVICE_ID_MISMATCH = 0x2DB, + BD_AUTH_CODOID_NOT_WHITELISTED = 0x2DC, + BD_AUTH_PLATFORM_TOKEN_ERROR = 0x2DD, + BD_AUTH_JSON_FORMAT_ERROR = 0x2DE, + BD_AUTH_REPLY_CONTENT_ERROR = 0x2DF, + BD_AUTH_THIRD_PARTY_TOKEN_EXPIRED = 0x2E0, + BD_AUTH_CONTINUING = 0x2E1, + BD_AUTH_PLATFORM_DEVICE_ID_ERROR = 0x2E4, + BD_NO_PROFILE_INFO_EXISTS = 0x320, + BD_FRIENDSHIP_NOT_REQUSTED = 0x384, + BD_NOT_A_FRIEND = 0x385, + BD_SELF_FRIENDSHIP_NOT_ALLOWED = 0x387, + BD_FRIENDSHIP_EXISTS = 0x388, + BD_PENDING_FRIENDSHIP_EXISTS = 0x389, + BD_USERID_BANNED = 0x38A, + BD_FRIENDS_FULL = 0x38C, + BD_FRIENDS_NO_RICH_PRESENCE = 0x38D, + BD_RICH_PRESENCE_TOO_LARGE = 0x38E, + BD_NO_FILE = 0x3E8, + BD_PERMISSION_DENIED = 0x3E9, + BD_FILESIZE_LIMIT_EXCEEDED = 0x3EA, + BD_FILENAME_MAX_LENGTH_EXCEEDED = 0x3EB, + BD_EXTERNAL_STORAGE_SERVICE_ERROR = 0x3EC, + BD_CHANNEL_DOES_NOT_EXIST = 0x44D, + BD_CHANNEL_ALREADY_SUBSCRIBED = 0x44E, + BD_CHANNEL_NOT_SUBSCRIBED = 0x44F, + BD_CHANNEL_FULL = 0x450, + BD_CHANNEL_SUBSCRIPTIONS_FULL = 0x451, + BD_CHANNEL_NO_SELF_WHISPERING = 0x452, + BD_CHANNEL_ADMIN_REQUIRED = 0x453, + BD_CHANNEL_TARGET_NOT_SUBSCRIBED = 0x454, + BD_CHANNEL_REQUIRES_PASSWORD = 0x455, + BD_CHANNEL_TARGET_IS_SELF = 0x456, + BD_CHANNEL_PUBLIC_BAN_NOT_ALLOWED = 0x457, + BD_CHANNEL_USER_BANNED = 0x458, + BD_CHANNEL_PUBLIC_PASSWORD_NOT_ALLOWED = 0x459, + BD_CHANNEL_PUBLIC_KICK_NOT_ALLOWED = 0x45A, + BD_CHANNEL_MUTED = 0x45B, + BD_EVENT_DESC_TRUNCATED = 0x4B0, + BD_CONTENT_UNLOCK_UNKNOWN_ERROR = 0x514, + BD_UNLOCK_KEY_INVALID = 0x515, + BD_UNLOCK_KEY_ALREADY_USED_UP = 0x516, + BD_SHARED_UNLOCK_LIMIT_REACHED = 0x517, + BD_DIFFERENT_HARDWARE_ID = 0x518, + BD_INVALID_CONTENT_OWNER = 0x519, + BD_CONTENT_UNLOCK_INVALID_USER = 0x51A, + BD_CONTENT_UNLOCK_INVALID_CATEGORY = 0x51B, + BD_KEY_ARCHIVE_INVALID_WRITE_TYPE = 0x5DC, + BD_KEY_ARCHIVE_EXCEEDED_MAX_IDS_PER_REQUEST = 0x5DD, + BD_BANDWIDTH_TEST_TRY_AGAIN = 0x712, + BD_BANDWIDTH_TEST_STILL_IN_PROGRESS = 0x713, + BD_BANDWIDTH_TEST_NOT_PROGRESS = 0x714, + BD_BANDWIDTH_TEST_SOCKET_ERROR = 0x715, + BD_INVALID_SESSION_NONCE = 0x76D, + BD_ARBITRATION_FAILURE = 0x76F, + BD_ARBITRATION_USER_NOT_REGISTERED = 0x771, + BD_ARBITRATION_NOT_CONFIGURED = 0x772, + BD_CONTENTSTREAMING_FILE_NOT_AVAILABLE = 0x7D0, + BD_CONTENTSTREAMING_STORAGE_SPACE_EXCEEDED = 0x7D1, + BD_CONTENTSTREAMING_NUM_FILES_EXCEEDED = 0x7D2, + BD_CONTENTSTREAMING_UPLOAD_BANDWIDTH_EXCEEDED = 0x7D3, + BD_CONTENTSTREAMING_FILENAME_MAX_LENGTH_EXCEEDED = 0x7D4, + BD_CONTENTSTREAMING_MAX_THUMB_DATA_SIZE_EXCEEDED = 0x7D5, + BD_CONTENTSTREAMING_DOWNLOAD_BANDWIDTH_EXCEEDED = 0x7D6, + BD_CONTENTSTREAMING_NOT_ENOUGH_DOWNLOAD_BUFFER_SPACE = 0x7D7, + BD_CONTENTSTREAMING_SERVER_NOT_CONFIGURED = 0x7D8, + BD_CONTENTSTREAMING_INVALID_APPLE_RECEIPT = 0x7DA, + BD_CONTENTSTREAMING_APPLE_STORE_NOT_AVAILABLE = 0x7DB, + BD_CONTENTSTREAMING_APPLE_RECEIPT_FILENAME_MISMATCH = 0x7DC, + BD_CONTENTSTREAMING_HTTP_ERROR = 0x7E4, + BD_CONTENTSTREAMING_FAILED_TO_START_HTTP = 0x7E5, + BD_CONTENTSTREAMING_LOCALE_INVALID = 0x7E6, + BD_CONTENTSTREAMING_LOCALE_MISSING = 0x7E7, + BD_VOTERANK_ERROR_EMPTY_RATING_SUBMISSION = 0x7EE, + BD_VOTERANK_ERROR_MAX_VOTES_EXCEEDED = 0x7EF, + BD_VOTERANK_ERROR_INVALID_RATING = 0x7F0, + BD_MAX_NUM_TAGS_EXCEEDED = 0x82A, + BD_TAGGED_COLLECTION_DOES_NOT_EXIST = 0x82B, + BD_EMPTY_TAG_ARRAY = 0x82C, + BD_INVALID_QUERY_ID = 0x834, + BD_NO_ENTRY_TO_UPDATE = 0x835, + BD_SESSION_INVITE_EXISTS = 0x836, + BD_INVALID_SESSION_ID = 0x837, + BD_ATTACHMENT_TOO_LARGE = 0x838, + BD_INVALID_GROUP_ID = 0xAF0, + BD_MAIL_INVALID_MAIL_ID_ERROR = 0xB55, + BD_UCD_SERVICE_ERROR = 0xC80, + BD_UCD_SERVICE_DISABLED = 0xC81, + BD_UCD_UNINTIALIZED_ERROR = 0xC82, + BD_UCD_ACCOUNT_ALREADY_REGISTERED = 0xC83, + BD_UCD_ACCOUNT_NOT_REGISTERED = 0xC84, + BD_UCD_AUTH_ATTEMPT_FAILED = 0xC85, + BD_UCD_ACCOUNT_LINKING_ERROR = 0xC86, + BD_UCD_ENCRYPTION_ERROR = 0xC87, + BD_UCD_ACCOUNT_DATA_INVALID = 0xC88, + BD_UCD_ACCOUNT_DATA_INVALID_FIRSTNAME = 0xC89, + BD_UCD_ACCOUNT_DATA_INVALID_LASTNAME = 0xC8A, + BD_UCD_ACCOUNT_DATA_INVALID_DOB = 0xC8B, + BD_UCD_ACCOUNT_DATA_INVALID_EMAIL = 0xC8C, + BD_UCD_ACCOUNT_DATA_INVALID_COUNTRY = 0xC8D, + BD_UCD_ACCOUNT_DATA_INVALID_POSTCODE = 0xC8E, + BD_UCD_ACCOUNT_DATA_INVALID_PASSWORD = 0xC8F, + BD_UCD_ACCOUNT_NAME_ALREADY_RESISTERED = 0xC94, + BD_UCD_ACCOUNT_EMAIL_ALREADY_RESISTERED = 0xC95, + BD_UCD_GUEST_ACCOUNT_AUTH_CONFLICT = 0xC96, + BD_TWITCH_SERVICE_ERROR = 0xC1D, + BD_TWITCH_ACCOUNT_ALREADY_LINKED = 0xC1E, + BD_TWITCH_NO_LINKED_ACCOUNT = 0xC1F, + BD_YOUTUBE_SERVICE_ERROR = 0xCE5, + BD_YOUTUBE_SERVICE_COMMUNICATION_ERROR = 0xCE6, + BD_YOUTUBE_USER_DENIED_AUTHORIZATION = 0xCE7, + BD_YOUTUBE_AUTH_MAX_TIME_EXCEEDED = 0xCE8, + BD_YOUTUBE_USER_UNAUTHORIZED = 0xCE9, + BD_YOUTUBE_UPLOAD_MAX_TIME_EXCEEDED = 0xCEA, + BD_YOUTUBE_DUPLICATE_UPLOAD = 0xCEB, + BD_YOUTUBE_FAILED_UPLOAD = 0xCEC, + BD_YOUTUBE_ACCOUNT_ALREADY_REGISTERED = 0xCED, + BD_YOUTUBE_ACCOUNT_NOT_REGISTERED = 0xCEE, + BD_YOUTUBE_CONTENT_SERVER_ERROR = 0xCEF, + BD_YOUTUBE_UPLOAD_DOES_NOT_EXIST = 0xCF0, + BD_YOUTUBE_NO_LINKED_ACCOUNT = 0xCF1, + BD_YOUTUBE_DEVELOPER_TAGS_INVALID = 0xCF2, + BD_TWITTER_AUTH_ATTEMPT_FAILED = 0xDAD, + BD_TWITTER_AUTH_TOKEN_INVALID = 0xDAE, + BD_TWITTER_UPDATE_LIMIT_REACHED = 0xDAF, + BD_TWITTER_UNAVAILABLE = 0xDB0, + BD_TWITTER_ERROR = 0xDB1, + BD_TWITTER_TIMED_OUT = 0xDB2, + BD_TWITTER_DISABLED_FOR_USER = 0xDB3, + BD_TWITTER_ACCOUNT_AMBIGUOUS = 0xDB4, + BD_TWITTER_MAXIMUM_ACCOUNTS_REACHED = 0xDB5, + BD_TWITTER_ACCOUNT_NOT_REGISTERED = 0xDB6, + BD_TWITTER_DUPLICATE_STATUS = 0xDB7, + BD_TWITTER_ACCOUNT_ALREADY_REGISTERED = 0xE1C, + BD_FACEBOOK_AUTH_ATTEMPT_FAILED = 0xE11, + BD_FACEBOOK_AUTH_TOKEN_INVALID = 0xE12, + BD_FACEBOOK_PHOTO_DOES_NOT_EXIST = 0xE13, + BD_FACEBOOK_PHOTO_INVALID = 0xE14, + BD_FACEBOOK_PHOTO_ALBUM_FULL = 0xE15, + BD_FACEBOOK_UNAVAILABLE = 0xE16, + BD_FACEBOOK_ERROR = 0xE17, + BD_FACEBOOK_TIMED_OUT = 0xE18, + BD_FACEBOOK_DISABLED_FOR_USER = 0xE19, + BD_FACEBOOK_ACCOUNT_AMBIGUOUS = 0xE1A, + BD_FACEBOOK_MAXIMUM_ACCOUNTS_REACHED = 0xE1B, + BD_FACEBOOK_INVALID_NUM_PICTURES_REQUESTED = 0xE1C, + BD_FACEBOOK_VIDEO_DOES_NOT_EXIST = 0xE1D, + BD_FACEBOOK_ACCOUNT_ALREADY_REGISTERED = 0xE1E, + BD_APNS_INVALID_PAYLOAD = 0xE74, + BD_APNS_INVALID_TOKEN_LENGTH_ERROR = 0xE76, + BD_MAX_CONSOLEID_LENGTH_EXCEEDED = 0xEE1, + BD_MAX_WHITELIST_LENGTH_EXCEEDED = 0xEE2, + BD_USERGROUP_NAME_ALREADY_EXISTS = 0x1770, + BD_INVALID_USERGROUP_ID = 0x1771, + BD_USER_ALREADY_IN_USERGROUP = 0x1772, + BD_USER_NOT_IN_USERGROUP = 0x1773, + BD_INVALID_USERGROUP_MEMBER_TYPE = 0x1774, + BD_TOO_MANY_MEMBERS_REQUESTED = 0x1775, + BD_USERGROUP_NAME_TOO_SHORT = 0x1776, + BD_RICH_PRESENCE_DATA_TOO_LARGE = 0x1A90, + BD_RICH_PRESENCE_TOO_MANY_USERS = 0x1A91, + BD_PRESENCE_DATA_TOO_LARGE = 0x283C, + BD_PRESENCE_TOO_MANY_USERS = 0x283D, + BD_USER_LOGGED_IN_OTHER_TITLE = 0x283E, + BD_USER_NOT_LOGGED_IN = 0x283F, + BD_SUBSCRIPTION_TOO_MANY_USERS = 0x1B58, + BD_SUBSCRIPTION_TICKET_PARSE_ERROR = 0x1B59, + BD_CODO_ID_INVALID_DATA = 0x1BBC, + BD_INVALID_MESSAGE_FORMAT = 0x1BBD, + BD_TLOG_TOO_MANY_MESSAGES = 0x1BBE, + BD_CODO_ID_NOT_IN_WHITELIST = 0x1BBF, + BD_TLOG_MESSAGE_TRANSFORMATION_ERROR = 0x1BC0, + BD_REWARDS_NOT_ENABLED = 0x1BC1, + BD_MARKETPLACE_ERROR = 0x1F40, + BD_MARKETPLACE_RESOURCE_NOT_FOUND = 0x1F41, + BD_MARKETPLACE_INVALID_CURRENCY = 0x1F42, + BD_MARKETPLACE_INVALID_PARAMETER = 0x1F43, + BD_MARKETPLACE_RESOURCE_CONFLICT = 0x1F44, + BD_MARKETPLACE_STORAGE_ERROR = 0x1F45, + BD_MARKETPLACE_INTEGRITY_ERROR = 0x1F46, + BD_MARKETPLACE_INSUFFICIENT_FUNDS_ERROR = 0x1F47, + BD_MARKETPLACE_MMP_SERVICE_ERROR = 0x1F48, + BD_MARKETPLACE_PRECONDITION_REQUIRED = 0x1F49, + BD_MARKETPLACE_ITEM_MULTIPLE_PURCHASE_ERROR = 0x1F4A, + BD_MARKETPLACE_MISSING_REQUIRED_ENTITLEMENT = 0x1F4B, + BD_MARKETPLACE_VALIDATION_ERROR = 0x1F4C, + BD_MARKETPLACE_TENCENT_PAYMENT_ERROR = 0x1F4D, + BD_MARKETPLACE_SKU_NOT_COUPON_ENABLED_ERROR = 0x1F4E, + BD_LEAGUE_INVALID_TEAM_SIZE = 0x1FA4, + BD_LEAGUE_INVALID_TEAM = 0x1FA5, + BD_LEAGUE_INVALID_SUBDIVISION = 0x1FA6, + BD_LEAGUE_INVALID_LEAGUE = 0x1FA7, + BD_LEAGUE_TOO_MANY_RESULTS_REQUESTED = 0x1FA8, + BD_LEAGUE_METADATA_TOO_LARGE = 0x1FA9, + BD_LEAGUE_TEAM_ICON_TOO_LARGE = 0x1FAA, + BD_LEAGUE_TEAM_NAME_TOO_LONG = 0x1FAB, + BD_LEAGUE_ARRAY_SIZE_MISMATCH = 0x1FAC, + BD_LEAGUE_SUBDIVISION_MISMATCH = 0x2008, + BD_LEAGUE_INVALID_WRITE_TYPE = 0x2009, + BD_LEAGUE_INVALID_STATS_DATA = 0x200A, + BD_LEAGUE_SUBDIVISION_UNRANKED = 0x200B, + BD_LEAGUE_CROSS_TEAM_STATS_WRITE_PREVENTED = 0x200C, + BD_LEAGUE_INVALID_STATS_SEASON = 0x200D, + BD_COMMERCE_ERROR = 0x206C, + BD_COMMERCE_RESOURCE_NOT_FOUND = 0x206D, + BD_COMMERCE_STORAGE_INVALID_PARAMETER = 0x206E, + BD_COMMERCE_APPLICATION_INVALID_PARAMETER = 0x206F, + BD_COMMERCE_RESOURCE_CONFLICT = 0x2070, + BD_COMMERCE_STORAGE_ERROR = 0x2071, + BD_COMMERCE_INTEGRITY_ERROR = 0x2072, + BD_COMMERCE_MMP_SERVICE_ERROR = 0x2073, + BD_COMMERCE_PERMISSION_DENIED = 0x2074, + BD_COMMERCE_INSUFFICIENT_FUNDS_ERROR = 0x2075, + BD_COMMERCE_UNKNOWN_CURRENCY = 0x2076, + BD_COMMERCE_INVALID_RECEIPT = 0x2077, + BD_COMMERCE_RECEIPT_USED = 0x2078, + BD_COMMERCE_TRANSACTION_ALREADY_APPLIED = 0x2079, + BD_COMMERCE_INVALID_CURRENCY_TYPE = 0x207A, + BD_CONNECTION_COUNTER_ERROR = 0x20D0, + BD_LINKED_ACCOUNTS_INVALID_CONTEXT = 0x2198, + BD_LINKED_ACCOUNTS_INVALID_PLATFORM = 0x2199, + BD_LINKED_ACCOUNTS_LINKED_ACCOUNTS_FETCH_ERROR = 0x219A, + BD_LINKED_ACCOUNTS_INVALID_ACCOUNT = 0x219B, + BD_GMSG_INVALID_CATEGORY_ID = 0x27D8, + BD_GMSG_CATEGORY_MEMBERSHIPS_LIMIT = 0x27D9, + BD_GMSG_NONMEMBER_POST_DISALLOWED = 0x27DA, + BD_GMSG_CATEGORY_DISALLOWS_CLIENT_TYPE = 0x27DB, + BD_GMSG_PAYLOAD_TOO_BIG = 0x27DC, + BD_GMSG_MEMBER_POST_DISALLOWED = 0x27DD, + BD_GMSG_OVERLOADED = 0x27DE, + BD_GMSG_USER_PERCATEGORY_POST_RATE_EXCEEDED = 0x27DF, + BD_GMSG_USER_GLOBAL_POST_RATE_EXCEEDED = 0x27E0, + BD_GMSG_GROUP_POST_RATE_EXCEEDED = 0x27E1, + BD_MAX_ERROR_CODE = 0x27E2, + }; + + enum bdNATType : uint8_t + { + BD_NAT_UNKNOWN = 0x0, + BD_NAT_OPEN = 0x1, + BD_NAT_MODERATE = 0x2, + BD_NAT_STRICT = 0x3, + }; + + enum itemTextStyle + { + ITEM_TEXTSTYLE_NORMAL = 0, + ITEM_TEXTSTYLE_SHADOWED = 3, + ITEM_TEXTSTYLE_SHADOWEDMORE = 6, + ITEM_TEXTSTYLE_BORDERED = 7, + ITEM_TEXTSTYLE_BORDEREDMORE = 8, + ITEM_TEXTSTYLE_MONOSPACE = 128, + ITEM_TEXTSTYLE_MONOSPACESHADOWED = 132, + }; + + enum errorParm + { + ERR_FATAL = 0, + ERR_DROP = 1, + ERR_SERVERDISCONNECT = 2, + ERR_DISCONNECT = 3, + ERR_SCRIPT = 4, + ERR_SCRIPT_DROP = 5, + ERR_LOCALIZATION = 6, + ERR_MAPLOADERRORSUMMARY = 7, + }; + + enum errorCode + { + ERROR_NONE = 0x0, + ERROR_FATAL = 0x1, + ERROR_DROP = 0x2, + ERROR_FROM_STARTUP = 0x4, + ERROR_SERVERDISCONNECT = 0x8, + ERROR_DISCONNECT = 0x10, + ERROR_SCRIPT = 0x20, + ERROR_SCRIPT_DROP = 0x40, + ERROR_LOCALIZATION = 0x80, + ERROR_UI = 0x100, + ERROR_LUA = 0x200, + ERROR_SOFTRESTART = 0x400, + ERROR_SOFTRESTART_KEEPDW = 0x800, + }; + + enum XAssetType + { + ASSET_TYPE_PHYSPRESET = 0x0, + ASSET_TYPE_PHYSCONSTRAINTS = 0x1, + ASSET_TYPE_DESTRUCTIBLEDEF = 0x2, + ASSET_TYPE_XANIMPARTS = 0x3, + ASSET_TYPE_XMODEL = 0x4, + ASSET_TYPE_XMODELMESH = 0x5, + ASSET_TYPE_MATERIAL = 0x6, + ASSET_TYPE_COMPUTE_SHADER_SET = 0x7, + ASSET_TYPE_TECHNIQUE_SET = 0x8, + ASSET_TYPE_IMAGE = 0x9, + ASSET_TYPE_SOUND = 0xA, + ASSET_TYPE_SOUND_PATCH = 0xB, + ASSET_TYPE_CLIPMAP = 0xC, + ASSET_TYPE_COMWORLD = 0xD, + ASSET_TYPE_GAMEWORLD = 0xE, + ASSET_TYPE_MAP_ENTS = 0xF, + ASSET_TYPE_GFXWORLD = 0x10, + ASSET_TYPE_LIGHT_DEF = 0x11, + ASSET_TYPE_LENSFLARE_DEF = 0x12, + ASSET_TYPE_UI_MAP = 0x13, + ASSET_TYPE_FONT = 0x14, + ASSET_TYPE_FONTICON = 0x15, + ASSET_TYPE_LOCALIZE_ENTRY = 0x16, + ASSET_TYPE_WEAPON = 0x17, + ASSET_TYPE_WEAPONDEF = 0x18, + ASSET_TYPE_WEAPON_VARIANT = 0x19, + ASSET_TYPE_WEAPON_FULL = 0x1A, + ASSET_TYPE_CGMEDIA = 0x1B, + ASSET_TYPE_PLAYERSOUNDS = 0x1C, + ASSET_TYPE_PLAYERFX = 0x1D, + ASSET_TYPE_SHAREDWEAPONSOUNDS = 0x1E, + ASSET_TYPE_ATTACHMENT = 0x1F, + ASSET_TYPE_ATTACHMENT_UNIQUE = 0x20, + ASSET_TYPE_WEAPON_CAMO = 0x21, + ASSET_TYPE_CUSTOMIZATION_TABLE = 0x22, + ASSET_TYPE_CUSTOMIZATION_TABLE_FE_IMAGES = 0x23, + ASSET_TYPE_CUSTOMIZATION_TABLE_COLOR = 0x24, + ASSET_TYPE_SNDDRIVER_GLOBALS = 0x25, + ASSET_TYPE_FX = 0x26, + ASSET_TYPE_TAGFX = 0x27, + ASSET_TYPE_NEW_LENSFLARE_DEF = 0x28, + ASSET_TYPE_IMPACT_FX = 0x29, + ASSET_TYPE_IMPACT_SOUND = 0x2A, + ASSET_TYPE_PLAYER_CHARACTER = 0x2B, + ASSET_TYPE_AITYPE = 0x2C, + ASSET_TYPE_CHARACTER = 0x2D, + ASSET_TYPE_XMODELALIAS = 0x2E, + ASSET_TYPE_RAWFILE = 0x2F, + ASSET_TYPE_STRINGTABLE = 0x30, + ASSET_TYPE_STRUCTURED_TABLE = 0x31, + ASSET_TYPE_LEADERBOARD = 0x32, + ASSET_TYPE_DDL = 0x33, + ASSET_TYPE_GLASSES = 0x34, + ASSET_TYPE_TEXTURELIST = 0x35, + ASSET_TYPE_SCRIPTPARSETREE = 0x36, + ASSET_TYPE_KEYVALUEPAIRS = 0x37, + ASSET_TYPE_VEHICLEDEF = 0x38, + ASSET_TYPE_ADDON_MAP_ENTS = 0x39, + ASSET_TYPE_TRACER = 0x3A, + ASSET_TYPE_SLUG = 0x3B, + ASSET_TYPE_SURFACEFX_TABLE = 0x3C, + ASSET_TYPE_SURFACESOUNDDEF = 0x3D, + ASSET_TYPE_FOOTSTEP_TABLE = 0x3E, + ASSET_TYPE_ENTITYFXIMPACTS = 0x3F, + ASSET_TYPE_ENTITYSOUNDIMPACTS = 0x40, + ASSET_TYPE_ZBARRIER = 0x41, + ASSET_TYPE_VEHICLEFXDEF = 0x42, + ASSET_TYPE_VEHICLESOUNDDEF = 0x43, + ASSET_TYPE_TYPEINFO = 0x44, + ASSET_TYPE_SCRIPTBUNDLE = 0x45, + ASSET_TYPE_SCRIPTBUNDLELIST = 0x46, + ASSET_TYPE_RUMBLE = 0x47, + ASSET_TYPE_BULLETPENETRATION = 0x48, + ASSET_TYPE_LOCDMGTABLE = 0x49, + ASSET_TYPE_AIMTABLE = 0x4A, + ASSET_TYPE_ANIMSELECTORTABLESET = 0x4B, + ASSET_TYPE_ANIMMAPPINGTABLE = 0x4C, + ASSET_TYPE_ANIMSTATEMACHINE = 0x4D, + ASSET_TYPE_BEHAVIORTREE = 0x4E, + ASSET_TYPE_BEHAVIORSTATEMACHINE = 0x4F, + ASSET_TYPE_TTF = 0x50, + ASSET_TYPE_SANIM = 0x51, + ASSET_TYPE_LIGHT_DESCRIPTION = 0x52, + ASSET_TYPE_SHELLSHOCK = 0x53, + ASSET_TYPE_XCAM = 0x54, + ASSET_TYPE_BG_CACHE = 0x55, + ASSET_TYPE_TEXTURE_COMBO = 0x56, + ASSET_TYPE_FLAMETABLE = 0x57, + ASSET_TYPE_BITFIELD = 0x58, + ASSET_TYPE_ATTACHMENT_COSMETIC_VARIANT = 0x59, + ASSET_TYPE_MAPTABLE = 0x5A, + ASSET_TYPE_MAPTABLE_LOADING_IMAGES = 0x5B, + ASSET_TYPE_MEDAL = 0x5C, + ASSET_TYPE_MEDALTABLE = 0x5D, + ASSET_TYPE_OBJECTIVE = 0x5E, + ASSET_TYPE_OBJECTIVE_LIST = 0x5F, + ASSET_TYPE_UMBRA_TOME = 0x60, + ASSET_TYPE_NAVMESH = 0x61, + ASSET_TYPE_NAVVOLUME = 0x62, + ASSET_TYPE_BINARYHTML = 0x63, + ASSET_TYPE_LASER = 0x64, + ASSET_TYPE_BEAM = 0x65, + ASSET_TYPE_STREAMER_HINT = 0x66, + ASSET_TYPE_COUNT = 0x67, + ASSET_TYPE_STRING = 0x68, + ASSET_TYPE_ASSETLIST = 0x69, + ASSET_TYPE_REPORT = 0x6A, + ASSET_TYPE_DEPEND = 0x68, + ASSET_TYPE_FULL_COUNT = 0x6C, + }; + + struct RawFile + { + const char* name; + int len; + const char* buffer; + }; + + struct XZoneBuffer + { + const void* data; + size_t dataSize; + }; + + struct XZoneInfo + { + const char* name; + int allocFlags; + int freeFlags; + int allocSlot; + int freeSlot; + XZoneBuffer fileBuffer; + }; + + typedef void (*xcommand_t)(); + + struct cmd_function_s + { + cmd_function_s* next; + const char* name; + const char* autoCompleteDir; + const char* autoCompleteExt; + xcommand_t function; + int autoComplete; + }; + + struct CmdArgs + { + int nesting; + int localClientNum[8]; + int controllerIndex[8]; + int argshift[8]; + int argc[8]; + const char** argv[8]; + char textPool[8192]; + const char* argvPool[512]; + int usedTextPool[8]; + int totalUsedArgvPool; + int totalUsedTextPool; + }; + + struct va_info_t + { + char va_string[4][1024]; + int index; + }; + + struct TLSData + { + va_info_t* vaInfo; + jmp_buf* errorJmpBuf; + void* traceInfo; + CmdArgs* cmdArgs; + void* errorData; + }; + + typedef uint32_t dvarStrHash_t; + + enum dvarType_t + { + DVAR_TYPE_INVALID = 0x0, + DVAR_TYPE_BOOL = 0x1, + DVAR_TYPE_FLOAT = 0x2, + DVAR_TYPE_FLOAT_2 = 0x3, + DVAR_TYPE_FLOAT_3 = 0x4, + DVAR_TYPE_FLOAT_4 = 0x5, + DVAR_TYPE_INT = 0x6, + DVAR_TYPE_ENUM = 0x7, + DVAR_TYPE_STRING = 0x8, + DVAR_TYPE_COLOR = 0x9, + DVAR_TYPE_INT64 = 0xA, + DVAR_TYPE_UINT64 = 0xB, + DVAR_TYPE_LINEAR_COLOR_RGB = 0xC, + DVAR_TYPE_COLOR_XYZ = 0xD, + DVAR_TYPE_COLOR_LAB = 0xE, + DVAR_TYPE_SESSIONMODE_BASE_DVAR = 0xF, + DVAR_TYPE_COUNT = 0x10, + }; + + enum dvarFlags_e + { + DVAR_NONE = 0, + DVAR_ARCHIVE = 1 << 0, + DVAR_USERINFO = 1 << 1, + DVAR_SERVERINFO = 1 << 2, + DVAR_SYSTEMINFO = 1 << 3, + DVAR_LATCH = 1 << 4, + DVAR_ROM = 1 << 5, + DVAR_SAVED = 1 << 6, + DVAR_INIT = 1 << 7, + DVAR_CHEAT = 1 << 8, + //DVAR_UNKNOWN = 1 << 9, + DVAR_EXTERNAL = 1 << 10, + //DVAR_UNKNOWN3x = 1 << 11-13, + DVAR_SESSIONMODE = 1 << 15 + }; + + typedef float vec_t; + + union vec4_t + { + vec_t v[4]; + //vec4_t::$E8049E02A67BEF20C2B48C1E90A72E45 _anon_0; + //vec4_t::$65A5F67E76558B5B186374890F5F7384 _anon_1; + //vec3_t xyz; + }; + + struct dvar_t; + + struct DvarValue + { + union + { + bool enabled; + int integer; + uint32_t unsignedInt; + int64_t integer64; + uint64_t unsignedInt64; + float value; + vec4_t vector; + const char* string; + byte color[4]; + const dvar_t* indirect[3]; + } value; + + uint64_t encryptedValue; + }; + + union DvarLimits + { + struct + { + int stringCount; + const char** strings; + } enumeration; + + struct + { + int min; + int max; + } integer; + + struct + { + int64_t min; + int64_t max; + } integer64; + + struct + { + uint64_t min; + uint64_t max; + } unsignedInt64; + + struct + { + float min; + float max; + } value; + + struct + { + vec_t min; + vec_t max; + } vector; + }; + + struct dvar_t + { + dvarStrHash_t name; + const char* debugName; + const char* description; + unsigned int flags; + dvarType_t type; + bool modified; + DvarValue current; + DvarValue latched; + DvarValue reset; + DvarLimits domain; + dvar_t* hashNext; + }; + + struct netipv4_t + { + byte a; + byte b; + byte c; + byte d; + }; + + enum netadrtype_t + { + NA_BOT = 0x0, + NA_BAD = 0x1, + NA_LOOPBACK = 0x2, + NA_RAWIP = 0x3, + NA_IP = 0x4, + }; + + enum netsrc_t + { + NS_NULL = -1, + NS_CLIENT1 = 0x0, + NS_CLIENT2 = 0x1, + NS_CLIENT3 = 0x2, + NS_CLIENT4 = 0x3, + NS_SERVER = 0x4, + NS_MAXCLIENTS = 0x4, + NS_PACKET = 0x5, + }; + + struct netadr_t + { + union + { + netipv4_t ipv4; + uint32_t addr; + }; + + uint16_t port; + netadrtype_t type; + netsrc_t localNetID; + }; + + struct XNADDR + { + byte addrBuff[37]; + }; + + struct bdSecurityID + { + byte ab[8]; + }; + + typedef bdSecurityID XNKID; + + struct bdSecurityKey + { + byte ab[16]; + }; + + typedef bdSecurityKey XNKEY; + + typedef uint64_t XUID; + + struct SerializedAdr + { + byte valid; + byte addrBuff[37]; + }; + + struct XSESSION_INFO + { + XNKID sessionID; + XNADDR hostAddress; + XNKEY keyExchangeKey; + }; + + typedef int qboolean; + + enum PacketModeList + { + PACKETDATA_FIRST = 0x0, + PACKETDATA_UNDEFINED = 0x0, + PACKETDATA_HEADER = 0x1, + PACKETDATA_OVERHEAD = 0x2, + PACKETDATA_DATA = 0x3, + PACKETDATA_RELIABLEDATA = 0x4, + PACKETDATA_ZEROFLOAT = 0x5, + PACKETDATA_SMALLFLOAT = 0x6, + PACKETDATA_LARGEFLOAT = 0x7, + PACKETDATA_ZEROINT = 0x8, + PACKETDATA_SMALLANGLE = 0x9, + PACKETDATA_ZEROANGLE = 0xA, + PACKETDATA_TIMEDELTA = 0xB, + PACKETDATA_TIME = 0xC, + PACKETDATA_24BITFLAGINDEX = 0xD, + PACKETDATA_GROUNDENTITY = 0xE, + PACKETDATA_ENTITYNUM = 0xF, + PACKETDATA_LASTFIELDCHANGED = 0x10, + PACKETDATA_NOTNETWORKDATA = 0x11, + PACKETDATA_ORIGINDELTA = 0x12, + PACKETDATA_ORIGIN = 0x13, + NUM_PACKETDATA_MODES = 0x14, + }; + + struct PacketMode + { + unsigned int start; + PacketModeList mode; + }; + + struct msg_t + { + qboolean overflowed; + qboolean readOnly; + byte* data; + byte* splitData; + int maxsize; + int cursize; + int splitSize; + int readcount; + int bit; + int lastEntityRef; + qboolean flush; + netsrc_t targetLocalNetID; + //PacketMode analysis; + }; + + typedef void* bdCommonAddrRef; + + struct HostInfo + { + uint64_t xuid; + char name[32]; + netadr_t netAdr; + SerializedAdr serializedAdr; + bdSecurityID secId; + bdSecurityKey secKey; + uint32_t serverLocation; + }; + + enum LobbyType + { + LOBBY_TYPE_INVALID = 0xFFFFFFFF, + LOBBY_TYPE_PRIVATE = 0x0, + LOBBY_TYPE_GAME = 0x1, + LOBBY_TYPE_TRANSITION = 0x2, + LOBBY_TYPE_COUNT = 0x3, + LOBBY_TYPE_FIRST = 0x0, + LOBBY_TYPE_LAST = 0x2, + LOBBY_TYPE_AUTO = 0x3, + }; + + enum LobbyNetworkMode + { + LOBBY_NETWORKMODE_INVALID = 0xFFFFFFFF, + LOBBY_NETWORKMODE_LOCAL = 0x0, + LOBBY_NETWORKMODE_LAN = 0x1, + LOBBY_NETWORKMODE_LIVE = 0x2, + LOBBY_NETWORKMODE_COUNT = 0x3, + }; + + enum LobbyMainMode + { + LOBBY_MAINMODE_INVALID = 0xFFFFFFFF, + LOBBY_MAINMODE_CP = 0x0, + LOBBY_MAINMODE_MP = 0x1, + LOBBY_MAINMODE_ZM = 0x2, + LOBBY_MAINMODE_COUNT = 0x3, + }; + + struct LobbyParams + { + LobbyNetworkMode networkMode; + LobbyMainMode mainMode; + }; + + enum JoinType + { + JOIN_TYPE_NORMAL = 0x0, + JOIN_TYPE_PLAYLIST = 0x1, + JOIN_TYPE_FRIEND = 0x2, + JOIN_TYPE_INVITE = 0x3, + JOIN_TYPE_PARTY = 0x4, + JOIN_TYPE_COUNT = 0x5, + }; + + struct JoinHost + { + HostInfo info; + LobbyType lobbyType; + LobbyParams lobbyParams; + uint64_t reservationKey; + int retryTime; + int retryCount; + }; + + enum JoinSourceState + { + JOIN_SOURCE_STATE_IDLE = 0x0, + JOIN_SOURCE_STATE_CONNECT_TO_NEXT_HOST = 0x1, + JOIN_SOURCE_STATE_ASSOCIATING = 0x2, + JOIN_SOURCE_STATE_HANDSHAKING = 0x3, + JOIN_SOURCE_STATE_WAITING_FOR_AGREEMENT = 0x4, + JOIN_SOURCE_STATE_CONNECTION_FAILED = 0x5, + JOIN_SOURCE_STATE_CONNECTION_SUCCESS = 0x6, + JOIN_SOURCE_STATE_ENDING_HOST = 0x7, + JOIN_SOURCE_STATE_CLEANUP = 0x8, + JOIN_SOURCE_STATE_COUNT = 0x9, + }; + + enum JoinResult + { + JOIN_RESULT_INVALID = 0x0, + JOIN_RESULT_SUCCESS = 0x1, + JOIN_RESULT_CONNECT_TO_HOST_FAILURE = 0x2, + JOIN_RESULT_PROBE_SEND_FAILURE = 0x3, + JOIN_RESULT_PROBE_TIMEOUT = 0x4, + JOIN_RESULT_PROBE_INVALID_LOBBY = 0x5, + JOIN_RESULT_PROBE_INVALID_INFO = 0x6, + JOIN_RESULT_PROBE_RESULT_INVALID = 0x7, + JOIN_RESULT_INVALID_LOBBY = 0x8, + JOIN_RESULT_SEND_AGREEMENT_REQUEST_FAILED = 0x9, + JOIN_RESULT_HANDSHAKE_WINDOW_EXPIRED = 0xA, + JOIN_RESULT_AGREEMENT_WINDOW_EXPIRED = 0xB, + JOIN_RESULT_JOIN_DISABLED = 0xC, + JOIN_RESULT_JOIN_ALREADY_IN_PROGRESS = 0xD, + JOIN_RESULT_NOT_JOINABLE_NOT_HOSTING = 0xE, + JOIN_RESULT_NOT_JOINABLE_NOT_IDLE = 0xF, + JOIN_RESULT_NOT_JOINABLE_CLOSED = 0x10, + JOIN_RESULT_NOT_JOINABLE_INVITE_ONLY = 0x11, + JOIN_RESULT_NOT_JOINABLE_FRIENDS_ONLY = 0x12, + JOIN_RESULT_LOBBY_FULL = 0x13, + JOIN_RESULT_NETWORK_MODE_MISMATCH = 0x14, + JOIN_RESULT_MISMATCH_PLAYLISTID = 0x15, + JOIN_RESULT_MISMATCH_PLAYLIST_VERSION_TO_NEW = 0x16, + JOIN_RESULT_MISMATCH_PLAYLIST_VERSION_TO_OLD = 0x17, + JOIN_RESULT_MISMATCH_PROTOCOL_VERSION = 0x18, + JOIN_RESULT_MISMATCH_NETFIELD_CHECKSUM = 0x19, + JOIN_RESULT_MISMATCH_FFOTD_VERSION_TO_NEW = 0x1A, + JOIN_RESULT_MISMATCH_FFOTD_VERSION_TO_OLD = 0x1B, + JOIN_RESULT_MIGRATE_IN_PROGRESS = 0x1C, + JOIN_RESULT_COULD_NOT_RESERVE = 0x1D, + JOIN_RESPONSE_COUNT = 0x1E, + }; + + typedef void (*joinCompleteCallback)(int, JoinResult); + + struct AgreementStatus + { + XUID xuid; + char name[32]; + bool responded; + bool agrees; + int startTime; + int responseTime; + }; + + struct Agreement + { + int nonce; + AgreementStatus status[18]; + int requestCount; + int responseCount; + int agreeCount; + }; + + struct Join + { + JoinSourceState state; + int actionId; + int startTime; + int duration; + ControllerIndex_t controllerIndex; + LobbyType sourceLobbyType; + LobbyType targetLobbyType; + joinCompleteCallback joinComplete; + JoinHost hostList[50]; + int hostCount; + int processedCount; + bool isFinalized; + JoinHost potentialHost; + Agreement agreement; + Agreement debugAgreement; + JoinType joinType; + JoinResult joinResult; }; struct ServerInfo - { - uint16_t m_usConnectionPort; - uint16_t m_usQueryPort; + { + uint16_t m_usConnectionPort; + uint16_t m_usQueryPort; uint32_t m_unIP; int m_nPing; byte unk[0x22]; @@ -1058,824 +1058,824 @@ namespace game char tags[128]; int unk5; int unk6; - }; - -#ifdef __cplusplus - namespace hks - { - struct lua_State; - struct HashTable; - struct StringTable; - struct cclosure; - typedef int hksBool; - typedef char hksChar; - typedef unsigned __int8 hksByte; - typedef __int16 hksShort16; - typedef unsigned __int16 hksUshort16; - typedef float HksNumber; - typedef int hksInt32; - typedef unsigned int hksUint32; - typedef __int64 hksInt64; - typedef unsigned __int64 hksUint64; - - typedef int HksGcCost; - - - typedef size_t hksSize; - typedef void* (*lua_Alloc)(void*, void*, size_t, size_t); - typedef hksInt32 (*lua_CFunction)(lua_State*); - - struct GenericChunkHeader - { - hksSize m_flags; - }; - - struct ChunkHeader : GenericChunkHeader - { - ChunkHeader* m_next; - }; - - struct ChunkList - { - ChunkHeader m_head; - }; - - struct UserData : ChunkHeader - { - unsigned __int64 m_envAndSizeOffsetHighBits; - unsigned __int64 m_metaAndSizeOffsetLowBits; - char m_data[8]; - }; - - struct InternString - { - unsigned __int64 m_flags; - unsigned __int64 m_lengthbits; - unsigned int m_hash; - char m_data[30]; - }; - - union HksValue - { - cclosure* cClosure; - void* closure; - UserData* userData; - HashTable* table; - void* tstruct; - InternString* str; - void* thread; - void* ptr; - float number; - unsigned int native; - bool boolean; - }; - - enum HksObjectType - { - TANY = 0xFFFFFFFE, - TNONE = 0xFFFFFFFF, - TNIL = 0x0, - TBOOLEAN = 0x1, - TLIGHTUSERDATA = 0x2, - TNUMBER = 0x3, - TSTRING = 0x4, - TTABLE = 0x5, - TFUNCTION = 0x6, - // idk - TUSERDATA = 0x7, - TTHREAD = 0x8, - TIFUNCTION = 0x9, - // Lua function - TCFUNCTION = 0xA, - // C function - TUI64 = 0xB, - TSTRUCT = 0xC, - NUM_TYPE_OBJECTS = 0xE, - }; - - struct HksObject - { - HksObjectType t; - HksValue v; - }; - - const struct hksInstruction - { - unsigned int code; - }; - - struct ActivationRecord - { - HksObject* m_base; - const hksInstruction* m_returnAddress; - __int16 m_tailCallDepth; - __int16 m_numVarargs; - int m_numExpectedReturns; - }; - - struct CallStack - { - ActivationRecord* m_records; - ActivationRecord* m_lastrecord; - ActivationRecord* m_current; - const hksInstruction* m_current_lua_pc; - const hksInstruction* m_hook_return_addr; - int m_hook_level; - }; - - struct ApiStack - { - HksObject* top; - HksObject* base; - HksObject* alloc_top; - HksObject* bottom; - }; - - struct UpValue : ChunkHeader - { - HksObject m_storage; - HksObject* loc; - UpValue* m_next; - }; - - struct CallSite - { - _SETJMP_FLOAT128 m_jumpBuffer[16]; - CallSite* m_prev; - }; - - enum Status - { - NEW = 0x1, - RUNNING = 0x2, - YIELDED = 0x3, - DEAD_ERROR = 0x4, - }; - - enum HksError - { - HKS_NO_ERROR = 0, - HKS_ERRSYNTAX = -4, - HKS_ERRFILE = -5, - HKS_ERRRUN = -100, - HKS_ERRMEM = -200, - HKS_ERRERR = -300, - HKS_THROWING_ERROR = -500, - HKS_GC_YIELD = 1, - }; - - struct lua_Debug - { - int event; - const char* name; - const char* namewhat; - const char* what; - const char* source; - int currentline; - int nups; - int nparams; - int ishksfunc; - int linedefined; - int lastlinedefined; - char short_src[512]; - int callstack_level; - int is_tail_call; - }; - - using lua_function = int(__fastcall*)(lua_State*); - - struct luaL_Reg - { - const char* name; - lua_function function; - }; - - struct Node - { - HksObject m_key; - HksObject m_value; - }; - - struct StringPinner - { - struct Node - { - InternString* m_strings[32]; - Node* m_prev; - }; - - lua_State* const m_state; - StringPinner* const m_prev; - InternString** m_nextStringsPlace; - Node m_firstNode; - Node* m_currentNode; - }; - - struct StringTable - { - InternString** m_data; - unsigned int m_count; - unsigned int m_mask; - StringPinner* m_pinnedStrings; - }; - - struct Metatable - { - }; - - struct HashTable : ChunkHeader - { - Metatable* m_meta; - unsigned int m_version; - unsigned int m_mask; - Node* m_hashPart; - HksObject* m_arrayPart; - unsigned int m_arraySize; - Node* m_freeNode; - }; - - struct cclosure : ChunkHeader - { - lua_function m_function; - HashTable* m_env; - __int16 m_numUpvalues; - __int16 m_flags; - InternString* m_name; - HksObject m_upvalues[1]; - }; - - enum HksCompilerSettings_BytecodeSharingFormat - { - BYTECODE_DEFAULT = 0x0, - BYTECODE_INPLACE = 0x1, - BYTECODE_REFERENCED = 0x2, - }; - - enum HksCompilerSettings_IntLiteralOptions - { - INT_LITERALS_NONE = 0x0, - INT_LITERALS_LUD = 0x1, - INT_LITERALS_32BIT = 0x1, - INT_LITERALS_UI64 = 0x2, - INT_LITERALS_64BIT = 0x2, - INT_LITERALS_ALL = 0x3, - }; - - struct HksCompilerSettings - { - int m_emitStructCode; - const char** m_stripNames; - int m_emitGlobalMemoization; - int _m_isHksGlobalMemoTestingMode; - HksCompilerSettings_BytecodeSharingFormat m_bytecodeSharingFormat; - HksCompilerSettings_IntLiteralOptions m_enableIntLiterals; - int (*m_debugMap)(const char*, int); - }; - - enum HksBytecodeSharingMode : __int64 - { - HKS_BYTECODE_SHARING_OFF = 0, - HKS_BYTECODE_SHARING_ON = 1, - HKS_BYTECODE_SHARING_SECURE = 2 - }; - - struct HksGcWeights - { - int m_removeString; - int m_finalizeUserdataNoMM; - int m_finalizeUserdataGcMM; - int m_cleanCoroutine; - int m_removeWeak; - int m_markObject; - int m_traverseString; - int m_traverseUserdata; - int m_traverseCoroutine; - int m_traverseWeakTable; - int m_freeChunk; - int m_sweepTraverse; - }; - - struct GarbageCollector_Stack - { - void* m_storage; - unsigned int m_numEntries; - unsigned int m_numAllocated; - }; - - struct ProtoList - { - void** m_protoList; - unsigned __int16 m_protoSize; - unsigned __int16 m_protoAllocSize; - }; - - struct MemoryManager; - - struct GarbageCollector - { - struct ResumeStack - { - void* m_storage; - hksInt32 m_numEntries; - hksUint32 m_numAllocated; - }; - - struct GreyStack - { - HksObject* m_storage; - hksSize m_numEntries; - hksSize m_numAllocated; - }; - - struct RemarkStack - { - HashTable** m_storage; - hksSize m_numAllocated; - hksSize m_numEntries; - }; - - struct WeakStack_Entry - { - hksInt32 m_weakness; - HashTable* m_table; - }; - - struct WeakStack - { - WeakStack_Entry* m_storage; - hksInt32 m_numEntries; - hksUint32 m_numAllocated; - }; - - HksGcCost m_target; - HksGcCost m_stepsLeft; - HksGcCost m_stepLimit; - HksGcWeights m_costs; - HksGcCost m_unit; - void* m_jumpPoint; - lua_State* m_mainState; - lua_State* m_finalizerState; - MemoryManager* m_memory; - void* m_emergencyGCMemory; - hksInt32 m_phase; - ResumeStack m_resumeStack; - GreyStack m_greyStack; - RemarkStack m_remarkStack; - WeakStack m_weakStack; - hksBool m_finalizing; - HksObject m_safeTableValue; - lua_State* m_startOfStateStackList; - lua_State* m_endOfStateStackList; - lua_State* m_currentState; - HksObject m_safeValue; - void* m_compiler; - void* m_bytecodeReader; - void* m_bytecodeWriter; - hksInt32 m_pauseMultiplier; - HksGcCost m_stepMultiplier; - hksSize m_emergencyMemorySize; - bool m_stopped; - lua_CFunction m_gcPolicy; - hksSize m_pauseTriggerMemoryUsage; - hksInt32 m_stepTriggerCountdown; - hksUint32 m_stringTableIndex; - hksUint32 m_stringTableSize; - UserData* m_lastBlackUD; - UserData* m_activeUD; - }; - - enum MemoryManager_ChunkColor - { - RED = 0x0, - BLACK = 0x1, - }; - - enum Hks_DeleteCheckingMode - { - HKS_DELETE_CHECKING_OFF = 0x0, - HKS_DELETE_CHECKING_ACCURATE = 0x1, - HKS_DELETE_CHECKING_SAFE = 0x2, - }; - - struct MemoryManager - { - enum ChunkColor : __int32 - { - WHITE = 0x0, - BLACK = 0x1, - }; - - lua_Alloc m_allocator; - void* m_allocatorUd; - ChunkColor m_chunkColor; - hksSize m_used; - hksSize m_highwatermark; - ChunkList m_allocationList; - ChunkList m_sweepList; - ChunkHeader* m_lastKeptChunk; - lua_State* m_state; - }; - - struct StaticStringCache - { - HksObject m_objects[41]; - }; - - enum HksBytecodeEndianness - { - HKS_BYTECODE_DEFAULT_ENDIAN = 0x0, - HKS_BYTECODE_BIG_ENDIAN = 0x1, - HKS_BYTECODE_LITTLE_ENDIAN = 0x2, - }; - - struct RuntimeProfileData_Stats - { - unsigned __int64 hksTime; - unsigned __int64 callbackTime; - unsigned __int64 gcTime; - unsigned __int64 cFinalizerTime; - unsigned __int64 compilerTime; - unsigned int hkssTimeSamples; - unsigned int callbackTimeSamples; - unsigned int gcTimeSamples; - unsigned int compilerTimeSamples; - unsigned int num_newuserdata; - unsigned int num_tablerehash; - unsigned int num_pushstring; - unsigned int num_pushcfunction; - unsigned int num_newtables; - }; - - struct RuntimeProfileData - { - __int64 stackDepth; - __int64 callbackDepth; - unsigned __int64 lastTimer; - RuntimeProfileData_Stats frameStats; - unsigned __int64 gcStartTime; - unsigned __int64 finalizerStartTime; - unsigned __int64 compilerStartTime; - unsigned __int64 compilerStartGCTime; - unsigned __int64 compilerStartGCFinalizerTime; - unsigned __int64 compilerCallbackStartTime; - __int64 compilerDepth; - void* outFile; - lua_State* rootState; - }; - - struct HksGlobal - { - MemoryManager m_memory; - GarbageCollector m_collector; - StringTable m_stringTable; - __int64 padding3; - HksBytecodeSharingMode m_bytecodeSharingMode; - int padding; - HksObject m_registry; - ChunkList m_userDataList; - lua_State* m_root; - StaticStringCache m_staticStringCache; - void* m_debugger; - void* m_profiler; - RuntimeProfileData m_runProfilerData; - HksCompilerSettings m_compilerSettings; - int (*m_panicFunction)(lua_State*); - void* m_luaplusObjectList; - int m_heapAssertionFrequency; - int m_heapAssertionCount; - void (*m_logFunction)(lua_State*, const char*, ...); - void (*m_emergencyGCFailFunction)(lua_State*, size_t); - HksBytecodeEndianness m_bytecodeDumpEndianness; - int padding2; - }; - - struct lua_State - { - ChunkHeader baseclass; - HksGlobal* m_global; - CallStack m_callStack; - ApiStack m_apistack; - UpValue* pending; - HksObject globals; - HksObject m_cEnv; - CallSite* m_callsites; - int m_numberOfCCalls; - void* m_context; - InternString* m_name; - lua_State* m_nextState; - lua_State* m_nextStateStack; - Status m_status; - HksError m_error; - }; - } -#endif - - typedef uint32_t ScrVarCanonicalName_t; - - enum svscmd_type - { - SV_CMD_CAN_IGNORE_0 = 0x0, - SV_CMD_RELIABLE_0 = 0x1, - }; - - struct client_s - { - int client_state; - char __pad0[0x28]; - netadr_t address; - char __pad1[0x5588]; - uint64_t xuid; - char __pad2[0xB5D84]; - int guid; - char __pad3[0x8]; - bool bIsTestClient; - char __pad4[0x29DAC]; - }; - -#ifdef __cplusplus - static_assert(sizeof(client_s) == 0xE5110); - - static_assert(offsetof(game::client_s, address) == 0x2C); - static_assert(offsetof(game::client_s, xuid) == 0x55C8); - static_assert(offsetof(game::client_s, guid) == 0xBB354); - static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); -#endif - - struct client_s_cl : client_s - { - char __pad1_0[0x60]; - }; - -#ifdef __cplusplus - static_assert(sizeof(client_s_cl) == 0xE5170); -#endif - - enum scriptInstance_t - { - SCRIPTINSTANCE_SERVER = 0x0, - SCRIPTINSTANCE_CLIENT = 0x1, - SCRIPT_INSTANCE_MAX = 0x2, - }; - - struct gclient_s - { - char __pad0[0x8C]; - float velocity[3]; - char __pad1[59504]; - char flags; - }; - - struct EntityState - { - int number; - }; - - struct gentity_s - { - EntityState s; - unsigned char __pad0[0x24C]; - gclient_s* client; - unsigned char __pad1[0x2A0]; - }; - -#ifdef __cplusplus - static_assert(sizeof(gentity_s) == 0x4F8); -#endif - - enum workshop_type - { - WORKSHOP_MOD = 0x1, - WORKSHOP_USERMAP = 0x2 - }; - - struct workshop_data - { - char title[100]; - char folderName[32]; - char publisherId[32]; - char description[256]; - char contentPathToZoneFiles[260]; - char absolutePathContentFolder[260]; - char absolutePathZoneFiles[260]; - int unk; // 1 - int unk2; // 0 - unsigned int publisherIdInteger; - int unk3; - unsigned int unk4; - workshop_type type; - }; - -#ifdef __cplusplus - static_assert(sizeof(workshop_data) == 0x4C8); -#endif - - struct DDLMember - { - const char* name; - int index; - void* parent; - int bitSize; - int limitSize; - int offset; - int type; - int externalIndex; - unsigned int rangeLimit; - unsigned int serverDelta; - unsigned int clientDelta; - int arraySize; - int enumIndex; - int permission; - }; - - struct DDLHash - { - int hash; - int index; - }; - - struct DDLHashTable - { - DDLHash* list; - int count; - int max; - }; - - struct DDLStruct - { - const char* name; - int bitSize; - int memberCount; - DDLMember* members; - DDLHashTable hashTableUpper; - DDLHashTable hashTableLower; - }; - - struct DDLEnum - { - const char* name; - int memberCount; - const char** members; - DDLHashTable hashTable; - }; - - struct DDLDef - { - char* name; - uint16_t version; - unsigned int checksum; - byte flags; - int bitSize; - int byteSize; - DDLStruct* structList; - int structCount; - DDLEnum* enumList; - int enumCount; - DDLDef* next; - int headerBitSize; - int headerByteSize; - int reserveSize; - int userFlagsSize; - bool paddingUsed; - }; - - struct DDLContext; - typedef void (* DDLWriteCB)(DDLContext*, void*); - - struct DDLContext - { - void* buff; - int len; - const DDLDef* def; - DDLWriteCB writeCB; - void* userData; - }; - - struct emblemChallengeLookup_t - { - __int16 challengeIndex; - unsigned char itemIndex; - }; - - enum CharacterItemType - { - CHARACTER_ITEM_TYPE_BODY = 0x0, - CHARACTER_ITEM_TYPE_HELMET = 0x1, - CHARACTER_ITEM_TYPE_COUNT = 0x2, - }; - - typedef __int16 BGEmblemBackgroundID; - - union XAssetHeader - { - /*PhysPreset* physPreset; - PhysConstraints* physConstraints; - DestructibleDef* destructibleDef; - XAnimParts* parts; - XModel* model; - XModelMesh* modelMesh; - Material* material; - MaterialComputeShaderSet* computeShaderSet; - MaterialTechniqueSet* techniqueSet; - GfxImage* image; - SndBank* sound; - SndPatch* soundPatch; - clipMap_t* clipMap; - ComWorld* comWorld; - GameWorld* gameWorld; - MapEnts* mapEnts; - GfxWorld* gfxWorld; - GfxLightDef* lightDef; - GfxLensFlareDef* lensFlareDef; - Font* font; - FontIcon* fontIcon; - LocalizeEntry* localize; - WeaponVariantDef* weapon; - WeaponAttachment* attachment; - WeaponAttachmentUnique* attachmentUnique; - WeaponCamo* weaponCamo; - CustomizationTable* customizationTable; - CustomizationColorInfo* customizationColorInfo; - SndDriverGlobals* sndDriverGlobals; - FxEffectDefHandleRaw fx; - TagFxSet* tagFX; - FxLensFlareDefPtr newLensFlareDef; - FxImpactTable* impactFx; - SoundsImpactTable* impactSounds; - CgMediaTable* cgMedia; - PlayerSoundsTable* playerSounds; - PlayerFXTable* playerFX; - SharedWeaponSounds* sharedWeaponSounds; - RawFile* rawfile; - StringTable* stringTable; - StructuredTable* structuredTable; - LeaderboardDef* leaderboardDef; - DDLRoot* ddlRoot; - Glasses* glasses; - TextureList* textureList; - ScriptParseTree* scriptParseTree; - KeyValuePairs* keyValuePairs; - VehicleDef* vehicleDef; - AddonMapEnts* addonMapEnts; - TracerDef* tracerDef; - Qdb* qdb; - Slug* slug; - SurfaceFXTableDef* surfaceFXTableDef; - SurfaceSoundDef* surfaceSoundDef; - FootstepTableDef* footstepTableDef; - EntitySoundImpacts* entitySoundImpacts; - EntityFxImpacts* entityFxImpacts; - ZBarrierDef* zbarrierDef; - VehicleFxDef* vehicleFxDef; - VehicleSoundDef* vehicleSoundDef; - ArchiveTypeInfoArray* typeInfo; - ScriptBundle* scriptBundle; - ScriptBundleList* scriptBundleList; - RumbleInfo* rumble; - BulletPenetrationTable* bulletPenetration; - LocDmgTable* locDmgTable; - AimTable* aimTable; - XModelAlias* xModelAlias; - Character* character; - AIType* aiType; - PlayerCharacter* player_character; - AnimSelectorTableSet* animSelectorTableSet; - AnimMappingTable* animMappingTable; - AnimStateMachine* animStateMachine; - BehaviorTree* behaviorTree; - BehaviorStateMachine* behaviorStateMachine; - TTFDef* ttfDef; - GfxSiegeAnim* sanim; - GfxLightDescription* lightDescription; - ShellshockParams* shellshock; - XCam* xcam; - BGCacheInfo* bgCache; - TextureCombo* textureCombo; - FlameTable* flameTable; - Bitfield* bitfield; - AttachmentCosmeticVariant* attachmentCosmeticVariant; - MapTable* mapTable; - Medal* medal; - MedalTable* medalTable; - Objective* objective; - ObjectiveList* objectiveList; - NavMeshData* navMesh; - NavVolumeData* navVolume; - BinaryHTML* binaryHTML; - LaserDef* laserDef; - BeamDef* beamDef; - StreamerHint* streamerHint;*/ - void* data; - RawFile* luaFile; - }; - - struct XAsset - { - XAssetType type; - XAssetHeader header; - }; - - typedef void XAssetEnum(XAssetHeader, void*); - -#ifdef __cplusplus -} -#endif + }; + +#ifdef __cplusplus + namespace hks + { + struct lua_State; + struct HashTable; + struct StringTable; + struct cclosure; + typedef int hksBool; + typedef char hksChar; + typedef unsigned __int8 hksByte; + typedef __int16 hksShort16; + typedef unsigned __int16 hksUshort16; + typedef float HksNumber; + typedef int hksInt32; + typedef unsigned int hksUint32; + typedef __int64 hksInt64; + typedef unsigned __int64 hksUint64; + + typedef int HksGcCost; + + + typedef size_t hksSize; + typedef void* (*lua_Alloc)(void*, void*, size_t, size_t); + typedef hksInt32 (*lua_CFunction)(lua_State*); + + struct GenericChunkHeader + { + hksSize m_flags; + }; + + struct ChunkHeader : GenericChunkHeader + { + ChunkHeader* m_next; + }; + + struct ChunkList + { + ChunkHeader m_head; + }; + + struct UserData : ChunkHeader + { + unsigned __int64 m_envAndSizeOffsetHighBits; + unsigned __int64 m_metaAndSizeOffsetLowBits; + char m_data[8]; + }; + + struct InternString + { + unsigned __int64 m_flags; + unsigned __int64 m_lengthbits; + unsigned int m_hash; + char m_data[30]; + }; + + union HksValue + { + cclosure* cClosure; + void* closure; + UserData* userData; + HashTable* table; + void* tstruct; + InternString* str; + void* thread; + void* ptr; + float number; + unsigned int native; + bool boolean; + }; + + enum HksObjectType + { + TANY = 0xFFFFFFFE, + TNONE = 0xFFFFFFFF, + TNIL = 0x0, + TBOOLEAN = 0x1, + TLIGHTUSERDATA = 0x2, + TNUMBER = 0x3, + TSTRING = 0x4, + TTABLE = 0x5, + TFUNCTION = 0x6, + // idk + TUSERDATA = 0x7, + TTHREAD = 0x8, + TIFUNCTION = 0x9, + // Lua function + TCFUNCTION = 0xA, + // C function + TUI64 = 0xB, + TSTRUCT = 0xC, + NUM_TYPE_OBJECTS = 0xE, + }; + + struct HksObject + { + HksObjectType t; + HksValue v; + }; + + const struct hksInstruction + { + unsigned int code; + }; + + struct ActivationRecord + { + HksObject* m_base; + const hksInstruction* m_returnAddress; + __int16 m_tailCallDepth; + __int16 m_numVarargs; + int m_numExpectedReturns; + }; + + struct CallStack + { + ActivationRecord* m_records; + ActivationRecord* m_lastrecord; + ActivationRecord* m_current; + const hksInstruction* m_current_lua_pc; + const hksInstruction* m_hook_return_addr; + int m_hook_level; + }; + + struct ApiStack + { + HksObject* top; + HksObject* base; + HksObject* alloc_top; + HksObject* bottom; + }; + + struct UpValue : ChunkHeader + { + HksObject m_storage; + HksObject* loc; + UpValue* m_next; + }; + + struct CallSite + { + _SETJMP_FLOAT128 m_jumpBuffer[16]; + CallSite* m_prev; + }; + + enum Status + { + NEW = 0x1, + RUNNING = 0x2, + YIELDED = 0x3, + DEAD_ERROR = 0x4, + }; + + enum HksError + { + HKS_NO_ERROR = 0, + HKS_ERRSYNTAX = -4, + HKS_ERRFILE = -5, + HKS_ERRRUN = -100, + HKS_ERRMEM = -200, + HKS_ERRERR = -300, + HKS_THROWING_ERROR = -500, + HKS_GC_YIELD = 1, + }; + + struct lua_Debug + { + int event; + const char* name; + const char* namewhat; + const char* what; + const char* source; + int currentline; + int nups; + int nparams; + int ishksfunc; + int linedefined; + int lastlinedefined; + char short_src[512]; + int callstack_level; + int is_tail_call; + }; + + using lua_function = int(__fastcall*)(lua_State*); + + struct luaL_Reg + { + const char* name; + lua_function function; + }; + + struct Node + { + HksObject m_key; + HksObject m_value; + }; + + struct StringPinner + { + struct Node + { + InternString* m_strings[32]; + Node* m_prev; + }; + + lua_State* const m_state; + StringPinner* const m_prev; + InternString** m_nextStringsPlace; + Node m_firstNode; + Node* m_currentNode; + }; + + struct StringTable + { + InternString** m_data; + unsigned int m_count; + unsigned int m_mask; + StringPinner* m_pinnedStrings; + }; + + struct Metatable + { + }; + + struct HashTable : ChunkHeader + { + Metatable* m_meta; + unsigned int m_version; + unsigned int m_mask; + Node* m_hashPart; + HksObject* m_arrayPart; + unsigned int m_arraySize; + Node* m_freeNode; + }; + + struct cclosure : ChunkHeader + { + lua_function m_function; + HashTable* m_env; + __int16 m_numUpvalues; + __int16 m_flags; + InternString* m_name; + HksObject m_upvalues[1]; + }; + + enum HksCompilerSettings_BytecodeSharingFormat + { + BYTECODE_DEFAULT = 0x0, + BYTECODE_INPLACE = 0x1, + BYTECODE_REFERENCED = 0x2, + }; + + enum HksCompilerSettings_IntLiteralOptions + { + INT_LITERALS_NONE = 0x0, + INT_LITERALS_LUD = 0x1, + INT_LITERALS_32BIT = 0x1, + INT_LITERALS_UI64 = 0x2, + INT_LITERALS_64BIT = 0x2, + INT_LITERALS_ALL = 0x3, + }; + + struct HksCompilerSettings + { + int m_emitStructCode; + const char** m_stripNames; + int m_emitGlobalMemoization; + int _m_isHksGlobalMemoTestingMode; + HksCompilerSettings_BytecodeSharingFormat m_bytecodeSharingFormat; + HksCompilerSettings_IntLiteralOptions m_enableIntLiterals; + int (*m_debugMap)(const char*, int); + }; + + enum HksBytecodeSharingMode : __int64 + { + HKS_BYTECODE_SHARING_OFF = 0, + HKS_BYTECODE_SHARING_ON = 1, + HKS_BYTECODE_SHARING_SECURE = 2 + }; + + struct HksGcWeights + { + int m_removeString; + int m_finalizeUserdataNoMM; + int m_finalizeUserdataGcMM; + int m_cleanCoroutine; + int m_removeWeak; + int m_markObject; + int m_traverseString; + int m_traverseUserdata; + int m_traverseCoroutine; + int m_traverseWeakTable; + int m_freeChunk; + int m_sweepTraverse; + }; + + struct GarbageCollector_Stack + { + void* m_storage; + unsigned int m_numEntries; + unsigned int m_numAllocated; + }; + + struct ProtoList + { + void** m_protoList; + unsigned __int16 m_protoSize; + unsigned __int16 m_protoAllocSize; + }; + + struct MemoryManager; + + struct GarbageCollector + { + struct ResumeStack + { + void* m_storage; + hksInt32 m_numEntries; + hksUint32 m_numAllocated; + }; + + struct GreyStack + { + HksObject* m_storage; + hksSize m_numEntries; + hksSize m_numAllocated; + }; + + struct RemarkStack + { + HashTable** m_storage; + hksSize m_numAllocated; + hksSize m_numEntries; + }; + + struct WeakStack_Entry + { + hksInt32 m_weakness; + HashTable* m_table; + }; + + struct WeakStack + { + WeakStack_Entry* m_storage; + hksInt32 m_numEntries; + hksUint32 m_numAllocated; + }; + + HksGcCost m_target; + HksGcCost m_stepsLeft; + HksGcCost m_stepLimit; + HksGcWeights m_costs; + HksGcCost m_unit; + void* m_jumpPoint; + lua_State* m_mainState; + lua_State* m_finalizerState; + MemoryManager* m_memory; + void* m_emergencyGCMemory; + hksInt32 m_phase; + ResumeStack m_resumeStack; + GreyStack m_greyStack; + RemarkStack m_remarkStack; + WeakStack m_weakStack; + hksBool m_finalizing; + HksObject m_safeTableValue; + lua_State* m_startOfStateStackList; + lua_State* m_endOfStateStackList; + lua_State* m_currentState; + HksObject m_safeValue; + void* m_compiler; + void* m_bytecodeReader; + void* m_bytecodeWriter; + hksInt32 m_pauseMultiplier; + HksGcCost m_stepMultiplier; + hksSize m_emergencyMemorySize; + bool m_stopped; + lua_CFunction m_gcPolicy; + hksSize m_pauseTriggerMemoryUsage; + hksInt32 m_stepTriggerCountdown; + hksUint32 m_stringTableIndex; + hksUint32 m_stringTableSize; + UserData* m_lastBlackUD; + UserData* m_activeUD; + }; + + enum MemoryManager_ChunkColor + { + RED = 0x0, + BLACK = 0x1, + }; + + enum Hks_DeleteCheckingMode + { + HKS_DELETE_CHECKING_OFF = 0x0, + HKS_DELETE_CHECKING_ACCURATE = 0x1, + HKS_DELETE_CHECKING_SAFE = 0x2, + }; + + struct MemoryManager + { + enum ChunkColor : __int32 + { + WHITE = 0x0, + BLACK = 0x1, + }; + + lua_Alloc m_allocator; + void* m_allocatorUd; + ChunkColor m_chunkColor; + hksSize m_used; + hksSize m_highwatermark; + ChunkList m_allocationList; + ChunkList m_sweepList; + ChunkHeader* m_lastKeptChunk; + lua_State* m_state; + }; + + struct StaticStringCache + { + HksObject m_objects[41]; + }; + + enum HksBytecodeEndianness + { + HKS_BYTECODE_DEFAULT_ENDIAN = 0x0, + HKS_BYTECODE_BIG_ENDIAN = 0x1, + HKS_BYTECODE_LITTLE_ENDIAN = 0x2, + }; + + struct RuntimeProfileData_Stats + { + unsigned __int64 hksTime; + unsigned __int64 callbackTime; + unsigned __int64 gcTime; + unsigned __int64 cFinalizerTime; + unsigned __int64 compilerTime; + unsigned int hkssTimeSamples; + unsigned int callbackTimeSamples; + unsigned int gcTimeSamples; + unsigned int compilerTimeSamples; + unsigned int num_newuserdata; + unsigned int num_tablerehash; + unsigned int num_pushstring; + unsigned int num_pushcfunction; + unsigned int num_newtables; + }; + + struct RuntimeProfileData + { + __int64 stackDepth; + __int64 callbackDepth; + unsigned __int64 lastTimer; + RuntimeProfileData_Stats frameStats; + unsigned __int64 gcStartTime; + unsigned __int64 finalizerStartTime; + unsigned __int64 compilerStartTime; + unsigned __int64 compilerStartGCTime; + unsigned __int64 compilerStartGCFinalizerTime; + unsigned __int64 compilerCallbackStartTime; + __int64 compilerDepth; + void* outFile; + lua_State* rootState; + }; + + struct HksGlobal + { + MemoryManager m_memory; + GarbageCollector m_collector; + StringTable m_stringTable; + __int64 padding3; + HksBytecodeSharingMode m_bytecodeSharingMode; + int padding; + HksObject m_registry; + ChunkList m_userDataList; + lua_State* m_root; + StaticStringCache m_staticStringCache; + void* m_debugger; + void* m_profiler; + RuntimeProfileData m_runProfilerData; + HksCompilerSettings m_compilerSettings; + int (*m_panicFunction)(lua_State*); + void* m_luaplusObjectList; + int m_heapAssertionFrequency; + int m_heapAssertionCount; + void (*m_logFunction)(lua_State*, const char*, ...); + void (*m_emergencyGCFailFunction)(lua_State*, size_t); + HksBytecodeEndianness m_bytecodeDumpEndianness; + int padding2; + }; + + struct lua_State + { + ChunkHeader baseclass; + HksGlobal* m_global; + CallStack m_callStack; + ApiStack m_apistack; + UpValue* pending; + HksObject globals; + HksObject m_cEnv; + CallSite* m_callsites; + int m_numberOfCCalls; + void* m_context; + InternString* m_name; + lua_State* m_nextState; + lua_State* m_nextStateStack; + Status m_status; + HksError m_error; + }; + } +#endif + + typedef uint32_t ScrVarCanonicalName_t; + + enum svscmd_type + { + SV_CMD_CAN_IGNORE_0 = 0x0, + SV_CMD_RELIABLE_0 = 0x1, + }; + + struct client_s + { + int client_state; + char __pad0[0x28]; + netadr_t address; + char __pad1[0x5588]; + uint64_t xuid; + char __pad2[0xB5D84]; + int guid; + char __pad3[0x8]; + bool bIsTestClient; + char __pad4[0x29DAC]; + }; + +#ifdef __cplusplus + static_assert(sizeof(client_s) == 0xE5110); + + static_assert(offsetof(game::client_s, address) == 0x2C); + static_assert(offsetof(game::client_s, xuid) == 0x55C8); + static_assert(offsetof(game::client_s, guid) == 0xBB354); + static_assert(offsetof(game::client_s, bIsTestClient) == 0xBB360); +#endif + + struct client_s_cl : client_s + { + char __pad1_0[0x60]; + }; + +#ifdef __cplusplus + static_assert(sizeof(client_s_cl) == 0xE5170); +#endif + + enum scriptInstance_t + { + SCRIPTINSTANCE_SERVER = 0x0, + SCRIPTINSTANCE_CLIENT = 0x1, + SCRIPT_INSTANCE_MAX = 0x2, + }; + + struct gclient_s + { + char __pad0[0x8C]; + float velocity[3]; + char __pad1[59504]; + char flags; + }; + + struct EntityState + { + int number; + }; + + struct gentity_s + { + EntityState s; + unsigned char __pad0[0x24C]; + gclient_s* client; + unsigned char __pad1[0x2A0]; + }; + +#ifdef __cplusplus + static_assert(sizeof(gentity_s) == 0x4F8); +#endif + + enum workshop_type + { + WORKSHOP_MOD = 0x1, + WORKSHOP_USERMAP = 0x2 + }; + + struct workshop_data + { + char title[100]; + char folderName[32]; + char publisherId[32]; + char description[256]; + char contentPathToZoneFiles[260]; + char absolutePathContentFolder[260]; + char absolutePathZoneFiles[260]; + int unk; // 1 + int unk2; // 0 + unsigned int publisherIdInteger; + int unk3; + unsigned int unk4; + workshop_type type; + }; + +#ifdef __cplusplus + static_assert(sizeof(workshop_data) == 0x4C8); +#endif + + struct DDLMember + { + const char* name; + int index; + void* parent; + int bitSize; + int limitSize; + int offset; + int type; + int externalIndex; + unsigned int rangeLimit; + unsigned int serverDelta; + unsigned int clientDelta; + int arraySize; + int enumIndex; + int permission; + }; + + struct DDLHash + { + int hash; + int index; + }; + + struct DDLHashTable + { + DDLHash* list; + int count; + int max; + }; + + struct DDLStruct + { + const char* name; + int bitSize; + int memberCount; + DDLMember* members; + DDLHashTable hashTableUpper; + DDLHashTable hashTableLower; + }; + + struct DDLEnum + { + const char* name; + int memberCount; + const char** members; + DDLHashTable hashTable; + }; + + struct DDLDef + { + char* name; + uint16_t version; + unsigned int checksum; + byte flags; + int bitSize; + int byteSize; + DDLStruct* structList; + int structCount; + DDLEnum* enumList; + int enumCount; + DDLDef* next; + int headerBitSize; + int headerByteSize; + int reserveSize; + int userFlagsSize; + bool paddingUsed; + }; + + struct DDLContext; + typedef void (* DDLWriteCB)(DDLContext*, void*); + + struct DDLContext + { + void* buff; + int len; + const DDLDef* def; + DDLWriteCB writeCB; + void* userData; + }; + + struct emblemChallengeLookup_t + { + __int16 challengeIndex; + unsigned char itemIndex; + }; + + enum CharacterItemType + { + CHARACTER_ITEM_TYPE_BODY = 0x0, + CHARACTER_ITEM_TYPE_HELMET = 0x1, + CHARACTER_ITEM_TYPE_COUNT = 0x2, + }; + + typedef __int16 BGEmblemBackgroundID; + + union XAssetHeader + { + /*PhysPreset* physPreset; + PhysConstraints* physConstraints; + DestructibleDef* destructibleDef; + XAnimParts* parts; + XModel* model; + XModelMesh* modelMesh; + Material* material; + MaterialComputeShaderSet* computeShaderSet; + MaterialTechniqueSet* techniqueSet; + GfxImage* image; + SndBank* sound; + SndPatch* soundPatch; + clipMap_t* clipMap; + ComWorld* comWorld; + GameWorld* gameWorld; + MapEnts* mapEnts; + GfxWorld* gfxWorld; + GfxLightDef* lightDef; + GfxLensFlareDef* lensFlareDef; + Font* font; + FontIcon* fontIcon; + LocalizeEntry* localize; + WeaponVariantDef* weapon; + WeaponAttachment* attachment; + WeaponAttachmentUnique* attachmentUnique; + WeaponCamo* weaponCamo; + CustomizationTable* customizationTable; + CustomizationColorInfo* customizationColorInfo; + SndDriverGlobals* sndDriverGlobals; + FxEffectDefHandleRaw fx; + TagFxSet* tagFX; + FxLensFlareDefPtr newLensFlareDef; + FxImpactTable* impactFx; + SoundsImpactTable* impactSounds; + CgMediaTable* cgMedia; + PlayerSoundsTable* playerSounds; + PlayerFXTable* playerFX; + SharedWeaponSounds* sharedWeaponSounds; + RawFile* rawfile; + StringTable* stringTable; + StructuredTable* structuredTable; + LeaderboardDef* leaderboardDef; + DDLRoot* ddlRoot; + Glasses* glasses; + TextureList* textureList; + ScriptParseTree* scriptParseTree; + KeyValuePairs* keyValuePairs; + VehicleDef* vehicleDef; + AddonMapEnts* addonMapEnts; + TracerDef* tracerDef; + Qdb* qdb; + Slug* slug; + SurfaceFXTableDef* surfaceFXTableDef; + SurfaceSoundDef* surfaceSoundDef; + FootstepTableDef* footstepTableDef; + EntitySoundImpacts* entitySoundImpacts; + EntityFxImpacts* entityFxImpacts; + ZBarrierDef* zbarrierDef; + VehicleFxDef* vehicleFxDef; + VehicleSoundDef* vehicleSoundDef; + ArchiveTypeInfoArray* typeInfo; + ScriptBundle* scriptBundle; + ScriptBundleList* scriptBundleList; + RumbleInfo* rumble; + BulletPenetrationTable* bulletPenetration; + LocDmgTable* locDmgTable; + AimTable* aimTable; + XModelAlias* xModelAlias; + Character* character; + AIType* aiType; + PlayerCharacter* player_character; + AnimSelectorTableSet* animSelectorTableSet; + AnimMappingTable* animMappingTable; + AnimStateMachine* animStateMachine; + BehaviorTree* behaviorTree; + BehaviorStateMachine* behaviorStateMachine; + TTFDef* ttfDef; + GfxSiegeAnim* sanim; + GfxLightDescription* lightDescription; + ShellshockParams* shellshock; + XCam* xcam; + BGCacheInfo* bgCache; + TextureCombo* textureCombo; + FlameTable* flameTable; + Bitfield* bitfield; + AttachmentCosmeticVariant* attachmentCosmeticVariant; + MapTable* mapTable; + Medal* medal; + MedalTable* medalTable; + Objective* objective; + ObjectiveList* objectiveList; + NavMeshData* navMesh; + NavVolumeData* navVolume; + BinaryHTML* binaryHTML; + LaserDef* laserDef; + BeamDef* beamDef; + StreamerHint* streamerHint;*/ + void* data; + RawFile* luaFile; + }; + + struct XAsset + { + XAssetType type; + XAssetHeader header; + }; + + typedef void XAssetEnum(XAssetHeader, void*); + +#ifdef __cplusplus +} +#endif diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 38090235..8109ed95 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -1,269 +1,272 @@ -#pragma once - -#include "structs.hpp" - -#define WEAK __declspec(selectany) - -namespace game -{ -#define Com_Error(code, fmt, ...) Com_Error_(__FILE__, __LINE__, code, fmt, ##__VA_ARGS__) - - // CL - WEAK symbol CL_ConnectFromLobby - {0x14134C570}; - WEAK symbol CL_GetClientName{ - 0x1413E3140 - }; - - // Game - WEAK symbol G_Say{0x0, 0x140299170}; - WEAK symbol G_LogPrintf{0x0, 0x1402A7BB0}; - - // Com - WEAK symbol Com_Printf{0x142148F60, 0x140505630}; - WEAK symbol Com_Error_{0x1420F8170, 0x140501470}; - WEAK symbol Com_SessionMode_IsMode{0x1420F7370}; - WEAK symbol Com_SessionMode_SetNetworkMode{0x1420F75B0, 0x140500B80}; - WEAK symbol Com_SessionMode_SetGameMode{0x1420F7570, 0x140500B40}; - WEAK symbol Com_SessionMode_SetMode{0x1420F7570}; - WEAK symbol Com_GametypeSettings_SetGametype{ - 0x1420F5980 - }; - WEAK symbol Com_GametypeSettings_GetUInt{0x1420F4E00, 0x1404FE5C0}; - WEAK symbol Com_IsRunningUILevel{0x142148350}; - WEAK symbol Com_SwitchMode{ - 0x14214A4D0 - }; - WEAK symbol Com_LoadRawTextFile{0x1420F61B0}; - - WEAK symbol Cbuf_AddText{0x1420EC010, 0x1404F75B0}; - WEAK symbol Cbuf_ExecuteBuffer{ - 0x14133BE10, 0x1404F78D0 - }; - WEAK symbol Cmd_AddCommandInternal{ - 0x1420ECC90, 0x1404F8210 - }; - WEAK symbol Cbuf_AddServerText_f{0x0, 0x1407DB4C0}; - WEAK symbol Cmd_AddServerCommandInternal - { - 0x0, 0x1404F8280 - }; - WEAK symbol Cmd_ExecuteSingleCommand{ - 0x1420ED380, 0x1404F8890 - }; - WEAK symbol Cmd_TokenizeStringKernel{0x1420EED60, 0x1404FA300}; - WEAK symbol Cmd_EndTokenizedString{0x1420ECED0, 0x1404F8420}; - WEAK symbol Con_GetTextCopy{0x14133A7D0, 0x140182C40}; - - // DB - WEAK symbol DB_LoadXAssets{ - 0x1414236A0 - }; - WEAK symbol DB_EnumXAssets{ - 0x141420970, 0x1401D5A50 - }; - WEAK symbol DB_FindXAssetHeader{ - 0x141420ED0, 0x1401D5FB0 - }; - WEAK symbol DB_GetXAssetName{0x1413E9DA0, 0x14019F080}; - WEAK symbol DB_FileExists{0x141420B40}; - WEAK symbol DB_ReleaseXAssets{0x1414247C0}; - - // Live +#pragma once + +#include "structs.hpp" + +#define WEAK __declspec(selectany) + +namespace game +{ +#define Com_Error(code, fmt, ...) Com_Error_(__FILE__, __LINE__, code, fmt, ##__VA_ARGS__) + + // CL + WEAK symbol CL_ConnectFromLobby + {0x14134C570}; + WEAK symbol CL_GetClientName{ + 0x1413E3140 + }; + + // Game + WEAK symbol G_Say{0x0, 0x140299170}; + WEAK symbol G_LogPrintf{0x0, 0x1402A7BB0}; + + // Com + WEAK symbol Com_Printf{0x142148F60, 0x140505630}; + WEAK symbol Com_Error_{0x1420F8170, 0x140501470}; + WEAK symbol Com_SessionMode_IsMode{0x1420F7370}; + WEAK symbol Com_SessionMode_SetNetworkMode{0x1420F75B0, 0x140500B80}; + WEAK symbol Com_SessionMode_SetGameMode{0x1420F7570, 0x140500B40}; + WEAK symbol Com_SessionMode_SetMode{0x1420F7570}; + WEAK symbol Com_GametypeSettings_SetGametype{ + 0x1420F5980 + }; + WEAK symbol Com_GametypeSettings_GetUInt{ + 0x1420F4E00, 0x1404FE5C0 + }; + WEAK symbol Com_IsRunningUILevel{0x142148350}; + WEAK symbol Com_SwitchMode{ + 0x14214A4D0 + }; + WEAK symbol Com_LoadRawTextFile{0x1420F61B0}; + + WEAK symbol Cbuf_AddText{0x1420EC010, 0x1404F75B0}; + WEAK symbol Cbuf_ExecuteBuffer{ + 0x14133BE10, 0x1404F78D0 + }; + WEAK symbol Cmd_AddCommandInternal{ + 0x1420ECC90, 0x1404F8210 + }; + WEAK symbol Cbuf_AddServerText_f{0x0, 0x1407DB4C0}; + WEAK symbol Cmd_AddServerCommandInternal + { + 0x0, 0x1404F8280 + }; + WEAK symbol Cmd_ExecuteSingleCommand{ + 0x1420ED380, 0x1404F8890 + }; + WEAK symbol Cmd_TokenizeStringKernel{0x1420EED60, 0x1404FA300}; + WEAK symbol Cmd_EndTokenizedString{0x1420ECED0, 0x1404F8420}; + WEAK symbol Con_GetTextCopy{0x14133A7D0, 0x140182C40}; + + // DB + WEAK symbol DB_LoadXAssets{ + 0x1414236A0 + }; + WEAK symbol DB_EnumXAssets{ + 0x141420970, 0x1401D5A50 + }; + WEAK symbol DB_FindXAssetHeader{ + 0x141420ED0, 0x1401D5FB0 + }; + WEAK symbol DB_GetXAssetName{0x1413E9DA0, 0x14019F080}; + WEAK symbol DB_FileExists{0x141420B40}; + WEAK symbol DB_ReleaseXAssets{0x1414247C0}; + + // Live WEAK symbol Live_GetConnectivityInformation{0x141E0C380}; // Info - WEAK symbol Info_ValueForKey{ 0x1422E87B0 }; - - // MSG - WEAK symbol MSG_ReadByte{0x142155450, 0x14050D1B0}; - - // NET - WEAK symbol NET_SendPacket{ - 0x1423323B0, 0x140596E40 - }; - WEAK symbol NET_StringToAdr{0x142172780, 0x140515110}; - - // Sys - WEAK symbol Sys_Milliseconds{0x142332870}; - WEAK symbol Sys_ShowConsole{0x1423333C0, 0x140597E40}; - WEAK symbol Sys_GetTLS{0x1421837B0, 0x140525EB0}; - WEAK symbol Sys_IsDatabaseReady{0x142183A60}; - - // Unnamed - WEAK symbol CopyString{0x1422AC220, 0x14056BD70}; - - WEAK symbol isModLoaded{0x1420D5020}; - WEAK symbol loadMod{0x1420D6930}; - - // Dvar - WEAK symbol Dvar_IsSessionModeBaseDvar{0x1422C23A0, 0x140576890}; - WEAK symbol Dvar_FindVar{0x1422BCCD0, 0x140575540}; - WEAK symbol Dvar_GenerateHash{0x14133DBF0, 0x140185800}; - WEAK symbol Dvar_FindMalleableVar{0x1422BCC40}; - WEAK symbol Dvar_GetDebugName{0x1422BD250}; - WEAK symbol Dvar_GetString{0x1422BF590, 0x140575E30}; - WEAK symbol Dvar_DisplayableValue{0x1422BC080}; - WEAK symbol Dvar_GetBool{0x1422BCED0}; - WEAK symbol Dvar_GetInt{0x0, 0x140575C20}; - WEAK symbol Dvar_GetFLoat{0x0, 0x140575B20}; - WEAK symbol Dvar_RegisterBool{ - 0x1422D0900, 0x14057B500 - }; - WEAK symbol Dvar_RegisterFloat{ - 0x0, 0x14057B6B0 - }; - WEAK symbol Dvar_SessionModeRegisterBool{ - 0x1422D0D40, 0x14057BAA0 - }; - WEAK symbol Dvar_SessionModeSetDefaultBool{ - 0x1422D0E90, 0x14057BCE0 - }; - WEAK symbol Dvar_RegisterString{ - 0x1422D0B70, 0x14057B890 - }; - WEAK symbol Dvar_ForEach{0x1422BCD00}; - WEAK symbol Dvar_SetFromStringByName{ - 0x1422C7500 - }; - WEAK symbol Dvar_GetSessionModeSpecificDvar{ - 0x1422BF500, 0x140575D90 - }; - - // UI - WEAK symbol UI_CoD_Init{0x141F29010, 0x1404A0A50}; - WEAK symbol UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50}; - WEAK symbol UI_CoD_Shutdown{0x141F32E10, 0x0}; - WEAK symbol UI_AddMenu{0x1427018F0, 0x0}; - WEAK symbol UI_CoD_GetRootNameForController{0x141F28940, 0x0}; - WEAK symbol Lua_CoD_LoadLuaFile{0x141F11A20, 0x0}; - WEAK symbol CG_LUIHUDRestart{0x140F7E970}; + WEAK symbol Info_ValueForKey{0x1422E87B0}; + + // MSG + WEAK symbol MSG_ReadByte{0x142155450, 0x14050D1B0}; + + // NET + WEAK symbol NET_OutOfBandData{0x142173600}; + WEAK symbol NET_SendPacket{ + 0x1423323B0, 0x140596E40 + }; + WEAK symbol NET_StringToAdr{0x142172780, 0x140515110}; + + // Sys + WEAK symbol Sys_Milliseconds{0x142332870}; + WEAK symbol Sys_ShowConsole{0x1423333C0, 0x140597E40}; + WEAK symbol Sys_GetTLS{0x1421837B0, 0x140525EB0}; + WEAK symbol Sys_IsDatabaseReady{0x142183A60}; + + // Unnamed + WEAK symbol CopyString{0x1422AC220, 0x14056BD70}; + + WEAK symbol isModLoaded{0x1420D5020}; + WEAK symbol loadMod{0x1420D6930}; + + // Dvar + WEAK symbol Dvar_IsSessionModeBaseDvar{0x1422C23A0, 0x140576890}; + WEAK symbol Dvar_FindVar{0x1422BCCD0, 0x140575540}; + WEAK symbol Dvar_GenerateHash{0x14133DBF0, 0x140185800}; + WEAK symbol Dvar_FindMalleableVar{0x1422BCC40}; + WEAK symbol Dvar_GetDebugName{0x1422BD250}; + WEAK symbol Dvar_GetString{0x1422BF590, 0x140575E30}; + WEAK symbol Dvar_DisplayableValue{0x1422BC080}; + WEAK symbol Dvar_GetBool{0x1422BCED0}; + WEAK symbol Dvar_GetInt{0x0, 0x140575C20}; + WEAK symbol Dvar_GetFLoat{0x0, 0x140575B20}; + WEAK symbol Dvar_RegisterBool{ + 0x1422D0900, 0x14057B500 + }; + WEAK symbol Dvar_RegisterFloat{ + 0x0, 0x14057B6B0 + }; + WEAK symbol Dvar_SessionModeRegisterBool{ + 0x1422D0D40, 0x14057BAA0 + }; + WEAK symbol Dvar_SessionModeSetDefaultBool{ + 0x1422D0E90, 0x14057BCE0 + }; + WEAK symbol Dvar_RegisterString{ + 0x1422D0B70, 0x14057B890 + }; + WEAK symbol Dvar_ForEach{0x1422BCD00}; + WEAK symbol Dvar_SetFromStringByName{ + 0x1422C7500 + }; + WEAK symbol Dvar_GetSessionModeSpecificDvar{ + 0x1422BF500, 0x140575D90 + }; + + // UI + WEAK symbol UI_CoD_Init{0x141F29010, 0x1404A0A50}; + WEAK symbol UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50}; + WEAK symbol UI_CoD_Shutdown{0x141F32E10, 0x0}; + WEAK symbol UI_AddMenu{0x1427018F0, 0x0}; + WEAK symbol UI_CoD_GetRootNameForController{0x141F28940, 0x0}; + WEAK symbol Lua_CoD_LoadLuaFile{0x141F11A20, 0x0}; + WEAK symbol CG_LUIHUDRestart{0x140F7E970}; WEAK symbol CL_CheckKeepDrawingConnectScreen{0x1413CCAE0}; - WEAK symbol Lua_SetTableInt{ 0x141F066E0 }; - - // Scr - WEAK symbol Scr_AddInt{0x1412E9870, 0x14016F160}; - WEAK symbol Scr_AddString{0x0, 0x14016F320}; - WEAK symbol Scr_GetString{0x0, 0x140171490}; - WEAK symbol Scr_Notify_Canon{ - 0x0, 0x1402F5FF0 - }; - WEAK symbol Scr_GetNumParam{0x0, 0x140171320}; - - WEAK symbol Cinematic_StartPlayback{0x1412BE3A0}; - WEAK symbol Cinematic_StopPlayback{0x1412BEA70}; - - // Rendering - WEAK symbol - R_AddCmdDrawText{ - 0x141CD98D0 - }; - - // PCache - WEAK symbol PCache_DeleteEntries{0x141E8D710}; - - // SV - WEAK symbol SV_Loaded{0x142252250, 0x140535460}; - WEAK symbol SV_AddTestClient{0x142248F40, 0x14052E3E0}; - WEAK symbol SV_DirectConnect{0x142249880, 0x14052EC60}; - WEAK symbol SV_GameSendServerCommand{ - 0x14224F580, 0x140532CA0 - }; - WEAK symbol SV_SendServerCommand{0x0, 0x140537F10}; - WEAK symbol SV_IsTestClient{0x14224AB60, 0x14052FF40}; - WEAK symbol SV_SpawnServer{ - 0x1422528C0, 0x140535B20 - }; - WEAK symbol SV_Cmd_TokenizeString{0x1420EF130, 0x1404FA6C0}; - WEAK symbol SV_Cmd_EndTokenizedString{0x1420EF0E0, 0x1404FA670}; - - // FS - WEAK symbol FS_AllocMem{0x1422AC9F0, 0x14056C340}; - - // Utils - WEAK symbol I_CleanStr{0x1422E9050, 0x140580E80}; - - // Variables - WEAK symbol cmd_functions{0x15689DF58, 0x14946F860}; - WEAK symbol sv_cmd_args{0x15689AE30, 0x14944C740}; - - WEAK symbol g_entities{0x0, 0x1471031B0}; - - WEAK symbol level_time{0x0, 0x1474FDC94}; - - WEAK symbol ip_socket{0x157E75818, 0x14A640988}; - - WEAK symbol s_join{0x15574A640}; - - WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; - WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; - - WEAK symbol fs_loadStack{0x157A65310, 0x14A39C650}; - - // Client and dedi struct size differs :( - WEAK symbol svs_clients_cl{0x1576F9318, 0}; - WEAK symbol svs_clients{0x0, 0x14A178E98}; - - // Dvar variables - WEAK symbol com_maxclients{0x0, 0x14948EE70}; - - namespace s_wcd - { - WEAK symbol codLogo{0x157E75A50, 0x14A640BC0}; - WEAK symbol hfBufferFont{0x157E75A58, 0x14A640BC8}; - WEAK symbol hWnd{0x157E75A40, 0x14A640BB0}; - WEAK symbol hwndBuffer{0x157E75A48, 0x14A640BB8}; - WEAK symbol hwndInputLine{0x157E75A60, 0x14A640BD0}; - WEAK symbol windowHeight{0x157E7606C, 0x14A6411DC}; - WEAK symbol windowWidth{0x157E76068, 0x14A6411D8}; - WEAK symbol SysInputLineWndProc{0x157E76070, 0x14A6411E0}; - } - - // Global game definitions - constexpr auto CMD_MAX_NESTING = 8; - - // Re-implementations - eModes Com_SessionMode_GetMode(); - - bool I_islower(int c); - bool I_isupper(int c); - - unsigned int Scr_CanonHash(const char* str); - - namespace hks - { - WEAK symbol lua_state{0x159C76D88, 0x14858C408}; - WEAK symbol hksi_lua_pushlstring{0x140A18430, 0x1401DE6F0}; - - WEAK symbol - hks_obj_settable{0x141D4B660, 0x1403F41B0}; - WEAK symbol - hks_obj_gettable{0x141D4ABF0, 0x1403F3750}; - WEAK symbol vm_call_internal{ - 0x141D70FE0, 0x140418E40 - }; - WEAK symbol Hashtable_Create{ - 0x141D3B5F0, 0x1403E46D0 - }; - WEAK symbol cclosure_Create{0x141D3B7E0, 0x1403E48C0}; - WEAK symbol hksi_luaL_ref{0x141D4D1A0, 0x1403F5CF0}; - WEAK symbol hksi_luaL_unref{0x141D4D320, 0x1403F5E70}; - - WEAK symbol hksi_hksL_loadbuffer{0x141D4BD80, 0x1403F48D0}; - WEAK symbol hksi_lua_getinfo{0x141D4D8D0, 0x1403F64B0}; - WEAK symbol hksi_lua_getstack{0x141D4DB90, 0x1403F6770}; - WEAK symbol hksi_luaL_error{0x141D4D050, 0x1403F5BA0}; - WEAK symbol s_compilerTypeName{0x140A18430}; - } -} + WEAK symbol Lua_SetTableInt{0x141F066E0}; + + // Scr + WEAK symbol Scr_AddInt{0x1412E9870, 0x14016F160}; + WEAK symbol Scr_AddString{0x0, 0x14016F320}; + WEAK symbol Scr_GetString{0x0, 0x140171490}; + WEAK symbol Scr_Notify_Canon{ + 0x0, 0x1402F5FF0 + }; + WEAK symbol Scr_GetNumParam{0x0, 0x140171320}; + + WEAK symbol Cinematic_StartPlayback{0x1412BE3A0}; + WEAK symbol Cinematic_StopPlayback{0x1412BEA70}; + + // Rendering + WEAK symbol + R_AddCmdDrawText{ + 0x141CD98D0 + }; + + // PCache + WEAK symbol PCache_DeleteEntries{0x141E8D710}; + + // SV + WEAK symbol SV_Loaded{0x142252250, 0x140535460}; + WEAK symbol SV_AddTestClient{0x142248F40, 0x14052E3E0}; + WEAK symbol SV_DirectConnect{0x142249880, 0x14052EC60}; + WEAK symbol SV_GameSendServerCommand{ + 0x14224F580, 0x140532CA0 + }; + WEAK symbol SV_SendServerCommand{0x0, 0x140537F10}; + WEAK symbol SV_IsTestClient{0x14224AB60, 0x14052FF40}; + WEAK symbol SV_SpawnServer{ + 0x1422528C0, 0x140535B20 + }; + WEAK symbol SV_Cmd_TokenizeString{0x1420EF130, 0x1404FA6C0}; + WEAK symbol SV_Cmd_EndTokenizedString{0x1420EF0E0, 0x1404FA670}; + + // FS + WEAK symbol FS_AllocMem{0x1422AC9F0, 0x14056C340}; + + // Utils + WEAK symbol I_CleanStr{0x1422E9050, 0x140580E80}; + + // Variables + WEAK symbol cmd_functions{0x15689DF58, 0x14946F860}; + WEAK symbol sv_cmd_args{0x15689AE30, 0x14944C740}; + + WEAK symbol g_entities{0x0, 0x1471031B0}; + + WEAK symbol level_time{0x0, 0x1474FDC94}; + + WEAK symbol ip_socket{0x157E75818, 0x14A640988}; + + WEAK symbol s_join{0x15574A640}; + + WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; + WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; + + WEAK symbol fs_loadStack{0x157A65310, 0x14A39C650}; + + // Client and dedi struct size differs :( + WEAK symbol svs_clients_cl{0x1576F9318, 0}; + WEAK symbol svs_clients{0x0, 0x14A178E98}; + + // Dvar variables + WEAK symbol com_maxclients{0x0, 0x14948EE70}; + + namespace s_wcd + { + WEAK symbol codLogo{0x157E75A50, 0x14A640BC0}; + WEAK symbol hfBufferFont{0x157E75A58, 0x14A640BC8}; + WEAK symbol hWnd{0x157E75A40, 0x14A640BB0}; + WEAK symbol hwndBuffer{0x157E75A48, 0x14A640BB8}; + WEAK symbol hwndInputLine{0x157E75A60, 0x14A640BD0}; + WEAK symbol windowHeight{0x157E7606C, 0x14A6411DC}; + WEAK symbol windowWidth{0x157E76068, 0x14A6411D8}; + WEAK symbol SysInputLineWndProc{0x157E76070, 0x14A6411E0}; + } + + // Global game definitions + constexpr auto CMD_MAX_NESTING = 8; + + // Re-implementations + eModes Com_SessionMode_GetMode(); + + bool I_islower(int c); + bool I_isupper(int c); + + unsigned int Scr_CanonHash(const char* str); + + namespace hks + { + WEAK symbol lua_state{0x159C76D88, 0x14858C408}; + WEAK symbol hksi_lua_pushlstring{0x140A18430, 0x1401DE6F0}; + + WEAK symbol + hks_obj_settable{0x141D4B660, 0x1403F41B0}; + WEAK symbol + hks_obj_gettable{0x141D4ABF0, 0x1403F3750}; + WEAK symbol vm_call_internal{ + 0x141D70FE0, 0x140418E40 + }; + WEAK symbol Hashtable_Create{ + 0x141D3B5F0, 0x1403E46D0 + }; + WEAK symbol cclosure_Create{0x141D3B7E0, 0x1403E48C0}; + WEAK symbol hksi_luaL_ref{0x141D4D1A0, 0x1403F5CF0}; + WEAK symbol hksi_luaL_unref{0x141D4D320, 0x1403F5E70}; + + WEAK symbol hksi_hksL_loadbuffer{0x141D4BD80, 0x1403F48D0}; + WEAK symbol hksi_lua_getinfo{0x141D4D8D0, 0x1403F64B0}; + WEAK symbol hksi_lua_getstack{0x141D4DB90, 0x1403F6770}; + WEAK symbol hksi_luaL_error{0x141D4D050, 0x1403F5BA0}; + WEAK symbol s_compilerTypeName{0x140A18430}; + } +} diff --git a/src/common/utils/byte_buffer.cpp b/src/common/utils/byte_buffer.cpp index 7a3d5b94..0303d07f 100644 --- a/src/common/utils/byte_buffer.cpp +++ b/src/common/utils/byte_buffer.cpp @@ -41,9 +41,9 @@ namespace utils this->offset_ += length; } - std::vector byte_buffer::read_data(const size_t length) + std::string byte_buffer::read_data(const size_t length) { - std::vector result{}; + std::string result{}; result.resize(length); this->read(result.data(), result.size()); diff --git a/src/common/utils/byte_buffer.hpp b/src/common/utils/byte_buffer.hpp index c4c33ec7..f9ee1924 100644 --- a/src/common/utils/byte_buffer.hpp +++ b/src/common/utils/byte_buffer.hpp @@ -20,6 +20,11 @@ namespace utils void write(const void* buffer, size_t length); + void write(const char* text) + { + this->write(text, strlen(text)); + } + void write_string(const char* str, const size_t length) { this->write(static_cast(length)); @@ -42,6 +47,13 @@ namespace utils this->write(&object, sizeof(object)); } + template<> + void write(const byte_buffer& object) + { + const auto& buffer = object.get_buffer(); + this->write(buffer.data(), buffer.size()); + } + template void write(const std::vector& vec) { @@ -109,7 +121,17 @@ namespace utils return result; } - std::vector read_data(size_t length); + size_t get_remaining_size() const + { + return this->buffer_.size() - offset_; + } + + std::string get_remaining_data() + { + return this->read_data(this->get_remaining_size()); + } + + std::string read_data(size_t length); private: bool writing_{false}; From 64b58e7ead844506187e2b533a51f6a06192d736 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 11 Apr 2023 20:51:46 +0200 Subject: [PATCH 074/102] feat(patches): fix unknown password command --- src/client/component/patches.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index bfec3e5c..0900b5a8 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -2,6 +2,10 @@ #include "loader/component_loader.hpp" #include +#include + +#include "scheduler.hpp" + #include namespace patches @@ -34,6 +38,11 @@ namespace patches utils::hook::set(game::select(0x14224DA53, 0x140531143), 3); utils::hook::set(game::select(0x14224DBB4, 0x1405312A8), 3); utils::hook::set(game::select(0x14224DF8C, 0x1405316DC), 3); + + scheduler::once([] + { + game::register_dvar_string("password", "", game::DVAR_USERINFO, "password"); + }, scheduler::pipeline::main); } }; } From 222dcc91ef556c1f0e65648bfa3a4a875076d156 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 11 Apr 2023 21:04:05 +0200 Subject: [PATCH 075/102] optimization(bots): remove outdated make_pair --- src/client/component/bots.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 0d06afd0..56d39d01 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -63,7 +63,7 @@ namespace bots entry = entry.substr(0, pos); } - bot_names.emplace_back(std::make_pair(entry, clan_abbrev)); + bot_names.emplace_back(entry, clan_abbrev); } return bot_names; From 231c19be935198ecfce63e21660182e05d1a8174 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Wed, 12 Apr 2023 11:06:45 +0200 Subject: [PATCH 076/102] feat: add update flag --- src/client/updater/file_updater.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/updater/file_updater.cpp b/src/client/updater/file_updater.cpp index 2de1c384..bee3cf86 100644 --- a/src/client/updater/file_updater.cpp +++ b/src/client/updater/file_updater.cpp @@ -5,6 +5,7 @@ #include "file_updater.hpp" #include +#include #include #include #include @@ -271,7 +272,7 @@ namespace updater bool file_updater::is_outdated_file(const file_info& file) const { #if !defined(NDEBUG) || !defined(CI) - if (file.name == UPDATE_HOST_BINARY) + if (file.name == UPDATE_HOST_BINARY && !utils::flags::has_flag("update")) { return false; } From ee85545e5a4dca75ddb2bb59974ac4862c0de91c Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:47:38 +0200 Subject: [PATCH 077/102] Mods support for dedicated servers --- src/client/component/getinfo.cpp | 3 + src/client/component/party.cpp | 21 ++- src/client/component/workshop.cpp | 162 ++++++++++++++---- src/client/component/workshop.hpp | 6 +- src/client/game/symbols.hpp | 2 +- .../steam/interfaces/matchmaking_servers.cpp | 6 +- 6 files changed, 151 insertions(+), 49 deletions(-) diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index 83d8209b..505c0dd6 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -5,6 +5,7 @@ #include "steam/steam.hpp" #include "network.hpp" +#include "workshop.hpp" #include #include @@ -114,6 +115,8 @@ namespace getinfo info.set("sv_running", std::to_string(game::is_server_running())); info.set("dedicated", game::is_server() ? "1" : "0"); info.set("hc", std::to_string(game::Com_GametypeSettings_GetUInt("hardcoremode", false))); + info.set("modname", workshop::get_mod_name(game::get_dvar_string("fs_game"))); + info.set("fs_game", game::get_dvar_string("fs_game")); info.set("shortversion", SHORTVERSION); network::send(target, "infoResponse", info.build(), '\n'); diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 7a80a301..837a97f9 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -37,12 +37,12 @@ namespace party } void connect_to_lobby(const game::netadr_t& addr, const std::string& mapname, const std::string& gamemode, - const std::string& pub_id) + const std::string& usermap_id, const std::string& mod_id) { - workshop::load_usermap_mod_if_needed(pub_id); + workshop::load_mod_if_needed(usermap_id, mod_id); game::XSESSION_INFO info{}; - game::CL_ConnectFromLobby(0, &info, &addr, 1, 0, mapname.data(), gamemode.data(), pub_id.data()); + game::CL_ConnectFromLobby(0, &info, &addr, 1, 0, mapname.data(), gamemode.data(), usermap_id.data()); } void launch_mode(const game::eModes mode) @@ -56,12 +56,12 @@ namespace party } void connect_to_lobby_with_mode(const game::netadr_t& addr, const game::eModes mode, const std::string& mapname, - const std::string& gametype, const std::string& pub_id, + const std::string& gametype, const std::string& usermap_id, const std::string& mod_id, const bool was_retried = false) { if (game::Com_SessionMode_IsMode(mode)) { - connect_to_lobby(addr, mapname, gametype, pub_id); + connect_to_lobby(addr, mapname, gametype, usermap_id, mod_id); return; } @@ -69,7 +69,7 @@ namespace party { scheduler::once([=] { - connect_to_lobby_with_mode(addr, mode, mapname, gametype, pub_id, true); + connect_to_lobby_with_mode(addr, mode, mapname, gametype, usermap_id, mod_id, true); }, scheduler::main, 5s); launch_mode(mode); @@ -177,6 +177,8 @@ namespace party return; } + const auto mod_id = info.get("fs_game"); + //const auto hostname = info.get("sv_hostname"); const auto playmode = info.get("playmode"); const auto mode = static_cast(std::atoi(playmode.data())); @@ -184,9 +186,10 @@ namespace party scheduler::once([=] { - const auto publisher_id = workshop::get_usermap_publisher_id(mapname); + const auto usermap_id = workshop::get_usermap_publisher_id(mapname); - if (workshop::check_valid_publisher_id(mapname, publisher_id)) + if (workshop::check_valid_usermap_id(mapname, usermap_id) && + workshop::check_valid_mod_id(mod_id)) { if (is_connecting_to_dedi) { @@ -194,7 +197,7 @@ namespace party } //connect_to_session(target, hostname, xuid, mode); - connect_to_lobby_with_mode(target, mode, mapname, gametype, publisher_id); + connect_to_lobby_with_mode(target, mode, mapname, gametype, usermap_id, mod_id); } }, scheduler::main); } diff --git a/src/client/component/workshop.cpp b/src/client/component/workshop.cpp index cb732447..824c74a5 100644 --- a/src/client/component/workshop.cpp +++ b/src/client/component/workshop.cpp @@ -5,48 +5,39 @@ #include "game/game.hpp" #include +#include +#include namespace workshop { - const std::string get_usermap_publisher_id(const std::string& mapname) - { - const auto total_usermaps = *reinterpret_cast(0x1567B3580_g); - - for (unsigned int i = 0; i < total_usermaps; ++i) - { - const auto usermap_data = reinterpret_cast(0x1567B3588_g + (sizeof(game::workshop_data) * i)); - if (usermap_data->folderName == mapname) - { - return usermap_data->publisherId; - } - } - - return ""; - } - - bool check_valid_publisher_id(const std::string& mapname, const std::string& pub_id) - { - if (!game::DB_FileExists(mapname.data(), 0) && pub_id.empty()) - { - game::Com_Error(0, "Can't find usermap: %s!\nMake sure you're subscribed to the workshop item.", mapname.data()); - return false; - } - - return true; - } - - void load_usermap_mod_if_needed(const std::string& pub_id) - { - if (!game::isModLoaded() && !pub_id.empty()) - { - game::loadMod(0, "usermaps", 0); - } - } - namespace { utils::hook::detour setup_server_map_hook; + bool has_mod(const std::string& pub_id) + { + const auto total_mods = *reinterpret_cast(0x15678D170_g); + + for (unsigned int i = 0; i < total_mods; ++i) + { + const auto mod_data = reinterpret_cast(0x15678D178_g + (sizeof(game::workshop_data) * i)); + if (mod_data->publisherId == pub_id) + { + return true; + } + } + + return false; + } + + void load_usermap_mod_if_needed(const std::string& publisher_id) + { + if (!game::isModLoaded() && !publisher_id.empty()) + { + game::loadMod(0, "usermaps", true); + } + } + void setup_server_map_stub(int localClientNum, const char* mapname, const char* gametype) { const auto publisher_id = get_usermap_publisher_id(mapname); @@ -72,6 +63,107 @@ namespace workshop } } + const std::string get_mod_name(const std::string& mod_id) + { + if (mod_id == "usermaps") + { + return mod_id; + } + + const utils::nt::library host{}; + std::string path; + + if (game::is_server()) + { + const auto base_path = host.get_folder().generic_string(); + path = utils::string::va("%s/mods/%s/zone/workshop.json", base_path.data(), mod_id.data()); + } + else + { + return mod_id; + } + + std::string json_str; + utils::io::read_file(path, &json_str); + + if (json_str.empty()) + { + printf("[ Workshop ] Workshop.json has not been found in mod folder: %s", mod_id.data()); + return mod_id; + } + + rapidjson::Document doc; + doc.Parse(json_str); + + if (doc.HasMember("Title")) + { + std::string title = doc["Title"].GetString(); + + if (title.size() > 31) + { + title.resize(31); + } + + return title; + } + else + { + printf("[ Workshop ] Workshop.json has no \"Title\" member."); + return mod_id; + } + } + + const std::string get_usermap_publisher_id(const std::string& mapname) + { + const auto total_usermaps = *reinterpret_cast(0x1567B3580_g); + + for (unsigned int i = 0; i < total_usermaps; ++i) + { + const auto usermap_data = reinterpret_cast(0x1567B3588_g + (sizeof(game::workshop_data) * i)); + if (usermap_data->folderName == mapname) + { + return usermap_data->publisherId; + } + } + + return {}; + } + + bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id) + { + if (!game::DB_FileExists(mapname.data(), 0) && pub_id.empty()) + { + game::Com_Error(0, "Can't find usermap: %s!\nMake sure you're subscribed to the workshop item.", mapname.data()); + return false; + } + + return true; + } + + bool check_valid_mod_id(const std::string& mod) + { + if (mod.empty() || mod == "usermaps") + { + return true; + } + + if (!has_mod(mod)) + { + game::Com_Error(0, "Can't find mod with publisher id: %s!\nMake sure you're subscribed to the workshop item.", mod.data()); + return false; + } + + return true; + } + + void load_mod_if_needed(const std::string& usermap, const std::string& mod) + { + if (!usermap.empty() || mod != "usermaps") + { + game::loadMod(0, mod.data(), true); + } + } + class component final : public client_component { public: diff --git a/src/client/component/workshop.hpp b/src/client/component/workshop.hpp index 1e6776c2..71e5098b 100644 --- a/src/client/component/workshop.hpp +++ b/src/client/component/workshop.hpp @@ -3,6 +3,8 @@ namespace workshop { const std::string get_usermap_publisher_id(const std::string& mapname); - bool check_valid_publisher_id(const std::string& mapname, const std::string& pub_id); - void load_usermap_mod_if_needed(const std::string& pub_id); + const std::string get_mod_name(const std::string& mod_id); + bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id); + bool check_valid_mod_id(const std::string& pub_id); + void load_mod_if_needed(const std::string& usermap, const std::string& mod); } diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 38090235..3ede8880 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -98,7 +98,7 @@ namespace game WEAK symbol CopyString{0x1422AC220, 0x14056BD70}; WEAK symbol isModLoaded{0x1420D5020}; - WEAK symbol loadMod{0x1420D6930}; + WEAK symbol loadMod{0x1420D6930}; // Dvar WEAK symbol Dvar_IsSessionModeBaseDvar{0x1422C23A0, 0x140576890}; diff --git a/src/client/steam/interfaces/matchmaking_servers.cpp b/src/client/steam/interfaces/matchmaking_servers.cpp index 79f0f784..b2996171 100644 --- a/src/client/steam/interfaces/matchmaking_servers.cpp +++ b/src/client/steam/interfaces/matchmaking_servers.cpp @@ -55,12 +55,14 @@ namespace steam const auto mode = game::eModes(std::atoi(playmode.data())); const auto* tags = ::utils::string::va( - R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\modName\\playerCount\%d\bots\%d\)", + R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\playerCount\%d\bots\%d\modName\%s\)", info.get("gametype").data(), info.get("dedicated") == "1" ? "true" : "false", info.get("hc") == "1" ? "true" : "false", mode == game::MODE_ZOMBIES ? "true" : "false", - server.m_nPlayers, atoi(info.get("bots").data())); + server.m_nPlayers, + atoi(info.get("bots").data()), + info.get("modname").data()); ::utils::string::copy(server.m_szGameTags, tags); server.m_steamID.bits = strtoull(info.get("xuid").data(), nullptr, 16); From c29d9e5806ad9db8e04484e2159358b63f5a0ba1 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Wed, 12 Apr 2023 18:43:16 +0200 Subject: [PATCH 078/102] Dispatch connect packet in the server thread --- src/client/component/auth.cpp | 5 ++++- src/client/component/scheduler.cpp | 11 ++++++----- src/client/game/symbols.hpp | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 57346b8f..ef9f773c 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -196,7 +196,10 @@ namespace auth std::string final_packet{}; if (game::fragment_handler::handle(target, buffer, final_packet)) { - dispatch_connect_packet(target, final_packet); + scheduler::once([t = target, p = std::move(final_packet)] + { + dispatch_connect_packet(t, p); + }); } } } diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index d4ac94b8..a115b1d9 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -88,7 +88,6 @@ namespace scheduler task_pipeline pipelines[pipeline::count]; utils::hook::detour r_end_frame_hook; - utils::hook::detour g_run_frame_hook; utils::hook::detour main_frame_hook; @@ -98,9 +97,9 @@ namespace scheduler r_end_frame_hook.invoke(); } - void server_frame_stub() + void g_clear_vehicle_inputs_stub() { - g_run_frame_hook.invoke(); + game::G_ClearVehicleInputs(); execute(pipeline::server); } @@ -168,12 +167,14 @@ namespace scheduler { if (!game::is_server()) { - r_end_frame_hook.create(0x142272B00_g, r_end_frame_stub); // some func called before R_EndFrame, maybe SND_EndFrame? + r_end_frame_hook.create(0x142272B00_g, r_end_frame_stub); } - main_frame_hook.create(game::select(0x1420F8E00, 0x1405020E0), main_frame_stub); // Com_Frame_Try_Block_Function + main_frame_hook.create(game::select(0x1420F8E00, 0x1405020E0), main_frame_stub); + + utils::hook::call(game::select(0x14225522E, 0x140538427), g_clear_vehicle_inputs_stub); } void pre_destroy() override diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 8109ed95..3165a4b5 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -75,6 +75,9 @@ namespace game WEAK symbol DB_FileExists{0x141420B40}; WEAK symbol DB_ReleaseXAssets{0x1414247C0}; + // G + WEAK symbol G_ClearVehicleInputs{0x1423812E0, 0x1405C1200}; + // Live WEAK symbol Live_GetConnectivityInformation{0x141E0C380}; From e8dba61553f8dddef1773d920ff486fc43716718 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Wed, 12 Apr 2023 18:50:39 +0200 Subject: [PATCH 079/102] I'm fucking dumb --- src/client/component/auth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index ef9f773c..67a625d5 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -199,7 +199,7 @@ namespace auth scheduler::once([t = target, p = std::move(final_packet)] { dispatch_connect_packet(t, p); - }); + }, scheduler::server); } } } From 4dc7fcd95e1691945934249281ddf18244261dde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 18:00:38 +0000 Subject: [PATCH 080/102] Bump deps/curl from `dc18b40` to `ca05e1a` Bumps [deps/curl](https://github.com/curl/curl) from `dc18b40` to `ca05e1a`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/dc18b40b406e9946a2198d66b6edb62575660faf...ca05e1afba7088c2f7e96ce47d2d3a249ce7a903) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index dc18b40b..ca05e1af 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit dc18b40b406e9946a2198d66b6edb62575660faf +Subproject commit ca05e1afba7088c2f7e96ce47d2d3a249ce7a903 From f3ffd7659eb6ecd62bd8d1957d2f390c558d7b0e Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Thu, 13 Apr 2023 11:35:06 +0200 Subject: [PATCH 081/102] Remove const return type --- src/client/component/workshop.cpp | 4 ++-- src/client/component/workshop.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/component/workshop.cpp b/src/client/component/workshop.cpp index 824c74a5..214ef824 100644 --- a/src/client/component/workshop.cpp +++ b/src/client/component/workshop.cpp @@ -63,7 +63,7 @@ namespace workshop } } - const std::string get_mod_name(const std::string& mod_id) + std::string get_mod_name(const std::string& mod_id) { if (mod_id == "usermaps") { @@ -113,7 +113,7 @@ namespace workshop } } - const std::string get_usermap_publisher_id(const std::string& mapname) + std::string get_usermap_publisher_id(const std::string& mapname) { const auto total_usermaps = *reinterpret_cast(0x1567B3580_g); diff --git a/src/client/component/workshop.hpp b/src/client/component/workshop.hpp index 71e5098b..5ef97818 100644 --- a/src/client/component/workshop.hpp +++ b/src/client/component/workshop.hpp @@ -2,8 +2,8 @@ namespace workshop { - const std::string get_usermap_publisher_id(const std::string& mapname); - const std::string get_mod_name(const std::string& mod_id); + std::string get_usermap_publisher_id(const std::string& mapname); + std::string get_mod_name(const std::string& mod_id); bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id); bool check_valid_mod_id(const std::string& pub_id); void load_mod_if_needed(const std::string& usermap, const std::string& mod); From 2fb7b42be8aa8e4c5d54797c7f9565d2145402f2 Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Thu, 13 Apr 2023 13:40:19 +0200 Subject: [PATCH 082/102] Catch parse errors --- src/client/component/workshop.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/client/component/workshop.cpp b/src/client/component/workshop.cpp index 214ef824..f633c691 100644 --- a/src/client/component/workshop.cpp +++ b/src/client/component/workshop.cpp @@ -88,12 +88,18 @@ namespace workshop if (json_str.empty()) { - printf("[ Workshop ] Workshop.json has not been found in mod folder: %s", mod_id.data()); + printf("[ Workshop ] workshop.json has not been found in mod folder: %s\n", mod_id.data()); return mod_id; } rapidjson::Document doc; - doc.Parse(json_str); + const rapidjson::ParseResult parse_result = doc.Parse(json_str); + + if (parse_result.IsError() || !doc.IsObject()) + { + printf("[ Workshop ] Unable to parse workshop.json\n"); + return mod_id; + } if (doc.HasMember("Title")) { @@ -108,7 +114,7 @@ namespace workshop } else { - printf("[ Workshop ] Workshop.json has no \"Title\" member."); + printf("[ Workshop ] workshop.json has no \"Title\" member.\n"); return mod_id; } } From 8372d34c3dbd3b1e005472d2d7cc4337be36b497 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 13 Apr 2023 17:18:07 +0200 Subject: [PATCH 083/102] Don't throw exceptions in list files util --- src/common/utils/io.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/utils/io.cpp b/src/common/utils/io.cpp index e981315d..6efce973 100644 --- a/src/common/utils/io.cpp +++ b/src/common/utils/io.cpp @@ -194,18 +194,19 @@ namespace utils::io std::vector list_files(const std::filesystem::path& directory, const bool recursive) { + std::error_code code{}; std::vector files; if (recursive) { - for (auto& file : std::filesystem::recursive_directory_iterator(directory)) + for (auto& file : std::filesystem::recursive_directory_iterator(directory, code)) { files.push_back(file.path()); } } else { - for (auto& file : std::filesystem::directory_iterator(directory)) + for (auto& file : std::filesystem::directory_iterator(directory, code)) { files.push_back(file.path()); } From 62b14eb542dc9ac3d8f814dce9b7c38d1c724782 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 13 Apr 2023 17:36:59 +0200 Subject: [PATCH 084/102] Prevent the game from modifying the process priority --- src/client/component/client_patches.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client/component/client_patches.cpp b/src/client/component/client_patches.cpp index 9d824961..f8a9a9b5 100644 --- a/src/client/component/client_patches.cpp +++ b/src/client/component/client_patches.cpp @@ -116,6 +116,9 @@ namespace client_patches { fix_amd_cpu_stuttering(); + // Don't modify process priority + utils::hook::nop(0x142334C98_g, 6); + // Kill microphones for now utils::hook::set(0x15AAE9254_g, mixer_open_stub); From accf537f50d6cda28c3cdbbef9ff114121f353f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 18:01:06 +0000 Subject: [PATCH 085/102] Bump deps/curl from `ca05e1a` to `7e68133` Bumps [deps/curl](https://github.com/curl/curl) from `ca05e1a` to `7e68133`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/ca05e1afba7088c2f7e96ce47d2d3a249ce7a903...7e68133d041376c1012571e5a2386bb03a620a8e) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index ca05e1af..7e68133d 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit ca05e1afba7088c2f7e96ce47d2d3a249ce7a903 +Subproject commit 7e68133d041376c1012571e5a2386bb03a620a8e From 81fe6bc7e170f9bef91a89a67eeddb0a1ed982e7 Mon Sep 17 00:00:00 2001 From: BrentVL-1952840 <70229620+Brentdevent@users.noreply.github.com> Date: Thu, 13 Apr 2023 20:17:56 +0200 Subject: [PATCH 086/102] Clean up + remove Com_Errors --- src/client/component/workshop.cpp | 33 +++++++++++-------------------- src/client/game/symbols.hpp | 1 + 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/client/component/workshop.cpp b/src/client/component/workshop.cpp index f633c691..f683d4b4 100644 --- a/src/client/component/workshop.cpp +++ b/src/client/component/workshop.cpp @@ -65,26 +65,15 @@ namespace workshop std::string get_mod_name(const std::string& mod_id) { - if (mod_id == "usermaps") + if (mod_id == "usermaps" || !game::is_server()) { return mod_id; } const utils::nt::library host{}; - std::string path; - - if (game::is_server()) - { - const auto base_path = host.get_folder().generic_string(); - path = utils::string::va("%s/mods/%s/zone/workshop.json", base_path.data(), mod_id.data()); - } - else - { - return mod_id; - } - - std::string json_str; - utils::io::read_file(path, &json_str); + const auto base_path = host.get_folder().generic_string(); + const auto path = utils::string::va("%s/mods/%s/zone/workshop.json", base_path.data(), mod_id.data()); + const auto json_str = utils::io::read_file(path); if (json_str.empty()) { @@ -112,11 +101,9 @@ namespace workshop return title; } - else - { - printf("[ Workshop ] workshop.json has no \"Title\" member.\n"); - return mod_id; - } + + printf("[ Workshop ] workshop.json has no \"Title\" member.\n"); + return mod_id; } std::string get_usermap_publisher_id(const std::string& mapname) @@ -139,7 +126,8 @@ namespace workshop { if (!game::DB_FileExists(mapname.data(), 0) && pub_id.empty()) { - game::Com_Error(0, "Can't find usermap: %s!\nMake sure you're subscribed to the workshop item.", mapname.data()); + game::UI_OpenErrorPopupWithMessage(0, 0x100, + utils::string::va("Can't find usermap: %s!\nMake sure you're subscribed to the workshop item.", mapname.data())); return false; } @@ -155,7 +143,8 @@ namespace workshop if (!has_mod(mod)) { - game::Com_Error(0, "Can't find mod with publisher id: %s!\nMake sure you're subscribed to the workshop item.", mod.data()); + game::UI_OpenErrorPopupWithMessage(0, 0x100, + utils::string::va("Can't find mod with publisher id: %s!\nMake sure you're subscribed to the workshop item.", mod.data())); return false; } diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 626d6df1..e011ceef 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -142,6 +142,7 @@ namespace game }; // UI + WEAK symbol UI_OpenErrorPopupWithMessage{0x14228DEE0}; WEAK symbol UI_CoD_Init{0x141F29010, 0x1404A0A50}; WEAK symbol UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50}; WEAK symbol UI_CoD_Shutdown{0x141F32E10, 0x0}; From 788d7e72e27d902771105b13c5127588d5be3321 Mon Sep 17 00:00:00 2001 From: efinst0rm Date: Thu, 13 Apr 2023 18:18:07 -0500 Subject: [PATCH 087/102] Update serversettings. Set level.gameForfeited to false. --- data/scripts/mp/gametypes/_serversettings.gsc | Bin 4446 -> 4518 bytes .../mp/gametypes/_serversettings.gsc_raw | 28 ++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/data/scripts/mp/gametypes/_serversettings.gsc b/data/scripts/mp/gametypes/_serversettings.gsc index cd63bd0b2ebb53e9107b14ed65d7fff569375288..0105b093db16db0bee7ce860fc6f1d226bf54fea 100644 GIT binary patch literal 4518 zcmZ8k33yc16+Uk!P>6AiOLaa)eY0ldxY~fwk=EJmGe!ceM5CibxbpTr~J)gWDU{(RZUK~W{Mm|6@>TiX~V1u!r6eN&| zv^S-*8Ed318WZVEw!I^gy{yV48`@)0YosBSYHWx!XF_9wiTX@;CL3$Htc_O;?2IJJiyajgm0;OoY&1+w#t~Yz*uqy~5fq zv!QIPp(T=RXidZ*-rf{zji$QeP3^I4cREH!<7E_YsHGvDY3hlAn+K-@>~1K6L@0q# z2OVDJl^ote3E-rg{;1%dN$GYqxlhU*tKKX zk6tH!pB_vV3ss&G^=$`;f5KbHE}au-Bbt6>zsnMBcpmAK2B=!H_l}(Izh-w?=UsRF z?m6L@nVxB9dHQ9v=`|Jv3Zccf2kDiXu6)wH=a;csLE|R+sbX^y6zc-&eAkFND)P#iQe$37UIL zv5Y*2vfaYlYzkJo8=yG(P^bZ5s(s#|x494;|Y? zdn{K(bM%YeDy0hTaE}*>^X)zvTdnHua-y8`f=DO!Q=Nr^*;Ei99ECO1e>cwGshVdZ9ETeMBF>xK zs3zyjP*)#B-7&pAN;Y^t6Sk6yxM)Xt{9Iu)lkQss_(VUI2JhVV??$C++y~0e9Mog( zip4zRS(=_*U^Trn7+p(wqW$c5SJu!R+>dTU=PMeLQ++>TgO*$0+4CXskMa9_lloub zUNoJ$SjcjVNk+f*T%PTQ#Mh@_R`T9omhnTdcwT&_LUtQeR_pHk{Tw|s$XK0eu8Ge2 zpaJY+9KQ`n8wRx+FP-yVt5kc3`2fp7qgGm8>?BzS*8N(WyN2l17NLXg0j#6D#r40* z$=DHpZy%jqnHJn4?z3J={7{j}OXoIWlPo$K=uvX;r9z^tG?458JaZ@fP7TqM>`4cm zYuxjch?_$Fap%0I<0!|x)rz=A2a{dxVw7|ad#y|-ujUc=2^AAKmy=Q5|Iw<>kbaWg za}S-RI}g3b-%_KW9cqZ5`rU|Zv&v-2(o+M`7U0S>ns8apf`dq^Q; zCAJl5qEGYT8ahuW1gI2oAL9$zI9}}NF83Sp=FMJy>Od!iU8ZRL;9S5<{e|zAya}GA zb3Q#^_%sA$Y`YfPG}RS5G!pl2^X}qWl~%IY#FXt1 zNXna>2Q84^t=g`TcCF$TV+?x3MIi_#1LQkQ)oP8~u(bbCsX?ce!`BKhFAr?c^wpD$ zartt0%uV)F4V# z@02iqDN^2RkwaJu#Wl9Qj_MgCJ6w|R(A~A)_=tgU4=Q27S_^cFxT~xWYU>!RrxgR% zI>dcScLw7v zgHI<3SK$3h!tE5mj(Kp1xN`MI(=*Uvly)69M-ca-*=!5~dUvLM5+SAQNZmhahhe{3 z4h9YAtIWIAp(x3A89WifUE#Jk2zRj`{O7QqMcmo8*Bpyrl$BN_opHoH;_WUjg^NCz z8RloYmY5u=uIGxBw>#xX!CBiR|Xa>ZC4*0YyzOY_~(CgN5o^A(KY=Our& z9sItKH8?PY+^^4(m!`V}g0;?E{Uzd+x%x}T?#b0(GoC*cn8o^=#7X*gST_65`mVlDhw5WT@S0C(Ipwigo@P`uUa+n?#bXJm8t9rUq~EIaF%Fzg@FT zt)D|Og|(-Z{8U?7v2JDTQX|Z0HiIT&cZEbhDcdymZPe{yr5v7TUi6dJvP>Amvul@jl-dZF>7`SlV z+#}QR>x14{qD;g_y<#W+qwaUm_vBs%@+5ykUi3ryFYq6AyZYlVA7OxzoI{>&d%}_e zqf}#D?@t0KK)-a`j>#p;G|Cs{0X&K^igE@d$|01C^AS(^4D#dk=O*yeq*vRc)2r+U zCh%L4r>^eOT9qTnQ#U8_f1hAqh%wSzW=zj0IpoL3mqLDge4CJ`E<&__X@dU51U+DG z#?R-FA3r}hL7$z#Z<=5~jQo}TWt1Nwe`RkO<$2`An!v467GVCzucvMTKRjW7zL~(6 zSsI zug5QFQATs7A;x%LQRL}HAYT%!rLD*x#rsZ_QGFF4KOUoIf<8Mz|0?P6+@L=g!GF|| z;W{9NLDgVxSbS0kj%kLsksigd2o3sh-%F9EFFBe!AL$W%;sZ9}ybVZD7e-j$AiWc1 z+we)971^9cUXIG+mu&iwo`Siw;gfC^Oa+`pdJ*RB8Oj~zrw+$3jsjfwM>v8Q`%WBk zG!COJbytKPM4T#!0J8>jYPG1o;e-!C;IOuBt|A0k3b@W6hk*3a_=yga_2Tt@Mq^WZv lT8-xPn`hC??am2-b5co`v1o6m&5=7 literal 4446 zcmZ8l32@Zq6@R-MFb3GJcSO|x{`dIreP78QA&@2uCIm>x0fc0;S7J8VCA$ep2r)La zwHXwp*rGCk3ZeqSC^`jG)G@^?4rrO0SX)7XVGOZ$td@2t^t}y#Sa&Die((Bz?|tvP z-e$0@YT=wbn0Ksd;~QH90MGplV8^w7%`E^kX9EmiBbr)E9zZMV?}nLRhUt$8gpdq& zwkA?ZV=x{H^K>%R*%eG(S0!5lo#Bu%7>LE11HrarJXf%Y)K!gz@v8R%-gAw=Je?eSEIgy}xoi2ma1y5p%Z28_}hEYCEi z!h!Z+OQ0hfhDc{?xFZznjkI=#Q@x2WjmVTyw2ke7M6$In3=SJuEns$l3!;rtj43@L z)D9_Z!BhlV)@PSV(Nwo25()fsDak8X38QMSSwu8_XnfSsWZ(DT znsofp=ki;=`MhITdDct)ps{;^ z;uzQMut{LlOLV)TtB!PC=p&#^)DSIotY1c0ok}RP_C)&lIG(kMna5O|hiryi<-Q5D zNvOci>-QPOjGxse&Y&D~-NMIl%3-!_{C7>>6H*65y~NRDCExq42N($)l1(A~Uww=t z-76k3Gv!b<5+=YV6*lHf2LJ1c`q-p@fsTh#gExQNyPXT|za zkFl)g^E{J<26HHC`gl0>8_Lrjv};xRDrn3J8AR0Ge^ij1@Q2l)nfvj`---8gPgrK? zz0O~{&tH`=?gEn0XP+zQfm@^BpNGQvso#~^w!(6wc7arU4=kzcz5lhvDrgro6Z#E0 zI;)%lR`7AWA{UwB=IJwkPA@7od7o41;Lkcy%Lgtxy9PWT+Jdz!h~De1jLwHmvCz4}y&B`sO`R7ikIL3~>AZZ%LhFFzRaOUk&9Ks2M6!CE z=YCD9o9MW&NKWTzw*rzpF6WUj&Q%4=(OvrEP~}9|oj=|Uc&CRNh97|Dfy5g>)_wqZ znP0dpc^M*N2KT>8aX<4E4cKB8wh!5j>=vt_rro^LE?D%fRM^yJJ>ovjD24SJfxX`> z)GoCjmqNv$uHP)Gk~*p|h84_|#}BtzK=v*x^f>F)^&7T7shXq7he|6ft~1S%7sW}| z>j(wtepykp$9FsK{TeAO%X5GuXXB2p2Qf;LwAc$L+9K^s5DzbRydf z^Gd|Mi`!xI!#D$>5#>@#AvaMncJp@CX?s4L@Ig{9|46&qK(Zl2VGZHVwO{oRF3zU- zeS9Z)+#eKMv^j#8q#~!EU4yts-3NSr&>3O*D(O*q_kcO~lPh!BVp%@ykwModCVOFB zf@HW?*AuS8wJnX??SW;#l0q4en=k*yupiV4k#*1*K-{SM0ON;8JkYbrXD^KOb;TZ; zG1GjLD;+O)*z{YEr<`P?UZ0(CKQ+&jQM~KjpnX>f2_E+c#XAMn5H*QfCT$_a{SSBC zTtay;>zFc|rN7BjE1gnLd8q03fq^0mWFO}ssxXNeT+s*~yd}GO+h&o!E9Tt9 z!>S$ba+*`vYkg0?s;%~)e;t`^yVsge=SaWVn``SYB^lnkYMRrxg$I~?oKv>~nlV?N zAiga8yv**eY&LB3)KN^bA%h}Fek|T856x$f1I!E5V5f(N z_v7+?WelNiy-_5^dZ&{2v)DMl;;Md!+Yi5xLF-}DoT4_*-)2UXA=PW>2Xon_V?Oul zsz^5BbGpfo*JWeLPZPdH&nkePqek9OhXrqt4F}9$=?bq%nC0H;vKMi;1)h9IKkMvH z8y55senIrv1(Z>xnU*19XUW>P@=-@sBrltsx<&Qf3_OAO^6;{@?-o@I-UL9e7Re9> zo?2U33i#`RUMyb5W20Vr2*0R$9d^HPOaM8;_mSuQkp3cmQMIZ%^XBIQ5C|_JPq#f` z2|>WhF|M(h0Cdw%;|tjY$};(_$n#?mgWaE@$6qn*CFF0<0ho=k^W%glpCD5Q^?aRG98yXd%mqI=>o~_8=SU&-~3;7#sCtydA=hqyUf*s2mKQC)7RwJK@pUTo7Mm{q?@{Bd0 z{DzRHTWC5z!0tw#cJnn}F3w%Hnl5->}DJmv2P=5bn=R%r8)u=~Iq+I+6Su zg|hgutnvAH=VjX4kk7;)%+hbq(qAAwo*m3DjN%tnWw>o1h5_eez8LJO3dhvL7}Dd| zs?orMd!Ynr`ZY#lmm)oiJ$6us;~qzXDlx+P7t#roy@>t9HJd}o=cDq>HJg5<-$$7V zd%9Wh9|CX~>Dw`IsQ=3%Z<*v7E!!aU?+>pm7+b(P)*e+np!O5GjRbxwFQ=yE0J<#}VNS9-q zk39atX{4!=Ct8KJRIw9Xjx<%?L_dx+RZK*mMgLUg5beP^Qe{H)R-~z#Ao?QGQ~?lO Nf^(-=o9OLG{~zTmftmmS diff --git a/data/scripts/mp/gametypes/_serversettings.gsc_raw b/data/scripts/mp/gametypes/_serversettings.gsc_raw index 02669e86..580e2966 100644 --- a/data/scripts/mp/gametypes/_serversettings.gsc_raw +++ b/data/scripts/mp/gametypes/_serversettings.gsc_raw @@ -17,27 +17,33 @@ function __init__() function init() { level.hostname = GetDvarString( "sv_hostname"); - if(level.hostname == "") + if (level.hostname == "") + { level.hostname = "CoDHost"; + } + SetDvar("sv_hostname", level.hostname); SetDvar("ui_hostname", level.hostname); level.motd = GetDvarString( "scr_motd" ); if(level.motd == "") + { level.motd = ""; + } SetDvar("scr_motd", level.motd); SetDvar("ui_motd", level.motd); - level.allowvote = GetDvarString( "g_allowvote"); + level.allowvote = GetDvarString( "g_allowvote" ); if(level.allowvote == "") + { level.allowvote = "1"; + } SetDvar("g_allowvote", level.allowvote); SetDvar("ui_allowvote", level.allowvote); - + level.allow_teamchange = "1"; SetDvar("ui_allow_teamchange", level.allow_teamchange); - level.friendlyfire = GetGametypeSetting( "friendlyfiretype" ); SetDvar("ui_friendlyfire", level.friendlyfire); @@ -57,6 +63,8 @@ function init() constrain_gametype(GetDvarString( "g_gametype")); constrain_map_size(level.mapsize); + thread setup_callbacks(); + for(;;) { update(); @@ -193,4 +201,14 @@ function constrain_map_size(mapsize) } } } -} \ No newline at end of file +} + +function setup_callbacks() +{ + level.onForfeit = &default_onForfeit; +} + +function default_onForfeit() +{ + level.gameForfeited = false; +} From cfed6a5c83361195b89026fb779563497bbccf0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 18:01:31 +0000 Subject: [PATCH 088/102] Bump deps/curl from `7e68133` to `7ed010c` Bumps [deps/curl](https://github.com/curl/curl) from `7e68133` to `7ed010c`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/7e68133d041376c1012571e5a2386bb03a620a8e...7ed010ce2192ae3e4d9663eaaa3a460f316b708b) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 7e68133d..7ed010ce 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 7e68133d041376c1012571e5a2386bb03a620a8e +Subproject commit 7ed010ce2192ae3e4d9663eaaa3a460f316b708b From b0a6523b6c1f9cc9c1329e0f1fbe419394bd403d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 18:01:34 +0000 Subject: [PATCH 089/102] Bump deps/zlib from `eb0e038` to `5799c14` Bumps [deps/zlib](https://github.com/madler/zlib) from `eb0e038` to `5799c14`. - [Release notes](https://github.com/madler/zlib/releases) - [Commits](https://github.com/madler/zlib/compare/eb0e038b297f2c9877ed8b3515c6718a4b65d485...5799c14c8526bf1aaa130c021982f831d155b46d) --- updated-dependencies: - dependency-name: deps/zlib dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/zlib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/zlib b/deps/zlib index eb0e038b..5799c14c 160000 --- a/deps/zlib +++ b/deps/zlib @@ -1 +1 @@ -Subproject commit eb0e038b297f2c9877ed8b3515c6718a4b65d485 +Subproject commit 5799c14c8526bf1aaa130c021982f831d155b46d From 230bd784f288850e2564f7455674797829a8616b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 15 Apr 2023 15:01:12 +0200 Subject: [PATCH 090/102] Remove unnecessary print --- src/client/component/auth.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 67a625d5..78a6b460 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -107,8 +107,6 @@ namespace auth buffer.write_string(data, static_cast(length)); - printf("Serialized with size: %llX\n", buffer.get_buffer().size()); - return buffer.move_buffer(); } From c5091bef79c7f5dc4fe2f5f0215cf12110f0356e Mon Sep 17 00:00:00 2001 From: efinst0rm Date: Sat, 15 Apr 2023 12:39:41 -0500 Subject: [PATCH 091/102] Use current production _serversettings.gsc --- data/scripts/mp/gametypes/_serversettings.gsc | Bin 4518 -> 4612 bytes .../mp/gametypes/_serversettings.gsc_raw | 25 +++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/data/scripts/mp/gametypes/_serversettings.gsc b/data/scripts/mp/gametypes/_serversettings.gsc index 0105b093db16db0bee7ce860fc6f1d226bf54fea..bf3985aab646d5b010b7fea76bcc9567366f1d51 100644 GIT binary patch literal 4612 zcmZ8k3viUx6+ZuNs4>dAg0x#@HlLZowu%)W9ivha5laEJj!GG&&~p-hvScSW|M|{2_dDm_ z|DJpA-&e9~;mjPE``|6z`vw_+fE3`#pPpH>04i?=xP*;lYA@vgG@<>MkPS|l{E0yX z$zXd^B9*iRwKgP@P2FK|JHcTGn;UW=S{KEf zCVGTgA%!iNia=~FBty^~PsOf{vNd55Jd>8XDUg4o~X++x^Y4~P2>AgxRTd}C#MKb-Uf6!|v z+k5XlhY7!;g;h$=n#D&{cN`@=?3JCCnQ(OFyo~xD{mlhZX!VVuypiMFWP8UiVb#2;m*m}fwLaofyTKXC(y3Jjqh9BMl|ml9-p&oTp8Ke+D)#{w zJ%m6V4|n`4whKtVEZPE?Ss6~{7W=~+SYX;X=VxE48~E7Gmug*bB@681j6G@pFV z$z6sIC*vgqdz&5e(8p}2NN)tYkVmVz%dz>t6*(9DGC4hGYg#lEdz;}oRtjnNmnbjy zYwO6ySt&-yL$cfw^b?m_2`yy{RvUykx%m=yT&1lipP0j^_!@mQ9Bi1f@6IF68edU7 zbmsNbzxGPl5xq`FvfN@%Tt=Hj4FSRb9Rt0`Du)zn7RMZY>XBy#(FNa8Wa;wXoZQxv zCt)A9Cc-2$uIgqv`Wd}o68cj<8bfcf4fU97nK14neqAGt^BjAW)q;fGl**w5mqS5(_I2jK%3!FDskkkv8qojtK|H6@el*8Ui@ZGil>)C{5$cOXh zz5T7RPYAc!gSj)7^g5PUzPKu7^X8L|emlHbsaer)zkrn%!(%1RAy`_OULcp;0j=we z^ZvA03wKlfS&ON5PirA2+l58b^ClyTm}X*sh)$@Ad*wL!Yr(MRmAGE>gdyf6{4$t3FZb3JHb-wRLx&MZzW=%bKW;a1W~z>gWd!Qkz_lYN>vPmC$*o ziFk+IP_V;HxlN}%vr={?Zs{0q;xiaL@y$0l$dvttDNp*XJbOHO}FD;vHupG|LBh0&klA z%u>UAB^PTx%&$UTt!}$60B zTA(82$aeOuARV0>#JgVou9bM-&WEnKYKREDKX+}mkI?$>E_5~^Z;#%u2tX$fnrit~ zJ73z-^3aSurV+OcJSNDmcaG${45a&%OT>tGi>pdWy!b|JH7wW#Ua#^oS2^)^9ngi4 z_a&d%UIcgh!SQd)t+_24drQ~8C$vqx4Bj(>c1#^N*M&$ortt(P^BvU_?-&dIXK_6X zy!TliGc#r1x;@r6{wHM@ti}{3e!q8Q8E9_-ZM|<|{V6sSO{~ATPB*ds@EpXwEg`Hw zwN(^&S$l@hkuz1Cb)TDY^z)+V?RlNbIhq%lVK)<*qZBRu#Bm@W5>#UzlQ=x!gX*2> z=9?(s{p#%IbF5!c3J+Mp^rodCzqfexHy@7`+pjoe@DLAWC)D#)x<=9k6#TU@$#6`) zHVEyqL68m_VO+N>-m^Lx3HyLm+=Y9(Mu>CXB(-caJn1Zjejd6Lz6GwX_~4^o9f}$L z<(1(+0F8dfMx&>gbit})+~ejmB3ZYOPoO)>GmsKb(3+v#P=s*_qoA{ zzggDy#SM4FRb#mgS?N(?O;&jR9^U;Z#z$2=|q+&SZs(=10q84j!$dy462e{Q- zwEN7Y^ZR?&QJg*MZUx1`-6{Gy2Y5OyGYE0=?3eva!2$hy*1RiHwx)JsG2p+MY_-pZ zC(v-=+HTU#P~?|=ZC`!M3sxx`(VKizejm$kQG1u1t{z&u#v)}u7`iy{46fIP-@a

GK^<{6v7qA5j?2qK@va6FTgC_}%_;8QSPxD(LKcH}%8M0O;%zbdT>J-n8`w06GUr zhcxh?`i&sP?-4o!1>J+Ke_X`k_X?eZLSHABcshVO8iSw{azGyWe*8!G=6>JP2N}o` z{S~p057{r^Ke{JtPrdvR1B~brVmenQV=@XA=1=?iBo-+W)9?`DO#hK-_Dj?7T=Dh( zPQ;n~eHj?Py%f6;AHn%b;rwL!y^nf2r-VE&Wb|XO-)&jf$1x(#>|cqP?kPh5u4(pN z)9i;b>>}j9fOszEl*y4j~KpVkhFM_s=NC5DV`fUz73} zVqqO2R-8bb$!ElQ%N%nH;!OMIY4`-<%sF-9_-HSjoFh<-BBq-939Fph*W)eI@aNMo zf8+K3L(}jD#F_D&xc+HR5Z+M=u@E1ZmFf`Ut+>->`kct{!8uWBr`e09;St0FC;4AO zEYuQWxdLlzC)Oj%a0LI+T@jZWv|s{SoG%ui^sRtX564g*$5xIGJg$!-lV$1-c&+*LNuQq3#)c(w&cd4k4DI@zhT~y(o{P&Wcak?=USGMOlS&+>7mf zY(|{F&Dc(0+mG`g!?E;XJBzIzed*pu+%kNRI}y|O6y~xnPc?9ME1C<-B A;Q#;t literal 4518 zcmZ8k33yc16+Uk!P>6AiOLaa)eY0ldxY~fwk=EJmGe!ceM5CibxbpTr~J)gWDU{(RZUK~W{Mm|6@>TiX~V1u!r6eN&| zv^S-*8Ed318WZVEw!I^gy{yV48`@)0YosBSYHWx!XF_9wiTX@;CL3$Htc_O;?2IJJiyajgm0;OoY&1+w#t~Yz*uqy~5fq zv!QIPp(T=RXidZ*-rf{zji$QeP3^I4cREH!<7E_YsHGvDY3hlAn+K-@>~1K6L@0q# z2OVDJl^ote3E-rg{;1%dN$GYqxlhU*tKKX zk6tH!pB_vV3ss&G^=$`;f5KbHE}au-Bbt6>zsnMBcpmAK2B=!H_l}(Izh-w?=UsRF z?m6L@nVxB9dHQ9v=`|Jv3Zccf2kDiXu6)wH=a;csLE|R+sbX^y6zc-&eAkFND)P#iQe$37UIL zv5Y*2vfaYlYzkJo8=yG(P^bZ5s(s#|x494;|Y? zdn{K(bM%YeDy0hTaE}*>^X)zvTdnHua-y8`f=DO!Q=Nr^*;Ei99ECO1e>cwGshVdZ9ETeMBF>xK zs3zyjP*)#B-7&pAN;Y^t6Sk6yxM)Xt{9Iu)lkQss_(VUI2JhVV??$C++y~0e9Mog( zip4zRS(=_*U^Trn7+p(wqW$c5SJu!R+>dTU=PMeLQ++>TgO*$0+4CXskMa9_lloub zUNoJ$SjcjVNk+f*T%PTQ#Mh@_R`T9omhnTdcwT&_LUtQeR_pHk{Tw|s$XK0eu8Ge2 zpaJY+9KQ`n8wRx+FP-yVt5kc3`2fp7qgGm8>?BzS*8N(WyN2l17NLXg0j#6D#r40* z$=DHpZy%jqnHJn4?z3J={7{j}OXoIWlPo$K=uvX;r9z^tG?458JaZ@fP7TqM>`4cm zYuxjch?_$Fap%0I<0!|x)rz=A2a{dxVw7|ad#y|-ujUc=2^AAKmy=Q5|Iw<>kbaWg za}S-RI}g3b-%_KW9cqZ5`rU|Zv&v-2(o+M`7U0S>ns8apf`dq^Q; zCAJl5qEGYT8ahuW1gI2oAL9$zI9}}NF83Sp=FMJy>Od!iU8ZRL;9S5<{e|zAya}GA zb3Q#^_%sA$Y`YfPG}RS5G!pl2^X}qWl~%IY#FXt1 zNXna>2Q84^t=g`TcCF$TV+?x3MIi_#1LQkQ)oP8~u(bbCsX?ce!`BKhFAr?c^wpD$ zartt0%uV)F4V# z@02iqDN^2RkwaJu#Wl9Qj_MgCJ6w|R(A~A)_=tgU4=Q27S_^cFxT~xWYU>!RrxgR% zI>dcScLw7v zgHI<3SK$3h!tE5mj(Kp1xN`MI(=*Uvly)69M-ca-*=!5~dUvLM5+SAQNZmhahhe{3 z4h9YAtIWIAp(x3A89WifUE#Jk2zRj`{O7QqMcmo8*Bpyrl$BN_opHoH;_WUjg^NCz z8RloYmY5u=uIGxBw>#xX!CBiR|Xa>ZC4*0YyzOY_~(CgN5o^A(KY=Our& z9sItKH8?PY+^^4(m!`V}g0;?E{Uzd+x%x}T?#b0(GoC*cn8o^=#7X*gST_65`mVlDhw5WT@S0C(Ipwigo@P`uUa+n?#bXJm8t9rUq~EIaF%Fzg@FT zt)D|Og|(-Z{8U?7v2JDTQX|Z0HiIT&cZEbhDcdymZPe{yr5v7TUi6dJvP>Amvul@jl-dZF>7`SlV z+#}QR>x14{qD;g_y<#W+qwaUm_vBs%@+5ykUi3ryFYq6AyZYlVA7OxzoI{>&d%}_e zqf}#D?@t0KK)-a`j>#p;G|Cs{0X&K^igE@d$|01C^AS(^4D#dk=O*yeq*vRc)2r+U zCh%L4r>^eOT9qTnQ#U8_f1hAqh%wSzW=zj0IpoL3mqLDge4CJ`E<&__X@dU51U+DG z#?R-FA3r}hL7$z#Z<=5~jQo}TWt1Nwe`RkO<$2`An!v467GVCzucvMTKRjW7zL~(6 zSsI zug5QFQATs7A;x%LQRL}HAYT%!rLD*x#rsZ_QGFF4KOUoIf<8Mz|0?P6+@L=g!GF|| z;W{9NLDgVxSbS0kj%kLsksigd2o3sh-%F9EFFBe!AL$W%;sZ9}ybVZD7e-j$AiWc1 z+we)971^9cUXIG+mu&iwo`Siw;gfC^Oa+`pdJ*RB8Oj~zrw+$3jsjfwM>v8Q`%WBk zG!COJbytKPM4T#!0J8>jYPG1o;e-!C;IOuBt|A0k3b@W6hk*3a_=yga_2Tt@Mq^WZv lT8-xPn`hC??am2-b5co`v1o6m&5=7 diff --git a/data/scripts/mp/gametypes/_serversettings.gsc_raw b/data/scripts/mp/gametypes/_serversettings.gsc_raw index 580e2966..e420ca3c 100644 --- a/data/scripts/mp/gametypes/_serversettings.gsc_raw +++ b/data/scripts/mp/gametypes/_serversettings.gsc_raw @@ -3,11 +3,9 @@ #using scripts\shared\callbacks_shared; #using scripts\shared\system_shared; -#insert scripts\shared\shared.gsh; - #namespace serversettings; -REGISTER_SYSTEM( "serversettings", &__init__, undefined ) +function autoexec __init__sytem__() { system::register("serversettings",&__init__,undefined,undefined); } function __init__() { @@ -17,36 +15,33 @@ function __init__() function init() { level.hostname = GetDvarString( "sv_hostname"); - if (level.hostname == "") - { + if(level.hostname == "") level.hostname = "CoDHost"; - } - SetDvar("sv_hostname", level.hostname); SetDvar("ui_hostname", level.hostname); + //makeDvarServerInfo("ui_hostname", "CoDHost"); level.motd = GetDvarString( "scr_motd" ); if(level.motd == "") - { level.motd = ""; - } SetDvar("scr_motd", level.motd); SetDvar("ui_motd", level.motd); + //makeDvarServerInfo("ui_motd", ""); level.allowvote = GetDvarString( "g_allowvote" ); if(level.allowvote == "") - { level.allowvote = "1"; - } SetDvar("g_allowvote", level.allowvote); SetDvar("ui_allowvote", level.allowvote); - + //makeDvarServerInfo("ui_allowvote", "1"); + level.allow_teamchange = "1"; SetDvar("ui_allow_teamchange", level.allow_teamchange); level.friendlyfire = GetGametypeSetting( "friendlyfiretype" ); SetDvar("ui_friendlyfire", level.friendlyfire); + //makeDvarServerInfo("ui_friendlyfire", "0"); if(GetDvarString( "scr_mapsize") == "") SetDvar("scr_mapsize", "64"); @@ -62,7 +57,7 @@ function init() constrain_gametype(GetDvarString( "g_gametype")); constrain_map_size(level.mapsize); - + thread setup_callbacks(); for(;;) @@ -88,7 +83,7 @@ function update() SetDvar("ui_motd", level.motd); } - g_allowvote = GetDvarString( "g_allowvote"); + g_allowvote = GetDvarString( "g_allowvote" ); if(level.allowvote != g_allowvote) { level.allowvote = g_allowvote; @@ -211,4 +206,4 @@ function setup_callbacks() function default_onForfeit() { level.gameForfeited = false; -} +} \ No newline at end of file From 6c07d84e23cfc097ba3acd70320d542027786c54 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 17 Apr 2023 18:42:52 +0200 Subject: [PATCH 092/102] Prepare colored name support --- src/client/component/auth.cpp | 80 ++++++++++++++++++++++++++++++++- src/client/component/auth.hpp | 1 + src/client/component/colors.cpp | 65 +++++++++++++++++++++------ src/client/component/party.hpp | 2 + src/client/game/utils.cpp | 34 ++++++++++++++ src/client/game/utils.hpp | 2 + src/client/std_include.hpp | 1 + 7 files changed, 170 insertions(+), 15 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 78a6b460..7c679aa8 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -2,6 +2,7 @@ #include "loader/component_loader.hpp" #include "auth.hpp" +#include "party.hpp" #include "command.hpp" #include "network.hpp" #include "scheduler.hpp" @@ -24,6 +25,8 @@ namespace auth { namespace { + std::array client_xuids{}; + std::string get_hdd_serial() { DWORD serial{}; @@ -151,6 +154,32 @@ namespace auth return 0; } + void distribute_player_xuid(const game::netadr_t& target, const size_t player_index, const uint64_t xuid) + { + if (player_index >= 18) + { + return; + } + + utils::byte_buffer buffer{}; + buffer.write(static_cast(player_index)); + buffer.write(xuid); + + game::foreach_connected_client([&](const game::client_s& client, size_t index) + { + network::send(client.address, "playerXuid", buffer.get_buffer()); + + if (index != player_index) + { + utils::byte_buffer current_buffer{}; + current_buffer.write(static_cast(index)); + current_buffer.write(client.xuid); + + network::send(target, "playerXuid", current_buffer.get_buffer()); + } + }); + } + void dispatch_connect_packet(const game::netadr_t& target, const std::string& data) { utils::byte_buffer buffer(data); @@ -173,13 +202,17 @@ namespace auth game::SV_DirectConnect(target); - game::foreach_connected_client([&](game::client_s& client) + size_t player_index = 18; + game::foreach_connected_client([&](game::client_s& client, size_t index) { if (client.address == target) { client.xuid = xuid; + player_index = index; } }); + + distribute_player_xuid(target, player_index, xuid); } void handle_connect_packet_fragment(const game::netadr_t& target, const network::data_view& data) @@ -200,6 +233,24 @@ namespace auth }, scheduler::server); } } + + void handle_player_xuid_packet(const game::netadr_t& target, const network::data_view& data) + { + if (game::is_server_running() || !party::is_host(target)) + { + return; + } + + utils::byte_buffer buffer(data); + + const auto player_id = buffer.read(); + const auto xuid = buffer.read(); + + if (player_id < client_xuids.size()) + { + client_xuids[player_id] = xuid; + } + } } uint64_t get_guid() @@ -217,6 +268,32 @@ namespace auth return guid; } + uint64_t get_guid(const size_t client_num) + { + if (client_num >= 18) + { + return 0; + } + + if (!game::is_server_running()) + { + return client_xuids[client_num]; + } + + uint64_t xuid = 0; + const auto callback = [&xuid](const game::client_s& client) + { + xuid = client.xuid; + }; + + if (!game::access_connected_client(client_num, callback)) + { + return 0; + } + + return xuid; + } + struct component final : generic_component { void post_unpack() override @@ -224,6 +301,7 @@ namespace auth // Skip connect handler utils::hook::set(game::select(0x142253EFA, 0x14053714A), 0xEB); network::on("connect", handle_connect_packet_fragment); + network::on("playerXuid", handle_player_xuid_packet); // Patch steam id bit check std::vector> patches{}; diff --git a/src/client/component/auth.hpp b/src/client/component/auth.hpp index 3ee0c53a..87c07f5e 100644 --- a/src/client/component/auth.hpp +++ b/src/client/component/auth.hpp @@ -3,4 +3,5 @@ namespace auth { uint64_t get_guid(); + uint64_t get_guid(size_t client_num); } diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp index 306c44b6..5c7f7b4e 100644 --- a/src/client/component/colors.cpp +++ b/src/client/component/colors.cpp @@ -3,6 +3,10 @@ #include "game/game.hpp" +#include "auth.hpp" + +#include "steam/steam.hpp" + #include #include @@ -10,8 +14,25 @@ namespace colors { namespace { - utils::hook::detour get_player_name_hook; - utils::hook::detour get_gamer_tag_hook; + utils::hook::detour cl_get_client_name_hook; + + std::optional get_color_for_xuid(const uint64_t xuid) + { + if (xuid == 0xCD02AF6448291209 + || xuid == 0x10F0C433E08E1357 + || xuid == 0x60E0FEFE42341715) + { + return 2; + } + + return {}; + } + + std::optional get_color_for_client(const int client_num) + { + const auto xuid = auth::get_guid(static_cast(client_num)); + return get_color_for_xuid(xuid); + } template void patch_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a = 255) @@ -36,23 +57,39 @@ namespace colors utils::hook::copy(g_color_table + index * 4, color_float, sizeof(color_float)); } - /*uint64_t get_player_name_stub(const uint64_t client, int client_num, char* buffer, const int size, - const bool has_clan_tag) + bool cl_get_client_name_stub(const int local_client_num, const int index, char* buf, const int size, + const bool add_clan_name) { - const auto res = get_player_name_hook.invoke(client, client_num, buffer, size, has_clan_tag); + const auto res = cl_get_client_name_hook.invoke(local_client_num, index, buf, size, add_clan_name); - if (_ReturnAddress() != reinterpret_cast(0x1406A7B56_g)) + if (_ReturnAddress() == reinterpret_cast(0x1406A7B56_g)) { - const auto val = utils::string::va("^%d%s", rand() % 7, buffer); - strncpy_s(buffer, size, val, size); + return res; } - return res; - }*/ + const auto color = get_color_for_client(index); + if (!color) + { + return res; + } - /*const char* get_gamer_tag_stub(const uint64_t num) + const auto val = utils::string::va("^%d%s", *color, buf); + utils::string::copy(buf, size, val); + + return res; + } + + /*const char* get_gamer_tag_stub(const uint32_t num) { - return utils::string::va("^3%s", get_gamer_tag_hook.invoke(num)); + const auto color = get_color_for_xuid(steam::SteamUser()->GetSteamID().bits); + const auto name = reinterpret_cast(0x141EC6E80)(num) + 8; + + if (!color || num) + { + return name; + } + + return utils::string::va("^1%s", *color, name); }*/ } @@ -68,8 +105,8 @@ namespace colors patch_color<6>(151, 80, 221); // 6 - Pink // Old addresses - //get_player_name_hook.create(0x1413E3140_g, get_player_name_stub); - //get_gamer_tag_hook.create(0x141EC7370_g, get_gamer_tag_stub); + cl_get_client_name_hook.create(game::CL_GetClientName, cl_get_client_name_stub); + //utils::hook::jump(0x141EC72E0_g, get_gamer_tag_stub); } }; } diff --git a/src/client/component/party.hpp b/src/client/component/party.hpp index f682a14e..b10ee95c 100644 --- a/src/client/component/party.hpp +++ b/src/client/component/party.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include "game/game.hpp" + namespace party { using query_callback_func = void(bool success, const game::netadr_t& host, const ::utils::info_string& info, uint32_t ping); diff --git a/src/client/game/utils.cpp b/src/client/game/utils.cpp index e374a73a..c61a4350 100644 --- a/src/client/game/utils.cpp +++ b/src/client/game/utils.cpp @@ -176,6 +176,30 @@ namespace game } } + + template + static bool access_client(T* client_states, const size_t index, const std::function& callback) + { + if (!client_states || !callback) + { + return false; + } + + if (index >= get_max_client_count()) + { + return false; + } + + auto& client = client_states[index]; + if (client.client_state <= 0) + { + return false; + } + + callback(client); + return true; + } + void foreach_client(const std::function& callback) { if (is_server()) @@ -214,4 +238,14 @@ namespace game callback(client); }); } + + bool access_connected_client(const size_t index, const std::function& callback) + { + if (is_server()) + { + return access_client(*svs_clients, index, callback); + } + + return access_client(*svs_clients_cl, index, callback); + } } diff --git a/src/client/game/utils.hpp b/src/client/game/utils.hpp index 09abd8e7..5bbc78c0 100644 --- a/src/client/game/utils.hpp +++ b/src/client/game/utils.hpp @@ -24,4 +24,6 @@ namespace game void foreach_connected_client(const std::function& callback); void foreach_connected_client(const std::function& callback); + + bool access_connected_client(size_t index, const std::function& callback); } diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index 59b83a41..422c5ed9 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -65,6 +65,7 @@ #endif #include +#include #include #include #include From 4be9292c3b01eef66f08e5ebaa9925b8968d2d64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 18:03:50 +0000 Subject: [PATCH 093/102] Bump deps/curl from `7ed010c` to `1c5ed24` Bumps [deps/curl](https://github.com/curl/curl) from `7ed010c` to `1c5ed24`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/7ed010ce2192ae3e4d9663eaaa3a460f316b708b...1c5ed24ee0e929a6f410fcc3729becfd2ee71211) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 7ed010ce..1c5ed24e 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 7ed010ce2192ae3e4d9663eaaa3a460f316b708b +Subproject commit 1c5ed24ee0e929a6f410fcc3729becfd2ee71211 From d7b835d0ebc5e853714d4e5c990ca78c35def41a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 18:03:53 +0000 Subject: [PATCH 094/102] Bump deps/zlib from `5799c14` to `6658868` Bumps [deps/zlib](https://github.com/madler/zlib) from `5799c14` to `6658868`. - [Release notes](https://github.com/madler/zlib/releases) - [Commits](https://github.com/madler/zlib/compare/5799c14c8526bf1aaa130c021982f831d155b46d...66588683b36042154ad35140bf9fcbb60c5d573c) --- updated-dependencies: - dependency-name: deps/zlib dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/zlib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/zlib b/deps/zlib index 5799c14c..66588683 160000 --- a/deps/zlib +++ b/deps/zlib @@ -1 +1 @@ -Subproject commit 5799c14c8526bf1aaa130c021982f831d155b46d +Subproject commit 66588683b36042154ad35140bf9fcbb60c5d573c From fa144b7dd65cffb030a2192d13efaeb422046ec7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 17 Apr 2023 20:08:49 +0200 Subject: [PATCH 095/102] Clear xuids before connecting --- src/client/component/auth.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 7c679aa8..3b56585e 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -135,6 +135,11 @@ namespace auth int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, const int len) { + for (auto& xuid : client_xuids) + { + xuid = 0; + } + try { const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; From e6e2805466d1d85b460b5675e8612eff7f8239f2 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 17 Apr 2023 20:33:41 +0200 Subject: [PATCH 096/102] Fix guid distribution for bots --- src/client/component/auth.cpp | 53 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 3b56585e..8a750cde 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -172,9 +172,12 @@ namespace auth game::foreach_connected_client([&](const game::client_s& client, size_t index) { - network::send(client.address, "playerXuid", buffer.get_buffer()); + if (client.address.type != game::NA_BOT) + { + network::send(client.address, "playerXuid", buffer.get_buffer()); + } - if (index != player_index) + if (index != player_index && target.type != game::NA_BOT) { utils::byte_buffer current_buffer{}; current_buffer.write(static_cast(index)); @@ -185,6 +188,30 @@ namespace auth }); } + void handle_new_player(const game::netadr_t& target) + { + const command::params_sv params{}; + if (params.size() < 2) + { + return; + } + + const utils::info_string info_string(params[1]); + const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 16); + + size_t player_index = 18; + game::foreach_connected_client([&](game::client_s& client, size_t index) + { + if (client.address == target) + { + client.xuid = xuid; + player_index = index; + } + }); + + distribute_player_xuid(target, player_index, xuid); + } + void dispatch_connect_packet(const game::netadr_t& target, const std::string& data) { utils::byte_buffer buffer(data); @@ -206,18 +233,7 @@ namespace auth profile_infos::add_and_distribute_profile_info(target, xuid, info); game::SV_DirectConnect(target); - - size_t player_index = 18; - game::foreach_connected_client([&](game::client_s& client, size_t index) - { - if (client.address == target) - { - client.xuid = xuid; - player_index = index; - } - }); - - distribute_player_xuid(target, player_index, xuid); + handle_new_player(target); } void handle_connect_packet_fragment(const game::netadr_t& target, const network::data_view& data) @@ -256,6 +272,12 @@ namespace auth client_xuids[player_id] = xuid; } } + + void direct_connect_bots_stub(const game::netadr_t address) + { + game::SV_DirectConnect(address); + handle_new_player(address); + } } uint64_t get_guid() @@ -308,6 +330,9 @@ namespace auth network::on("connect", handle_connect_packet_fragment); network::on("playerXuid", handle_player_xuid_packet); + // Intercept SV_DirectConnect in SV_AddTestClient + utils::hook::call(game::select(0x1422490DC, 0x14052E582), direct_connect_bots_stub); + // Patch steam id bit check std::vector> patches{}; const auto p = [&patches](const size_t a, const size_t b) From 4cab2a73bde904a9079f45ca24c0a0e7d9e41920 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 17 Apr 2023 21:13:18 +0200 Subject: [PATCH 097/102] Better fix for clearing stored guids --- src/client/component/auth.cpp | 13 ++++++++----- src/client/component/auth.hpp | 1 + src/client/component/party.cpp | 8 ++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 8a750cde..59228b5d 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -135,11 +135,6 @@ namespace auth int send_connect_data_stub(const game::netsrc_t sock, game::netadr_t* adr, const char* data, const int len) { - for (auto& xuid : client_xuids) - { - xuid = 0; - } - try { const auto is_connect_sequence = len >= 7 && strncmp("connect", data, 7) == 0; @@ -321,6 +316,14 @@ namespace auth return xuid; } + void clear_stored_guids() + { + for (auto& xuid : client_xuids) + { + xuid = 0; + } + } + struct component final : generic_component { void post_unpack() override diff --git a/src/client/component/auth.hpp b/src/client/component/auth.hpp index 87c07f5e..30341c98 100644 --- a/src/client/component/auth.hpp +++ b/src/client/component/auth.hpp @@ -4,4 +4,5 @@ namespace auth { uint64_t get_guid(); uint64_t get_guid(size_t client_num); + void clear_stored_guids(); } diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 837a97f9..403c0c3a 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -3,6 +3,7 @@ #include "game/game.hpp" #include "party.hpp" +#include "auth.hpp" #include "network.hpp" #include "scheduler.hpp" #include "workshop.hpp" @@ -39,6 +40,8 @@ namespace party void connect_to_lobby(const game::netadr_t& addr, const std::string& mapname, const std::string& gamemode, const std::string& usermap_id, const std::string& mod_id) { + auth::clear_stored_guids(); + workshop::load_mod_if_needed(usermap_id, mod_id); game::XSESSION_INFO info{}; @@ -56,7 +59,8 @@ namespace party } void connect_to_lobby_with_mode(const game::netadr_t& addr, const game::eModes mode, const std::string& mapname, - const std::string& gametype, const std::string& usermap_id, const std::string& mod_id, + const std::string& gametype, const std::string& usermap_id, + const std::string& mod_id, const bool was_retried = false) { if (game::Com_SessionMode_IsMode(mode)) @@ -189,7 +193,7 @@ namespace party const auto usermap_id = workshop::get_usermap_publisher_id(mapname); if (workshop::check_valid_usermap_id(mapname, usermap_id) && - workshop::check_valid_mod_id(mod_id)) + workshop::check_valid_mod_id(mod_id)) { if (is_connecting_to_dedi) { From 7f908163cadc1ef9ab2547c2cdcbff0ef1b7aff3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 17 Apr 2023 21:17:58 +0200 Subject: [PATCH 098/102] Small cleanup --- src/client/component/auth.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 59228b5d..1457ee8e 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -165,7 +165,7 @@ namespace auth buffer.write(static_cast(player_index)); buffer.write(xuid); - game::foreach_connected_client([&](const game::client_s& client, size_t index) + game::foreach_connected_client([&](const game::client_s& client, const size_t index) { if (client.address.type != game::NA_BOT) { @@ -195,7 +195,7 @@ namespace auth const auto xuid = strtoull(info_string.get("xuid").data(), nullptr, 16); size_t player_index = 18; - game::foreach_connected_client([&](game::client_s& client, size_t index) + game::foreach_connected_client([&](game::client_s& client, const size_t index) { if (client.address == target) { From ddb63bc5d29d97bebb96edf5226a4a66b528c42f Mon Sep 17 00:00:00 2001 From: ineed bots Date: Mon, 17 Apr 2023 19:56:32 -0600 Subject: [PATCH 099/102] Fix negativeAck exploit (crash DOS) --- src/client/component/patches.cpp | 20 ++++++++++++++++++-- src/client/game/structs.hpp | 12 ++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 0900b5a8..6a2b59e5 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -11,7 +11,20 @@ namespace patches { namespace - { + { + utils::hook::detour sv_executeclientmessages_hook; + + void sv_executeclientmessages_stub(game::client_s* cl, game::msg_t* msg) + { + if (cl->reliableAcknowledge < 0) + { + cl->reliableAcknowledge = cl->reliableSequence; + return; + } + + sv_executeclientmessages_hook.invoke(cl, msg); + } + void script_errors_stub(const char* file, int line, unsigned int code, const char* fmt, ...) { char buffer[0x1000]; @@ -37,7 +50,10 @@ namespace patches // Change 4 character name limit to 3 characters utils::hook::set(game::select(0x14224DA53, 0x140531143), 3); utils::hook::set(game::select(0x14224DBB4, 0x1405312A8), 3); - utils::hook::set(game::select(0x14224DF8C, 0x1405316DC), 3); + utils::hook::set(game::select(0x14224DF8C, 0x1405316DC), 3); + + // make sure client's reliableAck are not negative + sv_executeclientmessages_hook.create(game::select(0x14224A460, 0x14052F840), sv_executeclientmessages_stub); scheduler::once([] { diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 424c59ac..696a33c5 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1583,15 +1583,23 @@ namespace game int client_state; char __pad0[0x28]; netadr_t address; - char __pad1[0x5588]; + char gap_3C[20468]; + int reliableSequence; + int reliableAcknowledge; + char gap_5038[4]; + int messageAcknowledge; + char gap_5040[1416]; uint64_t xuid; char __pad2[0xB5D84]; int guid; char __pad3[0x8]; bool bIsTestClient; - char __pad4[0x29DAC]; + char gap_BB361[3]; + int serverId; + char gap_BB368[171432]; }; + #ifdef __cplusplus static_assert(sizeof(client_s) == 0xE5110); From b891d25b8729967b9072df5c06a1de6a10259cf5 Mon Sep 17 00:00:00 2001 From: ineed bots Date: Mon, 17 Apr 2023 22:04:57 -0600 Subject: [PATCH 100/102] Fix `cl` warning --- src/client/component/patches.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 6a2b59e5..ea4812a9 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -14,15 +14,15 @@ namespace patches { utils::hook::detour sv_executeclientmessages_hook; - void sv_executeclientmessages_stub(game::client_s* cl, game::msg_t* msg) + void sv_executeclientmessages_stub(game::client_s* client, game::msg_t* msg) { - if (cl->reliableAcknowledge < 0) + if (client->reliableAcknowledge < 0) { - cl->reliableAcknowledge = cl->reliableSequence; + client->reliableAcknowledge = client->reliableSequence; return; } - sv_executeclientmessages_hook.invoke(cl, msg); + sv_executeclientmessages_hook.invoke(client, msg); } void script_errors_stub(const char* file, int line, unsigned int code, const char* fmt, ...) From f27a1b97e70356cd7001ea47b97675a285fd08f3 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 18 Apr 2023 10:49:02 +0200 Subject: [PATCH 101/102] network: improve a patch --- src/client/component/network.cpp | 22 +++++- src/client/component/patches.cpp | 112 ++++++++++++++++--------------- src/client/game/structs.hpp | 12 ++-- src/client/game/symbols.hpp | 2 + 4 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 546d5a1f..04b5c1a6 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -163,7 +163,6 @@ namespace network : 0; } - uint64_t ret2() { return 2; @@ -173,6 +172,15 @@ namespace network { return 0; } + + void com_error_oob_stub(const char* file, int line, int code, [[maybe_unused]] const char* fmt, const char* error) + { + char buffer[1024]{}; + + strncpy_s(buffer, error, _TRUNCATE); + + game::Com_Error_(file, line, code, "%s", buffer); + } } void on(const std::string& command, const callback& callback) @@ -321,10 +329,20 @@ namespace network // NA_IP -> NA_RAWIP in NetAdr_ToString utils::hook::set(game::select(0x142172ED4, 0x140515864), game::NA_RAWIP); + // Kill 'echo' OOB handler + utils::hook::set(game::select(0x14134D0FB, 0x14018EE82), 0xEB); + if (game::is_server()) { // Remove restrictions for rcon commands - utils::hook::call(0x140538D5C_g, &con_restricted_execute_buf_stub); // SVC_RemoteCommand + utils::hook::call(0x140538D5C_g, con_restricted_execute_buf_stub); // SVC_RemoteCommand + + // Kill 'error' OOB handler on the dedi + utils::hook::nop(0x14018EF8B_g, 5); + } + else + { + utils::hook::call(0x14134D206_g, com_error_oob_stub); } // TODO: Fix that diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index ea4812a9..b7a2824f 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -1,66 +1,68 @@ -#include -#include "loader/component_loader.hpp" - -#include -#include - -#include "scheduler.hpp" - -#include - -namespace patches -{ - namespace - { - utils::hook::detour sv_executeclientmessages_hook; +#include +#include "loader/component_loader.hpp" - void sv_executeclientmessages_stub(game::client_s* client, game::msg_t* msg) - { +#include +#include + +#include "network.hpp" +#include "scheduler.hpp" + +#include + +namespace patches +{ + namespace + { + utils::hook::detour sv_execute_client_messages_hook; + + void sv_execute_client_messages_stub(game::client_s* client, game::msg_t* msg) + { if (client->reliableAcknowledge < 0) { client->reliableAcknowledge = client->reliableSequence; + network::send(client->address, "error", "EXE_LOSTRELIABLECOMMANDS"); return; } - sv_executeclientmessages_hook.invoke(client, msg); + sv_execute_client_messages_hook.invoke(client, msg); } - - void script_errors_stub(const char* file, int line, unsigned int code, const char* fmt, ...) - { - char buffer[0x1000]; - - { - va_list ap; - va_start(ap, fmt); - vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); - va_end(ap); - } - - game::Com_Error(game::ERROR_SCRIPT_DROP, "%s", buffer); - } - } - - struct component final : generic_component - { - void post_unpack() override - { - // don't make script errors fatal error - utils::hook::call(game::select(0x1412CAC4D, 0x140158EB2), script_errors_stub); - - // Change 4 character name limit to 3 characters - utils::hook::set(game::select(0x14224DA53, 0x140531143), 3); - utils::hook::set(game::select(0x14224DBB4, 0x1405312A8), 3); + + void script_errors_stub(const char* file, int line, unsigned int code, const char* fmt, ...) + { + char buffer[0x1000]; + + { + va_list ap; + va_start(ap, fmt); + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); + va_end(ap); + } + + game::Com_Error(game::ERROR_SCRIPT_DROP, "%s", buffer); + } + } + + struct component final : generic_component + { + void post_unpack() override + { + // don't make script errors fatal error + utils::hook::call(game::select(0x1412CAC4D, 0x140158EB2), script_errors_stub); + + // Change 4 character name limit to 3 characters + utils::hook::set(game::select(0x14224DA53, 0x140531143), 3); + utils::hook::set(game::select(0x14224DBB4, 0x1405312A8), 3); utils::hook::set(game::select(0x14224DF8C, 0x1405316DC), 3); // make sure client's reliableAck are not negative - sv_executeclientmessages_hook.create(game::select(0x14224A460, 0x14052F840), sv_executeclientmessages_stub); - - scheduler::once([] - { - game::register_dvar_string("password", "", game::DVAR_USERINFO, "password"); - }, scheduler::pipeline::main); - } - }; -} - -REGISTER_COMPONENT(patches::component) + sv_execute_client_messages_hook.create(game::select(0x14224A460, 0x14052F840), sv_execute_client_messages_stub); + + scheduler::once([] + { + game::register_dvar_string("password", "", game::DVAR_USERINFO, "password"); + }, scheduler::pipeline::main); + } + }; +} + +REGISTER_COMPONENT(patches::component) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 696a33c5..9876f2c4 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1583,20 +1583,20 @@ namespace game int client_state; char __pad0[0x28]; netadr_t address; - char gap_3C[20468]; + char __pad1[20468]; int reliableSequence; int reliableAcknowledge; - char gap_5038[4]; + char __pad2[4]; int messageAcknowledge; char gap_5040[1416]; uint64_t xuid; - char __pad2[0xB5D84]; + char __pad3[0xB5D84]; int guid; - char __pad3[0x8]; + char __pad4[0x8]; bool bIsTestClient; - char gap_BB361[3]; + char __pad5[3]; int serverId; - char gap_BB368[171432]; + char __pad6[171432]; }; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 36a82681..fbb93ad9 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -78,6 +78,8 @@ namespace game // G WEAK symbol G_ClearVehicleInputs{0x1423812E0, 0x1405C1200}; + WEAK symbol StuckInClient{0x1415A8360, 0x14023BFE0}; + // Live WEAK symbol Live_GetConnectivityInformation{0x141E0C380}; From 93bb54c6a40a0e93c9e52e66dd35d84b131bfdc6 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 18 Apr 2023 12:17:41 +0200 Subject: [PATCH 102/102] network: add comment --- src/client/component/network.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 04b5c1a6..4371a17a 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -342,6 +342,7 @@ namespace network } else { + // Truncate error string to make sure there are no buffer overruns later utils::hook::call(0x14134D206_g, com_error_oob_stub); }