sof2-sdk/code/game/g_antilag.c
2002-07-15 00:00:00 +00:00

336 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_DOUBLED_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.mins[0] = other->client->minSave[0];
other->r.mins[1] = other->client->minSave[1];
other->r.svFlags &= (~SVF_DOUBLED_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];
// 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_DOUBLED_BBOX;
}
// Relink the entity into the world
trap_LinkEntity ( other );
}
}