diff --git a/.gitmodules b/.gitmodules index 1840db1c..48b3e7b9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "source-sdk-2013"] path = source-sdk-2013 url = https://github.com/ValveSoftware/source-sdk-2013 +[submodule "simple-ipc"] + path = simple-ipc + url = https://github.com/nullifiedcat/simple-ipc diff --git a/detach b/detach index 17c95dc8..e57de3e3 100755 --- a/detach +++ b/detach @@ -29,8 +29,8 @@ if grep -q $(realpath bin/libcathook.so) /proc/${arr[$1]}/maps; then -ex "print \$library" \ -ex "call \$dlclose(\$library)" \ -ex "call \$dlclose(\$library)" \ - -ex "detach" \ - -ex "quit" + -ex "continue" \ + -ex "backtrace" echo "Detached" else echo "not found!" diff --git a/makefile b/makefile index 6ed4ec63..98b1ecff 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,8 @@ CXX=g++ -CXXFLAGS=-std=gnu++14 -D_POSIX=1 -DRAD_TELEMETRY_DISABLED -DLINUX=1 -D_LINUX=1 -DPOSIX=1 -DGNUC=1 -D_DEVELOPER=1 -DNO_MALLOC_OVERRIDE -O3 -g3 -ggdb -w -shared -Wall -Wno-unknown-pragmas -fmessage-length=0 -m32 -fvisibility=hidden -fPIC +CXXFLAGS=-std=gnu++14 -D_GLIBCXX_USE_CXX11_ABI=0 -D_POSIX=1 -DRAD_TELEMETRY_DISABLED -DLINUX=1 -D_LINUX=1 -DPOSIX=1 -DGNUC=1 -D_DEVELOPER=1 -DNO_MALLOC_OVERRIDE -O3 -g3 -ggdb -w -shared -Wall -Wno-unknown-pragmas -fmessage-length=0 -m32 -fvisibility=hidden -fPIC SDKFOLDER=$(realpath source-sdk-2013/mp/src) -INCLUDES=-I$(SDKFOLDER)/public -I$(SDKFOLDER)/mathlib -I$(SDKFOLDER)/common -I$(SDKFOLDER)/public/tier1 -I$(SDKFOLDER)/public/tier0 -I$(SDKFOLDER) +SIMPLE_IPC_DIR = $(realpath simple-ipc/src/include) +INCLUDES=-I$(SIMPLE_IPC_DIR) -I$(SDKFOLDER)/public -I$(SDKFOLDER)/mathlib -I$(SDKFOLDER)/common -I$(SDKFOLDER)/public/tier1 -I$(SDKFOLDER)/public/tier0 -I$(SDKFOLDER) CXXFLAGS += $(INCLUDES) LIB_DIR=lib LDFLAGS=-m32 -fno-gnu-unique -D_GLIBCXX_USE_CXX11_ABI=0 -shared -L$(realpath $(LIB_DIR)) @@ -11,6 +12,7 @@ OUT_NAME = libcathook.so TARGET_DIR = bin TARGET = $(TARGET_DIR)/$(OUT_NAME) SOURCES = $(shell find $(SRC_DIR) -name "*.cpp" -print) +SOURCES += $(shell find $(SIMPLE_IPC_DIR) -name "*.cpp" -print) OBJECTS = $(SOURCES:.cpp=.o) DEPENDS = $(SOURCES:.cpp=.d) SRC_SUBDIRS=$(shell find $(SRC_DIR) -type d -print) diff --git a/simple-ipc b/simple-ipc new file mode 160000 index 00000000..eccb7cc4 --- /dev/null +++ b/simple-ipc @@ -0,0 +1 @@ +Subproject commit eccb7cc43302b1c391b431d4415a7cdaf043fe6b diff --git a/src/common.h b/src/common.h index a47f1d21..b59f7748 100644 --- a/src/common.h +++ b/src/common.h @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include "aftercheaders.h" #include "drawing.h" #include "entitycache.h" @@ -35,6 +38,7 @@ #include "itemtypes.h" #include "chatstack.h" #include "textfile.h" +#include "ipc.h" #include "gui/GUI.h" #include "classid.h" #include "crits.h" diff --git a/src/drawing.cpp b/src/drawing.cpp index 85dc58da..54b7a59a 100644 --- a/src/drawing.cpp +++ b/src/drawing.cpp @@ -99,6 +99,7 @@ void colors::Init() { blu_u = Create(167, 75, 252, 255); yellow = Create(255, 255, 0, 255); green = Create(0, 255, 0, 255); + orange = Create(255, 120, 0, 255); } int colors::EntityF(CachedEntity* ent) { @@ -160,6 +161,8 @@ int colors::EntityF(CachedEntity* ent) { result = yellow; break; case DEVELOPER: result = RainbowCurrent(); break; + case BOT: + result = colors::orange; break; } } } @@ -233,8 +236,8 @@ void draw::Initialize() { g_IEngine->GetScreenSize(draw::width, draw::height); } - g_ISurface->SetFontGlyphSet(fonts::ESP, "TF2 Build", fonts::ESP_HEIGHT, 0, 0, 0, g_ISurface->FONTFLAG_DROPSHADOW); // or Ubuntu Mono Bold - g_ISurface->SetFontGlyphSet(fonts::MENU, "Verdana", fonts::MENU_HEIGHT, 0, 0, 0, g_ISurface->FONTFLAG_DROPSHADOW); + g_ISurface->SetFontGlyphSet(fonts::ESP, "TF2 Build", fonts::ESP_HEIGHT, 0, 0, 0, 0); // or Ubuntu Mono Bold + g_ISurface->SetFontGlyphSet(fonts::MENU, "Verdana", fonts::MENU_HEIGHT, 0, 0, 0, 0); g_ISurface->SetFontGlyphSet(fonts::MENU_BIG, "Verdana Bold", fonts::MENU_BIG_HEIGHT, 0, 0, 0, 0x0); } @@ -337,10 +340,10 @@ void draw::WString(unsigned long font, int x, int y, int color, int shadow, cons if (shadow) { unsigned char alpha = (color >> 24); int black_t = ((alpha == 255) ? colors::black : colors::Create(0, 0, 0, alpha / shadow)); - /*if (shadow > 0) { + if (shadow > 0) { draw::WString(font, x + 1, y + 1, black_t, false, text); } - if (shadow > 1 && !g_Settings.bFastOutline->GetBool()) { + if (shadow > 1) { draw::WString(font, x - 1, y + 1, black_t, false, text); draw::WString(font, x - 1, y - 1, black_t, false, text); draw::WString(font, x + 1, y - 1, black_t, false, text); @@ -348,7 +351,7 @@ void draw::WString(unsigned long font, int x, int y, int color, int shadow, cons draw::WString(font, x, y + 1, black_t, false, text); draw::WString(font, x, y - 1, black_t, false, text); draw::WString(font, x - 1, y, black_t, false, text); - }*/ + } } g_ISurface->DrawSetTextPos(x, y); g_ISurface->DrawSetTextColor(*reinterpret_cast(&color)); diff --git a/src/enums.h b/src/enums.h index 1021297c..9ff73354 100644 --- a/src/enums.h +++ b/src/enums.h @@ -94,7 +94,8 @@ enum relation { NEUTRAL = 0, FRIEND = 1, RAGE = 2, - DEVELOPER = 3 + DEVELOPER = 3, + BOT }; #endif /* ENUMS_H_ */ diff --git a/src/hack.cpp b/src/hack.cpp index 21ec90c3..1d49cb4b 100644 --- a/src/hack.cpp +++ b/src/hack.cpp @@ -53,9 +53,15 @@ bool hack::shutdown = false; +std::stack& hack::command_stack() { + static std::stack stack; + return stack; +} + void hack::InitHacks() { } +//std::mutex hack::command_stack_mutex; ConCommand* hack::c_Cat = 0; void hack::CC_Cat(const CCommand& args) { @@ -88,11 +94,13 @@ void hack::Initialize() { dumper.SaveDump(); ClientClass* cc = g_IBaseClient->GetAllClasses(); FILE* cd = fopen("/tmp/cathook-classdump.txt", "w"); - while (cc) { - fprintf(cd, "[%d] %s\n", cc->m_ClassID, cc->GetName()); - cc = cc->m_pNext; + if (cd) { + while (cc) { + fprintf(cd, "[%d] %s\n", cc->m_ClassID, cc->GetName()); + cc = cc->m_pNext; + } + fclose(cd); } - fclose(cd); if (TF2) g_pClassID = new ClassIDTF2(); else if (TF2C) g_pClassID = new ClassIDTF2C(); else if (HL2DM) g_pClassID = new ClassIDHL2DM(); @@ -157,7 +165,10 @@ void hack::Initialize() { if (TF2) g_GlowObjectManager = *reinterpret_cast(gSignatures.GetClientSignature("C1 E0 05 03 05") + 5); InitStrings(); hacks::shared::killsay::Init(); - logging::Info("Init done."); + hack::command_stack().push("exec cat_autoexec"); + hack::command_stack().push("cat_killsay_reload"); + hack::command_stack().push("cat_spam_reload"); + logging::Info("Hooked!"); } void hack::Think() { diff --git a/src/hack.h b/src/hack.h index ac6eea5a..3620be9e 100644 --- a/src/hack.h +++ b/src/hack.h @@ -15,8 +15,17 @@ class bf_read; class ConCommand; class CCommand; +#include "beforecheaders.h" +#include +#include +#include +#include "aftercheaders.h" + namespace hack { +//extern std::mutex command_stack_mutex; +std::stack& command_stack(); + extern bool shutdown; void Initialize(); diff --git a/src/hacks/AutoHeal.cpp b/src/hacks/AutoHeal.cpp index e449524d..7cbbc200 100644 --- a/src/hacks/AutoHeal.cpp +++ b/src/hacks/AutoHeal.cpp @@ -64,13 +64,24 @@ int HealingPriority(int idx) { int overheal = maxoverheal - (maxbuffedhealth - health); float overhealp = ((float)overheal / (float)maxoverheal); float healthp = ((float)health / (float)maxhealth); - if (GetRelation(ent) == relation::FRIEND) { + switch (GetRelation(ent)) { + case relation::FRIEND: priority += 70 * (1 - healthp); priority += 15 * (1 - overhealp); - } else { + break; + case relation::BOT: + priority += 100 * (1 - healthp); + priority += 15 * (1 - overhealp); + break; + default: priority += 50 * (1 - healthp); priority += 10 * (1 - overhealp); } + if (ipc::peer) { + if (hacks::shared::followbot::bot && hacks::shared::followbot::following_idx == idx) { + priority += 75; + } + } return priority; } diff --git a/src/hacks/ESP.cpp b/src/hacks/ESP.cpp index 98dc8fb3..4fab4a26 100644 --- a/src/hacks/ESP.cpp +++ b/src/hacks/ESP.cpp @@ -18,6 +18,7 @@ CatVar enabled(CV_SWITCH, "esp_enabled", "0", "ESP", "Master ESP switch"); CatVar entity_info(CV_SWITCH, "esp_entity", "0", "Entity ESP", "Show entity info (debug)"); CatVar teammates(CV_SWITCH, "esp_teammates", "0", "ESP Teammates", "Teammate ESP"); CatVar item_esp(CV_SWITCH, "esp_item", "1", "Item ESP", "Master Item ESP switch (health packs, etc.)"); +CatVar show_bot_id(CV_SWITCH, "esp_followbot_id", "1", "Followbot ESP", "Show followbot ID"); CatVar item_dropped_weapons(CV_SWITCH, "esp_item_weapons", "0", "Dropped weapons", "Show dropped weapons"); CatVar item_ammo_packs(CV_SWITCH, "esp_item_ammo", "0", "Ammo packs", "Show ammo packs"); CatVar item_health_packs(CV_SWITCH, "esp_item_health", "1", "Health packs", "Show health packs"); @@ -279,6 +280,14 @@ void ProcessEntity(CachedEntity* ent) { if (pclass > 0 && pclass < 10) AddEntityString(ent, classes[pclass - 1]); } + if (show_bot_id && ipc::peer && ent != LOCAL_E) { + for (unsigned i = 1; i < cat_ipc::max_peers; i++) { + if (!ipc::peer->memory->peer_data[i].free && ipc::peer->memory->peer_user_data[i].friendid == info.friendsID) { + AddEntityString(ent, format("BOT #", i)); + break; + } + } + } if (show_health) { AddEntityString(ent, format(ent->m_iHealth, '/', ent->m_iMaxHealth, " HP"), colors::Health(ent->m_iHealth, ent->m_iMaxHealth)); } diff --git a/src/hacks/ESP.h b/src/hacks/ESP.h index f55bf1ee..a112d038 100644 --- a/src/hacks/ESP.h +++ b/src/hacks/ESP.h @@ -26,6 +26,7 @@ extern CatVar local_esp; extern CatVar buildings; extern CatVar enabled; extern CatVar entity_info; +extern CatVar show_bot_id; extern CatVar teammates; extern CatVar item_esp; extern CatVar item_dropped_weapons; diff --git a/src/hacks/FollowBot.cpp b/src/hacks/FollowBot.cpp new file mode 100644 index 00000000..169b31da --- /dev/null +++ b/src/hacks/FollowBot.cpp @@ -0,0 +1,94 @@ +/* + * FollowBot.cpp + * + * Created on: Mar 20, 2017 + * Author: nullifiedcat + */ + +#include "FollowBot.h" + +#include "../common.h" + +namespace hacks { namespace shared { namespace followbot { + +unsigned follow_steamid { 0 }; +Vector last_direction; +float lost_time { 0 }; +int following_idx { 0 }; + +CatCommand move_to_crosshair("fb_move_to_point", "Moves a bot (or all bots) to crosshair", [](const CCommand& args) { + logging::Info("not yet implemented."); +}); +CatCommand follow("fb_follow", "Follows you (or player with SteamID specified)", [](const CCommand& args) { + follow_steamid = strtol(args.Arg(1), nullptr, 10); +}); +CatCommand follow_entity("fb_follow_entity", "Follows entity with specified entity ID", [](const CCommand& args) { + logging::Info("not yet implemented."); +}); +CatVar bot(CV_SWITCH, "fb_bot", "0", "This player is a bot", "Set to 1 in followbots' configs"); + +std::pair ComputeMove(const Vector& a, const Vector& b) { + Vector diff = (b - a); + if (diff.Length() == 0) return { 0, 0 }; + float v_cos = diff.x / diff.Length(); + float rad = acos(v_cos); + if (diff.y < 0) rad = -rad; + float yan = g_Settings.last_angles.y; + float yaw = DEG2RAD(yan); + float rad_diff = yaw - rad; + //g_pUserCmd->forwardmove = std::cos(rad_diff) * 450.0f; + //g_pUserCmd->sidemove = -std::sin(rad_diff) * 450.0f; + //float deg_move = DEG2RAD(g_pUserCmd->viewangles.y); + // xcosA + ysinA + // xsinA + ycosA + const float x = diff.x / diff.Length(); + const float y = diff.y / diff.Length(); + + const float xmove = (std::cos(yaw) * x + std::sin(yaw) * y); + const float ymove = (yaw < 0 ? 1 : 1) * (std::sin(yaw) * x + std::cos(yaw) * y); + const float movesum = std::abs(xmove) + std::abs(ymove); + + return { (xmove / movesum) * 450.0f, (ymove / movesum) * 450.0f }; +} + +void WalkTo(const Vector& vector) { + if (CE_VECTOR(LOCAL_E, netvar.vVelocity).IsZero(1.0f)) { + if (LOCAL_E->m_vecOrigin.DistTo(vector) > 200.0f) { + if (!g_pLocalPlayer->bZoomed) + g_pUserCmd->buttons |= IN_JUMP; + } + } + auto result = ComputeMove(LOCAL_E->m_vecOrigin, last_direction); + + g_pUserCmd->forwardmove = result.first; + g_pUserCmd->sidemove = result.second; +} + +void DoWalking() { + if (!bot) return; + following_idx = 0; + for (int i = 1; i < 32 && i < HIGHEST_ENTITY; i++) { + CachedEntity* ent = ENTITY(i); + if (CE_BAD(ent)) continue; + if (!ent->m_pPlayerInfo) continue; + if (ent->m_pPlayerInfo->friendsID == follow_steamid) { + following_idx = i; + break; + } + } + CachedEntity* found_entity = ENTITY(following_idx); + if (!found_entity->IsVisible()) { + if (!lost_time) { + lost_time = g_GlobalVars->curtime; + } + if (g_GlobalVars->curtime - lost_time < 2.0f) { + WalkTo(last_direction); + } + } else { + lost_time = 0; + if (found_entity->m_vecOrigin.DistTo(LOCAL_E->m_vecOrigin) > 200.0f) WalkTo(found_entity->m_vecOrigin); + last_direction = found_entity->m_vecOrigin; + } +} + +}}} diff --git a/src/hacks/FollowBot.h b/src/hacks/FollowBot.h new file mode 100644 index 00000000..112b794e --- /dev/null +++ b/src/hacks/FollowBot.h @@ -0,0 +1,29 @@ +/* + * FollowBot.h + * + * Created on: Mar 19, 2017 + * Author: nullifiedcat + */ + +#ifndef HACKS_FOLLOWBOT_H_ +#define HACKS_FOLLOWBOT_H_ + +class CatCommand; +class CatVar; + +namespace hacks { namespace shared { namespace followbot { + +extern CatCommand move_to_crosshair; +extern CatCommand follow; +extern CatCommand follow_entity; +extern CatVar bot; + +extern unsigned follow_steamid; +extern int following_idx; + +void DoWalking(); +void PrintDebug(); + +}}} + +#endif /* HACKS_FOLLOWBOT_H_ */ diff --git a/src/hacks/hacklist.h b/src/hacks/hacklist.h index 1f9a5c7e..aa54bc8b 100644 --- a/src/hacks/hacklist.h +++ b/src/hacks/hacklist.h @@ -25,5 +25,6 @@ #include "Achievement.h" #include "Spam.h" #include "Noisemaker.h" +#include "FollowBot.h" #endif /* HACKS_HACKLIST_H_ */ diff --git a/src/helpers.cpp b/src/helpers.cpp index a87d65ae..e3246bb9 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -20,16 +20,20 @@ void BeginConVars() { FILE* hAutoexec = fopen(strfmt("%scfg/cat_autoexec.cfg", g_pszTFPath), "r+"); if (!hAutoexec) { hAutoexec = fopen(strfmt("%scfg/cat_autoexec.cfg", g_pszTFPath), "w"); - fprintf(hAutoexec, "// Put your custom cathook settings in this file\n// This script will be executed EACH TIME YOU INJECT CATHOOK\n"); - fclose(hAutoexec); + if (hAutoexec) { + fprintf(hAutoexec, "// Put your custom cathook settings in this file\n// This script will be executed EACH TIME YOU INJECT CATHOOK\n"); + fclose(hAutoexec); + } } else fclose(hAutoexec); FILE* hMatchexec = fopen(strfmt("%scfg/cat_matchexec.cfg", g_pszTFPath), "r+"); if (!hMatchexec) { hMatchexec = fopen(strfmt("%scfg/cat_matchexec.cfg", g_pszTFPath), "w"); - fprintf(hMatchexec, "// Put your custom cathook settings in this file\n// This script will be executed EACH TIME YOU JOIN A MATCH\n"); - fclose(hMatchexec); + if (hMatchexec) { + fprintf(hMatchexec, "// Put your custom cathook settings in this file\n// This script will be executed EACH TIME YOU JOIN A MATCH\n"); + fclose(hMatchexec); + } } else fclose(hMatchexec); - fprintf(hConVarsFile, "// THIS FILE IS AUTO-GENERATED BY CATHOOK\n// DO NOT EDIT IT, ALL CHANGES WILL BE UNDONE!\n// If you want to change default settings, add changed convars to cat_autoexec.cfg\n"); + if (hConVarsFile) fprintf(hConVarsFile, "// THIS FILE IS AUTO-GENERATED BY CATHOOK\n// DO NOT EDIT IT, ALL CHANGES WILL BE UNDONE!\n// If you want to change default settings, add changed convars to cat_autoexec.cfg\n"); SetCVarInterface(g_ICvar); } @@ -536,11 +540,15 @@ bool GetProjectileData(CachedEntity* weapon, float& speed, float& gravity) { return (rspeed || rgrav); } +constexpr unsigned developer_list[] = { 347272825, 401679596 }; + bool Developer(CachedEntity* ent) { -#if _DEVELOPER == 1 - return (ent == LOCAL_E); -#endif - return (ent->m_pPlayerInfo && ent->m_pPlayerInfo->friendsID == 347272825UL); + if (ent->m_pPlayerInfo) { + for (int i = 0; i < sizeof(developer_list) / sizeof(unsigned); i++) { + if (developer_list[i] == ent->m_pPlayerInfo->friendsID) return true; + } + } + return false; } /*const char* MakeInfoString(IClientEntity* player) { @@ -616,6 +624,15 @@ relation GetRelation(CachedEntity* ent) { if (rage[i] == ent->m_pPlayerInfo->friendsID) return relation::RAGE; } if (Developer(ent)) return relation::DEVELOPER; + + if (ipc::peer) { + for (unsigned i = 1; i < cat_ipc::max_peers; i++) { + if (!ipc::peer->memory->peer_data[i].free && ipc::peer->memory->peer_user_data[i].friendid == ent->m_pPlayerInfo->friendsID) { + return relation::BOT; + } + } + } + return relation::NEUTRAL; } diff --git a/src/hooks/CreateMove.cpp b/src/hooks/CreateMove.cpp index b178fe0f..6600227a 100644 --- a/src/hooks/CreateMove.cpp +++ b/src/hooks/CreateMove.cpp @@ -165,6 +165,10 @@ bool CreateMove_hook(void* thisptr, float inputSample, CUserCmd* cmd) { ret = false; } + + if (CE_GOOD(g_pLocalPlayer->entity) && !g_pLocalPlayer->life_state) { + hacks::shared::followbot::DoWalking(); + } if (cmd) g_Settings.last_angles = cmd->viewangles; } diff --git a/src/hooks/PaintTraverse.cpp b/src/hooks/PaintTraverse.cpp index 318dfdea..25078d12 100644 --- a/src/hooks/PaintTraverse.cpp +++ b/src/hooks/PaintTraverse.cpp @@ -39,18 +39,18 @@ void PaintTraverse_hook(void* p, unsigned int vp, bool fr, bool ar) { if (call_default) SAFE_CALL(((PaintTraverse_t*)hooks::hkPanel->GetMethod(hooks::offPaintTraverse))(p, vp, fr, ar)); + // To avoid threading problems. + { + //std::lock_guard guard(hack::command_stack_mutex); + while (!hack::command_stack().empty()) { + g_IEngine->ExecuteClientCmd(hack::command_stack().top().c_str()); + hack::command_stack().pop(); + } + } + PROF_SECTION(PaintTraverse); if (vp == panel_top) draw_flag = true; if (!cathook) return; - // Because of single-multi thread shit I'm gonna put this thing riiiight here. - - static bool autoexec_done = false; - if (!autoexec_done) { - g_IEngine->ExecuteClientCmd("exec cat_autoexec"); - g_IEngine->ExecuteClientCmd("cat_killsay_reload"); - g_IEngine->ExecuteClientCmd("cat_spam_reload"); - autoexec_done = true; - } if (!panel_top) { const char* name = g_IPanel->GetName(vp); @@ -89,6 +89,7 @@ void PaintTraverse_hook(void* p, unsigned int vp, bool fr, bool ar) { SAFE_CALL(hacks::shared::misc::Draw()); SAFE_CALL(hacks::shared::esp::Draw()); if (TF) SAFE_CALL(hacks::tf::spyalert::Draw()); + //hacks::shared::followbot::PrintDebug(); } #if GUI_ENABLED == true diff --git a/src/ipc.cpp b/src/ipc.cpp new file mode 100644 index 00000000..3f98fd61 --- /dev/null +++ b/src/ipc.cpp @@ -0,0 +1,92 @@ +/* + * ipc.cpp + * + * Created on: Mar 19, 2017 + * Author: nullifiedcat + */ + +#include "ipc.h" + +#include "common.h" +#include "hack.h" + +namespace ipc { + +void CommandCallback(cat_ipc::command_s& command, void* payload) { + if (!strcmp("exec", (const char*)command.cmd_data) && payload) { + //std::lock_guard lock(hack::command_stack_mutex); + hack::command_stack().push(std::string((const char*)payload)); + } +} + +std::atomic thread_running(false); +pthread_t listener_thread { 0 }; + +void* listen(void*) { + while (thread_running) { + if (peer->HasCommands()) { + peer->ProcessCommands(); + } + usleep(10000); + } + return 0; +} + +CatCommand connect("ipc_connect", "Connect to IPC server", []() { + if (peer || thread_running) { + logging::Info("Already connected!"); + return; + } + peer = new peer_t("cathook_followbot_server", false, false); + peer->Connect(); + logging::Info("peer count: %i", peer->memory->peer_count); + logging::Info("magic number: 0x%08x", peer->memory->global_data.magic_number); + logging::Info("magic number offset: 0x%08x", (uintptr_t)&peer->memory->global_data.magic_number - (uintptr_t)peer->memory); + peer->SetCallback(CommandCallback); + StoreClientData(); + thread_running = true; + pthread_create(&listener_thread, nullptr, listen, nullptr); +}); +CatCommand disconnect("ipc_disconnect", "Disconnect from IPC server", []() { + thread_running = false; + pthread_join(listener_thread, nullptr); + if (peer) delete peer; + listener_thread = 0; + peer = nullptr; +}); +CatCommand exec("ipc_exec", "Execute command (first argument = bot ID)", [](const CCommand& args) { + char* endptr = nullptr; + unsigned target_id = strtol(args.Arg(1), &endptr, 10); + if (endptr == args.Arg(1)) { + logging::Info("Target id is NaN!"); + return; + } + if (target_id == 0 || target_id > 31) { + logging::Info("Invalid target id: %u", target_id); + return; + } + { + if (peer->memory->peer_data[target_id].free) { + logging::Info("Trying to send command to a dead peer"); + return; + } + } + std::string command = std::string(args.ArgS()); + command = command.substr(command.find(' ', 0) + 1); + peer->SendMessage("exec", (1 << target_id), command.c_str(), command.length() + 1); +}); +CatCommand exec_all("ipc_exec_all", "Execute command (on every peer)", [](const CCommand& args) { + peer->SendMessage("exec", 0, args.ArgS(), strlen(args.ArgS()) + 1); +}); +CatVar server_name(CV_STRING, "ipc_server", "cathook_followbot_server", "IPC server name"); + +peer_t* peer { nullptr }; + +void StoreClientData() { + peer_t::MutexLock lock(peer); + user_data_s& data = peer->memory->peer_user_data[peer->client_id]; + data.friendid = g_ISteamUser->GetSteamID().GetAccountID(); + strncpy(data.name, g_ISteamFriends->GetPersonaName(), sizeof(data.name)); +} + +} diff --git a/src/ipc.h b/src/ipc.h new file mode 100644 index 00000000..464cf9aa --- /dev/null +++ b/src/ipc.h @@ -0,0 +1,45 @@ +/* + * ipc.h + * + * Created on: Mar 19, 2017 + * Author: nullifiedcat + */ + +#ifndef IPC_H_ +#define IPC_H_ + +#include "ipcb.hpp" +#include "pthread.h" + +class CatCommand; +class CatVar; + +namespace ipc { + +extern CatCommand connect; +extern CatCommand disconnect; +extern CatCommand exec; +extern CatCommand exec_all; +extern CatVar server_name; + +extern pthread_t listener_thread; +constexpr unsigned cathook_magic_number = 0x0DEADCA7; + +struct server_data_s { + unsigned magic_number; +}; + +struct user_data_s { + char name[32]; + unsigned friendid; +}; + +using peer_t = cat_ipc::Peer; + +extern peer_t* peer; + +void StoreClientData(); + +} + +#endif /* IPC_H_ */