931 lines
30 KiB
C++
931 lines
30 KiB
C++
/*
|
|
* others.cpp
|
|
*
|
|
* Created on: Jan 8, 2017
|
|
* Author: nullifiedcat
|
|
*/
|
|
|
|
#include "common.hpp"
|
|
#include "ucccccp/ucccccp.hpp"
|
|
#include "hack.hpp"
|
|
#include "hitrate.hpp"
|
|
#include "chatlog.hpp"
|
|
#include "netmessage.hpp"
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#if ENABLE_VISUALS == 1
|
|
|
|
static CatVar no_invisibility(CV_SWITCH, "no_invis", "0", "Remove Invisibility",
|
|
"Useful with chams!");
|
|
|
|
// This hook isn't used yet!
|
|
int C_TFPlayer__DrawModel_hook(IClientEntity *_this, int flags)
|
|
{
|
|
float old_invis = *(float *) ((uintptr_t) _this + 79u);
|
|
if (no_invisibility)
|
|
{
|
|
if (old_invis < 1.0f)
|
|
{
|
|
*(float *) ((uintptr_t) _this + 79u) = 0.5f;
|
|
}
|
|
}
|
|
|
|
*(float *) ((uintptr_t) _this + 79u) = old_invis;
|
|
}
|
|
|
|
static CatVar no_arms(CV_SWITCH, "no_arms", "0", "No Arms",
|
|
"Removes arms from first person");
|
|
static CatVar no_hats(CV_SWITCH, "no_hats", "0", "No Hats",
|
|
"Removes non-stock hats");
|
|
float last_say = 0.0f;
|
|
void DrawModelExecute_hook(IVModelRender *_this, const DrawModelState_t &state,
|
|
const ModelRenderInfo_t &info, matrix3x4_t *matrix)
|
|
{
|
|
static const DrawModelExecute_t original =
|
|
(DrawModelExecute_t) hooks::modelrender.GetMethod(
|
|
offsets::DrawModelExecute());
|
|
static const char *name;
|
|
static std::string sname;
|
|
static IClientUnknown *unk;
|
|
static IClientEntity *ent;
|
|
|
|
if (!cathook ||
|
|
!(spectator_target || no_arms || no_hats ||
|
|
(clean_screenshots && g_IEngine->IsTakingScreenshot())))
|
|
{
|
|
original(_this, state, info, matrix);
|
|
return;
|
|
}
|
|
|
|
PROF_SECTION(DrawModelExecute);
|
|
|
|
if (no_arms || no_hats)
|
|
{
|
|
if (info.pModel)
|
|
{
|
|
name = g_IModelInfo->GetModelName(info.pModel);
|
|
if (name)
|
|
{
|
|
sname = name;
|
|
if (no_arms && sname.find("arms") != std::string::npos)
|
|
{
|
|
return;
|
|
}
|
|
else if (no_hats &&
|
|
sname.find("player/items") != std::string::npos)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unk = info.pRenderable->GetIClientUnknown();
|
|
if (unk)
|
|
{
|
|
ent = unk->GetIClientEntity();
|
|
if (ent)
|
|
{
|
|
if (ent->entindex() == spectator_target)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
if (ent && !effect_chams::g_EffectChams.drawing &&
|
|
effect_chams::g_EffectChams.ShouldRenderChams(ent))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
original(_this, state, info, matrix);
|
|
}
|
|
|
|
int IN_KeyEvent_hook(void *_this, int eventcode, int keynum,
|
|
const char *pszCurrentBinding)
|
|
{
|
|
static const IN_KeyEvent_t original =
|
|
(IN_KeyEvent_t) hooks::client.GetMethod(offsets::IN_KeyEvent());
|
|
#if ENABLE_GUI
|
|
/*
|
|
if (g_pGUI->ConsumesKey((ButtonCode_t)keynum) && g_pGUI->Visible()) {
|
|
return 0;
|
|
}
|
|
*/
|
|
#endif
|
|
return original(_this, eventcode, keynum, pszCurrentBinding);
|
|
}
|
|
|
|
CatVar override_fov_zoomed(CV_FLOAT, "fov_zoomed", "0", "FOV override (zoomed)",
|
|
"Overrides FOV with this value when zoomed in "
|
|
"(default FOV when zoomed is 20)");
|
|
CatVar override_fov(CV_FLOAT, "fov", "0", "FOV override",
|
|
"Overrides FOV with this value");
|
|
|
|
CatVar freecam(CV_KEY, "debug_freecam", "0", "Freecam");
|
|
int spectator_target{ 0 };
|
|
|
|
CatCommand spectate("spectate", "Spectate", [](const CCommand &args) {
|
|
if (args.ArgC() < 1)
|
|
{
|
|
spectator_target = 0;
|
|
return;
|
|
}
|
|
int id = atoi(args.Arg(1));
|
|
if (!id)
|
|
spectator_target = 0;
|
|
else
|
|
{
|
|
spectator_target = g_IEngine->GetPlayerForUserID(id);
|
|
}
|
|
});
|
|
|
|
void OverrideView_hook(void *_this, CViewSetup *setup)
|
|
{
|
|
static const OverrideView_t original =
|
|
(OverrideView_t) hooks::clientmode.GetMethod(offsets::OverrideView());
|
|
static bool zoomed;
|
|
original(_this, setup);
|
|
if (!cathook)
|
|
return;
|
|
if (g_pLocalPlayer->bZoomed && override_fov_zoomed)
|
|
{
|
|
setup->fov = override_fov_zoomed;
|
|
}
|
|
else
|
|
{
|
|
if (override_fov)
|
|
{
|
|
setup->fov = override_fov;
|
|
}
|
|
}
|
|
|
|
if (spectator_target)
|
|
{
|
|
CachedEntity *spec = ENTITY(spectator_target);
|
|
if (CE_GOOD(spec) && !CE_BYTE(spec, netvar.iLifeState))
|
|
{
|
|
setup->origin =
|
|
spec->m_vecOrigin + CE_VECTOR(spec, netvar.vViewOffset);
|
|
// why not spectate yourself
|
|
if (spec == LOCAL_E)
|
|
{
|
|
setup->angles =
|
|
CE_VAR(spec, netvar.m_angEyeAnglesLocal, QAngle);
|
|
}
|
|
else
|
|
{
|
|
setup->angles = CE_VAR(spec, netvar.m_angEyeAngles, QAngle);
|
|
}
|
|
}
|
|
if (g_IInputSystem->IsButtonDown(ButtonCode_t::KEY_SPACE))
|
|
{
|
|
spectator_target = 0;
|
|
}
|
|
}
|
|
|
|
if (freecam)
|
|
{
|
|
static Vector freecam_origin{ 0 };
|
|
static bool freecam_last{ false };
|
|
if (freecam.KeyDown())
|
|
{
|
|
if (not freecam_last)
|
|
{
|
|
freecam_origin = setup->origin;
|
|
}
|
|
float sp, sy, cp, cy;
|
|
QAngle angle;
|
|
Vector forward;
|
|
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 *= 4;
|
|
freecam_origin += forward;
|
|
setup->origin = freecam_origin;
|
|
}
|
|
freecam_last = freecam.KeyDown();
|
|
}
|
|
|
|
draw::fov = setup->fov;
|
|
}
|
|
|
|
#endif
|
|
|
|
bool CanPacket_hook(void *_this)
|
|
{
|
|
const CanPacket_t original =
|
|
(CanPacket_t) hooks::netchannel.GetMethod(offsets::CanPacket());
|
|
return *bSendPackets && original(_this);
|
|
}
|
|
|
|
CUserCmd *GetUserCmd_hook(IInput *_this, int sequence_number)
|
|
{
|
|
static const GetUserCmd_t original =
|
|
(GetUserCmd_t) hooks::input.GetMethod(offsets::GetUserCmd());
|
|
static CUserCmd *def;
|
|
static int oldcmd;
|
|
static INetChannel *ch;
|
|
|
|
def = original(_this, sequence_number);
|
|
if (def &&
|
|
command_number_mod.find(def->command_number) !=
|
|
command_number_mod.end())
|
|
{
|
|
// logging::Info("Replacing command %i with %i", def->command_number,
|
|
// command_number_mod[def->command_number]);
|
|
oldcmd = def->command_number;
|
|
def->command_number = command_number_mod[def->command_number];
|
|
def->random_seed =
|
|
MD5_PseudoRandom(unsigned(def->command_number)) & 0x7fffffff;
|
|
command_number_mod.erase(command_number_mod.find(oldcmd));
|
|
*(int *) ((unsigned) g_IBaseClientState +
|
|
offsets::lastoutgoingcommand()) = def->command_number - 1;
|
|
ch =
|
|
(INetChannel *) g_IEngine
|
|
->GetNetChannelInfo(); //*(INetChannel**)((unsigned)g_IBaseClientState
|
|
//+ offsets::m_NetChannel());
|
|
*(int *) ((unsigned) ch + offsets::m_nOutSequenceNr()) =
|
|
def->command_number - 1;
|
|
}
|
|
return def;
|
|
}
|
|
|
|
static CatVar log_sent(CV_SWITCH, "debug_log_sent_messages", "0",
|
|
"Log sent messages");
|
|
|
|
static CatCommand plus_use_action_slot_item_server(
|
|
"+cat_use_action_slot_item_server", "use_action_slot_item_server", []() {
|
|
KeyValues *kv = new KeyValues("+use_action_slot_item_server");
|
|
g_pLocalPlayer->using_action_slot_item = true;
|
|
g_IEngine->ServerCmdKeyValues(kv);
|
|
});
|
|
|
|
static CatCommand minus_use_action_slot_item_server(
|
|
"-cat_use_action_slot_item_server", "use_action_slot_item_server", []() {
|
|
KeyValues *kv = new KeyValues("-use_action_slot_item_server");
|
|
g_pLocalPlayer->using_action_slot_item = false;
|
|
g_IEngine->ServerCmdKeyValues(kv);
|
|
});
|
|
|
|
static CatVar newlines_msg(CV_INT, "chat_newlines", "0", "Prefix newlines",
|
|
"Add # newlines before each your message", 0, 24);
|
|
// TODO replace \\n with \n
|
|
// TODO name \\n = \n
|
|
// static CatVar queue_messages(CV_SWITCH, "chat_queue", "0", "Queue messages",
|
|
// "Use this if you want to use spam/killsay and still be able to chat normally
|
|
// (without having your msgs eaten by valve cooldown)");
|
|
|
|
static CatVar airstuck(CV_KEY, "airstuck", "0", "Airstuck");
|
|
static CatVar crypt_chat(
|
|
CV_SWITCH, "chat_crypto", "0", "Crypto chat",
|
|
"Start message with !! and it will be only visible to cathook users");
|
|
static CatVar chat_filter(CV_STRING, "chat_censor", "",
|
|
"Spam Chat with newlines if the chosen words are "
|
|
"said, seperate with commas");
|
|
static CatVar chat_filter_enabled(CV_SWITCH, "chat_censor_enabled", "0",
|
|
"enable censor");
|
|
|
|
bool SendNetMsg_hook(void *_this, INetMessage &msg, bool bForceReliable = false,
|
|
bool bVoice = false)
|
|
{
|
|
static size_t say_idx, say_team_idx;
|
|
static int offset;
|
|
static std::string newlines;
|
|
static NET_StringCmd stringcmd;
|
|
|
|
// This is a INetChannel hook - it SHOULDN'T be static because netchannel
|
|
// changes.
|
|
const SendNetMsg_t original =
|
|
(SendNetMsg_t) hooks::netchannel.GetMethod(offsets::SendNetMsg());
|
|
// net_StringCmd
|
|
if (msg.GetType() == 4 && (newlines_msg || crypt_chat))
|
|
{
|
|
std::string str(msg.ToString());
|
|
say_idx = str.find("net_StringCmd: \"say \"");
|
|
say_team_idx = str.find("net_StringCmd: \"say_team \"");
|
|
if (!say_idx || !say_team_idx)
|
|
{
|
|
offset = say_idx ? 26 : 21;
|
|
bool crpt = false;
|
|
if (crypt_chat)
|
|
{
|
|
std::string msg(str.substr(offset));
|
|
msg = msg.substr(0, msg.length() - 2);
|
|
if (msg.find("!!") == 0)
|
|
{
|
|
msg = ucccccp::encrypt(msg.substr(2));
|
|
str = str.substr(0, offset) + msg + "\"\"";
|
|
crpt = true;
|
|
}
|
|
}
|
|
if (!crpt && newlines_msg)
|
|
{
|
|
// TODO move out? update in a value change callback?
|
|
newlines = std::string((int) newlines_msg, '\n');
|
|
str.insert(offset, newlines);
|
|
}
|
|
str = str.substr(16, str.length() - 17);
|
|
// if (queue_messages && !chat_stack::CanSend()) {
|
|
stringcmd.m_szCommand = str.c_str();
|
|
return original(_this, stringcmd, bForceReliable, bVoice);
|
|
//}
|
|
}
|
|
}
|
|
static ConVar *sv_player_usercommand_timeout =
|
|
g_ICvar->FindVar("sv_player_usercommand_timeout");
|
|
static float lastcmd = 0.0f;
|
|
if (lastcmd > g_GlobalVars->absoluteframetime)
|
|
{
|
|
lastcmd = g_GlobalVars->absoluteframetime;
|
|
}
|
|
if (airstuck.KeyDown() && !g_Settings.bInvalid)
|
|
{
|
|
if (CE_GOOD(LOCAL_E))
|
|
{
|
|
if (lastcmd + sv_player_usercommand_timeout->GetFloat() - 0.1f <
|
|
g_GlobalVars->curtime)
|
|
{
|
|
if (msg.GetType() == clc_Move)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
lastcmd = g_GlobalVars->absoluteframetime;
|
|
}
|
|
}
|
|
}
|
|
if (log_sent && msg.GetType() != 3 && msg.GetType() != 9)
|
|
{
|
|
logging::Info("=> %s [%i] %s", msg.GetName(), msg.GetType(),
|
|
msg.ToString());
|
|
unsigned char buf[4096];
|
|
bf_write buffer("cathook_debug_buffer", buf, 4096);
|
|
logging::Info("Writing %i", msg.WriteToBuffer(buffer));
|
|
std::string bytes = "";
|
|
constexpr char h2c[] = "0123456789abcdef";
|
|
for (int i = 0; i < buffer.GetNumBytesWritten(); i++)
|
|
{
|
|
// bytes += format(h2c[(buf[i] & 0xF0) >> 4], h2c[(buf[i] & 0xF)], '
|
|
// ');
|
|
bytes += format((unsigned short) buf[i], ' ');
|
|
}
|
|
logging::Info("%i bytes => %s", buffer.GetNumBytesWritten(),
|
|
bytes.c_str());
|
|
}
|
|
return original(_this, msg, bForceReliable, bVoice);
|
|
}
|
|
|
|
static CatVar die_if_vac(CV_SWITCH, "die_if_vac", "0", "Die if VAC banned");
|
|
|
|
void Shutdown_hook(void *_this, const char *reason)
|
|
{
|
|
g_Settings.bInvalid = true;
|
|
// This is a INetChannel hook - it SHOULDN'T be static because netchannel
|
|
// changes.
|
|
const Shutdown_t original =
|
|
(Shutdown_t) hooks::netchannel.GetMethod(offsets::Shutdown());
|
|
logging::Info("Disconnect: %s", reason);
|
|
if (strstr(reason, "banned"))
|
|
{
|
|
if (die_if_vac)
|
|
{
|
|
logging::Info("VAC banned");
|
|
*(int *) 0 = 0;
|
|
exit(1);
|
|
}
|
|
}
|
|
#if ENABLE_IPC
|
|
ipc::UpdateServerAddress(true);
|
|
#endif
|
|
if (cathook && (disconnect_reason.convar_parent->m_StringLength > 3) &&
|
|
strstr(reason, "user"))
|
|
{
|
|
original(_this, disconnect_reason_newlined);
|
|
}
|
|
else
|
|
{
|
|
original(_this, reason);
|
|
}
|
|
|
|
if (hacks::shared::autojoin::auto_queue)
|
|
tfmm::abandon();
|
|
}
|
|
|
|
static CatVar resolver(CV_SWITCH, "resolver", "0", "Resolve angles");
|
|
|
|
CatEnum namesteal_enum({ "OFF", "PASSIVE", "ACTIVE" });
|
|
CatVar namesteal(namesteal_enum, "name_stealer", "0", "Name Stealer",
|
|
"Attemt to steal your teammates names. Usefull for avoiding "
|
|
"kicks\nPassive only changes when the name stolen is no "
|
|
"longer the best name to use\nActive Attemps to change the "
|
|
"name whenever possible");
|
|
|
|
static std::string stolen_name;
|
|
|
|
// Func to get a new entity to steal name from and returns true if a target has
|
|
// been found
|
|
bool StolenName()
|
|
{
|
|
|
|
// Array to store potential namestealer targets with a bookkeeper to tell
|
|
// how full it is
|
|
int potential_targets[32];
|
|
int potential_targets_length = 0;
|
|
|
|
// Go through entities looking for potential targets
|
|
for (int i = 1; i < HIGHEST_ENTITY; i++)
|
|
{
|
|
CachedEntity *ent = ENTITY(i);
|
|
|
|
// Check if ent is a good target
|
|
if (!ent)
|
|
continue;
|
|
if (ent == LOCAL_E)
|
|
continue;
|
|
if (!ent->m_Type == ENTITY_PLAYER)
|
|
continue;
|
|
if (ent->m_bEnemy)
|
|
continue;
|
|
|
|
// Check if name is current one
|
|
player_info_s info;
|
|
if (g_IEngine->GetPlayerInfo(ent->m_IDX, &info))
|
|
{
|
|
|
|
// If our name is the same as current, than change it
|
|
if (std::string(info.name) == stolen_name)
|
|
{
|
|
// Since we found the ent we stole our name from and it is still
|
|
// good, if user settings are passive, then we return true and
|
|
// dont alter our name
|
|
if ((int) namesteal == 1)
|
|
{
|
|
return true;
|
|
// Otherwise we continue to change our name to something
|
|
// else
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
|
|
// a ent without a name is no ent we need, contine for a different
|
|
// one
|
|
}
|
|
else
|
|
continue;
|
|
|
|
// Save the ent to our array
|
|
potential_targets[potential_targets_length] = i;
|
|
potential_targets_length++;
|
|
|
|
// With our maximum amount of players reached, dont search for anymore
|
|
if (potential_targets_length >= 32)
|
|
break;
|
|
}
|
|
|
|
// Checks to prevent crashes
|
|
if (potential_targets_length == 0)
|
|
return false;
|
|
|
|
// Get random number that we can use with our array
|
|
int target_random_num =
|
|
floor(RandFloatRange(0, potential_targets_length - 0.1F));
|
|
|
|
// Get a idx from our random array position
|
|
int new_target = potential_targets[target_random_num];
|
|
|
|
// Grab username of user
|
|
player_info_s info;
|
|
if (g_IEngine->GetPlayerInfo(new_target, &info))
|
|
{
|
|
|
|
// If our name is the same as current, than change it and return true
|
|
stolen_name = std::string(info.name);
|
|
return true;
|
|
}
|
|
|
|
// Didnt get playerinfo
|
|
return false;
|
|
}
|
|
|
|
static CatVar ipc_name(CV_STRING, "name_ipc", "", "IPC Name");
|
|
|
|
const char *GetFriendPersonaName_hook(ISteamFriends *_this, CSteamID steamID)
|
|
{
|
|
static const GetFriendPersonaName_t original =
|
|
(GetFriendPersonaName_t) hooks::steamfriends.GetMethod(
|
|
offsets::GetFriendPersonaName());
|
|
|
|
#if ENABLE_IPC
|
|
if (ipc::peer)
|
|
{
|
|
static std::string namestr(ipc_name.GetString());
|
|
namestr.assign(ipc_name.GetString());
|
|
if (namestr.length() > 3)
|
|
{
|
|
ReplaceString(namestr, "%%", std::to_string(ipc::peer->client_id));
|
|
return namestr.c_str();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Check User settings if namesteal is allowed
|
|
if (namesteal && steamID == g_ISteamUser->GetSteamID())
|
|
{
|
|
|
|
// We dont want to steal names while not in-game as there are no targets
|
|
// to steal from. We want to be on a team as well to get teammates names
|
|
if (g_IEngine->IsInGame() && g_pLocalPlayer->team)
|
|
{
|
|
|
|
// Check if we have a username to steal, func automaticly steals a
|
|
// name in it.
|
|
if (StolenName())
|
|
{
|
|
|
|
// Return the name that has changed from the func above
|
|
return format(stolen_name, "\x0F").c_str();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((strlen(force_name.GetString()) > 1) &&
|
|
steamID == g_ISteamUser->GetSteamID())
|
|
{
|
|
|
|
return force_name_newlined;
|
|
}
|
|
return original(_this, steamID);
|
|
}
|
|
|
|
void FireGameEvent_hook(void *_this, IGameEvent *event)
|
|
{
|
|
static const FireGameEvent_t original =
|
|
(FireGameEvent_t) hooks::clientmode4.GetMethod(
|
|
offsets::FireGameEvent());
|
|
const char *name = event->GetName();
|
|
if (name)
|
|
{
|
|
if (event_log)
|
|
{
|
|
if (!strcmp(name, "player_connect_client") ||
|
|
!strcmp(name, "player_disconnect") ||
|
|
!strcmp(name, "player_team"))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
// hacks::tf2::killstreak::fire_event(event);
|
|
}
|
|
original(_this, event);
|
|
}
|
|
|
|
#if ENABLE_VISUALS == 1
|
|
void FrameStageNotify_hook(void *_this, int stage)
|
|
{
|
|
static IClientEntity *ent;
|
|
|
|
PROF_SECTION(FrameStageNotify_TOTAL);
|
|
|
|
static const FrameStageNotify_t original =
|
|
(FrameStageNotify_t) hooks::client.GetMethod(
|
|
offsets::FrameStageNotify());
|
|
|
|
if (!g_IEngine->IsInGame())
|
|
g_Settings.bInvalid = true;
|
|
{
|
|
PROF_SECTION(FSN_skinchanger);
|
|
hacks::tf2::skinchanger::FrameStageNotify(stage);
|
|
}
|
|
if (resolver && cathook && !g_Settings.bInvalid &&
|
|
stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START)
|
|
{
|
|
PROF_SECTION(FSN_resolver);
|
|
for (int i = 1; i < 32 && i < HIGHEST_ENTITY; i++)
|
|
{
|
|
if (i == g_IEngine->GetLocalPlayer())
|
|
continue;
|
|
ent = g_IEntityList->GetClientEntity(i);
|
|
if (ent && !ent->IsDormant() && !NET_BYTE(ent, netvar.iLifeState))
|
|
{
|
|
Vector &angles = NET_VECTOR(ent, netvar.m_angEyeAngles);
|
|
if (angles.x >= 90)
|
|
angles.x = -89;
|
|
if (angles.x <= -90)
|
|
angles.x = 89;
|
|
angles.y = fmod(angles.y + 180.0f, 360.0f);
|
|
if (angles.y < 0)
|
|
angles.y += 360.0f;
|
|
angles.y -= 180.0f;
|
|
}
|
|
}
|
|
}
|
|
if (cathook && !g_Settings.bInvalid && stage == FRAME_RENDER_START)
|
|
{
|
|
IF_GAME(IsTF())
|
|
{
|
|
if (CE_GOOD(LOCAL_E) && no_zoom)
|
|
RemoveCondition<TFCond_Zoomed>(LOCAL_E);
|
|
}
|
|
if (force_thirdperson && !g_pLocalPlayer->life_state &&
|
|
CE_GOOD(g_pLocalPlayer->entity))
|
|
{
|
|
CE_INT(g_pLocalPlayer->entity, netvar.nForceTauntCam) = 1;
|
|
}
|
|
if (stage == 5 && show_antiaim && g_IInput->CAM_IsThirdPerson())
|
|
{
|
|
if (CE_GOOD(g_pLocalPlayer->entity))
|
|
{
|
|
CE_FLOAT(g_pLocalPlayer->entity, netvar.deadflag + 4) =
|
|
g_Settings.last_angles.x;
|
|
CE_FLOAT(g_pLocalPlayer->entity, netvar.deadflag + 8) =
|
|
g_Settings.last_angles.y;
|
|
}
|
|
}
|
|
}
|
|
original(_this, stage);
|
|
}
|
|
#endif /* TEXTMODE */
|
|
|
|
static CatVar clean_chat(CV_SWITCH, "clean_chat", "0", "Clean chat",
|
|
"Removes newlines from chat");
|
|
static CatVar dispatch_log(CV_SWITCH, "debug_log_usermessages", "0",
|
|
"Log dispatched user messages");
|
|
|
|
bool DispatchUserMessage_hook(void *_this, int type, bf_read &buf)
|
|
{
|
|
int loop_index, s, i, j;
|
|
char *data, c;
|
|
|
|
static const DispatchUserMessage_t original =
|
|
(DispatchUserMessage_t) hooks::client.GetMethod(
|
|
offsets::DispatchUserMessage());
|
|
if (type == 4)
|
|
{
|
|
loop_index = 0;
|
|
s = buf.GetNumBytesLeft();
|
|
if (s < 256)
|
|
{
|
|
data = (char *) alloca(s);
|
|
for (i = 0; i < s; i++)
|
|
data[i] = buf.ReadByte();
|
|
j = 0;
|
|
std::string name;
|
|
std::string message;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
while ((c = data[j++]) && (loop_index < 128))
|
|
{
|
|
loop_index++;
|
|
if (clean_chat)
|
|
if ((c == '\n' || c == '\r') && (i == 1 || i == 2))
|
|
data[j - 1] = '*';
|
|
if (i == 1)
|
|
name.push_back(c);
|
|
if (i == 2)
|
|
message.push_back(c);
|
|
}
|
|
}
|
|
if (chat_filter_enabled)
|
|
{
|
|
if (!strcmp(chat_filter.GetString(), ""))
|
|
{
|
|
std::string tmp = {};
|
|
int iii = 0;
|
|
player_info_s info;
|
|
g_IEngine->GetPlayerInfo(LOCAL_E->m_IDX, &info);
|
|
std::string name2 = info.name;
|
|
std::string claz = {};
|
|
switch (g_pLocalPlayer->clazz) {
|
|
case tf_scout:
|
|
claz = "scout";
|
|
break;
|
|
case tf_soldier:
|
|
claz = "soldier";
|
|
break;
|
|
case tf_pyro:
|
|
claz = "pyro";
|
|
break;
|
|
case tf_demoman:
|
|
claz = "demo";
|
|
break;
|
|
case tf_engineer:
|
|
claz = "engi";
|
|
break;
|
|
case tf_heavy:
|
|
claz = "heavy";
|
|
break;
|
|
case tf_medic:
|
|
claz = "med";
|
|
break;
|
|
case tf_sniper:
|
|
claz = "sniper";
|
|
break;
|
|
case tf_spy:
|
|
claz = "spy";
|
|
break;
|
|
}
|
|
for (char i : name2)
|
|
{
|
|
if (iii == 3)
|
|
{
|
|
iii++;
|
|
continue;
|
|
}
|
|
else if (iii < 2)
|
|
{
|
|
iii++;
|
|
tmp += i;
|
|
}
|
|
}
|
|
i = 0;
|
|
name2 = tmp;
|
|
std::vector<std::string> res = { "skid", "script", "cheat", "hak", "hac", "f1", "hax","vac",
|
|
"ban", "lmao", "bot",
|
|
"cat", "kick", name2, claz };
|
|
std::string message2 = message;
|
|
std::transform(message2.begin(), message2.end(),
|
|
message2.begin(), ::tolower);
|
|
std::string temp;
|
|
for (char i : message2)
|
|
{
|
|
if (i == '4')
|
|
temp += "a";
|
|
else if (i == '3')
|
|
temp += "e";
|
|
else if (i == '0')
|
|
temp += "o";
|
|
else if (i == '6')
|
|
temp += "g";
|
|
else if (i == '5')
|
|
temp += "s";
|
|
else if (i == '7')
|
|
temp += "t";
|
|
else
|
|
temp += i;
|
|
}
|
|
message2 = temp;
|
|
temp = "";
|
|
for (auto filter : res)
|
|
{
|
|
if (boost::contains(message2,filter))
|
|
{
|
|
logging::Info("gay");
|
|
std::string blanks(". "
|
|
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
|
|
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
|
|
"\n ");
|
|
chat_stack::Say(blanks,
|
|
true);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string input = chat_filter.GetString();
|
|
std::transform(input.begin(), input.end(), input.begin(),
|
|
::tolower);
|
|
|
|
std::string message2;
|
|
std::vector<std::string> result{};
|
|
std::string temp{};
|
|
int prevj = 0;
|
|
int previ;
|
|
boost::split(result, input, boost::is_any_of(","));
|
|
for (int ii = 0; ii < result.size() - 1; i++)
|
|
{
|
|
std::string i = result[ii];
|
|
for (int j = 0; j < i.size() - 1; j++)
|
|
{
|
|
char c = i[j];
|
|
if (prevj < j)
|
|
{
|
|
prevj++;
|
|
result[i[j]] = temp;
|
|
temp = "";
|
|
}
|
|
if (c == '4')
|
|
temp += "a";
|
|
else if (c == '3')
|
|
temp += "e";
|
|
else if (c == '0')
|
|
temp += "o";
|
|
else if (c == '6')
|
|
temp += "g";
|
|
else if (c == '5')
|
|
temp += "s";
|
|
else if (c == '7')
|
|
temp += "t";
|
|
else
|
|
temp += c;
|
|
}
|
|
}
|
|
for (char i : message2)
|
|
{
|
|
if (i == '4')
|
|
temp += "a";
|
|
else if (i == '3')
|
|
temp += "e";
|
|
else if (i == '0')
|
|
temp += "o";
|
|
else if (i == '6')
|
|
temp += "g";
|
|
else if (i == '5')
|
|
temp += 's';
|
|
else if (i == '7')
|
|
temp += 't';
|
|
else
|
|
temp += i;
|
|
}
|
|
temp = "";
|
|
for (auto filter : result)
|
|
{
|
|
if (boost::contains(message2, filter))
|
|
{
|
|
std::string blanks(
|
|
". \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n ");
|
|
chat_stack::Say(blanks, true);
|
|
PrintChat("Cleared Chat");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (crypt_chat)
|
|
{
|
|
if (message.find("!!") == 0)
|
|
{
|
|
if (ucccccp::validate(message))
|
|
{
|
|
PrintChat("\x07%06X%s\x01: %s", 0xe05938, name.c_str(),
|
|
ucccccp::decrypt(message).c_str());
|
|
}
|
|
}
|
|
}
|
|
chatlog::LogMessage(data[0], message);
|
|
buf = bf_read(data, s);
|
|
buf.Seek(0);
|
|
}
|
|
}
|
|
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<int>(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);
|
|
}
|
|
|
|
void LevelInit_hook(void *_this, const char *newmap)
|
|
{
|
|
static const LevelInit_t original =
|
|
(LevelInit_t) hooks::clientmode.GetMethod(offsets::LevelInit());
|
|
playerlist::Save();
|
|
g_IEngine->ClientCmd_Unrestricted("exec cat_matchexec");
|
|
hacks::shared::aimbot::Reset();
|
|
chat_stack::Reset();
|
|
hacks::shared::anticheat::ResetEverything();
|
|
original(_this, newmap);
|
|
hacks::shared::walkbot::OnLevelInit();
|
|
#if ENABLE_IPC
|
|
if (ipc::peer)
|
|
{
|
|
ipc::peer->memory->peer_user_data[ipc::peer->client_id].ts_connected =
|
|
time(nullptr);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void LevelShutdown_hook(void *_this)
|
|
{
|
|
static const LevelShutdown_t original =
|
|
LevelShutdown_t(hooks::clientmode.GetMethod(offsets::LevelShutdown()));
|
|
need_name_change = true;
|
|
playerlist::Save();
|
|
g_Settings.bInvalid = true;
|
|
hacks::shared::aimbot::Reset();
|
|
chat_stack::Reset();
|
|
hacks::shared::anticheat::ResetEverything();
|
|
original(_this);
|
|
#if ENABLE_IPC
|
|
if (ipc::peer)
|
|
{
|
|
ipc::peer->memory->peer_user_data[ipc::peer->client_id]
|
|
.ts_disconnected = time(nullptr);
|
|
}
|
|
#endif
|
|
}
|