void EnginePrediction::StartPrediction(SDK::CUserCmd* cmd)
{
auto local_player = INTERFACES::ClientEntityList->GetClientEntity(INTERFACES::Engine->GetLocalPlayer());
if (!local_player)
return;
auto weapon = reinterpret_cast<SDK::CBaseWeapon*>(INTERFACES::ClientEntityList->GetClientEntityFromHandle((void*)local_player->GetActiveWeaponIndex()));
m_flags_backup = local_player->GetFlags();
local_player->m_pCurrentCommand() = cmd;
static bool is_initialized = false;
if (!is_initialized)
{
m_random_seed = *(int**)(UTILS::FindPattern("client.dll", (PBYTE)"\x8B\x0D\00\x00\x00\x00\xBA\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x83\xC4\x04", "xx????x????x????xxx") + 2);
m_prediction_player = *reinterpret_cast<SDK::CBaseEntity***>(UTILS::FindPattern("client.dll", (PBYTE)"\x89\x35\x00\x00\x00\x00\xF3\x0F\x10\x48", "xx????xxxx") + 2);
is_initialized = true;
}
if (!m_movedata)
m_movedata = (char*)(calloc(1, sizeof(SDK::CMoveData)));
INTERFACES::MoveHelper->SetHost(local_player);
*m_random_seed = cmd->random_seed;
*m_prediction_player = local_player;
INTERFACES::Globals->curtime = UTILS::GetCurtime();
INTERFACES::Globals->frametime = INTERFACES::Globals->interval_per_tick;
//Here we're doing CBasePlayer::UpdateButtonState // NOTE: hard to tell when offsets changed, think of more longterm solution or just dont do this.
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_flForwardMove = cmd->forwardmove;
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_flSideMove = cmd->sidemove;
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_flUpMove = cmd->upmove;
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_nButtons = cmd->buttons;
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_vecViewAngles = cmd->viewangles;
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_vecAngles = cmd->viewangles;
reinterpret_cast<SDK::CMoveData*>(m_movedata)->m_nImpulseCommand = cmd->impulse;
int buttonsChanged = cmd->buttons ^ *reinterpret_cast<int*>(uintptr_t(local_player) + 0x31E8);
*reinterpret_cast<int*>(uintptr_t(local_player) + 0x31DC) = (uintptr_t(local_player) + 0x31E8);
*reinterpret_cast<int*>(uintptr_t(local_player) + 0x31E8) = cmd->buttons;
*reinterpret_cast<int*>(uintptr_t(local_player) + 0x31E0) = cmd->buttons & buttonsChanged; //m_afButtonPressed ~ The changed ones still down are "pressed"
*reinterpret_cast<int*>(uintptr_t(local_player) + 0x31E4) = buttonsChanged & ~cmd->buttons; //m_afButtonReleased ~ The ones not down are "released"
INTERFACES::GameMovement->StartTrackPredictionErrors(local_player);
m_tickbase_backup = local_player->GetTickBase();
INTERFACES::Prediction->SetupMove(local_player, cmd, INTERFACES::MoveHelper, reinterpret_cast<SDK::CMoveData*>(m_movedata));
INTERFACES::GameMovement->ProcessMovement(local_player, reinterpret_cast<SDK::CMoveData*>(m_movedata));
INTERFACES::Prediction->FinishMove(local_player, cmd, reinterpret_cast<SDK::CMoveData*>(m_movedata));
if(weapon)
weapon->UpdateAccuracyPenalty();
}