Created
January 4, 2015 06:28
-
-
Save AltimorTASDK/bcfcd3af95b65dc63571 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* CSGO has a bug where players aren't animated on the server while jumping | |
* straight up. 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, | |
int sequence); | |
// CBaseAnimating::SequenceDuration | |
static SequenceDuration_t SequenceDuration; | |
// Takes duration in xmm1 | |
using DrawServerHitboxes_t = void(__thiscall*)( | |
const CBaseAnimating *base_animating, | |
bool monocolor); | |
// CBaseAnimating::DrawServerHitboxes | |
static DrawServerHitboxes_t DrawServerHitboxes; | |
/** | |
* 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 hitbox_debug("sv_hitbox_debug", "0"); | |
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 | |
* | |
* Manually update cycles while jumping. Start at 1 tick if the sequence has | |
* changed, otherwise advance by 1 tick from the previous record. | |
*/ | |
static void __stdcall hook_UpdateLagRecords( | |
const CBaseAnimating *player, | |
CUtlFixedLinkedList<LagRecord> *track, | |
const int a3) | |
{ | |
orig_UpdateLagRecords(player, track, a3); | |
auto &record = track->Element(track->Head()); | |
if(record.m_masterSequence != 8) // "Hop" sequence | |
return; | |
const auto idx = track->Next(track->Head()); | |
if(!track->IsValidIndex(idx)) | |
return; | |
const auto update_cycle = [player]( | |
float *cycle, | |
const float old_cycle, | |
const int seq, | |
const int old_seq) | |
{ | |
const auto dur = SequenceDuration_wrap(player, seq); | |
*cycle = 1.f / dur / 64.f + (seq == old_seq ? old_cycle : 0.f); | |
}; | |
const auto &prev_record = track->Element(idx); | |
update_cycle( | |
&record.m_masterCycle, | |
prev_record.m_masterCycle, | |
record.m_masterSequence, | |
prev_record.m_masterSequence); | |
for(auto i = 0; i < MAX_LAYER_RECORDS; i++) { | |
auto &layer = record.m_layerRecords[i]; | |
const auto &prev_layer = prev_record.m_layerRecords[i]; | |
update_cycle( | |
&layer.m_cycle, | |
prev_layer.m_cycle, | |
layer.m_sequence, | |
prev_layer.m_sequence); | |
} | |
if(hitbox_debug.GetBool()) { | |
_asm xorps xmm1, xmm1 // duration 0 | |
DrawServerHitboxes(player, false); | |
} | |
} | |
/** | |
* 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); | |
const auto *DrawServerHitboxes_sig = "\x83\xEC\x50\x53\x56\x8B\x35"; | |
const auto *DrawServerHitboxes_mask = "xxxxxxx"; | |
DrawServerHitboxes = (DrawServerHitboxes_t)(sigscan( | |
start, | |
end, | |
DrawServerHitboxes_sig, | |
DrawServerHitboxes_mask) - 0x3); | |
} 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