summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/bg_misc.c112
-rw-r--r--src/game/bg_public.h1
-rw-r--r--src/game/g_active.c113
-rw-r--r--src/game/g_local.h12
-rw-r--r--src/game/g_main.c2
5 files changed, 118 insertions, 122 deletions
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 4b0d56f..8810c12 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -3416,118 +3416,6 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean
s->otherEntityNum = ps->otherEntityNum;
}
-
-/*
-========================
-BG_PlayerStateToEntityStateExtraPolate
-
-This is done after each set of usercmd_t on the server,
-and after local prediction on the client
-========================
-*/
-void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap )
-{
- int i;
-
- if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR || ps->pm_type == PM_FREEZE )
- s->eType = ET_INVISIBLE;
- else if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
- s->eType = ET_INVISIBLE;
- else
- s->eType = ET_PLAYER;
-
- s->number = ps->clientNum;
-
- s->pos.trType = TR_LINEAR_STOP;
- VectorCopy( ps->origin, s->pos.trBase );
-
- if( snap )
- SnapVector( s->pos.trBase );
-
- // set the trDelta for flag direction and linear prediction
- VectorCopy( ps->velocity, s->pos.trDelta );
- // set the time for linear prediction
- s->pos.trTime = time;
- // set maximum extra polation time
- s->pos.trDuration = 50; // 1000 / sv_fps (default = 20)
-
- s->apos.trType = TR_INTERPOLATE;
- VectorCopy( ps->viewangles, s->apos.trBase );
- if( snap )
- SnapVector( s->apos.trBase );
-
- //TA: i need for other things :)
- //s->angles2[YAW] = ps->movementDir;
- s->time2 = ps->movementDir;
- s->legsAnim = ps->legsAnim;
- s->torsoAnim = ps->torsoAnim;
- s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
- // so corpses can also reference the proper config
- s->eFlags = ps->eFlags;
-
- if( ps->stats[STAT_HEALTH] <= 0 )
- s->eFlags |= EF_DEAD;
- else
- s->eFlags &= ~EF_DEAD;
-
- if( ps->stats[ STAT_STATE ] & SS_BLOBLOCKED )
- s->eFlags |= EF_BLOBLOCKED;
- else
- s->eFlags &= ~EF_BLOBLOCKED;
-
- if( ps->externalEvent )
- {
- s->event = ps->externalEvent;
- s->eventParm = ps->externalEventParm;
- }
- else if( ps->entityEventSequence < ps->eventSequence )
- {
- int seq;
-
- if( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS )
- ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
-
- seq = ps->entityEventSequence & ( MAX_PS_EVENTS - 1 );
- s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
- s->eventParm = ps->eventParms[ seq ];
- ps->entityEventSequence++;
- }
-
- s->weapon = ps->weapon;
- s->groundEntityNum = ps->groundEntityNum;
-
- //store items held and active items in modelindex and modelindex2
- s->modelindex = 0;
- s->modelindex2 = 0;
-
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, ps->stats ) )
- {
- s->modelindex |= 1 << i;
-
- if( BG_UpgradeIsActive( i, ps->stats ) )
- s->modelindex2 |= 1 << i;
- }
- }
-
- // use misc field to store team/class info:
- s->misc = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 );
-
- //TA: have to get the surfNormal thru somehow...
- VectorCopy( ps->grapplePoint, s->angles2 );
- if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- s->eFlags |= EF_WALLCLIMBCEILING;
-
- s->loopSound = ps->loopSound;
- s->generic1 = ps->generic1;
-
- if( s->generic1 <= WPM_NONE || s->generic1 >= WPM_NUM_WEAPONMODES )
- s->generic1 = WPM_PRIMARY;
-
- s->otherEntityNum = ps->otherEntityNum;
-}
-
/*
========================
BG_WeaponIsFull
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 790e206..98c0755 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -1258,7 +1258,6 @@ void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t res
void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );
void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap );
-void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap );
qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime );
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 5bee472..c1cc9f0 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1568,6 +1568,98 @@ static void ClientGradualFunds( gentity_t *ent )
/*
==============
+ClientSavePosition
+==============
+*/
+static void ClientSavePosition(gentity_t *ent, int client_time)
+{
+ savedPosition_t *pos;
+
+ pos = ent->client->savedPositions +
+ (ent->client->savedPositionsCount + 1) % MAX_SAVED_POSITIONS;
+ ent->client->savedPositionsCount++;
+
+ VectorCopy(ent->s.pos.trBase, pos->origin);
+ pos->time = level.time;
+ pos->client_time = client_time;
+}
+
+/*
+==============
+ClientExtrapolate
+==============
+*/
+static void ClientExtrapolate(gentity_t *ent)
+{
+ savedPosition_t *pos1, *pos2;
+ vec3_t dxdt;
+ int flags, time_delta, time_since;
+
+ flags = g_smoothClients.integer;
+ if (!flags)
+ return;
+
+ // Don't bother if the player is lagging too hard.
+ if (ent->s.eFlags & EF_CONNECTION)
+ return;
+
+ // Need at least 2 samples for linear extrapolation.
+ if (ent->client->savedPositionsCount < 2)
+ return;
+
+ pos1 = ent->client->savedPositions +
+ ent->client->savedPositionsCount % MAX_SAVED_POSITIONS;
+ pos2 = ent->client->savedPositions +
+ (ent->client->savedPositionsCount + MAX_SAVED_POSITIONS - 1)
+ % MAX_SAVED_POSITIONS;
+
+ switch ((flags & (2 | 4 | 8)) >> 1) {
+ default:
+ Com_Printf("^3warning: g_smoothClients has a bad value\n");
+ case 0:
+ time_delta = pos2->time - pos1->time;
+ break;
+ case 1:
+ time_delta = pos2->client_time - pos1->client_time;
+ break;
+ case 2:
+ time_delta = 50;
+ break;
+ case 3:
+ time_delta = 25;
+ break;
+ case 4:
+ time_delta = 16;
+ break;
+ }
+
+ VectorSubtract(pos2->origin, pos1->origin, dxdt);
+ VectorScale(dxdt, pos2->time - pos1->time, dxdt);
+
+ if (flags & 16)
+ time_since = level.time - pos2->client_time;
+ else
+ time_since = level.time - pos2->time;
+
+ VectorMA(pos1->origin, time_delta, dxdt, ent->s.pos.trBase);
+
+ if (g_debugExtrapolation.integer) {
+ Com_Printf("Extrapolated player %i:\n", (int)(ent - g_entities));
+ Com_Printf(" pos1=(%f, %f, %f) at t=%i, t'=%i\n",
+ pos1->origin[0], pos1->origin[1], pos1->origin[2],
+ pos1->time, pos1->client_time);
+ Com_Printf(" pos2=(%f, %f, %f) at t=%i, t'=%i\n",
+ pos2->origin[0], pos2->origin[1], pos2->origin[2],
+ pos2->time, pos2->client_time);
+ Com_Printf(" dxdt=(%f, %f, %f), td=%i, ts=%i\n",
+ dxdt[0], dxdt[1], dxdt[2], time_delta, time_since);
+ Com_Printf(" out=(%f, %f, %f)\n", ent->s.pos.trBase[0],
+ ent->s.pos.trBase[1], ent->s.pos.trBase[2]);
+ }
+}
+
+/*
+==============
ClientThink
This will be called once for each client frame, which will
@@ -1882,10 +1974,7 @@ void ClientThink_real( gentity_t *ent )
if ( level.paused ) client->ps.pm_type = real_pm_type;
- if( g_smoothClients.integer )
- BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
- else
- BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+ BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
SendPendingPredictableEvents( &ent->client->ps );
@@ -2036,6 +2125,8 @@ void ClientThink_real( gentity_t *ent )
ent->suicideTime = 0;
}
+
+ ClientSavePosition( ent, ucmd->serverTime );
}
/*
@@ -2170,7 +2261,7 @@ void ClientEndFrame( gentity_t *ent )
P_DamageFeedback( ent );
// add the EF_CONNECTION flag if we haven't gotten commands recently
- if( level.time - ent->client->lastCmdTime > 1000 )
+ if( level.time - ent->client->lastCmdTime > 500 )
ent->s.eFlags |= EF_CONNECTION;
else
ent->s.eFlags &= ~EF_CONNECTION;
@@ -2184,10 +2275,14 @@ void ClientEndFrame( gentity_t *ent )
G_SetClientSound( ent );
// set the latest infor
- if( g_smoothClients.integer )
- BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
- else
- BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+ BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+
+ if( ent->client->extrapolate )
+ ClientExtrapolate( ent );
+
+ // This flag will go down as soon as a client frame is received.
+ // If a frame isn't received then it'll stay up and trigger extrapolation.
+ ent->client->extrapolate = qtrue;
SendPendingPredictableEvents( &ent->client->ps );
}
diff --git a/src/game/g_local.h b/src/game/g_local.h
index a3c02c8..28bd059 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -450,6 +450,13 @@ typedef struct unlagged_s {
qboolean used;
} unlagged_t;
+#define MAX_SAVED_POSITIONS 3
+typedef struct {
+ vec3_t origin;
+ int time;
+ int client_time;
+} savedPosition_t;
+
// this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess'
struct gclient_s
@@ -550,6 +557,10 @@ struct gclient_s
int tkcredits[ MAX_CLIENTS ];
int revertCookie;
+
+ qboolean extrapolate;
+ savedPosition_t savedPositions[MAX_SAVED_POSITIONS];
+ int savedPositionsCount;
};
@@ -1391,6 +1402,7 @@ extern vmCvar_t g_popularMapsVotePercent;
extern vmCvar_t g_banIPs;
extern vmCvar_t g_filterBan;
extern vmCvar_t g_smoothClients;
+extern vmCvar_t g_debugExtrapolation;
extern vmCvar_t g_outdatedClientMessage;
extern vmCvar_t pmove_fixed;
extern vmCvar_t pmove_msec;
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 55508be..1c6d84e 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -122,6 +122,7 @@ vmCvar_t g_popularMapsVotePercent;
vmCvar_t g_banIPs;
vmCvar_t g_filterBan;
vmCvar_t g_smoothClients;
+vmCvar_t g_debugExtrapolation;
vmCvar_t g_outdatedClientMessage;
vmCvar_t pmove_fixed;
vmCvar_t pmove_msec;
@@ -416,6 +417,7 @@ static cvarTable_t gameCvarTable[ ] =
"Set a name by pressing Escape and choosing Options", CVAR_ARCHIVE, 0, qfalse},
{ &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
+ { &g_debugExtrapolation, "g_debugExtrapolation", "0", 0, 0, qfalse},
{ &g_outdatedClientMessage, "g_outdatedClientMessage", "", CVAR_ARCHIVE, 0, qfalse},
{ &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse},
{ &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse},