345 lines
11 KiB
C
345 lines
11 KiB
C
// Copyright (C) 2000-2001 Raven Software, Inc.
|
|
//
|
|
// g_antilag.c -- handles server side anti-lag
|
|
|
|
#include "g_local.h"
|
|
|
|
|
|
/*
|
|
================
|
|
G_UpdateClientAntiLag
|
|
================
|
|
*/
|
|
void G_UpdateClientAntiLag ( gentity_t* ent )
|
|
{
|
|
int head;
|
|
int newtime;
|
|
|
|
head = ent->client->antilagHead;
|
|
|
|
// If on a new frame snap the head up to the end of the last frame and
|
|
// add a new head
|
|
if ( ent->client->antilag[head].leveltime < level.time )
|
|
{
|
|
ent->client->antilag[head].time = level.previousTime;
|
|
|
|
// Move to the next position
|
|
if ( (++ent->client->antilagHead) > MAX_ANTILAG )
|
|
{
|
|
ent->client->antilagHead = 0;
|
|
}
|
|
|
|
head = ent->client->antilagHead;
|
|
}
|
|
|
|
// Bots only move once per frame
|
|
if ( ent->r.svFlags & SVF_BOT )
|
|
{
|
|
newtime = level.time;
|
|
}
|
|
else
|
|
{
|
|
// calculate the actual server time
|
|
newtime = level.previousTime + trap_Milliseconds() - level.frameStartTime;
|
|
|
|
if ( newtime > level.time )
|
|
{
|
|
newtime = level.time;
|
|
}
|
|
else if ( newtime <= level.previousTime )
|
|
{
|
|
newtime = level.previousTime + 1;
|
|
}
|
|
}
|
|
|
|
// Copy the clients current state into the antilag cache
|
|
ent->client->antilag[head].leveltime = level.time;
|
|
ent->client->antilag[head].time = newtime;
|
|
VectorCopy ( ent->r.currentOrigin, ent->client->antilag[head].rOrigin );
|
|
VectorCopy ( ent->r.currentAngles, ent->client->antilag[head].rAngles );
|
|
VectorCopy ( ent->r.mins, ent->client->antilag[head].mins );
|
|
VectorCopy ( ent->r.maxs, ent->client->antilag[head].maxs );
|
|
|
|
VectorCopy ( ent->client->ghoulLegsAngles, ent->client->antilag[head].legsAngles );
|
|
VectorCopy ( ent->client->ghoulLowerTorsoAngles, ent->client->antilag[head].lowerTorsoAngles );
|
|
VectorCopy ( ent->client->ghoulUpperTorsoAngles, ent->client->antilag[head].upperTorsoAngles );
|
|
VectorCopy ( ent->client->ghoulHeadAngles, ent->client->antilag[head].headAngles );
|
|
|
|
ent->client->antilag[head].legsAnim = ent->s.legsAnim;
|
|
ent->client->antilag[head].torsoAnim = ent->s.torsoAnim;
|
|
ent->client->antilag[head].pm_flags = ent->client->ps.pm_flags;
|
|
ent->client->antilag[head].leanTime = ent->client->ps.leanTime;
|
|
}
|
|
|
|
/*
|
|
================
|
|
G_UndoClientAntiLag
|
|
================
|
|
*/
|
|
void G_UndoClientAntiLag ( gentity_t* ent )
|
|
{
|
|
// If the client isnt already in the past then
|
|
// dont bother doing anything
|
|
if ( ent->client->antilagUndo.leveltime != level.time )
|
|
return;
|
|
|
|
// Move the client back into reality by moving over the undo information
|
|
VectorCopy ( ent->client->antilagUndo.rOrigin, ent->r.currentOrigin );
|
|
VectorCopy ( ent->client->antilagUndo.rAngles, ent->r.currentAngles );
|
|
VectorCopy ( ent->client->antilagUndo.mins, ent->r.mins );
|
|
VectorCopy ( ent->client->antilagUndo.maxs, ent->r.maxs );
|
|
|
|
VectorCopy ( ent->client->antilagUndo.legsAngles, ent->client->ghoulLegsAngles );
|
|
VectorCopy ( ent->client->antilagUndo.lowerTorsoAngles, ent->client->ghoulLowerTorsoAngles );
|
|
VectorCopy ( ent->client->antilagUndo.upperTorsoAngles, ent->client->ghoulUpperTorsoAngles );
|
|
VectorCopy ( ent->client->antilagUndo.headAngles, ent->client->ghoulHeadAngles );
|
|
|
|
ent->s.legsAnim = ent->client->antilagUndo.legsAnim;
|
|
ent->s.torsoAnim = ent->client->antilagUndo.torsoAnim;
|
|
ent->client->ps.pm_flags = ent->client->antilagUndo.pm_flags;
|
|
ent->client->ps.leanTime = ent->client->antilagUndo.leanTime;
|
|
|
|
// Mark the undo information so it cant be used again
|
|
ent->client->antilagUndo.leveltime = 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
G_ApplyClientAntiLag
|
|
================
|
|
*/
|
|
void G_ApplyClientAntiLag ( gentity_t* ent, int time )
|
|
{
|
|
float lerp;
|
|
int from;
|
|
int to;
|
|
|
|
// Find the two pieces of history information that sandwitch the
|
|
// time we are looking for
|
|
from = ent->client->antilagHead;
|
|
to = ent->client->antilagHead;
|
|
do
|
|
{
|
|
if ( ent->client->antilag[from].time <= time )
|
|
{
|
|
break;
|
|
}
|
|
|
|
to = from;
|
|
from--;
|
|
|
|
if ( from < 0 )
|
|
{
|
|
from = MAX_ANTILAG - 1;
|
|
}
|
|
}
|
|
while ( from != ent->client->antilagHead );
|
|
|
|
// If the from is equal to the to then there wasnt even
|
|
// one piece of information worth using so just use the current time frame
|
|
if ( from == to )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Save the undo information if its not already saved
|
|
if ( ent->client->antilagUndo.leveltime != level.time )
|
|
{
|
|
// Save the undo information
|
|
ent->client->antilagUndo.leveltime = level.time;
|
|
|
|
VectorCopy ( ent->r.currentOrigin, ent->client->antilagUndo.rOrigin );
|
|
VectorCopy ( ent->r.currentAngles, ent->client->antilagUndo.rAngles );
|
|
VectorCopy ( ent->r.mins, ent->client->antilagUndo.mins );
|
|
VectorCopy ( ent->r.maxs, ent->client->antilagUndo.maxs );
|
|
|
|
VectorCopy ( ent->client->ghoulLegsAngles, ent->client->antilagUndo.legsAngles );
|
|
VectorCopy ( ent->client->ghoulLowerTorsoAngles, ent->client->antilagUndo.lowerTorsoAngles );
|
|
VectorCopy ( ent->client->ghoulUpperTorsoAngles, ent->client->antilagUndo.upperTorsoAngles );
|
|
VectorCopy ( ent->client->ghoulHeadAngles, ent->client->antilagUndo.headAngles );
|
|
|
|
ent->client->antilagUndo.legsAnim = ent->s.legsAnim;
|
|
ent->client->antilagUndo.torsoAnim = ent->s.torsoAnim;
|
|
ent->client->antilagUndo.pm_flags = ent->client->ps.pm_flags;
|
|
ent->client->antilagUndo.leanTime = ent->client->ps.leanTime;
|
|
}
|
|
|
|
// If the best history found was the last in the list then
|
|
// dont lerp, just use the last one
|
|
if ( from == ent->client->antilagHead )
|
|
{
|
|
VectorCopy ( ent->client->antilag[to].rOrigin, ent->r.currentOrigin );
|
|
VectorCopy ( ent->client->antilag[to].rAngles, ent->r.currentAngles );
|
|
VectorCopy ( ent->client->antilag[to].mins, ent->r.maxs );
|
|
VectorCopy ( ent->client->antilag[to].maxs, ent->r.mins );
|
|
|
|
VectorCopy ( ent->client->antilag[to].legsAngles, ent->client->ghoulLegsAngles );
|
|
VectorCopy ( ent->client->antilag[to].lowerTorsoAngles, ent->client->ghoulLowerTorsoAngles );
|
|
VectorCopy ( ent->client->antilag[to].upperTorsoAngles, ent->client->ghoulUpperTorsoAngles );
|
|
VectorCopy ( ent->client->antilag[to].headAngles, ent->client->ghoulHeadAngles );
|
|
|
|
ent->s.legsAnim = ent->client->antilag[to].legsAnim;
|
|
ent->s.torsoAnim = ent->client->antilag[to].torsoAnim;
|
|
ent->client->ps.pm_flags = ent->client->antilag[to].pm_flags;
|
|
ent->client->ps.leanTime = ent->client->antilag[to].leanTime;
|
|
}
|
|
else
|
|
{
|
|
// Calculate the lerp value to use for the vectors
|
|
lerp = (float)(time - ent->client->antilag[from].time) / (float)(ent->client->antilag[to].time - ent->client->antilag[from].time);
|
|
|
|
// Lerp all the vectors between the before and after history information
|
|
LerpVector ( ent->client->antilag[from].rOrigin, ent->client->antilag[to].rOrigin, lerp, ent->r.currentOrigin );
|
|
LerpVector ( ent->client->antilag[from].rAngles, ent->client->antilag[to].rAngles, lerp, ent->r.currentAngles );
|
|
LerpVector ( ent->client->antilag[from].maxs, ent->client->antilag[to].maxs, lerp, ent->r.maxs );
|
|
LerpVector ( ent->client->antilag[from].mins, ent->client->antilag[to].mins, lerp, ent->r.mins );
|
|
|
|
LerpVector ( ent->client->antilag[from].legsAngles, ent->client->antilag[to].legsAngles, lerp, ent->client->ghoulLegsAngles );
|
|
LerpVector ( ent->client->antilag[from].lowerTorsoAngles, ent->client->antilag[to].lowerTorsoAngles, lerp, ent->client->ghoulLowerTorsoAngles );
|
|
LerpVector ( ent->client->antilag[from].upperTorsoAngles, ent->client->antilag[to].upperTorsoAngles, lerp, ent->client->ghoulUpperTorsoAngles );
|
|
LerpVector ( ent->client->antilag[from].headAngles, ent->client->antilag[to].headAngles, lerp, ent->client->ghoulHeadAngles );
|
|
|
|
ent->client->ps.leanTime = ent->client->antilag[from].leanTime + (ent->client->antilag[from].leanTime-ent->client->antilag[to].leanTime) * lerp;
|
|
|
|
ent->s.legsAnim = ent->client->antilag[to].legsAnim;
|
|
ent->s.torsoAnim = ent->client->antilag[to].torsoAnim;
|
|
ent->client->ps.pm_flags = ent->client->antilag[to].pm_flags;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
G_UndoAntiLag
|
|
================
|
|
*/
|
|
void G_UndoAntiLag ( void )
|
|
{
|
|
int i;
|
|
|
|
// Undo all history
|
|
for ( i = 0; i < level.numConnectedClients; i ++ )
|
|
{
|
|
gentity_t* other = &g_entities[level.sortedClients[i]];
|
|
|
|
if ( other->client->pers.connected != CON_CONNECTED )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Skip clients that are spectating
|
|
if ( G_IsClientSpectating ( other->client ) || G_IsClientDead ( other->client ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( other->r.svFlags & SVF_INFLATED_BBOX )
|
|
{
|
|
// Put the hitbox back the way it was
|
|
other->r.maxs[0] = other->client->maxSave[0];
|
|
other->r.maxs[1] = other->client->maxSave[1];
|
|
other->r.maxs[2] = other->client->maxSave[2];
|
|
|
|
other->r.mins[0] = other->client->minSave[0];
|
|
other->r.mins[1] = other->client->minSave[1];
|
|
|
|
other->r.svFlags &= (~SVF_INFLATED_BBOX);
|
|
}
|
|
|
|
G_UndoClientAntiLag ( other );
|
|
|
|
// Relink the entity into the world
|
|
trap_LinkEntity ( other );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
G_ApplyAntiLag
|
|
================
|
|
*/
|
|
void G_ApplyAntiLag ( gentity_t* ref, qboolean enlargeHitBox )
|
|
{
|
|
int i;
|
|
int reftime;
|
|
|
|
// Figure out the reference time based on the reference clients server time
|
|
reftime = ref->client->pers.cmd.serverTime;
|
|
if ( reftime > level.time )
|
|
{
|
|
reftime = level.time;
|
|
}
|
|
|
|
// Move all the clients back into the reference clients time frame.
|
|
for ( i = 0; i < level.numConnectedClients; i ++ )
|
|
{
|
|
gentity_t* other = &g_entities[level.sortedClients[i]];
|
|
|
|
if ( other->client->pers.connected != CON_CONNECTED )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Skip the reference client
|
|
if ( other == ref )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Skip entities not in use
|
|
if ( !other->inuse )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Skip clients that are spectating
|
|
if ( G_IsClientSpectating ( other->client ) || G_IsClientDead ( other->client ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Dont bring them back in time unless requested
|
|
if ( !(ref->r.svFlags & SVF_BOT) & ref->client->pers.antiLag )
|
|
{
|
|
// Apply the antilag to this player
|
|
G_ApplyClientAntiLag ( other, reftime );
|
|
}
|
|
|
|
if ( enlargeHitBox )
|
|
{
|
|
other->client->minSave[0] = other->r.mins[0];
|
|
other->client->minSave[1] = other->r.mins[1];
|
|
|
|
other->client->maxSave[0] = other->r.maxs[0];
|
|
other->client->maxSave[1] = other->r.maxs[1];
|
|
other->client->maxSave[2] = other->r.maxs[2];
|
|
|
|
if ( other->client->ps.pm_flags & PMF_DUCKED )
|
|
{
|
|
other->r.maxs[2] += 10;
|
|
}
|
|
|
|
// Adjust the hit box to account for hands and such
|
|
// that are sticking out of the normal bounding box
|
|
|
|
if ( other->client->ps.pm_flags & PMF_LEANING )
|
|
{
|
|
other->r.maxs[0] *= 3.0f;
|
|
other->r.maxs[1] *= 3.0f;
|
|
other->r.mins[0] *= 3.0f;
|
|
other->r.mins[1] *= 3.0f;
|
|
}
|
|
else
|
|
{
|
|
other->r.maxs[0] *= 2.0f;
|
|
other->r.maxs[1] *= 2.0f;
|
|
other->r.mins[0] *= 2.0f;
|
|
other->r.mins[1] *= 2.0f;
|
|
}
|
|
|
|
other->r.svFlags |= SVF_INFLATED_BBOX;
|
|
}
|
|
|
|
// Relink the entity into the world
|
|
trap_LinkEntity ( other );
|
|
}
|
|
}
|