Merge pull request #17 from nullifiedcat/followbot-command

Followbot command
This commit is contained in:
nullifiedcat 2017-03-24 23:50:11 +03:00 committed by GitHub
commit 7957563e1c
12 changed files with 261 additions and 41 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
*.d
*.o
bin/*
bin/*
/core

@ -1 +1 @@
Subproject commit eccb7cc43302b1c391b431d4415a7cdaf043fe6b
Subproject commit e532876ffd707a48389d54ff904dcc40a84f2839

View File

@ -17,6 +17,8 @@
#include <atomic>
#include <cmath>
#include <fstream>
#include <set>
#include <algorithm>
#include "aftercheaders.h"
#include "drawing.h"
#include "entitycache.h"

View File

@ -17,24 +17,131 @@ float lost_time { 0 };
float idle_time { 0 };
int following_idx { 0 };
std::set<int> selection {};
std::set<int> selection_secondary {};
float destination_point_time { 0.0f };
Vector destination_point {};
bool destination_reached { false };
bool allow_moving { true };
bool IsBot(CachedEntity* entity) {
if (!ipc::peer) return false;
if (entity->m_Type == ENTITY_PLAYER) {
if (entity->m_pPlayerInfo) {
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 == entity->m_pPlayerInfo->friendsID) {
return true;
}
}
}
}
}
return false;
}
void SelectEntity(int idx) {
logging::Info("Selecting entity %i", idx);
CachedEntity* entity = ENTITY(idx);
if (CE_BAD(entity)) return;
std::set<int>& current_selection = IsBot(entity) ? selection : selection_secondary;
if (current_selection.find(idx) != current_selection.end()) {
current_selection.erase(current_selection.find(idx));
logging::Info("Deselected!");
} else {
current_selection.insert(idx);
logging::Info("Selected!");
}
}
void AddMessageHandlers(ipc::peer_t* peer) {
peer->SetCommandHandler(ipc::commands::set_follow_steamid, [](cat_ipc::command_s& command, void* payload) {
logging::Info("IPC Message: now following %ld", *(unsigned*)&command.cmd_data);
hacks::shared::followbot::follow_steamid = *(unsigned*)&command.cmd_data;
});
peer->SetCommandHandler(ipc::commands::move_to_vector, [](cat_ipc::command_s& command, void* payload) {
float* data = (float*)&command.cmd_data;
logging::Info("IPC Message: moving to %.2f %.2f %.2f", data[0], data[1], data[2]);
destination_point = Vector(data[0], data[1], data[2]);
destination_point_time = g_GlobalVars->curtime;
destination_reached = false;
});
peer->SetCommandHandler(ipc::commands::start_moving, [](cat_ipc::command_s& command, void* payload) {
allow_moving = true;
});
peer->SetCommandHandler(ipc::commands::stop_moving, [](cat_ipc::command_s& command, void* payload) {
allow_moving = false;
});
}
CatCommand follow_me("fb_follow_me", "Makes all bots follow you", []() {
if (ipc::peer) {
unsigned id = g_ISteamUser->GetSteamID().GetAccountID();
ipc::peer->SendMessage("owner", 0, &id, sizeof(id));
ipc::peer->SendMessage((const char*)&id, 0, ipc::commands::set_follow_steamid, 0, 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.");
unsigned MakeMask() {
unsigned result = 0;
if (!ipc::peer) return 0;
// O(n^2) ik
for (const auto& idx : selection) {
CachedEntity* ent = ENTITY(idx);
if (CE_BAD(ent)) continue;
if (!ent->m_pPlayerInfo) continue;
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) {
result |= (1 << i);
}
}
}
return result;
}
CatCommand tool("fb_tool", "Followbot multitool", [](const CCommand& args) {
if (!ipc::peer) return;
if (args.ArgC() == 1) {
// TODO open a gui or something...
} else {
if (!strcmp(args.Arg(1), "select")) {
logging::Info("FB TOOL -> SELECT");
if (g_IInputSystem->IsButtonDown(ButtonCode_t::KEY_LSHIFT)) {
// Shift cleans selection..
selection.clear();
selection_secondary.clear();
logging::Info("Selection cleared!");
} else {
logging::Info("Selecting entity...");
int eindex = 0;
WhatIAmLookingAt(&eindex, nullptr);
if (eindex) {
SelectEntity(eindex);
}
}
} else if (!strcmp(args.Arg(1), "move")) {
logging::Info("FB TOOL -> MOVE");
Vector destination;
WhatIAmLookingAt(nullptr, &destination);
float array[3] = { destination.x, destination.y, destination.z };
ipc::peer->SendMessage((const char*)array, MakeMask(), ipc::commands::move_to_vector, nullptr, 0);
} else if (!strcmp(args.Arg(1), "stay")) {
logging::Info("FB TOOL -> STAY");
ipc::peer->SendMessage(nullptr, MakeMask(), ipc::commands::stop_moving, nullptr, 0);
} else if (!strcmp(args.Arg(1), "follow")) {
logging::Info("FB TOOL -> FOLLOW");
ipc::peer->SendMessage(nullptr, MakeMask(), ipc::commands::start_moving, nullptr, 0);
}
}
});
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");
CatVar mimic_slot(CV_SWITCH, "fb_mimic_slot", "1", "Mimic selected weapon", "If enabled, this bot will select same weapon slot as the owner");
CatVar always_medigun(CV_SWITCH, "fb_always_medigun", "1", "Always use Medigun", "Medics will always use Medigun");
//CatVar sync_taunt(CV_SWITCH, "fb_sync_taunt", "1", "Synchronize taunts", "Bots will taunt if owner is taunting");
// I've spent 2 days on writing this method.
// I couldn't succeed.
@ -54,7 +161,7 @@ std::pair<float, float> ComputeMove(const Vector& a, const Vector& b) {
// I've removed that too early.
void PrintDebug() {
/*
const Vector& a = LOCAL_E->m_vecOrigin;
const Vector& b = last_direction;
@ -74,7 +181,7 @@ void PrintDebug() {
auto move = ComputeMove(a, b);
AddSideString(format("forward: ", move.first));
AddSideString(format("side: ", move.second));
AddSideString(format("side: ", move.second));*/
}
void WalkTo(const Vector& vector) {
@ -89,12 +196,44 @@ void WalkTo(const Vector& vector) {
idle_time = 0;
}
}
auto result = ComputeMove(LOCAL_E->m_vecOrigin, last_direction);
auto result = ComputeMove(LOCAL_E->m_vecOrigin, vector);
g_pUserCmd->forwardmove = result.first;
g_pUserCmd->sidemove = result.second;
}
void AfterCreateMove() {
auto it = selection.begin();
while (it != selection.end()) {
int idx = *it;
CachedEntity* entity = ENTITY(idx);
if (CE_BAD(entity)) {
selection.erase(it++);
} else {
hacks::shared::esp::AddEntityString(entity, "[SELECTED]", colors::orange);
if (fmod(g_GlobalVars->curtime, 2.0f) < 1.0f) {
hacks::shared::esp::SetEntityColor(entity, colors::yellow);
}
++it;
}
}
it = selection_secondary.begin();
while (it != selection_secondary.end()) {
int idx = *it;
CachedEntity* entity = ENTITY(idx);
if (CE_BAD(entity)) {
selection_secondary.erase(it++);
} else {
hacks::shared::esp::AddEntityString(entity, "[SELECTED (SECONDARY)]", colors::orange);
if (fmod(g_GlobalVars->curtime, 2.0f) < 1.0f) {
hacks::shared::esp::SetEntityColor(entity, colors::yellow);
}
++it;
}
}
DoWalking();
}
void DoWalking() {
if (!bot) return;
following_idx = 0;
@ -112,7 +251,7 @@ void DoWalking() {
static float last_slot_check = 0.0f;
if (g_GlobalVars->curtime < last_slot_check) last_slot_check = 0.0f;
if (mimic_slot && (g_GlobalVars->curtime - last_slot_check > 1.0f) && !g_pLocalPlayer->life_state && !CE_BYTE(found_entity, netvar.iLifeState)) {
if (following_idx && (always_medigun || mimic_slot) && (g_GlobalVars->curtime - last_slot_check > 1.0f) && !g_pLocalPlayer->life_state && !CE_BYTE(found_entity, netvar.iLifeState)) {
int owner_weapon_eid = (CE_INT(found_entity, netvar.hActiveWeapon) & 0xFFF);
IClientEntity* owner_weapon = g_IEntityList->GetClientEntity(owner_weapon_eid);
if (owner_weapon && CE_GOOD(g_pLocalPlayer->weapon())) {
@ -121,8 +260,14 @@ void DoWalking() {
vfunc<bool(*)(IClientEntity*)>(owner_weapon, 190, 0)(owner_weapon)) {
int my_slot = vfunc<int(*)(IClientEntity*)>(g_pLocalPlayer->weapon()->m_pEntity, 395, 0)(g_pLocalPlayer->weapon()->m_pEntity);
int owner_slot = vfunc<int(*)(IClientEntity*)>(owner_weapon, 395, 0)(owner_weapon);
if (my_slot != owner_slot) {
g_IEngine->ExecuteClientCmd(format("slot", owner_slot + 1).c_str());
if (g_pLocalPlayer->clazz == tf_medic && always_medigun) {
if (my_slot != 1) {
g_IEngine->ExecuteClientCmd("slot2");
}
} else {
if (my_slot != owner_slot) {
g_IEngine->ExecuteClientCmd(format("slot", owner_slot + 1).c_str());
}
}
}
// FIXME proper classes
@ -131,22 +276,37 @@ void DoWalking() {
last_slot_check = g_GlobalVars->curtime;
}
if (!found_entity->IsVisible()) {
if (!lost_time) {
lost_time = g_GlobalVars->curtime;
if (destination_point_time > g_GlobalVars->curtime) destination_point_time = 0.0f;
if (!destination_reached && (g_GlobalVars->curtime - destination_point_time < 5.0f)) {
WalkTo(destination_point);
last_direction = destination_point;
if (g_pLocalPlayer->v_Origin.DistTo(destination_point) < 50.0f) destination_reached = true;
} else if (following_idx) {
if (allow_moving) {
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) > 150.0f) {
WalkTo(found_entity->m_vecOrigin);
}
last_direction = found_entity->m_vecOrigin;
}
}
if (g_GlobalVars->curtime - lost_time < 2.0f) {
WalkTo(last_direction);
}
} else {
lost_time = 0;
}
if (following_idx) {
if (found_entity->m_vecOrigin.DistTo(LOCAL_E->m_vecOrigin) > 150.0f) {
if (LOCAL_E->m_vecOrigin.DistTo(found_entity->m_vecOrigin) > 350.0f) {
if (g_pLocalPlayer->bZoomed) g_pUserCmd->buttons |= IN_ATTACK2;
}
WalkTo(found_entity->m_vecOrigin);
}
last_direction = found_entity->m_vecOrigin;
if (CE_INT(found_entity, netvar.iClass) == tf_heavy && g_pLocalPlayer->clazz == tf_heavy) {
if (HasCondition(found_entity, TFCond_Slowed)) {
g_pUserCmd->buttons |= IN_ATTACK2;

View File

@ -10,6 +10,9 @@
class CatCommand;
class CatVar;
class CachedEntity;
#include "../ipc.h"
namespace hacks { namespace shared { namespace followbot {
@ -21,8 +24,11 @@ extern CatVar bot;
extern unsigned follow_steamid;
extern int following_idx;
bool IsBot(CachedEntity* entity);
void DoWalking();
void PrintDebug();
void AddMessageHandlers(ipc::peer_t* peer);
void AfterCreateMove();
}}}

View File

@ -41,7 +41,7 @@ void CreateMove() {
if (crit && !IsPlayerCritBoosted(LOCAL_E)) {
g_pUserCmd->buttons &= ~IN_ATTACK;
}
} else if (((GetWeaponMode(LOCAL_E) == weapon_melee && crit_melee) || crit_hack) && RandomCrits() && WeaponCanCrit()) {
} else if (((GetWeaponMode(LOCAL_E) == weapon_melee && crit_melee) || crit_hack) && RandomCrits() && WeaponCanCrit() && (g_pLocalPlayer->weapon()->m_iClassID != g_pClassID->CTFKnife)) {
if (!crit) g_pUserCmd->buttons &= ~IN_ATTACK;
}

View File

@ -636,6 +636,34 @@ relation GetRelation(CachedEntity* ent) {
return relation::NEUTRAL;
}
void WhatIAmLookingAt(int* result_eindex, Vector* result_pos) {
Ray_t ray;
trace::g_pFilterDefault->SetSelf(RAW_ENT(g_pLocalPlayer->entity));
Vector forward;
float sp, sy, cp, cy;
QAngle angle;
g_IEngine->GetViewAngles(angle);
sy = sinf(DEG2RAD(angle[1]));
cy = cosf(DEG2RAD(angle[1]));
sp = sinf(DEG2RAD(angle[0]));
cp = cosf(DEG2RAD(angle[0]));
forward.x = cp * cy;
forward.y = cp * sy;
forward.z = -sp;
forward = forward * 8192.0f + g_pLocalPlayer->v_Eye;
ray.Init(g_pLocalPlayer->v_Eye, forward);
trace_t trace;
g_ITrace->TraceRay(ray, 0x4200400B, trace::g_pFilterDefault, &trace);
if (result_pos)
*result_pos = trace.endpos;
if (result_eindex) {
*result_eindex = 0;
}
if (trace.m_pEnt && result_eindex) {
*result_eindex = ((IClientEntity*)(trace.m_pEnt))->entindex();
}
}
bool IsSentryBuster(CachedEntity* entity) {
return (entity->m_Type == EntityType::ENTITY_PLAYER &&
CE_INT(entity, netvar.iClass) == tf_class::tf_demoman &&

View File

@ -83,6 +83,8 @@ void ReplaceString(char* target, char* what, char* with_what);
// TODO move that to weaponid.h
bool IsAmbassador(CachedEntity* ent);
void WhatIAmLookingAt(int* result_eindex, Vector* result_pos);
void Patch(void* address, void* patch, size_t length);
void AimAt(Vector origin, Vector target, CUserCmd* cmd);

View File

@ -128,7 +128,7 @@ bool CreateMove_hook(void* thisptr, float inputSample, CUserCmd* cmd) {
}
if (found_entity && CE_GOOD(found_entity)) {
if (jointeam && team_joining_state == 1 && (g_GlobalVars->curtime - last_jointeam_try) > 1.0f) {
if (jointeam && (g_GlobalVars->curtime - last_jointeam_try) > 1.0f) {
last_jointeam_try = g_GlobalVars->curtime;
switch (CE_INT(found_entity, netvar.iTeamNum)) {
case TEAM_RED:
@ -220,7 +220,7 @@ bool CreateMove_hook(void* thisptr, float inputSample, CUserCmd* cmd) {
}
if (CE_GOOD(g_pLocalPlayer->entity) && !g_pLocalPlayer->life_state) {
SAFE_CALL(hacks::shared::followbot::DoWalking());
SAFE_CALL(hacks::shared::followbot::AfterCreateMove());
}
if (cmd)
g_Settings.last_angles = cmd->viewangles;

View File

@ -12,16 +12,6 @@
namespace ipc {
void CommandCallback(cat_ipc::command_s& command, void* payload) {
if (!strcmp("exec", (const char*)command.cmd_data) && payload) {
//std::lock_guard<std::mutex> lock(hack::command_stack_mutex);
hack::command_stack().push(std::string((const char*)payload));
} else if (!strcmp("owner", (const char*)command.cmd_data) && payload) {
logging::Info("Bot owner set to %ld", *(unsigned*)payload);
hacks::shared::followbot::follow_steamid = *(unsigned*)payload;
}
}
std::atomic<bool> thread_running(false);
pthread_t listener_thread { 0 };
@ -52,11 +42,17 @@ CatCommand connect("ipc_connect", "Connect to IPC server", []() {
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);
peer->SetCommandHandler(commands::execute_client_cmd, [](cat_ipc::command_s& command, void* payload) {
hack::command_stack().push(std::string((const char*)&command.cmd_data));
});
peer->SetCommandHandler(commands::execute_client_cmd_long, [](cat_ipc::command_s& command, void* payload) {
hack::command_stack().push(std::string((const char*)payload));
});
hacks::shared::followbot::AddMessageHandlers(peer);
StoreClientData();
thread_running = true;
pthread_create(&listener_thread, nullptr, listen, nullptr);
} catch (std::runtime_error& error) {
} catch (std::exception& error) {
logging::Info("Runtime error: %s", error.what());
}
@ -87,10 +83,21 @@ CatCommand exec("ipc_exec", "Execute command (first argument = bot ID)", [](cons
}
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);
ReplaceString(command, " && ", " ; ");
if (command.length() >= 63) {
peer->SendMessage(0, (1 << target_id), ipc::commands::execute_client_cmd_long, command.c_str(), command.length() + 1);
} else {
peer->SendMessage(command.c_str(), (1 << target_id), ipc::commands::execute_client_cmd, 0, 0);
}
});
CatCommand exec_all("ipc_exec_all", "Execute command (on every peer)", [](const CCommand& args) {
peer->SendMessage("exec", 0, args.ArgS(), strlen(args.ArgS()) + 1);
std::string command = args.ArgS();
ReplaceString(command, " && ", " ; ");
if (command.length() >= 63) {
peer->SendMessage(0, 0, ipc::commands::execute_client_cmd_long, command.c_str(), command.length() + 1);
} else {
peer->SendMessage(command.c_str(), 0, ipc::commands::execute_client_cmd, 0, 0);
}
});
CatVar server_name(CV_STRING, "ipc_server", "cathook_followbot_server", "IPC server name");

View File

@ -8,14 +8,27 @@
#ifndef IPC_H_
#define IPC_H_
#include "beforecheaders.h"
#include "ipcb.hpp"
#include "pthread.h"
#include "aftercheaders.h"
class CatCommand;
class CatVar;
namespace ipc {
namespace commands {
constexpr unsigned execute_client_cmd = 1;
constexpr unsigned set_follow_steamid = 2;
constexpr unsigned execute_client_cmd_long = 3;
constexpr unsigned move_to_vector = 4;
constexpr unsigned stop_moving = 5;
constexpr unsigned start_moving = 6;
}
extern CatCommand connect;
extern CatCommand disconnect;
extern CatCommand exec;

View File

@ -12,6 +12,7 @@ void LocalPlayer::Update() {
entity_idx = g_IEngine->GetLocalPlayer();
entity = ENTITY(entity_idx);
if (CE_BAD(entity)) {
team = 0;
return;
}
team = CE_INT(entity, netvar.iTeamNum);