CSGO: On shot backtracking
Hello,
decided to share full code concerning this since I deleted some parts out of the pub release of glad v2 and the leaked one that is around has it.
bool __fastcall Handlers::TempEntities_h(void* ECX, void* EDX, void* msg)
{
if (!g_LocalPlayer || !g_EngineClient->IsInGame() || !g_EngineClient->IsConnected())
return o_TempEntities(ECX, msg);
bool ret = o_TempEntities(ECX, msg);
auto CL_ParseEventDelta = [](void *RawData, void *pToData, RecvTable *pRecvTable)
{
// "RecvTable_DecodeZeros: table '%s' missing a decoder.", look at the function that calls it.
static uintptr_t CL_ParseEventDeltaF = (uintptr_t)Utils::PatternScan(GetModuleHandle("engine.dll"), ("55 8B EC 83 E4 F8 53 57"));
__asm
{
mov ecx, RawData
mov edx, pToData
push pRecvTable
call CL_ParseEventDeltaF
add esp, 4
}
};
// Filtering events
if (!g_Options.rage_lagcompensation || !g_LocalPlayer->IsAlive())
return ret;
CEventInfo *ei = g_ClientState->events; //0x4DEC
CEventInfo *next = NULL;
if (!ei)
return ret;
do
{
next = *(CEventInfo**)((uintptr_t)ei + 0x38);
uint16_t classID = ei->classID - 1;
auto m_pCreateEventFn = ei->pClientClass->m_pCreateEventFn; // ei->pClientClass->m_pCreateEventFn ptr
if (!m_pCreateEventFn)
continue;
IClientNetworkable *pCE = m_pCreateEventFn();
if (!pCE)
continue;
if (classID == ClassId::ClassId_CTEFireBullets)
{
// set fire_delay to zero to send out event so its not here later.
ei->fire_delay = 0.0f;
auto pRecvTable = ei->pClientClass->m_pRecvTable;
void *BasePtr = pCE->GetDataTableBasePtr();
// Decode data into client event object and use the DTBasePtr to get the netvars
CL_ParseEventDelta(ei->pData, BasePtr, pRecvTable);
if (!BasePtr)
continue;
// This nigga right HERE just fired a BULLET MANE
int EntityIndex = *(int*)((uintptr_t)BasePtr + 0x10) + 1;
auto pEntity = (C_BasePlayer*)g_EntityList->GetClientEntity(EntityIndex);
if (pEntity && pEntity->GetClientClass() && pEntity->GetClientClass()->m_ClassID == ClassId::ClassId_CCSPlayer && pEntity->m_iTeamNum() != g_LocalPlayer->m_iTeamNum())
{
QAngle EyeAngles = QAngle(*(float*)((uintptr_t)BasePtr + 0x24), *(float*)((uintptr_t)BasePtr + 0x28), 0.0f),
CalcedAngle = Math::CalcAngle(pEntity->GetEyePos(), g_LocalPlayer->GetEyePos());
*(float*)((uintptr_t)BasePtr + 0x24) = CalcedAngle.pitch;
*(float*)((uintptr_t)BasePtr + 0x28) = CalcedAngle.yaw;
*(float*)((uintptr_t)BasePtr + 0x2C) = 0;
float
event_time = TICKS_TO_TIME(g_GlobalVars->tickcount),
player_time = pEntity->m_flSimulationTime();
// Extrapolate tick to hit those fag scouters etc
auto lag_records = CMBacktracking::Get().m_LagRecord[pEntity->EntIndex()];
float shot_time = event_time;
for (auto& record : lag_records)
{
if (TICKS_TO_TIME(record.m_iTickCount) <= event_time)
{
shot_time = record.m_flSimulationTime + (event_time - TICKS_TO_TIME(record.m_iTickCount)); // also get choked from this
#ifdef _DEBUG
g_CVar->ConsoleColorPrintf(Color(0, 255, 0, 255), "Found exact shot time: %f, ticks choked to get here: %d\n", shot_time, TIME_TO_TICKS(event_time - TICKS_TO_TIME(record.m_iTickCount)));
#endif
break;
}
#ifdef _DEBUG
else
g_CVar->ConsolePrintf("Bad curtime difference, EVENT: %f, RECORD: %f\n", event_time, TICKS_TO_TIME(record.m_iTickCount));
#endif
}
#ifdef _DEBUG
g_CVar->ConsolePrintf("Calced angs: %f %f, Event angs: %f %f, CURTIME_TICKOUNT: %f, SIMTIME: %f, CALCED_TIME: %f\n", CalcedAngle.pitch, CalcedAngle.yaw, EyeAngles.pitch, EyeAngles.yaw, event_time, player_time, shot_time);
#endif
if (!lag_records.empty())
{
int choked = floorf((event_time - player_time) / g_GlobalVars->interval_per_tick) + 0.5;
choked = (choked > 14 ? 14 : choked < 1 ? 0 : choked);
pEntity->m_vecOrigin() = (lag_records.begin()->m_vecOrigin + (g_GlobalVars->interval_per_tick * lag_records.begin()->m_vecVelocity * choked));
}
CMBacktracking::Get().SetOverwriteTick(pEntity, CalcedAngle, shot_time, 1);
}
}
ei = next;
} while (next != NULL);
return ret;
}
class CEventInfo
{
public:
uint16_t classID; //0x0000 0 implies not in use
char pad_0002[2]; //0x0002
float fire_delay; //0x0004 If non-zero, the delay time when the event should be fired ( fixed up on the client )
char pad_0008[4]; //0x0008
ClientClass *pClientClass; //0x000C
void *pData; //0x0010 Raw event data
char pad_0014[48]; //0x0014
}; //Size: 0x0044
Please note: As long as the enemy is choking while shooting you will go nuts.
Also this is missing fixes to the desynced hitboxes since you aren’t able to tell where the head was when the player shot due to a desync issue.
This is left as a homework to figure out how to fix it.
|