From e90301acd9502a5f62e9ea99ef8e89ecd7ccf4d6 Mon Sep 17 00:00:00 2001 From: quaK Date: Thu, 11 Jul 2024 00:34:55 +0300 Subject: [PATCH] add logprint --- src/client/component/gsc/script_extension.cpp | 17 ---- src/client/component/logprint.cpp | 79 +++++++++++++++++++ src/client/component/party.cpp | 2 +- src/client/component/rcon.cpp | 2 +- src/client/component/scripting.cpp | 8 +- src/client/game/dvars.cpp | 3 + src/client/game/dvars.hpp | 3 + src/client/game/game.cpp | 27 +++++++ src/client/game/game.hpp | 2 + src/client/game/structs.hpp | 64 ++++++++++++++- src/client/game/symbols.hpp | 6 +- 11 files changed, 183 insertions(+), 30 deletions(-) create mode 100644 src/client/component/logprint.cpp diff --git a/src/client/component/gsc/script_extension.cpp b/src/client/component/gsc/script_extension.cpp index b1ab3e8f..c8fd918d 100644 --- a/src/client/component/gsc/script_extension.cpp +++ b/src/client/component/gsc/script_extension.cpp @@ -385,23 +385,6 @@ namespace gsc return utils::string::to_upper(string); }); - /* - function::add("logprint", [](const function_args& args) - { - std::string buffer{}; - - for (auto i = 0u; i < args.size(); ++i) - { - const auto string = args[i].as(); - buffer.append(string); - } - - game::G_LogPrintf("%s", buffer.data()); - - return scripting::script_value{}; - }); - */ - function::add("executecommand", [](const function_args& args) { command::execute(args[0].as(), false); diff --git a/src/client/component/logprint.cpp b/src/client/component/logprint.cpp new file mode 100644 index 00000000..ffa78403 --- /dev/null +++ b/src/client/component/logprint.cpp @@ -0,0 +1,79 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "scheduler.hpp" + +#include "gsc/script_extension.hpp" + +#include + +namespace logprint +{ + namespace + { + utils::hook::detour g_say_hook; + void g_say_stub(game::gentity_s* ent, game::gentity_s* target, int mode, const char* chat_text) + { + const char* cmd = mode == game::SAY_TEAM ? "say_team" : "say"; + if (mode == game::SAY_TEAM && (ent->client->sess.cs.team - 1 > 1 || game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_CP)) + { + cmd = "say"; + } + + game::G_LogPrintf("%s;%s;%i;%s;%s\n", + cmd, + game::SV_GameMP_GetGuid(ent->s.number), + ent->s.number, + ent->client->sess.cs.name, + &chat_text[1]); + + g_say_hook.invoke(ent, target, mode, chat_text); + } + + void touch_log_pickup_stub(char* buffer, const char* guid, const unsigned int ent_number, const char* name, const char* weapon_name) + { + game::G_LogPrintf(buffer, guid, ent_number, name, weapon_name); + game::LUI_Interface_DebugPrint(buffer, guid, ent_number, name, weapon_name); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + gsc::function::add("logprint", [](const gsc::function_args& args) + { + std::string buffer{}; + + for (auto i = 0u; i < args.size(); ++i) + { + const auto string = args[i].as(); + buffer.append(string); + } + + game::G_LogPrintf("%s", buffer.data()); + + return scripting::script_value{}; + }); + + // Reimplement game log + scheduler::once([]() + { + dvars::logfile = game::Dvar_RegisterBool("logfile", true, game::DVAR_FLAG_NONE, "Enable game logging"); + dvars::g_log = game::Dvar_RegisterString("g_log", "iw7-mod\\logs\\games_mp.log", game::DVAR_FLAG_NONE, "Log file path"); + }, scheduler::pipeline::main); + + // Hook say client command + g_say_hook.create(0x140B10C00, g_say_stub); + + // Hook LUI_Interface_DebugPrint call in GItemsMP::TouchLogPickup + utils::hook::call(0x140448F1D, touch_log_pickup_stub); + } + }; +} + +REGISTER_COMPONENT(logprint::component) \ No newline at end of file diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 253585b6..3b112176 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -293,7 +293,7 @@ namespace party if (game::g_entities[i].client) { char client_name[32] = { 0 }; - strncpy_s(client_name, game::g_entities[i].client->name, sizeof(client_name)); + strncpy_s(client_name, game::g_entities[i].client->sess.name, sizeof(client_name)); game::I_CleanStr(client_name); if (client_name == name) diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp index 2d5f0073..728f36d5 100644 --- a/src/client/component/rcon.cpp +++ b/src/client/component/rcon.cpp @@ -96,7 +96,7 @@ namespace rcon if (client->header.state >= 1 && client->gentity && client->gentity->client) { char clean_name[32] = { 0 }; - strncpy_s(clean_name, client->gentity->client->name, sizeof(clean_name)); + strncpy_s(clean_name, client->gentity->client->sess.name, sizeof(clean_name)); game::I_CleanStr(clean_name); buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n", diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp index 9a76932b..d6570688 100644 --- a/src/client/component/scripting.cpp +++ b/src/client/component/scripting.cpp @@ -188,8 +188,8 @@ namespace scripting console::info("gamename: %s\n", "IW7"); console::info("gamedate: %s\n", __DATE__); - //G_LogPrintf("------------------------------------------------------------\n"); - //G_LogPrintf("InitGame: %s\n", serverinfo); + game::G_LogPrintf("------------------------------------------------------------\n"); + game::G_LogPrintf("InitGame\n"); } sv_initgame_vm_hook.invoke(init_settings); @@ -206,8 +206,8 @@ namespace scripting { console::info("==== ShutdownGame (%d) ====\n", full_clear); - //G_LogPrintf("ShutdownGame:\n"); - //G_LogPrintf("------------------------------------------------------------\n"); + game::G_LogPrintf("ShutdownGame:\n"); + game::G_LogPrintf("------------------------------------------------------------\n"); } shutdown_game_pre(full_clear); diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index a57ff23a..13a762f5 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -40,6 +40,9 @@ namespace dvars game::dvar_t* bg_bounces = nullptr; game::dvar_t* bg_playerEjection = nullptr; + game::dvar_t* logfile = nullptr; + game::dvar_t* g_log = nullptr; + std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain) { if (domain.vector.min == -FLT_MAX) diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index a52bcd90..8457f34c 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -37,6 +37,9 @@ namespace dvars extern game::dvar_t* bg_bounces; extern game::dvar_t* bg_playerEjection; + extern game::dvar_t* logfile; + extern game::dvar_t* g_log; + std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain); std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain); std::string dvar_get_name(const game::dvar_t* dvar); diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index a08e2e9c..fa4cf07a 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -1,8 +1,10 @@ #include #include "game.hpp" +#include "dvars.hpp" #include #include +#include namespace game { @@ -226,6 +228,31 @@ namespace game { return svs_clients[client_num]->remoteAddress.type == NA_BOT; } + + void G_LogPrintf(const char* fmt, ...) + { + if (!dvars::logfile->current.enabled) + { + return; + } + + char va_buffer[0x400] = { 0 }; + + va_list ap; + va_start(ap, fmt); + vsprintf_s(va_buffer, fmt, ap); + va_end(ap); + + const auto file = dvars::g_log->current.string; + const auto time = *game::level_time / 1000; + + utils::io::write_file(file, utils::string::va("%3i:%i%i %s", + time / 60, + time % 60 / 10, + time % 60 % 10, + va_buffer + ), true); + } } size_t reverse_b(const size_t ptr) diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 2463c143..04d234e3 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -67,6 +67,8 @@ namespace game bool SV_ClientIsBot(client_t* client); bool SV_ClientIsBot(unsigned int client_num); + + void G_LogPrintf(const char* fmt, ...); } size_t reverse_b(const size_t ptr); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index bd581e44..823f94b7 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -553,6 +553,13 @@ namespace game XAnimEntry entries[1]; }; + enum SayModes + { + SAY_ALL = 0x0, + SAY_TEAM = 0x1, + SAY_TELL = 0x2, + }; + namespace entity { enum connstate_t : std::uint32_t @@ -770,16 +777,65 @@ namespace game }; assert_offsetof(pml_t, msec, 40); + enum clientConnected_t + { + CON_DISCONNECTED = 0x0, + CON_CONNECTING = 0x1, + CON_CONNECTED = 0x2, + }; + + enum sessionState_t + { + SESS_STATE_PLAYING = 0x0, + SESS_STATE_DEAD = 0x1, + SESS_STATE_SPECTATOR = 0x2, + SESS_STATE_INTERMISSION = 0x3, + }; + + enum team_t : std::int32_t + { + TEAM_FREE = 0x0, + TEAM_BAD = 0x0, + TEAM_AXIS = 0x1, + TEAM_ALLIES = 0x2, + TEAM_SPECTATOR = 0x3, + TEAM_NUM_TEAMS = 0x4, + }; + + struct clientState_s + { + int clientIndex; + team_t team; + char __pad0[108]; + char name[32]; + }; + + struct clientSession_t + { + clientConnected_t connected; + sessionState_t sessionState; + char __pad0[280]; + char name[32]; + char __pad1[12]; + clientState_s cs; + }; // unk size + struct gclient_s { playerState_s ps; - char __pad0[19376 - sizeof(playerState_s)]; - char name[32]; // 19376 - char __pad1[1516]; + char __pad0[19088 - sizeof(playerState_s)]; + clientSession_t sess; // 19088 + char __pad1[20924 - sizeof(clientSession_t) - 19088]; int flags; // 20924 }; // sizeof = 29208? - static_assert(offsetof(gclient_s, name) == 19376); + assert_offsetof(gclient_s, sess.sessionState, 19092); + assert_offsetof(gclient_s, sess.name, 19376); + + assert_offsetof(gclient_s, sess.cs, 19420); + assert_offsetof(gclient_s, sess.cs.team, 19424); + assert_offsetof(gclient_s, sess.cs.name, 19536); + static_assert(offsetof(gclient_s, flags) == 20924); #pragma pack(push, 1) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 695401b6..2d5be05d 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -152,15 +152,15 @@ namespace game WEAK symbol LUI_OpenMenu{ 0x140CC0CA0 }; WEAK symbol LUI_CloseMenu{ 0x140CC0C40 }; WEAK symbol LUI_CoD_CLoseAll{ 0x1406135C0 }; + WEAK symbol LUI_Interface_DebugPrint{ 0x14061C43F }; + WEAK symbol LUI_EnterCriticalSection{ 0x140600080 }; + WEAK symbol LUI_LeaveCriticalSection{ 0x140602280 }; WEAK symbol Live_SyncOnlineDataFlags{ 0x140DC5CE0 }; WEAK symbol Live_GetXuid{ 0x140D32A20 }; WEAK symbol Lobby_GetPartyData{ 0x1409C3E20 }; - WEAK symbol LUI_EnterCriticalSection{ 0x140600080 }; - WEAK symbol LUI_LeaveCriticalSection{ 0x140602280 }; - WEAK symbol Material_RegisterHandle{ 0x140E11CE0 }; WEAK symbol Menu_IsMenuOpenAndVisible{ 0x14061CA70 };