Skip to content

Instantly share code, notes, and snippets.

@AltimorTASDK
Created January 1, 2015 20:45
Show Gist options
  • Save AltimorTASDK/7916872a3b4c478532ea to your computer and use it in GitHub Desktop.
Save AltimorTASDK/7916872a3b4c478532ea to your computer and use it in GitHub Desktop.
/*
* Lag compensation has a bug where animation cycletime is off by two ticks,
* which makes it difficult to hit people jumping or transitioning to a duck.
* Altimor has taken a break from his Persona 3 toaster waifu to correct this
* catastrophe. APPLAUSE
*/
#include "util.h"
#include "plugin.h"
#include "lagcomp.h"
#include "baseanimating.h"
#include <stdexcept>
#include <cstdint>
#include <Windows.h>
#include <detours.h>
// Returns in xmm0
using SequenceDuration_t = __m128(__thiscall*)(
const CBaseAnimating *base_animating,
const void *studiohdr,
const int sequence);
// CBaseAnimating::SequenceDuration
static SequenceDuration_t SequenceDuration;
/**
* SequenceDuration_wrap - Make SequenceDuration usable from C++ code
* @base_animating: Pointer to the CBaseAnimating
* @sequence: Sequence number
*
* Return a 32 bit float instead of a 128 bit xmm register
*/
static float SequenceDuration_wrap(
const CBaseAnimating *base_animating,
const int sequence)
{
const auto *studiohdr = *(void**)((uintptr_t)(base_animating) + 0x490);
const auto xmm0 = SequenceDuration(base_animating, studiohdr, sequence);
float result;
_mm_store_ss(&result, xmm0);
return result;
}
ConVar cycle_offset("sv_lagcomp_anim_offset", "2");
using UpdateLagRecords_t = void(__stdcall*)(
const CBaseAnimating *player,
CUtlFixedLinkedList<LagRecord> *track,
const int a3);
static UpdateLagRecords_t orig_UpdateLagRecords;
/**
* hook_UpdateLagRecords - Hook for CLagCompensationManager::UpdateLagRecords
* @player: Pointer to player to be updated
* @track: Pointer to list of LagRecords
* @a3: Never used in the original function, great job Valve
*
* Advance the master cycle and layer cycles by the desired number of ticks
*/
static void __stdcall hook_UpdateLagRecords(
const CBaseAnimating *player,
CUtlFixedLinkedList<LagRecord> *track,
const int a3)
{
orig_UpdateLagRecords(player, track, a3);
const auto apply_fix = [player](float *cycle, const int sequence)
{
const auto duration = SequenceDuration_wrap(player, sequence);
*cycle += cycle_offset.GetFloat() / duration / 64.f;
};
auto &record = track->Element(track->Head());
apply_fix(&record.m_masterCycle, record.m_masterSequence);
for(auto &layer : record.m_layerRecords)
apply_fix(&layer.m_cycle, layer.m_sequence);
}
/**
* plugin::Load - Valve plugin load method override
* @interfaceFactory: engine.dll factory
* @gameServerFactory: server.dll factory
*
* Grab offsets and detour the function where anim cycletime is saved
*/
bool plugin::Load(
CreateInterfaceFn interfaceFactory,
CreateInterfaceFn gameServerFactory)
{
ConnectTier1Libraries(&interfaceFactory, 1);
ConnectTier2Libraries(&interfaceFactory, 1);
ConVar_Register(0);
uintptr_t start, end;
get_module_bounds("server.dll", &start, &end);
// Scan for CLagCompensationManager::UpdateLagRecords
uintptr_t UpdateLagRecords;
try {
const auto *UpdateLagRecords_sig = "\x53\x56\x57\x81\xF9";
const auto *UpdateLagRecords_mask = "xxxxx";
UpdateLagRecords = sigscan(
start,
end,
UpdateLagRecords_sig,
UpdateLagRecords_mask) - 0xF;
const auto *SequenceDuration_sig = "\x85\xF6\x75\x2F\x8B\x47\x5C";
const auto *SequenceDuration_mask = "xxxxxxx";
SequenceDuration = (SequenceDuration_t)(sigscan(
start,
end,
SequenceDuration_sig,
SequenceDuration_mask) - 0xA);
} catch(...) {
Error("Sigscans failed!\n");
return false;
}
orig_UpdateLagRecords = (UpdateLagRecords_t)(DetourFunction(
(byte*)(UpdateLagRecords),
(byte*)(hook_UpdateLagRecords)));
return true;
}
/**
* plugin::Unload - Valve plugin unload method override
*
* Unregister the ICVar and disconnect libraries
*/
void plugin::Unload()
{
ConVar_Unregister();
DisconnectTier2Libraries();
DisconnectTier1Libraries();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment