Skip to content

Commit

Permalink
improve lag compensation
Browse files Browse the repository at this point in the history
reduced rewind error (about 20ms -> 10ms average). Blood splashes don't lag behind the monster.
  • Loading branch information
wootguy committed Nov 19, 2024
1 parent 89329c3 commit ae10a58
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 12 deletions.
5 changes: 4 additions & 1 deletion dlls/monster/CBaseMonster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "defaultai.h"
#include "CMonsterMaker.h"
#include "hlds_hooks.h"
#include "lagcomp.h"

#define MONSTER_CUT_CORNER_DIST 8 // 8 means the monster's bounding box is contained without the box of the node in WC

Expand Down Expand Up @@ -4814,10 +4815,12 @@ void CBaseMonster::TraceAttack(entvars_t* pevAttacker, float flDamage, Vector ve
UTIL_Shrapnel(ptr->vecEndPos, ptr->vecPlaneNormal, flDamage, bitsDamageType);
}
if (bitsDamageType & DMG_BLOOD) {
Vector bloodPos = ptr->vecEndPos + get_lagcomp_offset(entindex());

// headshots should always show big blood, no matter how little damage was done.
// The idea is that blood size should be used primarly as an indicator that you hit the weak point.
float bloodSize = ptr->iHitgroup == HITGROUP_HEAD ? V_max(flDamage, 30) : flDamage;
SpawnBlood(ptr->vecEndPos, BloodColor(), bloodSize);
SpawnBlood(bloodPos, BloodColor(), bloodSize);
TraceBleed(bloodSize, vecDir, ptr, bitsDamageType);
}

Expand Down
37 changes: 26 additions & 11 deletions dlls/util/lagcomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ struct WorldState {
};

struct RewindInfo {
bool wasRewound;
bool isCompensated;
EntState restoreState;
};
Expand All @@ -40,6 +39,18 @@ cvar_t* sv_unlag = NULL;
int g_pingHistoryIdx = 0;
float g_pingHistory[PING_SMOOTHING_COUNT][32];

int g_currentRewindIdx = 0;

Vector get_lagcomp_offset(int entindex) {
RewindInfo& info = g_rewinds[entindex];

if (info.isCompensated) {
return info.restoreState.origin - g_worldHistory[g_currentRewindIdx].ents[entindex].origin;
}

return g_vecZero;
}

void update_player_pings() {
for (int i = 1; i <= gpGlobals->maxClients; i++) {
CBaseEntity* plr = UTIL_PlayerByIndex(i);
Expand Down Expand Up @@ -137,18 +148,22 @@ void lagcomp_begin(CBasePlayer* plr) {
bool foundState = false;
float now = g_engfuncs.pfnTime();
float targetTime = now - ping;
float bestDelta = FLT_MAX;

for (int i = 0; i < g_historyWritten; i++) {
float delta = fabs(g_worldHistory[i].time - targetTime);

if (g_worldHistory[idx].time <= targetTime) {
if (delta < bestDelta) {
bestDelta = delta;
foundState = true;
break;
}
else if (--idx < 0) {
idx = MAX_UNLAG_STATES - 1;
idx = i;
}
}

g_currentRewindIdx = idx;

//ALERT(at_console, "best delta %.3f, comp %.2f ago\n", bestDelta, now - targetTime);

if (!foundState) {
ALERT(at_console, "Can't rewind for %.2fs ping.\n", ping);
return;
Expand Down Expand Up @@ -177,11 +192,11 @@ void lagcomp_begin(CBasePlayer* plr) {
restoreState.sequence = vars.sequence;
restoreState.frame = vars.frame;

EntState& entState = worldState.ents[i];
vars.sequence = entState.sequence;
vars.frame = entState.frame;
vars.angles = entState.angles;
UTIL_SetOrigin(&vars, entState.origin);
EntState& rewindState = worldState.ents[i];
vars.sequence = rewindState.sequence;
vars.frame = rewindState.frame;
vars.angles = rewindState.angles;
UTIL_SetOrigin(&vars, rewindState.origin);
}

g_didRewind = true;
Expand Down
3 changes: 3 additions & 0 deletions dlls/util/lagcomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ void lagcomp_begin(CBasePlayer* plr);

// must be called after lagcomp_begin to restore the current world state after a rewind
void lagcomp_end();

// returns difference between lag compensated position and server's position
Vector get_lagcomp_offset(int entindex);

0 comments on commit ae10a58

Please sign in to comment.