From ae6f1f2e5f924fbe7554052e2ebc7e6e6018e931 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Sat, 30 Dec 2017 19:14:53 +0300 Subject: [PATCH 1/3] catbot-update --- include/hacks/CatBot.hpp | 22 ++++ include/hacks/hacklist.hpp | 1 + include/ipc.hpp | 61 +++++++--- src/hack.cpp | 1 + src/hacks/CatBot.cpp | 234 +++++++++++++++++++++++++++++++++++++ src/hacks/Walkbot.cpp | 78 +------------ src/hooks/others.cpp | 7 +- src/ipc.cpp | 101 +++++++++------- 8 files changed, 362 insertions(+), 143 deletions(-) create mode 100644 include/hacks/CatBot.hpp create mode 100644 src/hacks/CatBot.cpp diff --git a/include/hacks/CatBot.hpp b/include/hacks/CatBot.hpp new file mode 100644 index 00000000..5a4d6b5e --- /dev/null +++ b/include/hacks/CatBot.hpp @@ -0,0 +1,22 @@ +/* + * CatBot.hpp + * + * Created on: Dec 30, 2017 + * Author: nullifiedcat + */ + +#pragma once + +#include "common.hpp" + +namespace hacks { namespace shared { namespace catbot { + +bool is_a_catbot(unsigned steamID); +bool should_ignore_player(CachedEntity *player); +void update_ipc_data(ipc::user_data_s& data); +void update(); +void init(); + +} +} +} diff --git a/include/hacks/hacklist.hpp b/include/hacks/hacklist.hpp index 2c433a33..46c2b48f 100644 --- a/include/hacks/hacklist.hpp +++ b/include/hacks/hacklist.hpp @@ -42,5 +42,6 @@ #include "FollowBot.hpp" #include "Announcer.hpp" #include "Killstreak.hpp" +#include "CatBot.hpp" #endif /* HACKS_HACKLIST_HPP_ */ diff --git a/include/ipc.hpp b/include/ipc.hpp index 65e3166b..c27b279c 100644 --- a/include/ipc.hpp +++ b/include/ipc.hpp @@ -48,34 +48,63 @@ struct server_data_s struct user_data_s { char name[32]; - char server[22]; unsigned friendid; + bool connected; - bool good; - int health; - int health_max; - char life_state; - int team; - int clazz; - int score; - int last_score; - int total_score; + time_t heartbeat; - float x; - float y; - float z; + time_t ts_injected; time_t ts_connected; time_t ts_disconnected; - int shots; - int hits; - int headshots; + + struct accumulated_t + { + int kills; // TODO + int deaths; // TODO + int score; + + int shots; + int hits; + int headshots; + } accumulated; + + struct + { + bool good; + + int kills; // TODO + int deaths; // TODO + int score; + + int shots; // TODO + int hits; // TODO + int headshots; // TODO + + int team; + int role; // class + char life_state; + int health; + int health_max; + + float x; + float y; + float z; + + int player_count; + int bot_count; + + char server[24]; + char mapname[32]; + } ingame; }; using peer_t = cat_ipc::Peer; extern peer_t *peer; +void update_mapname(); + void Heartbeat(); void UpdateTemporaryData(); void UpdateServerAddress(bool shutdown = false); diff --git a/src/hack.cpp b/src/hack.cpp index 9723bb50..68ae0b94 100644 --- a/src/hack.cpp +++ b/src/hack.cpp @@ -343,6 +343,7 @@ g_pGUI->Setup(); hacks::shared::killsay::Init(); hacks::shared::announcer::init(); hacks::tf2::killstreak::init(); + hacks::shared::catbot::init(); logging::Info("Hooked!"); velocity::Init(); playerlist::Load(); diff --git a/src/hacks/CatBot.cpp b/src/hacks/CatBot.cpp new file mode 100644 index 00000000..c1862219 --- /dev/null +++ b/src/hacks/CatBot.cpp @@ -0,0 +1,234 @@ +/* + * CatBot.cpp + * + * Created on: Dec 30, 2017 + * Author: nullifiedcat + */ + +#include "common.hpp" +#include "hack.hpp" + +namespace hacks { namespace shared { namespace catbot { + +static CatVar enabled(CV_SWITCH, "cbu", "0", "CatBot Utils"); +static CatVar abandon_if_bots_gte(CV_INT, "cbu_abandon_if_bots_gte", "0", "Abandon if bots >="); +static CatVar abandon_if_ipc_bots_gte(CV_INT, "cbu_abandon_if_ipc_bots_gte", "0", "Abandon if IPC bots >="); +static CatVar abandon_if_humans_lte(CV_INT, "cbu_abandon_if_humans_lte", "0", "Abandon if humans <="); +static CatVar abandon_if_players_lte(CV_INT, "cbu_abandon_if_players_lte", "0", "Abandon if players <="); +static CatVar mark_human_threshold(CV_INT, "cbu_mark_human_threshold", "2", "Mark human after N kills"); +static CatVar random_votekicks(CV_SWITCH, "cbu_random_votekicks", "0", "Randomly initiate votekicks"); + +struct catbot_user_state +{ + int treacherous_kills{ 0 }; +}; + +std::unordered_map human_detecting_map{}; + +bool is_a_catbot(unsigned steamID) +{ + auto it = human_detecting_map.find(steamID); + if (it == human_detecting_map.end()) + return false; + + //if (!(*it).second.has_bot_name) + // return false; + + if ((*it).second.treacherous_kills <= int(mark_human_threshold)) + { + return true; + } + + return false; +} + +void on_killed_by(int userid) +{ + CachedEntity *player = ENTITY(g_IEngine->GetPlayerForUserID(userid)); + + if (CE_BAD(player)) + return; + + unsigned steamID = player->player_info.friendsID; + + if (human_detecting_map.find(steamID) == human_detecting_map.end()) + return; + + //if (human_detecting_map[steamID].has_bot_name) + human_detecting_map[steamID].treacherous_kills++; +} + +void do_random_votekick() +{ + std::vector targets; + for (int i = 1; i <= g_GlobalVars->maxClients; ++i) + { + player_info_s info; + if (!g_IEngine->GetPlayerInfo(i, &info)) + continue; + + if (g_pPlayerResource->GetTeam(i) != g_pLocalPlayer->team) + continue; + + if (is_a_catbot(info.friendsID)) + continue; + + targets.push_back(info.userID); + } + + if (targets.empty()) + return; + + hack::ExecuteCommand("callvote kick " + std::to_string(targets[rand() % targets.size()])); +} + +void update_catbot_list() +{ + for (int i = 1; i < g_GlobalVars->maxClients; ++i) + { + player_info_s info; + if (!g_IEngine->GetPlayerInfo(i, &info)) + continue; + + info.name[31] = 0; + if (strcasestr(info.name, "cat-bot") || + strcasestr(info.name, "just disable vac tf")) + { + if (human_detecting_map.find(info.friendsID) == human_detecting_map.end()) + { + human_detecting_map.insert(std::make_pair(info.friendsID, catbot_user_state{ 0 })); + } + } + } + +} + +class CatBotEventListener : public IGameEventListener2 +{ + virtual void FireGameEvent(IGameEvent *event) + { + if (!enabled) + return; + + int killer_id = g_IEngine->GetPlayerForUserID(event->GetInt("attacker")); + int victim_id = g_IEngine->GetPlayerForUserID(event->GetInt("userid")); + + if (victim_id == g_IEngine->GetLocalPlayer()) + { + on_killed_by(killer_id); + return; + } + } +}; + +CatBotEventListener &listener() +{ + static CatBotEventListener object{}; + return object; +} + +Timer timer_votekicks{}; +Timer timer_catbot_list{}; +Timer timer_abandon{}; + +int count_bots{ 0 }; + +bool should_ignore_player(CachedEntity *player) +{ + if (CE_BAD(player)) + return false; + + return is_a_catbot(player->player_info.friendsID); +} + +void update_ipc_data(ipc::user_data_s& data) +{ + data.ingame.bot_count = count_bots; +} + +void update() +{ + if (!enabled) + return; + + if (g_Settings.bInvalid) + return; + + if (CE_BAD(LOCAL_E)) + return; + + if (random_votekicks && timer_votekicks.test_and_set(5000)) + do_random_votekick(); + if (timer_catbot_list.test_and_set(3000)) + update_catbot_list(); + if (timer_abandon.test_and_set(2000)) + { + count_bots = 0; + int count_ipc = 0; + int count_total = 0; + + for (int i = 1; i <= g_GlobalVars->maxClients; ++i) + { + if (g_IEntityList->GetClientEntity(i)) + ++count_total; + else + continue; + + player_info_s info; + if (!g_IEngine->GetPlayerInfo(i, &info)) + continue; + + if (is_a_catbot(info.friendsID)) + ++count_bots; + + if (playerlist::AccessData(info.friendsID).state == playerlist::k_EState::IPC) + ++count_ipc; + } + + if (abandon_if_bots_gte) + { + if (count_bots >= int(abandon_if_bots_gte)) + { + logging::Info("Abandoning because there are %d bots in game, and abandon_if_bots_gte is %d.", count_bots, int(abandon_if_bots_gte)); + tfmm::abandon(); + return; + } + } + if (abandon_if_ipc_bots_gte) + { + if (count_ipc >= int(abandon_if_ipc_bots_gte)) + { + logging::Info("Abandoning because there are %d local players in game, and abandon_if_ipc_bots_gte is %d.", count_ipc, int(abandon_if_ipc_bots_gte)); + tfmm::abandon(); + return; + } + } + if (abandon_if_humans_lte) + { + if (count_total - count_bots <= int(abandon_if_humans_lte)) + { + logging::Info("Abandoning because there are %d non-bots in game, and abandon_if_humans_lte is %d.", count_total - count_bots, int(abandon_if_ipc_bots_gte)); + tfmm::abandon(); + return; + } + } + if (abandon_if_players_lte) + { + if (count_total <= int(abandon_if_humans_lte)) + { + logging::Info("Abandoning because there are %d total players in game, and abandon_if_humans_lte is %d.", count_total, int(abandon_if_humans_lte)); + tfmm::abandon(); + return; + } + } + } +} + +void init() +{ + g_IEventManager2->AddListener(&listener(), "player_death", false); +} + +} +} +} diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 87ebbd0e..4c94b1fc 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -1148,78 +1148,6 @@ void OnLevelInit() } } -static CatVar wb_abandon_too_many_bots(CV_INT, "wb_population_control", "0", - "Abandon if bots >"); - -Timer abandon_timer{}; - -CatVar wb_abandon_players_leq(CV_SWITCH, "wb_abandon_players_leq", "0", "Leave if non-bot player count <="); - -void check_player_count() -{ -#if ENABLE_IPC - if (ipc::peer && wb_abandon_players_leq) - { - - } -#endif -} - -void CheckLivingSpace() -{ -#if ENABLE_IPC - if (ipc::peer && wb_abandon_too_many_bots) - { - std::vector players{}; - for (int j = 1; j < 32; j++) - { - player_info_s info; - if (g_IEngine->GetPlayerInfo(j, &info)) - { - if (info.friendsID) - players.push_back(info.friendsID); - } - } - int count = 0; - unsigned highest = 0; - std::vector botlist{}; - for (unsigned i = 0; i < cat_ipc::max_peers; i++) - { - if (!ipc::peer->memory->peer_data[i].free) - { - for (auto &k : players) - { - if (ipc::peer->memory->peer_user_data[i].friendid && - k == ipc::peer->memory->peer_user_data[i].friendid) - { - botlist.push_back(i); - count++; - highest = i; - } - } - } - } - - if (ipc::peer->client_id == highest && - count > int(wb_abandon_too_many_bots)) - { - if (abandon_timer.test_and_set(1000 * 5)) - { - logging::Info("Found %d other bots in-game, abandoning (%u)", - count, ipc::peer->client_id); - for (auto i : botlist) - { - logging::Info( - "-> Bot %d with ID %u", i, - ipc::peer->memory->peer_user_data[i].friendid); - } - tfmm::abandon(); - } - } - } -#endif -} - Timer quit_timer{}; void Move() @@ -1254,14 +1182,10 @@ void Move() { logging::Info("No map file, abandon"); tfmm::abandon(); + return; } } } - static Timer livingspace_timer{}; - if (livingspace_timer.test_and_set(1000 * 2)) - { - CheckLivingSpace(); - } if (nodes.size() == 0) return; if (force_slot) diff --git a/src/hooks/others.cpp b/src/hooks/others.cpp index c98830bc..6d31562d 100644 --- a/src/hooks/others.cpp +++ b/src/hooks/others.cpp @@ -384,7 +384,7 @@ void Shutdown_hook(void *_this, const char *reason) const Shutdown_t original = (Shutdown_t) hooks::netchannel.GetMethod(offsets::Shutdown()); logging::Info("Disconnect: %s", reason); - if (strstr(reason, "VAC banned")) + if (strstr(reason, "banned")) { if (die_if_vac) { @@ -393,10 +393,6 @@ void Shutdown_hook(void *_this, const char *reason) exit(1); } } - else if (strstr(reason, "VAC")) - { - logging::Info("VAC error?"); - } #if ENABLE_IPC ipc::UpdateServerAddress(true); #endif @@ -618,6 +614,7 @@ void FrameStageNotify_hook(void *_this, int stage) if (resolver && cathook && !g_Settings.bInvalid && stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START) { + hacks::shared::catbot::update(); PROF_SECTION(FSN_resolver); for (int i = 1; i < 32 && i < HIGHEST_ENTITY; i++) { diff --git a/src/ipc.cpp b/src/ipc.cpp index d121a55c..ad79b8f0 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -51,10 +51,13 @@ CatCommand connect("ipc_connect", "Connect to IPC server", []() { }); hacks::shared::followbot::AddMessageHandlers(peer); user_data_s &data = peer->memory->peer_user_data[peer->client_id]; - // Preserve total score - int o_total_score = data.total_score; + + // Preserve accumulated data + ipc::user_data_s::accumulated_t accumulated; + memcpy(&accumulated, &data.accumulated, sizeof(accumulated)); memset(&data, 0, sizeof(data)); - data.total_score = o_total_score; + memcpy(&data.accumulated, &accumulated, sizeof(accumulated)); + StoreClientData(); Heartbeat(); } @@ -66,21 +69,6 @@ CatCommand connect("ipc_connect", "Connect to IPC server", []() { } }); -CatCommand lobby("ipc_lobby", "Join a lobby", [](const CCommand &args) { - std::string input(args.ArgS()); - std::size_t lobby_id_start = input.find("[L:1:"); - if (lobby_id_start == std::string::npos) - { - logging::Info("couldn't find lobby ID!"); - return; - } - input = input.substr(lobby_id_start + 5); - unsigned long lobby32 = strtoul(input.c_str(), nullptr, 10); - unsigned long long lobby64 = ((25559040ull << 32) | lobby32); - logging::Info("lobby64 ID: %llu", lobby64); - peer->SendMessage(format("connect_lobby ", lobby64).c_str(), 0, - ipc::commands::execute_client_cmd, 0, 0); -}); CatCommand disconnect("ipc_disconnect", "Disconnect from IPC server", []() { if (peer) delete peer; @@ -194,49 +182,72 @@ void UpdateServerAddress(bool shutdown) user_data_s &data = peer->memory->peer_user_data[peer->client_id]; data.friendid = g_ISteamUser->GetSteamID().GetAccountID(); - strncpy(data.server, s_addr, sizeof(data.server)); + strncpy(data.ingame.server, s_addr, sizeof(data.ingame.server)); +} + +void update_mapname() +{ + if (not peer) + return; + + user_data_s &data = peer->memory->peer_user_data[peer->client_id]; + strncpy(data.ingame.mapname, GetLevelName().c_str(), sizeof(data.ingame.mapname)); } void UpdateTemporaryData() { user_data_s &data = peer->memory->peer_user_data[peer->client_id]; + data.connected = g_IEngine->IsInGame(); - data.shots = hitrate::count_shots; - data.hits = hitrate::count_hits; - data.headshots = hitrate::count_hits_head; + // TODO kills, deaths + data.accumulated.shots = hitrate::count_shots; + data.accumulated.hits = hitrate::count_hits; + data.accumulated.headshots = hitrate::count_hits_head; + if (data.connected) { IClientEntity *player = g_IEntityList->GetClientEntity(g_IEngine->GetLocalPlayer()); if (player) { - data.good = true; - data.health = NET_INT(player, netvar.iHealth); - data.health_max = g_pPlayerResource->GetMaxHealth(LOCAL_E); - data.clazz = g_pPlayerResource->GetClass(LOCAL_E); - data.life_state = NET_BYTE(player, netvar.iLifeState); - data.score = + data.ingame.good = true; + // TODO kills, deaths, shots, hits, headshots + + int score_saved = data.ingame.score; + + data.ingame.score = g_pPlayerResource->GetScore(g_IEngine->GetLocalPlayer()); - if (data.last_score != data.score) - { - if (data.last_score > data.score) - { - data.total_score += data.score; - } - else - { - data.total_score += (data.score - data.last_score); - } - data.last_score = data.score; - } - data.team = g_pPlayerResource->GetTeam(g_IEngine->GetLocalPlayer()); - data.x = g_pLocalPlayer->v_Origin.x; - data.y = g_pLocalPlayer->v_Origin.y; - data.z = g_pLocalPlayer->v_Origin.z; + data.ingame.team = g_pPlayerResource->GetTeam(g_IEngine->GetLocalPlayer()); + data.ingame.role = g_pPlayerResource->GetClass(LOCAL_E); + data.ingame.life_state = NET_BYTE(player, netvar.iLifeState); + data.ingame.health = NET_INT(player, netvar.iHealth); + data.ingame.health_max = g_pPlayerResource->GetMaxHealth(LOCAL_E); + + if (score_saved > data.ingame.score) + score_saved = 0; + + data.accumulated.score += data.ingame.score - score_saved; + + data.ingame.x = g_pLocalPlayer->v_Origin.x; + data.ingame.y = g_pLocalPlayer->v_Origin.y; + data.ingame.z = g_pLocalPlayer->v_Origin.z; + + int players = 0; + + for (int i = 1; i <= g_GlobalVars->maxClients; ++i) + { + if (g_IEntityList->GetClientEntity(i)) + ++players; + else + continue; + } + + data.ingame.player_count = players; + hacks::shared::catbot::update_ipc_data(data); } else { - data.good = false; + data.ingame.good = false; } } } From 96fcefaa014de6faa1c1113871a80a6bc2ad6368 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Sun, 31 Dec 2017 10:54:15 +0300 Subject: [PATCH 2/3] I think that works --- src/hacks/Aimbot.cpp | 2 ++ src/hacks/CatBot.cpp | 9 ++++++++- src/hooks/others.cpp | 2 +- src/ipc.cpp | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/hacks/Aimbot.cpp b/src/hacks/Aimbot.cpp index d2da5429..ed50d77a 100644 --- a/src/hacks/Aimbot.cpp +++ b/src/hacks/Aimbot.cpp @@ -548,6 +548,8 @@ bool IsTargetStateGood(CachedEntity *entity) return false; } } + if (hacks::shared::catbot::should_ignore_player(entity)) + return false; // Preform hitbox prediction int hitbox = BestHitbox(entity); AimbotCalculatedData_s &cd = calculated_data_array[entity->m_IDX]; diff --git a/src/hacks/CatBot.cpp b/src/hacks/CatBot.cpp index c1862219..9b85164b 100644 --- a/src/hacks/CatBot.cpp +++ b/src/hacks/CatBot.cpp @@ -56,6 +56,7 @@ void on_killed_by(int userid) //if (human_detecting_map[steamID].has_bot_name) human_detecting_map[steamID].treacherous_kills++; + logging::Info("Treacherous kill #%d: %s [U:1:%u]", human_detecting_map[steamID].treacherous_kills, player->player_info.name, player->player_info.friendsID); } void do_random_votekick() @@ -79,7 +80,12 @@ void do_random_votekick() if (targets.empty()) return; - hack::ExecuteCommand("callvote kick " + std::to_string(targets[rand() % targets.size()])); + int target = targets[rand() % targets.size()]; + player_info_s info; + if (!g_IEngine->GetPlayerInfo(g_IEngine->GetPlayerForUserID(target), &info)) + return; + logging::Info("Calling vote to kick '%s' [U:1:%u] (%d / %u)", info.name, info.friendsID, target, targets.size()); + hack::ExecuteCommand("callvote kick " + std::to_string(target) + " cheating"); } void update_catbot_list() @@ -96,6 +102,7 @@ void update_catbot_list() { if (human_detecting_map.find(info.friendsID) == human_detecting_map.end()) { + logging::Info("Found bot %s [U:1:%u]", info.name, info.friendsID); human_detecting_map.insert(std::make_pair(info.friendsID, catbot_user_state{ 0 })); } } diff --git a/src/hooks/others.cpp b/src/hooks/others.cpp index 6d31562d..ea28dde0 100644 --- a/src/hooks/others.cpp +++ b/src/hooks/others.cpp @@ -604,6 +604,7 @@ void FrameStageNotify_hook(void *_this, int stage) #endif if (stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START && !g_Settings.bInvalid) { + hacks::shared::catbot::update(); angles::Update(); hacks::shared::anticheat::CreateMove(); if (hitrate_check) @@ -614,7 +615,6 @@ void FrameStageNotify_hook(void *_this, int stage) if (resolver && cathook && !g_Settings.bInvalid && stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START) { - hacks::shared::catbot::update(); PROF_SECTION(FSN_resolver); for (int i = 1; i < 32 && i < HIGHEST_ENTITY; i++) { diff --git a/src/ipc.cpp b/src/ipc.cpp index ad79b8f0..54e78a18 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -249,6 +249,8 @@ void UpdateTemporaryData() { data.ingame.good = false; } + if (g_IEngine->GetLevelName()) + update_mapname(); } } From 43e02bd19adaf24e15a13eee3fe940785a9d80fb Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Sun, 31 Dec 2017 13:19:47 +0300 Subject: [PATCH 3/3] vote logging --- include/common.hpp | 1 + include/votelogger.hpp | 19 ++++++++++++++ src/hacks/CatBot.cpp | 1 - src/hooks/others.cpp | 13 ++++++++-- src/votelogger.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 include/votelogger.hpp create mode 100644 src/votelogger.cpp diff --git a/include/common.hpp b/include/common.hpp index d29b9aa5..6ed18d34 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -100,6 +100,7 @@ #include "tfmm.hpp" #include "hooks/hookedmethods.hpp" #include "classinfo/classinfo.hpp" +#include "votelogger.hpp" #include "crits.hpp" #include "textmode.hpp" #include "backpacktf.hpp" diff --git a/include/votelogger.hpp b/include/votelogger.hpp new file mode 100644 index 00000000..61e14f37 --- /dev/null +++ b/include/votelogger.hpp @@ -0,0 +1,19 @@ +/* + * votelogger.hpp + * + * Created on: Dec 31, 2017 + * Author: nullifiedcat + */ + +#pragma once + +class bf_read; + +namespace votelogger +{ + +void user_message(bf_read& buffer, int type); + +} + + diff --git a/src/hacks/CatBot.cpp b/src/hacks/CatBot.cpp index 9b85164b..6c405058 100644 --- a/src/hacks/CatBot.cpp +++ b/src/hacks/CatBot.cpp @@ -84,7 +84,6 @@ void do_random_votekick() player_info_s info; if (!g_IEngine->GetPlayerInfo(g_IEngine->GetPlayerForUserID(target), &info)) return; - logging::Info("Calling vote to kick '%s' [U:1:%u] (%d / %u)", info.name, info.friendsID, target, targets.size()); hack::ExecuteCommand("callvote kick " + std::to_string(target) + " cheating"); } diff --git a/src/hooks/others.cpp b/src/hooks/others.cpp index ea28dde0..272a0336 100644 --- a/src/hooks/others.cpp +++ b/src/hooks/others.cpp @@ -667,8 +667,8 @@ void FrameStageNotify_hook(void *_this, int stage) std::lock_guard guard(hack::command_stack_mutex); while (!hack::command_stack().empty()) { - logging::Info("executing %s", - hack::command_stack().top().c_str()); + //logging::Info("executing %s", + // hack::command_stack().top().c_str()); g_IEngine->ClientCmd_Unrestricted( hack::command_stack().top().c_str()); hack::command_stack().pop(); @@ -782,7 +782,16 @@ bool DispatchUserMessage_hook(void *_this, int type, bf_read &buf) if (dispatch_log) { logging::Info("D> %i", type); + std::ostringstream str{}; + while (buf.GetNumBytesLeft()) + { + unsigned char byte = buf.ReadByte(); + str << std::hex << std::setw(2) << std::setfill('0') << static_cast(byte) << ' '; + } + logging::Info("MESSAGE %d, DATA = [ %s ]", type, str.str().c_str()); + buf.Seek(0); } + votelogger::user_message(buf, type); return original(_this, type, buf); } diff --git a/src/votelogger.cpp b/src/votelogger.cpp new file mode 100644 index 00000000..c155101c --- /dev/null +++ b/src/votelogger.cpp @@ -0,0 +1,59 @@ +/* + * votelogger.cpp + * + * Created on: Dec 31, 2017 + * Author: nullifiedcat + */ + +#include "common.hpp" + +namespace votelogger +{ + +static CatVar enabled(CV_SWITCH, "votelog", "0", "Log votes"); + +void user_message(bf_read& buffer, int type) +{ + if (!enabled) + return; + + switch (type) + { + case 45: + // Call Vote Failed + break; + case 46: { + unsigned char caller = buffer.ReadByte(); + // unknown + buffer.ReadByte(); + char reason[64]; + char name[64]; + buffer.ReadString(reason, 64, false, nullptr); + buffer.ReadString(name, 64, false, nullptr); + unsigned char eid = buffer.ReadByte(); + buffer.Seek(0); + eid >>= 1; + + unsigned steamID = 0; + player_info_s info; + if (g_IEngine->GetPlayerInfo(eid, &info)) + { + steamID = info.friendsID; + } + + logging::Info("Vote called to kick %s [U:1:%u] for %s", name, steamID, reason); + break; + } + case 47: + logging::Info("Vote passed"); + break; + case 48: + logging::Info("Vote failed"); + break; + case 49: + logging::Info("VoteSetup?"); + break; + } +} + +}