diff options
Diffstat (limited to 'src/cgame/cg_predict.c')
-rw-r--r-- | src/cgame/cg_predict.c | 384 |
1 files changed, 180 insertions, 204 deletions
diff --git a/src/cgame/cg_predict.c b/src/cgame/cg_predict.c index d28c9ba6..fabe1065 100644 --- a/src/cgame/cg_predict.c +++ b/src/cgame/cg_predict.c @@ -36,33 +36,36 @@ of the entities that are actually solid, to make for more efficient collision detection ==================== */ -void CG_BuildSolidList( void ) { - int i; - centity_t *cent; - snapshot_t *snap; +void CG_BuildSolidList( void ) +{ + int i; + centity_t *cent; + snapshot_t *snap; entityState_t *ent; cg_numSolidEntities = 0; cg_numTriggerEntities = 0; - if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) { + if( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) snap = cg.nextSnap; - } else { + else snap = cg.snap; - } - for ( i = 0 ; i < snap->numEntities ; i++ ) { + for( i = 0; i < snap->numEntities; i++ ) + { cent = &cg_entities[ snap->entities[ i ].number ]; ent = ¢->currentState; - if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) { - cg_triggerEntities[cg_numTriggerEntities] = cent; + if( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) + { + cg_triggerEntities[ cg_numTriggerEntities ] = cent; cg_numTriggerEntities++; continue; } - if ( cent->nextState.solid ) { - cg_solidEntities[cg_numSolidEntities] = cent; + if( cent->nextState.solid ) + { + cg_solidEntities[ cg_numSolidEntities ] = cent; cg_numSolidEntities++; continue; } @@ -76,38 +79,42 @@ CG_ClipMoveToEntities ==================== */ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask, trace_t *tr, qboolean capsule ) { - int i, x, zd, zu; - trace_t trace; + int skipNumber, int mask, trace_t *tr, qboolean capsule ) +{ + int i, x, zd, zu; + trace_t trace; entityState_t *ent; clipHandle_t cmodel; - vec3_t bmins, bmaxs; - vec3_t origin, angles; - centity_t *cent; + vec3_t bmins, bmaxs; + vec3_t origin, angles; + centity_t *cent; - for ( i = 0 ; i < cg_numSolidEntities ; i++ ) { + for( i = 0; i < cg_numSolidEntities; i++ ) + { cent = cg_solidEntities[ i ]; ent = ¢->currentState; - if ( ent->number == skipNumber ) { + if( ent->number == skipNumber ) continue; - } - if ( ent->solid == SOLID_BMODEL ) { + if( ent->solid == SOLID_BMODEL ) + { // special value for bmodel cmodel = trap_CM_InlineModel( ent->modelindex ); VectorCopy( cent->lerpAngles, angles ); BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin ); - } else { + } + else + { // encoded bbox - x = (ent->solid & 255); - zd = ((ent->solid>>8) & 255); - zu = ((ent->solid>>16) & 255) - 32; + x = ( ent->solid & 255 ); + zd = ( ( ent->solid >> 8 ) & 255 ); + zu = ( ( ent->solid >> 16 ) & 255 ) - 32; - bmins[0] = bmins[1] = -x; - bmaxs[0] = bmaxs[1] = x; - bmins[2] = -zd; - bmaxs[2] = zu; + bmins[ 0 ] = bmins[ 1 ] = -x; + bmaxs[ 0 ] = bmaxs[ 1 ] = x; + bmins[ 2 ] = -zd; + bmaxs[ 2 ] = zu; cmodel = trap_CM_TempBoxModel( bmins, bmaxs ); VectorCopy( vec3_origin, angles ); @@ -118,23 +125,24 @@ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const if( capsule ) { trap_CM_TransformedCapsuleTrace ( &trace, start, end, - mins, maxs, cmodel, mask, origin, angles); - } + mins, maxs, cmodel, mask, origin, angles ); + } else { trap_CM_TransformedBoxTrace ( &trace, start, end, - mins, maxs, cmodel, mask, origin, angles); + mins, maxs, cmodel, mask, origin, angles ); } - if (trace.allsolid || trace.fraction < tr->fraction) { + if( trace.allsolid || trace.fraction < tr->fraction ) + { trace.entityNum = ent->number; *tr = trace; - } else if (trace.startsolid) { - tr->startsolid = qtrue; } - if ( tr->allsolid ) { + else if( trace.startsolid ) + tr->startsolid = qtrue; + + if( tr->allsolid ) return; - } } } @@ -144,13 +152,14 @@ CG_Trace ================ */ void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask ) { + int skipNumber, int mask ) +{ trace_t t; - trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask); + trap_CM_BoxTrace( &t, start, end, mins, maxs, 0, mask ); t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE; // check all other solid models - CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t, qfalse); + CG_ClipMoveToEntities( start, mins, maxs, end, skipNumber, mask, &t, qfalse ); *result = t; } @@ -161,13 +170,14 @@ CG_CapTrace ================ */ void CG_CapTrace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask ) { + int skipNumber, int mask ) +{ trace_t t; - trap_CM_CapsuleTrace ( &t, start, end, mins, maxs, 0, mask); + trap_CM_CapsuleTrace( &t, start, end, mins, maxs, 0, mask ); t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE; // check all other solid models - CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t, qtrue); + CG_ClipMoveToEntities( start, mins, maxs, end, skipNumber, mask, &t, qtrue ); *result = t; } @@ -219,9 +229,10 @@ Generates cg.predictedPlayerState by interpolating between cg.snap->player_state and cg.nextFrame->player_state ======================== */ -static void CG_InterpolatePlayerState( qboolean grabAngles ) { - float f; - int i; +static void CG_InterpolatePlayerState( qboolean grabAngles ) +{ + float f; + int i; playerState_t *out; snapshot_t *prev, *next; @@ -232,84 +243,42 @@ static void CG_InterpolatePlayerState( qboolean grabAngles ) { *out = cg.snap->ps; // if we are still allowing local input, short circuit the view angles - if ( grabAngles ) { + if( grabAngles ) + { usercmd_t cmd; int cmdNum; - cmdNum = trap_GetCurrentCmdNumber(); + cmdNum = trap_GetCurrentCmdNumber( ); trap_GetUserCmd( cmdNum, &cmd ); PM_UpdateViewAngles( out, &cmd ); } // if the next frame is a teleport, we can't lerp to it - if ( cg.nextFrameTeleport ) { + if( cg.nextFrameTeleport ) return; - } - if ( !next || next->serverTime <= prev->serverTime ) { + if( !next || next->serverTime <= prev->serverTime ) return; - } f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime ); i = next->ps.bobCycle; - if ( i < prev->ps.bobCycle ) { + if( i < prev->ps.bobCycle ) i += 256; // handle wraparound - } + out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle ); - for ( i = 0 ; i < 3 ; i++ ) { - out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] ); - if ( !grabAngles ) { - out->viewangles[i] = LerpAngle( - prev->ps.viewangles[i], next->ps.viewangles[i], f ); - } - out->velocity[i] = prev->ps.velocity[i] + - f * (next->ps.velocity[i] - prev->ps.velocity[i] ); - } - -} - -/* -=================== -CG_TouchItem -=================== -*/ -static void CG_TouchItem( centity_t *cent ) { - gitem_t *item; - int ammo, clips, maxclips; - - BG_unpackAmmoArray( item->giTag, cg.predictedPlayerState.ammo, cg.predictedPlayerState.powerups, &ammo, &clips, &maxclips ); - - if ( !cg_predictItems.integer ) { - return; + for( i = 0; i < 3; i++ ) + { + out->origin[ i ] = prev->ps.origin[ i ] + f * ( next->ps.origin[ i ] - prev->ps.origin[ i ] ); + + if( !grabAngles ) + out->viewangles[ i ] = LerpAngle( prev->ps.viewangles[ i ], next->ps.viewangles[ i ], f ); + + out->velocity[ i ] = prev->ps.velocity[ i ] + + f * (next->ps.velocity[ i ] - prev->ps.velocity[ i ] ); } -/* if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) { - return; - }*/ - - // never pick an item up twice in a prediction - if ( cent->miscTime == cg.time ) { - return; - } - - // grab it - BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState); - - // remove it from the frame so it won't be drawn - cent->currentState.eFlags |= EF_NODRAW; - - // don't touch it again this prediction - cent->miscTime = cg.time; - - // if its a weapon, give them some predicted ammo so the autoswitch will work -/* if ( item->giType == IT_WEAPON ) { - BG_packWeapon( item->giTag, cg.predictedPlayerState.stats ); - if ( ammo == 0 && clips == 0 ) { - BG_packAmmoArray( item->giTag, cg.predictedPlayerState.ammo, cg.predictedPlayerState.powerups, 1, 0, 0 ); - } - }*/ } @@ -320,59 +289,51 @@ CG_TouchTriggerPrediction Predict push triggers and items ========================= */ -static void CG_TouchTriggerPrediction( void ) { - int i; - trace_t trace; +static void CG_TouchTriggerPrediction( void ) +{ + int i; + trace_t trace; entityState_t *ent; - clipHandle_t cmodel; - centity_t *cent; - qboolean spectator; + clipHandle_t cmodel; + centity_t *cent; + qboolean spectator; // dead clients don't activate triggers - if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { + if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) return; - } spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR ); - if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) { + if( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) return; - } - for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) { + for( i = 0; i < cg_numTriggerEntities; i++ ) + { cent = cg_triggerEntities[ i ]; ent = ¢->currentState; - if ( ent->eType == ET_ITEM && !spectator ) { - CG_TouchItem( cent ); + if( ent->solid != SOLID_BMODEL ) continue; - } - - if ( ent->solid != SOLID_BMODEL ) { - continue; - } cmodel = trap_CM_InlineModel( ent->modelindex ); - if ( !cmodel ) { + if( !cmodel ) continue; - } trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin, - cg_pmove.mins, cg_pmove.maxs, cmodel, -1 ); + cg_pmove.mins, cg_pmove.maxs, cmodel, -1 ); - if ( !trace.startsolid ) { + if( !trace.startsolid ) continue; - } - if ( ent->eType == ET_TELEPORT_TRIGGER ) { + if( ent->eType == ET_TELEPORT_TRIGGER ) cg.hyperspace = qtrue; - } else if ( ent->eType == ET_PUSH_TRIGGER ) { + else if( ent->eType == ET_PUSH_TRIGGER ) BG_TouchJumpPad( &cg.predictedPlayerState, ent ); - } } // if we didn't touch a jump pad this pmove frame - if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) { + if( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) + { cg.predictedPlayerState.jumppad_frame = 0; cg.predictedPlayerState.jumppad_ent = 0; } @@ -406,7 +367,8 @@ We detect prediction errors and allow them to be decayed off over several frames to ease the jerk. ================= */ -void CG_PredictPlayerState( void ) { +void CG_PredictPlayerState( void ) +{ int cmdNum, current, i; playerState_t oldPlayerState; qboolean moved; @@ -418,20 +380,23 @@ void CG_PredictPlayerState( void ) { // if this is the first frame we must guarantee // predictedPlayerState is valid even if there is some // other error condition - if ( !cg.validPPS ) { + if( !cg.validPPS ) + { cg.validPPS = qtrue; cg.predictedPlayerState = cg.snap->ps; } // demo playback just copies the moves - if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) { + if( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) + { CG_InterpolatePlayerState( qfalse ); return; } // non-predicting local movement will grab the latest angles - if ( cg_nopredict.integer || cg_synchronousClients.integer ) { + if( cg_nopredict.integer || cg_synchronousClients.integer ) + { CG_InterpolatePlayerState( qtrue ); return; } @@ -441,33 +406,33 @@ void CG_PredictPlayerState( void ) { cg_pmove.trace = CG_Trace; cg_pmove.pointcontents = CG_PointContents; - //TA: FIXME BIG NEON SIGN..... COULD MAYBE BE A FIX FOR THAT HACK IN bg_pmove.c.. MAYBE \/ - if ( cg_pmove.ps->pm_type == PM_DEAD ) { + if( cg_pmove.ps->pm_type == PM_DEAD ) cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; - } - else { + else cg_pmove.tracemask = MASK_PLAYERSOLID; - } - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + + if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies - } + cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0; // save the state before the pmove so we can detect transitions oldPlayerState = cg.predictedPlayerState; - current = trap_GetCurrentCmdNumber(); + current = trap_GetCurrentCmdNumber( ); // if we don't have the commands right after the snapshot, we // can't accurately predict a current position, so just freeze at // the last good position we had cmdNum = current - CMD_BACKUP + 1; trap_GetUserCmd( cmdNum, &oldestCmd ); - if ( oldestCmd.serverTime > cg.snap->ps.commandTime - && oldestCmd.serverTime < cg.time ) { // special check for map_restart - if ( cg_showmiss.integer ) { - CG_Printf ("exceeded PACKET_BACKUP on commands\n"); - } + + if( oldestCmd.serverTime > cg.snap->ps.commandTime && + oldestCmd.serverTime < cg.time ) + { // special check for map_restart + if( cg_showmiss.integer ) + CG_Printf( "exceeded PACKET_BACKUP on commands\n" ); + return; } @@ -478,92 +443,103 @@ void CG_PredictPlayerState( void ) { // the server time is beyond our current cg.time, // because predicted player positions are going to // be ahead of everything else anyway - if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) { + if( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) + { cg.predictedPlayerState = cg.nextSnap->ps; cg.physicsTime = cg.nextSnap->serverTime; - } else { + } + else + { cg.predictedPlayerState = cg.snap->ps; cg.physicsTime = cg.snap->serverTime; } - if ( pmove_msec.integer < 8 ) { - trap_Cvar_Set("pmove_msec", "8"); - } - else if (pmove_msec.integer > 33) { - trap_Cvar_Set("pmove_msec", "33"); - } + if( pmove_msec.integer < 8 ) + trap_Cvar_Set( "pmove_msec", "8" ); + else if( pmove_msec.integer > 33 ) + trap_Cvar_Set( "pmove_msec", "33" ); cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer; cg_pmove.pmove_msec = pmove_msec.integer; // run cmds moved = qfalse; - for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) { + + for( cmdNum = current - CMD_BACKUP + 1; cmdNum <= current; cmdNum++ ) + { // get the command trap_GetUserCmd( cmdNum, &cg_pmove.cmd ); - if ( cg_pmove.pmove_fixed ) { + if( cg_pmove.pmove_fixed ) PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd ); - } // don't do anything if the time is before the snapshot player time - if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) { + if( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) continue; - } // don't do anything if the command was from a previous map_restart - if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) { + if( cg_pmove.cmd.serverTime > latestCmd.serverTime ) continue; - } // check for a prediction error from last frame // on a lan, this will often be the exact value // from the snapshot, but on a wan we will have // to predict several commands to get to the point // we want to compare - if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) { + if( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) + { vec3_t delta; - float len; + float len; - if ( cg.thisFrameTeleport ) { + if( cg.thisFrameTeleport ) + { // a teleport will not cause an error decay VectorClear( cg.predictedError ); - if ( cg_showmiss.integer ) { + + if( cg_showmiss.integer ) CG_Printf( "PredictionTeleport\n" ); - } + cg.thisFrameTeleport = qfalse; - } else { + } + else + { vec3_t adjusted; CG_AdjustPositionForMover( cg.predictedPlayerState.origin, cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted ); - if ( cg_showmiss.integer ) { - if (!VectorCompare( oldPlayerState.origin, adjusted )) { + if( cg_showmiss.integer ) + { + if( !VectorCompare( oldPlayerState.origin, adjusted ) ) CG_Printf("prediction error\n"); - } } + VectorSubtract( oldPlayerState.origin, adjusted, delta ); len = VectorLength( delta ); - if ( len > 0.1 ) { - if ( cg_showmiss.integer ) { - CG_Printf("Prediction miss: %f\n", len); - } - if ( cg_errorDecay.integer ) { + + if( len > 0.1 ) + { + if( cg_showmiss.integer ) + CG_Printf( "Prediction miss: %f\n", len ); + + if( cg_errorDecay.integer ) + { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; - if ( f < 0 ) { + + if( f < 0 ) f = 0; - } - if ( f > 0 && cg_showmiss.integer ) { - CG_Printf("Double prediction decay: %f\n", f); - } + + if( f > 0 && cg_showmiss.integer ) + CG_Printf( "Double prediction decay: %f\n", f ); + VectorScale( cg.predictedError, f, cg.predictedError ); - } else { - VectorClear( cg.predictedError ); } + else + VectorClear( cg.predictedError ); + VectorAdd( delta, cg.predictedError, cg.predictedError ); cg.predictedErrorTime = cg.oldTime; } @@ -575,29 +551,29 @@ void CG_PredictPlayerState( void ) { for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) cg_pmove.autoWeaponHit[ i ] = qfalse; - if ( cg_pmove.pmove_fixed ) { - cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer; - } + if( cg_pmove.pmove_fixed ) + cg_pmove.cmd.serverTime = ( ( cg_pmove.cmd.serverTime + pmove_msec.integer - 1 ) / + pmove_msec.integer ) * pmove_msec.integer; - Pmove (&cg_pmove); + Pmove( &cg_pmove ); moved = qtrue; // add push trigger movement effects - CG_TouchTriggerPrediction(); + CG_TouchTriggerPrediction( ); // check for predictable events that changed from previous predictions //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState); } - if ( cg_showmiss.integer > 1 ) { + if( cg_showmiss.integer > 1 ) CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time ); - } - if ( !moved ) { - if ( cg_showmiss.integer ) { + if( !moved ) + { + if( cg_showmiss.integer ) CG_Printf( "not moved\n" ); - } + return; } @@ -606,21 +582,21 @@ void CG_PredictPlayerState( void ) { cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.time, cg.predictedPlayerState.origin ); - if ( cg_showmiss.integer ) { - if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) { - CG_Printf("WARNING: dropped event\n"); - } + if( cg_showmiss.integer ) + { + if( cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS ) + CG_Printf( "WARNING: dropped event\n" ); } // fire events and other transition triggered things CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState ); - if ( cg_showmiss.integer ) { - if (cg.eventSequence > cg.predictedPlayerState.eventSequence) { - CG_Printf("WARNING: double event\n"); + if( cg_showmiss.integer ) + { + if( cg.eventSequence > cg.predictedPlayerState.eventSequence ) + { + CG_Printf( "WARNING: double event\n" ); cg.eventSequence = cg.predictedPlayerState.eventSequence; } } } - - |