diff --git a/deps/gsc-tool b/deps/gsc-tool index e4cb6a7..616595f 160000 --- a/deps/gsc-tool +++ b/deps/gsc-tool @@ -1 +1 @@ -Subproject commit e4cb6a7819726d9ea33cd6a52f0dcd9382258b47 +Subproject commit 616595f8e0dd62d6d57ed7a4ef7635a4c65e5dde diff --git a/deps/libtomcrypt b/deps/libtomcrypt index 2e9f2b5..54f0456 160000 --- a/deps/libtomcrypt +++ b/deps/libtomcrypt @@ -1 +1 @@ -Subproject commit 2e9f2b5e44dd498dba60e5175c6c7effa5ff3728 +Subproject commit 54f0456559c8f64b93273a7c71c88a46550eed4e diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 70656d7..c69be34 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -62,7 +62,6 @@ namespace bots return; } - // SV_BotGetRandomName const auto* const bot_name = game::SV_BotGetRandomName(); const auto* bot_ent = game::SV_AddBot(bot_name); if (bot_ent) diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index d41cd1e..1f0c43d 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -1,14 +1,13 @@ #include #include "loader/component_loader.hpp" - #include "game/game.hpp" +#include "game/engine/sv_game.hpp" #include "game/dvars.hpp" #include "command.hpp" #include "console.hpp" -#include "game_console.hpp" -#include "scheduler.hpp" #include "fastfiles.hpp" +#include "game_console.hpp" #include #include @@ -236,15 +235,13 @@ namespace command { if (!dvars::sv_cheats->current.enabled) { - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - "f \"Cheats are not enabled on this server\""); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); return false; } if (ent->health < 1) { - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - "f \"You must be alive to use this command\""); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You must be alive to use this command\""); return false; } @@ -582,8 +579,7 @@ namespace command ent->flags ^= game::FL_GODMODE; - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off")); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off")); }); add_sv("demigod", [](game::mp::gentity_s* ent, const params_sv&) @@ -593,8 +589,7 @@ namespace command ent->flags ^= game::FL_DEMI_GODMODE; - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off")); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off")); }); add_sv("notarget", [](game::mp::gentity_s* ent, const params_sv&) @@ -604,8 +599,7 @@ namespace command ent->flags ^= game::FL_NOTARGET; - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off")); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off")); }); add_sv("noclip", [](game::mp::gentity_s* ent, const params_sv&) @@ -615,8 +609,7 @@ namespace command ent->client->flags ^= 1; - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off")); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off")); }); add_sv("ufo", [](game::mp::gentity_s* ent, const params_sv&) @@ -626,8 +619,7 @@ namespace command ent->client->flags ^= 2; - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off")); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off")); }); add_sv("give", [](game::mp::gentity_s* ent, const params_sv& params) @@ -637,8 +629,7 @@ namespace command if (params.size() < 2) { - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - "f \"You did not specify a weapon name\""); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\""); return; } @@ -661,8 +652,7 @@ namespace command if (params.size() < 2) { - game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, - "f \"You did not specify a weapon name\""); + game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\""); return; } diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index beef80d..ccc66ad 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -1,6 +1,7 @@ #include #include "loader/component_loader.hpp" #include "game/game.hpp" +#include "game/engine/sv_game.hpp" #include "console.hpp" #include "scheduler.hpp" @@ -99,8 +100,7 @@ namespace dedicated for (const auto& command : queue) { - game::Cbuf_AddText(0, command.data()); - game::Cbuf_AddText(0, "\n"); + command::execute(command); } } @@ -123,36 +123,10 @@ namespace dedicated void kill_server() { - for (auto i = 0; i < *game::mp::svs_numclients; ++i) - { - if (game::mp::svs_clients[i].header.state >= 3) - { - game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE, - utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); - } - } + game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); com_quit_f_hook.invoke(); } - - void sys_error_stub(const char* msg, ...) - { - char buffer[2048]{}; - - va_list ap; - va_start(ap, msg); - - vsnprintf_s(buffer, _TRUNCATE, msg, ap); - - va_end(ap); - - scheduler::once([] - { - command::execute("map_rotate"); - }, scheduler::main, 3s); - - game::Com_Error(game::ERR_DROP, "%s", buffer); - } } void initialize() @@ -190,8 +164,6 @@ namespace dedicated // Don't allow sv_hostname to be changed by the game dvars::disable::set_string("sv_hostname"); - // Stop crashing from sys_errors - utils::hook::jump(0x1404D6260, sys_error_stub); // Hook R_SyncGpu utils::hook::jump(0x1405A7630, sync_gpu_stub); diff --git a/src/client/component/dvar_cheats.cpp b/src/client/component/dvar_cheats.cpp index b105be0..1e972b0 100644 --- a/src/client/component/dvar_cheats.cpp +++ b/src/client/component/dvar_cheats.cpp @@ -1,7 +1,7 @@ #include #include "loader/component_loader.hpp" - #include "game/game.hpp" +#include "game/engine/sv_game.hpp" #include "game/dvars.hpp" #include "console.hpp" @@ -130,7 +130,7 @@ namespace dvar_cheats const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack const auto* command = utils::string::va("q %s \"%s\"", dvar, value); - game::SV_GameSendServerCommand(entity_num, game::SV_CMD_RELIABLE, command); + game::engine::SV_GameSendServerCommand(static_cast(entity_num), game::SV_CMD_RELIABLE, command); } const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a) diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp index 9196af1..3d22ef2 100644 --- a/src/client/component/filesystem.cpp +++ b/src/client/component/filesystem.cpp @@ -64,20 +64,22 @@ namespace filesystem void startup() { - register_path("s1"); + const auto base = std::filesystem::current_path(); + + register_path(base / "s1"); register_path(get_binary_directory() + "\\data"); - if (get_binary_directory() != std::filesystem::current_path()) + if (get_binary_directory() != base) { - register_path(std::filesystem::current_path() / "data"); + register_path(base / "data"); } // game's search paths - register_path("devraw"); - register_path("devraw_shared"); - register_path("raw_shared"); - register_path("raw"); - register_path("main"); + register_path(base / "devraw"); + register_path(base / "devraw_shared"); + register_path(base / "raw_shared"); + register_path(base / "raw"); + register_path(base / "main"); } void check_for_startup() diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp index 83cfacc..7bc80bd 100644 --- a/src/client/component/gsc/script_loading.cpp +++ b/src/client/component/gsc/script_loading.cpp @@ -419,7 +419,7 @@ namespace gsc public: void post_load() override { - gsc_ctx = std::make_unique(); + gsc_ctx = std::make_unique(xsk::gsc::instance::server); } void post_unpack() override diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp index 7aa9a9e..320d5fa 100644 --- a/src/client/component/lui.cpp +++ b/src/client/component/lui.cpp @@ -29,7 +29,7 @@ namespace lui { if (params.size() <= 1) { - console::info("usage: lui_open \n"); + console::info("USAGE: %s \n", params.get(0)); return; } @@ -40,7 +40,7 @@ namespace lui { if (params.size() <= 1) { - console::info("usage: lui_open_popup \n"); + console::info("USAGE: %s \n", params.get(0)); return; } diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 15905c8..1749047 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -1,6 +1,7 @@ #include #include "loader/component_loader.hpp" #include "game/game.hpp" +#include "game/engine/sv_game.hpp" #include "game/dvars.hpp" #include "party.hpp" @@ -442,7 +443,7 @@ namespace party { scheduler::once([i, reason] { - game::SV_KickClientNum(i, reason.data()); + game::SV_KickClientNum(i, reason.c_str()); }, scheduler::pipeline::server); } return; @@ -456,7 +457,7 @@ namespace party scheduler::once([client_num, reason]() { - game::SV_KickClientNum(client_num, reason.data()); + game::SV_KickClientNum(client_num, reason.c_str()); }, scheduler::pipeline::server); }); @@ -476,9 +477,8 @@ namespace party const auto message = params.join(2); const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; - game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s: %s\"", 84, name, message.data())); - printf("%s -> %i: %s\n", name, client_num, message.data()); + game::engine::SV_GameSendServerCommand(static_cast(client_num), game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.c_str())); + printf("%s -> %i: %s\n", name, client_num, message.c_str()); }); command::add("tellraw", [](const command::params& params) @@ -491,9 +491,8 @@ namespace party const auto client_num = atoi(params.get(1)); const auto message = params.join(2); - game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s\"", 84, message.data())); - printf("%i: %s\n", client_num, message.data()); + game::engine::SV_GameSendServerCommand(static_cast(client_num), game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.c_str())); + printf("%i: %s\n", client_num, message.c_str()); }); command::add("say", [](const command::params& params) @@ -506,9 +505,8 @@ namespace party const auto message = params.join(1); const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; - game::SV_GameSendServerCommand( - -1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); - printf("%s: %s\n", name, message.data()); + game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.c_str())); + printf("%s: %s\n", name, message.c_str()); }); command::add("sayraw", [](const command::params& params) @@ -520,8 +518,7 @@ namespace party const auto message = params.join(1); - game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s\"", 84, message.data())); + game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.c_str())); printf("%s\n", message.data()); }); diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 4cc58a1..7cbfdbe 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -1,6 +1,7 @@ #include #include "loader/component_loader.hpp" #include "game/game.hpp" +#include "game/engine/sv_game.hpp" #include "game/dvars.hpp" #include "command.hpp" @@ -178,7 +179,7 @@ namespace patches const auto client = &game::mp::svs_clients[ent->s.number]; // 22 => "end_game" - if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK) + if (menu_id == 22 && client->header.netchan.remoteAddress.type != game::NA_LOOPBACK) { return; } @@ -239,6 +240,10 @@ namespace patches static void patch_mp() { + // Bypass Arxan function + utils::hook::nop(0x14043E120, 9); + utils::hook::jump(0x14043E120, game::engine::SV_GameSendServerCommand); + // Use name dvar live_get_local_client_name_hook.create(0x1404D47F0, &live_get_local_client_name); diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp index d0fdf45..123dc80 100644 --- a/src/client/component/rcon.cpp +++ b/src/client/component/rcon.cpp @@ -96,8 +96,8 @@ namespace rcon (client->header.state == 2) ? "CNCT" : (client->header.state == 1) ? "ZMBI" : utils::string::va("%4i", game::SV_GetClientPing(i)), game::SV_GetGuid(i), clean_name, - network::net_adr_to_string(client->header.remoteAddress), - client->header.remoteAddress.port) + network::net_adr_to_string(client->header.netchan.remoteAddress), + client->header.netchan.remoteAddress.port) ); } diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index c2e9393..0f7d3f9 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -206,6 +206,27 @@ namespace ui_scripting setup_functions(); lua["print"] = function(reinterpret_cast(0x14007CB70)); + + lua["directoryexists"] = [](const std::string& string) + { + return utils::io::directory_exists(string); + }; + + lua["listfiles"] = [](const std::string& string) + { + return utils::io::list_files(string); + }; + + lua["directoryisempty"] = [](const std::string& string) + { + return utils::io::directory_is_empty(string); + }; + + lua["fileexists"] = [](const std::string& string) + { + return utils::io::file_exists(string); + }; + lua["table"]["unpack"] = lua["unpack"]; lua["luiglobals"] = lua; diff --git a/src/client/game/engine/sv_game.cpp b/src/client/game/engine/sv_game.cpp new file mode 100644 index 0000000..b5dd968 --- /dev/null +++ b/src/client/game/engine/sv_game.cpp @@ -0,0 +1,181 @@ +#include +#include + +#include "sv_game.hpp" + +#include + +#include + +namespace game::engine +{ + char* SV_ExpandNewlines(char* in) + { + static char string[1024]; + + unsigned int l = 0; + while (*in && l < sizeof(string) - 3) + { + if (*in == '\n') + { + string[l++] = '\\'; + string[l++] = 'n'; + } + else + { + if (*in != '\x14' && *in != '\x15') + { + string[l++] = *in; + } + } + + ++in; + } + + string[l] = '\0'; + return string; + } + + void SV_CullIgnorableServerCommands(mp::client_t* client) + { + int to = client->reliableSent + 1; + for (int from = to; from <= client->reliableSequence; ++from) + { + int from_index = from & 0x7F; + assert(client->netBuf.reliableCommandInfo[from_index].time >= 0); + if (client->netBuf.reliableCommandInfo[from_index].type) + { + int to_index = to & 0x7F; + if (to_index != from_index) + { + client->netBuf.reliableCommandInfo[to_index] = client->netBuf.reliableCommandInfo[from_index]; + } + + ++to; + } + } + + client->reliableSequence = to - 1; + } + + void SV_DelayDropClient(mp::client_t* drop, const char* reason) + { + assert(drop); + assert(reason); + assert(drop->header.state != mp::CS_FREE); + if (drop->header.state == mp::CS_ZOMBIE) + { +#ifdef _DEBUG + console::info("(drop->dropReason) = %s", drop->dropReason); +#endif + } + else if (!drop->dropReason) + { + drop->dropReason = reason; + } + } + + void SV_AddServerCommand(mp::client_t* client, svscmd_type type, const char* cmd) + { + static_assert(offsetof(mp::client_t, netBuf.reliableCommandInfo[0].cmd) == 0xC44); + + if (client->testClient == TC_BOT) + { + return; + } + + if (client->reliableSequence - client->reliableAcknowledge < 64 && client->header.state == mp::CS_ACTIVE || (SV_CullIgnorableServerCommands(client), type)) + { + int len = static_cast(std::strlen(cmd)) + 1; + int to = SV_CanReplaceServerCommand(client, reinterpret_cast(cmd), len); + if (to < 0) + { + ++client->reliableSequence; + } + else + { + int from = to + 1; + while (from <= client->reliableSequence) + { + client->netBuf.reliableCommandInfo[to & 0x7F] = client->netBuf.reliableCommandInfo[from & 0x7F]; + ++from; + ++to; + } + } + + if (client->reliableSequence - client->reliableAcknowledge == 129) + { +#ifdef _DEBUG + console::info("===== pending server commands =====\n"); + int i = 0; + for (i = client->reliableAcknowledge + 1; i <= client->reliableSequence; ++i) + { + console::info("cmd %5d: %8d: %s\n", i, client->netBuf.reliableCommandInfo[i & 0x7F].time, client->netBuf.reliableCommandInfo[i & 0x7F].cmd); + } + console::info("cmd %5d: %8d: %s\n", i, *game::mp::serverTime, cmd); +#endif + NET_OutOfBandPrint(NS_SERVER, &client->header.netchan.remoteAddress, "disconnect"); + SV_DelayDropClient(client, "EXE_SERVERCOMMANDOVERFLOW"); + type = SV_CMD_RELIABLE; + cmd = utils::string::va("%c \"EXE_SERVERCOMMANDOVERFLOW\"", 'r'); + } + + int index = client->reliableSequence & 0x7F; + MSG_WriteReliableCommandToBuffer(cmd, client->netBuf.reliableCommandInfo[index].cmd, sizeof(client->netBuf.reliableCommandInfo[index].cmd)); + client->netBuf.reliableCommandInfo[index].time = *game::mp::serverTime; + client->netBuf.reliableCommandInfo[index].type = type; + } + } + + void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...) + { + mp::client_t* client; + int j, len; + va_list va; + + const auto server_command_buf_large = std::make_unique(0x20000); + + va_start(va, fmt); + len = vsnprintf_s(server_command_buf_large.get(), 0x20000, _TRUNCATE, fmt, va); + va_end(va); + + assert(len >= 0); + + if (cl) + { + SV_AddServerCommand(cl, type, server_command_buf_large.get()); + return; + } + + if (environment::is_dedi() && !std::strncmp(server_command_buf_large.get(), "print", 5)) + { + console::info("broadcast: %s\n", SV_ExpandNewlines(server_command_buf_large.get())); + } + + const auto* sv_maxclients = Dvar_FindVar("sv_maxclients"); + for (j = 0, client = mp::svs_clients; j < sv_maxclients->current.integer; j++, client++) + { + if (client->header.state < mp::CS_CLIENTLOADING) + { + continue; + } + + SV_AddServerCommand(client, type, server_command_buf_large.get()); + } + } + + void SV_GameSendServerCommand(char clientNum, svscmd_type type, const char* text) + { + [[maybe_unused]] const auto* sv_maxclients = Dvar_FindVar("sv_maxclients"); + + if (clientNum == -1) + { + SV_SendServerCommand(nullptr, type, "%s", text); + return; + } + + assert(sv_maxclients->current.integer >= 1 && sv_maxclients->current.integer <= 18); + assert(static_cast(clientNum) < sv_maxclients->current.unsignedInt); + SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text); + } +} diff --git a/src/client/game/engine/sv_game.hpp b/src/client/game/engine/sv_game.hpp new file mode 100644 index 0000000..32fb804 --- /dev/null +++ b/src/client/game/engine/sv_game.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace game::engine +{ + void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...); + void SV_GameSendServerCommand(char clientNum, svscmd_type type, const char* text); +} diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index dbef2e0..b7e7afa 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -855,10 +855,11 @@ namespace game int readcount; int bit; int lastEntityRef; - netsrc_t targetLocalNetID; int useZlib; }; + static_assert(sizeof(msg_t) == 0x38); + enum errorParm { ERR_FATAL = 0, @@ -1416,8 +1417,44 @@ namespace game static_assert(sizeof(pml_t) == 0x130); + struct netProfilePacket_t + { + int iTime; + int iSize; + int bFragment; + }; + + struct netProfileStream_t + { + netProfilePacket_t packets[60]; + int iCurrPacket; + int iBytesPerSecond; + int iLastBPSCalcTime; + int iCountedPackets; + int iCountedFragments; + int iFragmentPercentage; + int iLargestPacket; + int iSmallestPacket; + }; + + struct netProfileInfo_t + { + netProfileStream_t send; + netProfileStream_t recieve; + }; + namespace mp { + enum + { + CS_FREE = 0x0, + CS_ZOMBIE = 0x1, + CS_RECONNECTING = 0x2, + CS_CONNECTED = 0x3, + CS_CLIENTLOADING = 0x4, + CS_ACTIVE = 0x5, + }; + struct cachedSnapshot_t { int archivedFrame; @@ -1470,33 +1507,141 @@ namespace game { }; + struct netchan_t + { + int outgoingSequence; + netsrc_t sock; + int dropped; + int incomingSequence; + netadr_s remoteAddress; + int fragmentSequence; + int fragmentLength; + char* fragmentBuffer; + int fragmentBufferSize; + int unsentFragments; + int unsentFragmentStart; + int unsentLength; + char* unsentBuffer; + int unsentBufferSize; + netProfileInfo_t prof; + }; + struct clientHeader_t { int state; - char __pad0[36]; - netadr_s remoteAddress; - }; // size = ? + int sendAsActive; + int deltaMessage; + int rateDelayed; + int hasAckedBaselineData; + int hugeSnapshotSent; + netchan_t netchan; + float predictedOrigin[3]; + int predictedOriginServerTime; + int migrationState; + unsigned int predictedVehicleSplineId; + int predictedVehicleTargetEntity; + float predictedVehicleOrigin[3]; + int predictedVehicleServerTime; + int ackedMessage[32]; + unsigned int ackedMessageCount; + int sentMessage[32]; + int wasKillcam[32]; + unsigned int sendMessageCount; + bool overrideDeltaMessage; + int overrideSequenceNumber; + int sequenceResume; + int isInKillcam; + }; + + struct svscmd_info_t + { + int time; + int type; + char cmd[1024]; + }; + + static_assert(sizeof(svscmd_info_t) == 0x408); + + struct client_net_buffers_t + { + svscmd_info_t reliableCommandInfo[128]; + char netchanOutgoingBuffer[131072]; + char netchanIncomingBuffer[2048]; + }; + + struct usercmd_s + { + int serverTime; + unsigned int buttons; + int angles[3]; + Weapon weapon; + Weapon offHand; + char forwardmove; + char rightmove; + unsigned __int16 airburstMarkDistance; + __int16 meleeChargeEnt; + unsigned __int8 meleeChargeDist; + char selectedLoc[2]; + unsigned __int8 selectedLocAngle; + char remoteControlAngles[2]; + char remoteControlMove[3]; + unsigned int sightedClientsMask; + unsigned __int16 spawnTraceEntIndex; + unsigned int sightedSpawnsMask[2]; + unsigned int partialSightedSpawnsMask[2]; + }; + + static_assert(sizeof(usercmd_s) == 0x44); struct client_t { clientHeader_t header; - char __pad0[3044]; + const char* dropReason; + char userinfo[0x400]; int reliableSequence; int reliableAcknowledge; - char __pad1[265864]; + int reliableSent; + int messageAcknowledge; + int largeCommandSequence; + int gamestateMessageNum; + int challenge; + client_net_buffers_t netBuf; + int cumulThinkTime; + int beginCmdIndex; + int currCmdIndex; + usercmd_s lastUsercmd; + usercmd_s cmds[8]; + int lastClientCommand; gentity_s* gentity; // 268976 - char name[32]; // 268984 - char __pad2[8]; + char name[32]; + int lastPacketTime; + int lastConnectTime; int nextSnapshotTime; // 269024 - char __pad3[544]; + char __pad3[532]; + int pureAuthentic; + unsigned int streamSyncWaitBits; + unsigned int streamSyncWaitTimeout; LiveClientDropType liveDropRequest; // 269572 char __pad4[24]; TestClientType testClient; // 269600 char __pad5[391700]; }; // size = 661304 + static_assert(offsetof(client_t, header.netchan.unsentFragments) == 0x54); + static_assert(offsetof(client_t, header.migrationState) == 0x660); + static_assert(offsetof(client_t, userinfo) == 0x820); + static_assert(offsetof(client_t, reliableSequence) == 0xC20); + static_assert(offsetof(client_t, reliableAcknowledge) == 0xC24); + static_assert(offsetof(client_t, reliableSent) == 0xC28); + static_assert(offsetof(client_t, messageAcknowledge) == 0xC2C); + static_assert(offsetof(client_t, largeCommandSequence) == 0xC30); + static_assert(offsetof(client_t, lastUsercmd) == 0x41848); + static_assert(offsetof(client_t, lastClientCommand) == 0x41AAC); static_assert(offsetof(client_t, gentity) == 0x41AB0); + static_assert(offsetof(client_t, name) == 0x41AB8); + static_assert(offsetof(client_t, lastPacketTime) == 0x41AD8); static_assert(offsetof(client_t, nextSnapshotTime) == 0x41AE0); + static_assert(offsetof(client_t, pureAuthentic) == 0x41CF8); static_assert(offsetof(client_t, liveDropRequest) == 0x41D04); static_assert(offsetof(client_t, testClient) == 0x41D20); static_assert(sizeof(client_t) == 0xA1738); @@ -1508,7 +1653,9 @@ namespace game { char __pad[56135]; int flags; // 56136 - }; + }; // Incomplete + + static_assert(offsetof(gclient_s, flags) == 56136); struct gentity_s { diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 426712c..6b35668 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -184,7 +184,7 @@ namespace game WEAK symbol SV_DropClient{0, 0x140438A30}; WEAK symbol SV_ExecuteClientCommand{0, 0x15121D8E6}; WEAK symbol SV_FastRestart{0, 0x1404374E0}; - WEAK symbol SV_GameSendServerCommand{0x1403F3A70, 0x14043E120}; + WEAK symbol SV_CanReplaceServerCommand{0x0, 0x140441A00}; WEAK symbol SV_GetGuid{0, 0x14043E1E0}; WEAK symbol SV_GetClientPing{0, 0x14043E1C0}; WEAK symbol SV_GetPlayerstateForClientNum{0x1403F3AB0, 0x14043E260}; @@ -221,6 +221,8 @@ namespace game WEAK symbol I_strncpyz{0x1403793B0, 0x1404C9E60}; + WEAK symbol MSG_WriteReliableCommandToBuffer{0x0, 0x1403E1090}; + WEAK symbol longjmp{0x14059C5C0, 0x1406FD930}; WEAK symbol _setjmp{0x14059CD00, 0x1406FE070}; diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index 0ab229c..5a5ba55 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include