summaryrefslogtreecommitdiff
path: root/src/game/g_active.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_active.c')
-rw-r--r--src/game/g_active.c113
1 files changed, 104 insertions, 9 deletions
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 );
}