This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

383 lines
14 KiB
C++

/*
*
* We do hooking here!
* Eventually you will be able to pass your function into here to do stuff
*with the hooked functions
*
*
*/
#include <cstdlib> // Needed to get client mode
#include <thread>
#include "../../../framework/game.hpp"
#include "../../../hacks/hooking.hpp"
#include "../../../hacks/signature.hpp"
#include "../../../util/catvars.hpp"
#include "../../../util/chrono.hpp"
#include "../../../util/logging.hpp"
#include "../../../util/platform.hpp"
#include "../util/mathlib.hpp"
#include "../util/netvars.hpp"
#include "../util/worldtoscreen.hpp"
#if defined(NEKO_TF2)
#include "../util/conditions.hpp"
#endif
#include "ifaces.hpp"
#include "hooks.hpp"
namespace offsets {
constexpr int CreateMove = Platform(22, 21);
constexpr int OverrideView = 17;
constexpr int PaintTraverse = Platform(42, 41);
constexpr int FrameStageNotify = 35;
constexpr int SendNetMsg = 41;
} // namespace offsets
namespace modules::source::hooks {
// Here we store our main hooks
static VMTHook clientmode;
static VMTHook client;
static VMTHook panel;
static VMTHook netmsg;
// Here we have our hooked functions
CUserCmd* ui_cmd =
nullptr; // For functions not directly in cm but ones that use the cmd
bool using_silent = false;
Vector LastAngles; // We save angles from CreateMove to use down in
// FrameStageNotify
#if defined(_WIN32)
static bool __fastcall CreateMove_hook(void* thisptr, void* edx,
float inputSample, CUserCmd* cmd) {
using CreateMove_t = bool(__thiscall*)(void*, float, CUserCmd*);
#else
static bool CreateMove_hook(void* thisptr, float inputSample, CUserCmd* cmd) {
using CreateMove_t = bool (*)(void*, float, CUserCmd*);
#endif
const CreateMove_t original = clientmode.GetMethod<CreateMove_t>(
offsets::CreateMove); // We call this on return so that we can process
// our stuff before create move
if (!cmd)
return original(thisptr, inputSample,
cmd); // Cant do anything without cmd
ui_cmd = cmd; // Update the cmd
// Update ingame
if (!game::GetInGame()) return original(thisptr, inputSample, cmd);
// Run the frameworks worldtick
events::world.Emit();
// Run the original to get result
// I do this so we can make the game think we are at the normal pos and
// angles while we send the silent angles to the server Unsure if this is
// the case tho but it works
bool ret = original(thisptr, inputSample, cmd);
// Save this so we can use it in FrameStageNotify to show angles in
// thirdperson
LastAngles = cmd->viewangles;
// If we are using silent aim, we return false
if (using_silent) {
// To use silent, we just dont return true, but we need to still correct
// movement so we do that too
Vector camera_angle;
iface::engine->GetViewAngles(camera_angle);
CatVector ang = VectorAngles(
CatVector(cmd->forwardmove, cmd->sidemove, cmd->upmove));
float yaw = DEG2RAD(ang.y - camera_angle.y + cmd->viewangles.y);
float speed = sqrt(cmd->forwardmove * cmd->forwardmove +
cmd->sidemove * cmd->sidemove);
cmd->forwardmove = cos(yaw) * speed;
cmd->sidemove = sin(yaw) * speed;
using_silent = false;
return false;
}
return ret;
}
#if defined(NEKO_TF2)
static CatVarBool no_zoom({"Visuals", "Misc"}, "no_zoom", false, "No Zoom",
"Disables scope overlay and zoom");
#endif
#if defined(_WIN32)
static void __fastcall PaintTraverse_hook(IPanel* _this, void* edx,
unsigned int vp, bool fr, bool ar) {
using PaintTraverse_t =
void(__thiscall*)(IPanel*, unsigned int, bool, bool);
#else
static void PaintTraverse_hook(IPanel* _this, unsigned int vp, bool fr,
bool ar) {
using PaintTraverse_t = void (*)(IPanel*, unsigned int, bool, bool);
#endif
const PaintTraverse_t original =
panel.GetMethod<PaintTraverse_t>(offsets::PaintTraverse);
static unsigned long panel_top = 0;
if (!panel_top && !strcmp("MatSystemTopPanel", _this->GetName(vp)))
panel_top = vp;
static unsigned long panel_focus = 0;
if (!panel_focus && !strcmp("FocusOverlayPanel", _this->GetName(vp)))
panel_focus = vp;
// No Zoom
#if defined(NEKO_TF2)
static unsigned long panel_scope = 0;
if (!panel_scope && !strcmp("HudScope", _this->GetName(vp)))
panel_scope = vp;
if (no_zoom && vp == panel_scope) return;
#endif
original(_this, vp, fr, ar); // Call the original function before we draw
// Logic to determine whether we should draw, no idea how it works
static bool draw_flag = false;
if (vp == panel_top) draw_flag = true;
if (vp != panel_focus) return;
_this->SetTopmostPopup(panel_focus, true);
if (!draw_flag) return;
draw_flag = false;
// TODO: find the id of the one we print in
// debug_log.Puts(_this->GetName(vp));
events::draw.Emit(); // Call the managers draw tick
}
static CatVarInt fov_override({"Visuals", "Misc"}, "fov", 0, "Fov Override",
"Change fov");
static void OverrideView_hook(void* _this, CViewSetup* setup) {
using OverrideView_t = void (*)(void*, CViewSetup*);
const OverrideView_t original =
clientmode.GetMethod<OverrideView_t>(offsets::OverrideView);
original(_this, setup);
// Set this for wts
wts::wts_viewsetup = setup;
// No-Zoom
#if defined(NEKO_TF2)
static ConVar* fov_desired = iface::cvar->FindVar("fov_desired");
auto local_ent =
iface::entity_list->GetClientEntity(iface::engine->GetLocalPlayer());
if (no_zoom) {
// IF we are zoomed
if (local_ent && !local_ent->IsDormant() &&
HasCondition(local_ent, TfCond::kZoomed)) {
if (fov_override)
setup->fov = fov_override;
else
setup->fov = fov_desired->GetFloat();
}
} else if (!local_ent || !HasCondition(local_ent, TfCond::kZoomed))
#endif
if (fov_override) setup->fov = fov_override;
}
static CatVarBool force_thirdperson(
{"Visuals", "Misc"}, "thirdperson", false, "Force Thirdperson",
"Forces thirdperson mode 99.9% of the time");
static void FrameStageNotify_hook(IClient* _this, int stage) {
using FrameStageNotify_t = void (*)(IClient*, int);
const FrameStageNotify_t original =
client.GetMethod<FrameStageNotify_t>(offsets::FrameStageNotify);
if (stage == FRAME_RENDER_START) {
IClientEntity* local_ent = iface::entity_list->GetClientEntity(
iface::engine->GetLocalPlayer());
if (local_ent && !local_ent->IsDormant() &&
!netvars::m_lifeState.Get(local_ent)) {
#if defined(NEKO_TF2)
// Force Thirdperson
netvars::m_nForceTauntCam.Get(local_ent) = force_thirdperson;
// To show antiaim in thirdperson
if (force_thirdperson &&
stage == 5) { //&& g_IInput && g_IInput->CAM_IsThirdPerson()) {
*reinterpret_cast<float*>(
reinterpret_cast<uintptr_t>(local_ent) +
netvars::deadflag.GetOffset() + 4) = LastAngles.x;
*reinterpret_cast<float*>(
reinterpret_cast<uintptr_t>(local_ent) +
netvars::deadflag.GetOffset() + 8) = LastAngles.y;
}
#endif
}
}
original(_this, stage);
}
// MrSteyk and Raspbian i think wanted be to try a few things.... Still wont
// have a working sig finder....
/*typedef void(__cdecl *ReadUserCmdtd)(bf_read *buf, CUserCmd *move, CUserCmd
*from); ReadUserCmdtd ReadUserCmdFN = nullptr; using ReadUsercmd_t =
void(*)(bf_read* buf, CUserCmd* move, CUserCmd* from); static ReadUsercmd_t
ReadUsercmd = nullptr;
typedef void(__cdecl *WriteUserCmdtd)(bf_write *buf, CUserCmd *to, CUserCmd
*from); WriteUserCmdtd WriteUserCmdFN = nullptr;*/
static CatVarKey timeshift({"Misc"}, "timeshift", CatKey::kNone, "Timeshift");
static bool SendNetMsg_hook(INetChannel* _this, INetMessage& msg,
bool force_reliable, bool voice) {
using SendNetMsg_t = bool (*)(INetChannel*, INetMessage&, bool, bool);
const SendNetMsg_t original =
netmsg.GetMethod<SendNetMsg_t>(offsets::SendNetMsg);
return original(_this, msg, force_reliable, voice);
}
/*if (!strcmp("clc_Move", msg.GetName()) && timeshift && timeshift.Depressed())
{
if (!ReadUserCmdFN) {
ReadUserCmdFN = (ReadUserCmdtd)0xCALLME;
}
if (!WriteUserCmdFN) {
WriteUserCmdFN = (WriteUserCmdtd)0xCALLME;
}
auto Cl_Move = (CLC_Move&)msg;
int totalcmds = Cl_Move.m_nNewCommands;//+ Cl_Move.m_nBackupCommands
CUserCmd *from, *to;
CUserCmd cmds[CMD_MAXBACKUP] = {};
CUserCmd cmdNull;
cmdNull.Reset();
save_pos = Cl_Move.m_DataOut.m_iCurBit;
Cl_Move.m_DataOut.Reset();
from = &cmdNull;
for (i = 0; i <= totalcmds; i++){
to = &cmds[i];
ReadUserCmdFN((bf_read*)&Cl_Move.m_DataOut, to, from);
from = to;
}
Cl_Move.m_DataOut.m_iCurBit = save_pos;
real_commands = totalcmds;
last_command_number = cmds[totalcmds].command_number;
last_tick_count = cmds[totalcmds].tick_count + 200;
while (totalcmds <= MAX_USERCMD) {
to = &cmds[rand() % real_commands];//b1g random
to->command_number = last_command_number + totalcmds -
real_commands + 1; to->tick_count = last_tick_count + totalcmds - real_commands
+ 1; WriteUserCmdFN(&Cl_Move.m_DataOut, to, from); if (totalcmds >
real_commands) { cmds[totalcmds] = *to;
}
from = to;
totalcmds++;
}
last_command_number = cmds[totalcmds].command_number;
last_tick_count = cmds[totalcmds].tick_count;
Cl_Move.m_nNewCommands = totalcmds - Cl_Move.m_nBackupCommands;
netchan->m_nOutSequenceNr += 10;
cGMOD_hooks.NetChannelHook.GetOriginalMethod<NET_CHANNEL_tdSendNetMsg>(40)(netchan,
th, msg, bForceReliable, bVoice); netchan->Transmit();
netchan->m_nOutSequenceNrAck = netchan->m_nOutSequenceNr;
//////////////////////////////////////////////////////////
for (int iter = 0; iter <= 228; iter++) {
moveMsg.m_DataOut.StartWriting(data, sizeof(data));
moveMsg.m_nBackupCommands = 0;
moveMsg.m_nNewCommands = totalcmds;
for (int iter = 0; iter <= totalcmds; iter++) {
to = &cmds[rand() % totalcmds];
to->command_number = last_command_number + iter + 1;
to->tick_count = last_tick_count + iter + 1;
WriteUserCmdFN(&moveMsg.m_DataOut, to, from);
from = to;
}
last_command_number += totalcmds;
last_tick_count += totalcmds;
msg = moveMsg;
cGMOD_hooks.NetChannelHook.GetOriginalMethod<NET_CHANNEL_tdSendNetMsg>(40)(netchan,
th, msg, bForceReliable, bVoice); netchan->Transmit();
netchan->m_nOutSequenceNrAck = netchan->m_nOutSequenceNr;
}
return true;
}
return
cGMOD_hooks.NetChannelHook.GetOriginalMethod<NET_CHANNEL_tdSendNetMsg>(40)(netchan,
th, msg, bForceReliable, bVoice);*/
//}
// static bool SendNetMsg_hook(void *_this, INetMessage &msg, bool
// bForceReliable = false, bool bVoice = false) {
// Use this to init our hooks
void Init() {
// Because getting this to work is slow, why not let it run in another
// thread
auto HookClientmode = []() {
// Client mode
uintptr_t* tmp;
#if !defined(_WIN32)
while (!(
tmp = **(uintptr_t***)(((*(uintptr_t**)iface::client)[10]) + 1))) {
}
#else
while (!(
tmp = **(uintptr_t***)(((*(uintptr_t**)iface::client)[10]) + 5))) {
} // Thanks rud
#endif
clientmode.Set(static_cast<void*>(tmp));
clientmode.HookMethod((void*)CreateMove_hook,
offsets::CreateMove); // World Tick
clientmode.HookMethod((void*)OverrideView_hook,
offsets::OverrideView); // Override View
clientmode.Apply();
};
std::thread client_mode_finder(HookClientmode);
client_mode_finder.detach();
// Panel
panel.Set(iface::panel);
panel.HookMethod((void*)PaintTraverse_hook,
offsets::PaintTraverse); // Draw Tick
panel.Apply();
// Client
client.Set(iface::client);
client.HookMethod((void*)FrameStageNotify_hook, offsets::FrameStageNotify);
client.Apply();
/*events::world.Listen([](){
// As to try to prevent lag we do a check ever sec
static CatTimer do_stuff;
if (do_stuff.ResetAfter(std::chrono::seconds(1))) {
// We check if we arent hooked anymore because source does that
INetChannel* channel =
reinterpret_cast<INetChannel*>(iface::engine->GetNetChannelInfo()); if
(channel && *reinterpret_cast<void**>(channel) !=
netmsg.vtable_replacement.get()) { netmsg.Set(channel);
netmsg.HookMethod((void*)SendNetMsg_hook, offsets::SendNetMsg);
netmsg.Apply();
}
}
});*/
// ReadUsercmd = GetSignature<ReadUsercmd_t>(sharedobj::client, "55 89 E5 57
// 56 53 83 EC 1C 8B 7D 0C 8B 75 10 8B 5D 08 39 F7 0F");
// Should we do this... i dont really know lel
// client_mode_finder.join();
}
} // namespace modules::source::hooks