diff options
Diffstat (limited to 'src/game/g_active.c')
-rw-r--r-- | src/game/g_active.c | 113 |
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 ); } |