diff options
-rw-r--r-- | src/game/bg_misc.c | 112 | ||||
-rw-r--r-- | src/game/bg_public.h | 1 | ||||
-rw-r--r-- | src/game/g_active.c | 113 | ||||
-rw-r--r-- | src/game/g_local.h | 12 | ||||
-rw-r--r-- | src/game/g_main.c | 2 |
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}, |