home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / cg_predict.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  15.2 KB  |  573 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // cg_predict.c -- this file generates cg.predictedPlayerState by either
  4. // interpolating between snapshots from the server or locally predicting
  5. // ahead the client's movement.
  6. // It also handles local physics interaction, like fragments bouncing off walls
  7.  
  8. #include "cg_local.h"
  9.  
  10. static    pmove_t        cg_pmove;
  11.  
  12. static    int            cg_numSolidEntities;
  13. static    centity_t    *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
  14. static    int            cg_numTriggerEntities;
  15. static    centity_t    *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
  16.  
  17. /*
  18. ====================
  19. CG_BuildSolidList
  20.  
  21. When a new cg.snap has been set, this function builds a sublist
  22. of the entities that are actually solid, to make for more
  23. efficient collision detection
  24. ====================
  25. */
  26. void CG_BuildSolidList( void ) {
  27.     int            i;
  28.     centity_t    *cent;
  29.     snapshot_t    *snap;
  30.     entityState_t    *ent;
  31.  
  32.     cg_numSolidEntities = 0;
  33.     cg_numTriggerEntities = 0;
  34.  
  35.     if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
  36.         snap = cg.nextSnap;
  37.     } else {
  38.         snap = cg.snap;
  39.     }
  40.  
  41.     for ( i = 0 ; i < snap->numEntities ; i++ ) {
  42.         cent = &cg_entities[ snap->entities[ i ].number ];
  43.         ent = ¢->currentState;
  44.  
  45.         if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
  46.             cg_triggerEntities[cg_numTriggerEntities] = cent;
  47.             cg_numTriggerEntities++;
  48.             continue;
  49.         }
  50.  
  51.         if ( cent->nextState.solid ) {
  52.             cg_solidEntities[cg_numSolidEntities] = cent;
  53.             cg_numSolidEntities++;
  54.             continue;
  55.         }
  56.     }
  57. }
  58.  
  59. /*
  60. ====================
  61. CG_ClipMoveToEntities
  62.  
  63. ====================
  64. */
  65. static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
  66.                             int skipNumber, int mask, trace_t *tr ) {
  67.     int            i, x, zd, zu;
  68.     trace_t        trace;
  69.     entityState_t    *ent;
  70.     clipHandle_t     cmodel;
  71.     vec3_t        bmins, bmaxs;
  72.     vec3_t        origin, angles;
  73.     centity_t    *cent;
  74.  
  75.     for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
  76.         cent = cg_solidEntities[ i ];
  77.         ent = ¢->currentState;
  78.  
  79.         if ( ent->number == skipNumber ) {
  80.             continue;
  81.         }
  82.  
  83.         if ( ent->solid == SOLID_BMODEL ) {
  84.             // special value for bmodel
  85.             cmodel = trap_CM_InlineModel( ent->modelindex );
  86.             VectorCopy( cent->lerpAngles, angles );
  87.             BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin );
  88.         } else {
  89.             // encoded bbox
  90.             x = (ent->solid & 255);
  91.             zd = ((ent->solid>>8) & 255);
  92.             zu = ((ent->solid>>16) & 255) - 32;
  93.  
  94.             bmins[0] = bmins[1] = -x;
  95.             bmaxs[0] = bmaxs[1] = x;
  96.             bmins[2] = -zd;
  97.             bmaxs[2] = zu;
  98.  
  99.             cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
  100.             VectorCopy( vec3_origin, angles );
  101.             VectorCopy( cent->lerpOrigin, origin );
  102.         }
  103.  
  104.  
  105.         trap_CM_TransformedBoxTrace ( &trace, start, end,
  106.             mins, maxs, cmodel,  mask, origin, angles);
  107.  
  108.         if (trace.allsolid || trace.fraction < tr->fraction) {
  109.             trace.entityNum = ent->number;
  110.             *tr = trace;
  111.         } else if (trace.startsolid) {
  112.             tr->startsolid = qtrue;
  113.         }
  114.         if ( tr->allsolid ) {
  115.             return;
  116.         }
  117.     }
  118. }
  119.  
  120. /*
  121. ================
  122. CG_Trace
  123. ================
  124. */
  125. void    CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, 
  126.                      int skipNumber, int mask ) {
  127.     trace_t    t;
  128.  
  129.     trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
  130.     t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
  131.     // check all other solid models
  132.     CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
  133.  
  134.     *result = t;
  135. }
  136.  
  137. /*
  138. ================
  139. CG_PointContents
  140. ================
  141. */
  142. int        CG_PointContents( const vec3_t point, int passEntityNum ) {
  143.     int            i;
  144.     entityState_t    *ent;
  145.     centity_t    *cent;
  146.     clipHandle_t cmodel;
  147.     int            contents;
  148.  
  149.     contents = trap_CM_PointContents (point, 0);
  150.  
  151.     for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
  152.         cent = cg_solidEntities[ i ];
  153.  
  154.         ent = ¢->currentState;
  155.  
  156.         if ( ent->number == passEntityNum ) {
  157.             continue;
  158.         }
  159.  
  160.         if (ent->solid != SOLID_BMODEL) { // special value for bmodel
  161.             continue;
  162.         }
  163.  
  164.         cmodel = trap_CM_InlineModel( ent->modelindex );
  165.         if ( !cmodel ) {
  166.             continue;
  167.         }
  168.  
  169.         contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
  170.     }
  171.  
  172.     return contents;
  173. }
  174.  
  175.  
  176. /*
  177. ========================
  178. CG_InterpolatePlayerState
  179.  
  180. Generates cg.predictedPlayerState by interpolating between
  181. cg.snap->player_state and cg.nextFrame->player_state
  182. ========================
  183. */
  184. static void CG_InterpolatePlayerState( qboolean grabAngles ) {
  185.     float            f;
  186.     int                i;
  187.     playerState_t    *out;
  188.     snapshot_t        *prev, *next;
  189.  
  190.     out = &cg.predictedPlayerState;
  191.     prev = cg.snap;
  192.     next = cg.nextSnap;
  193.  
  194.     *out = cg.snap->ps;
  195.  
  196.     // if we are still allowing local input, short circuit the view angles
  197.     if ( grabAngles ) {
  198.         usercmd_t    cmd;
  199.         int            cmdNum;
  200.  
  201.         cmdNum = trap_GetCurrentCmdNumber();
  202.         trap_GetUserCmd( cmdNum, &cmd );
  203.  
  204.         PM_UpdateViewAngles( out, &cmd );
  205.     }
  206.  
  207.     // if the next frame is a teleport, we can't lerp to it
  208.     if ( cg.nextFrameTeleport ) {
  209.         return;
  210.     }
  211.  
  212.     if ( !next || next->serverTime <= prev->serverTime ) {
  213.         return;
  214.     }
  215.  
  216.     f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
  217.  
  218.     i = next->ps.bobCycle;
  219.     if ( i < prev->ps.bobCycle ) {
  220.         i += 256;        // handle wraparound
  221.     }
  222.     out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
  223.  
  224.     for ( i = 0 ; i < 3 ; i++ ) {
  225.         out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
  226.         if ( !grabAngles ) {
  227.             out->viewangles[i] = LerpAngle( 
  228.                 prev->ps.viewangles[i], next->ps.viewangles[i], f );
  229.         }
  230.         out->velocity[i] = prev->ps.velocity[i] + 
  231.             f * (next->ps.velocity[i] - prev->ps.velocity[i] );
  232.     }
  233.  
  234. }
  235.  
  236. /*
  237. ===================
  238. CG_TouchItem
  239. ===================
  240. */
  241. static void CG_TouchItem( centity_t *cent ) {
  242.     gitem_t        *item;
  243.  
  244.     if ( !cg_predictItems.integer ) {
  245.         return;
  246.     }
  247.     if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) {
  248.         return;
  249.     }
  250.  
  251.     // never pick an item up twice in a prediction
  252.     if ( cent->miscTime == cg.time ) {
  253.         return;
  254.     }
  255.  
  256.     if ( !BG_CanItemBeGrabbed( ¢->currentState, &cg.predictedPlayerState ) ) {
  257.         return;        // can't hold it
  258.     }
  259.  
  260.     item = &bg_itemlist[ cent->currentState.modelindex ];
  261.  
  262.     // Special case for flags.  
  263.     // We don't predict touching our own flag
  264.     if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
  265.         item->giTag == PW_REDFLAG)
  266.         return;
  267.     if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
  268.         item->giTag == PW_BLUEFLAG)
  269.         return;
  270.  
  271.     // grab it
  272.     BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);
  273.  
  274.     // remove it from the frame so it won't be drawn
  275.     cent->currentState.eFlags |= EF_NODRAW;
  276.  
  277.     // don't touch it again this prediction
  278.     cent->miscTime = cg.time;
  279.  
  280.     // if its a weapon, give them some predicted ammo so the autoswitch will work
  281.     if ( item->giType == IT_WEAPON ) {
  282.         cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
  283.         if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
  284.             cg.predictedPlayerState.ammo[ item->giTag ] = 1;
  285.         }
  286.     }
  287. }
  288.  
  289.  
  290. /*
  291. =========================
  292. CG_TouchTriggerPrediction
  293.  
  294. Predict push triggers and items
  295. =========================
  296. */
  297. static void CG_TouchTriggerPrediction( void ) {
  298.     int            i;
  299.     trace_t        trace;
  300.     entityState_t    *ent;
  301.     clipHandle_t cmodel;
  302.     centity_t    *cent;
  303.     qboolean    spectator;
  304.  
  305.     // dead clients don't activate triggers
  306.     if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
  307.         return;
  308.     }
  309.  
  310.     spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
  311.  
  312.     if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
  313.         return;
  314.     }
  315.  
  316.     for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
  317.         cent = cg_triggerEntities[ i ];
  318.         ent = ¢->currentState;
  319.  
  320.         if ( ent->eType == ET_ITEM && !spectator ) {
  321.             CG_TouchItem( cent );
  322.             continue;
  323.         }
  324.  
  325.         if ( ent->solid != SOLID_BMODEL ) {
  326.             continue;
  327.         }
  328.  
  329.         cmodel = trap_CM_InlineModel( ent->modelindex );
  330.         if ( !cmodel ) {
  331.             continue;
  332.         }
  333.  
  334.         trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin, 
  335.             cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
  336.  
  337.         if ( !trace.startsolid ) {
  338.             continue;
  339.         }
  340.  
  341.         if ( ent->eType == ET_TELEPORT_TRIGGER ) {
  342.             cg.hyperspace = qtrue;
  343.         } else {
  344.             float    s;
  345.             vec3_t    dir;
  346.  
  347.             // we hit this push trigger
  348.             if ( spectator ) {
  349.                 continue;
  350.             }
  351.  
  352.             // flying characters don't hit bounce pads
  353.             if ( cg.predictedPlayerState.powerups[PW_FLIGHT] ) {
  354.                 continue;
  355.             }
  356.  
  357.             // if we are already flying along the bounce direction, don't play sound again
  358.             VectorNormalize2( ent->origin2, dir );
  359.             s = DotProduct( cg.predictedPlayerState.velocity, dir );
  360.             if ( s < 500 ) {
  361.                 // don't play the event sound again if we are in a fat trigger
  362.                 BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, 0, &cg.predictedPlayerState );
  363.             }
  364.             VectorCopy( ent->origin2, cg.predictedPlayerState.velocity );
  365.         }
  366.     }
  367. }
  368.  
  369.  
  370.  
  371. /*
  372. =================
  373. CG_PredictPlayerState
  374.  
  375. Generates cg.predictedPlayerState for the current cg.time
  376. cg.predictedPlayerState is guaranteed to be valid after exiting.
  377.  
  378. For demo playback, this will be an interpolation between two valid
  379. playerState_t.
  380.  
  381. For normal gameplay, it will be the result of predicted usercmd_t on
  382. top of the most recent playerState_t received from the server.
  383.  
  384. Each new snapshot will usually have one or more new usercmd over the last,
  385. but we simulate all unacknowledged commands each time, not just the new ones.
  386. This means that on an internet connection, quite a few pmoves may be issued
  387. each frame.
  388.  
  389. OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
  390. differs from the predicted one.  Would require saving all intermediate
  391. playerState_t during prediction.
  392.  
  393. We detect prediction errors and allow them to be decayed off over several frames
  394. to ease the jerk.
  395. =================
  396. */
  397. void CG_PredictPlayerState( void ) {
  398.     int            cmdNum, current;
  399.     playerState_t    oldPlayerState;
  400.     qboolean    moved;
  401.     usercmd_t    oldestCmd;
  402.     usercmd_t    latestCmd;
  403.  
  404.     cg.hyperspace = qfalse;    // will be set if touching a trigger_teleport
  405.  
  406.     // if this is the first frame we must guarantee
  407.     // predictedPlayerState is valid even if there is some
  408.     // other error condition
  409.     if ( !cg.validPPS ) {
  410.         cg.validPPS = qtrue;
  411.         cg.predictedPlayerState = cg.snap->ps;
  412.     }
  413.  
  414.  
  415.     // demo playback just copies the moves
  416.     if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
  417.         CG_InterpolatePlayerState( qfalse );
  418.         return;
  419.     }
  420.  
  421.     // non-predicting local movement will grab the latest angles
  422.     if ( cg_nopredict.integer || cg_syncronousClients.integer ) {
  423.         CG_InterpolatePlayerState( qtrue );
  424.         return;
  425.     }
  426.  
  427.     // prepare for pmove
  428.     cg_pmove.ps = &cg.predictedPlayerState;
  429.     cg_pmove.trace = CG_Trace;
  430.     cg_pmove.pointcontents = CG_PointContents;
  431.     if ( cg_pmove.ps->pm_type == PM_DEAD ) {
  432.         cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
  433.     }
  434.     else {
  435.         cg_pmove.tracemask = MASK_PLAYERSOLID;
  436.     }
  437.     if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
  438.         cg_pmove.tracemask &= ~CONTENTS_BODY;    // spectators can fly through bodies
  439.     }
  440.     cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
  441.  
  442.     // save the state before the pmove so we can detect transitions
  443.     oldPlayerState = cg.predictedPlayerState;
  444.  
  445.     current = trap_GetCurrentCmdNumber();
  446.  
  447.     // if we don't have the commands right after the snapshot, we
  448.     // can't accurately predict a current position, so just freeze at
  449.     // the last good position we had
  450.     cmdNum = current - CMD_BACKUP + 1;
  451.     trap_GetUserCmd( cmdNum, &oldestCmd );
  452.     if ( oldestCmd.serverTime > cg.snap->ps.commandTime 
  453.         && oldestCmd.serverTime < cg.time ) {    // special check for map_restart
  454.         if ( cg_showmiss.integer ) {
  455.             CG_Printf ("exceeded PACKET_BACKUP on commands\n");
  456.         }
  457.         return;
  458.     }
  459.  
  460.     // get the latest command so we can know which commands are from previous map_restarts
  461.     trap_GetUserCmd( current, &latestCmd );
  462.  
  463.     // get the most recent information we have, even if
  464.     // the server time is beyond our current cg.time,
  465.     // because predicted player positions are going to 
  466.     // be ahead of everything else anyway
  467.     if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
  468.         cg.predictedPlayerState = cg.nextSnap->ps;
  469.         cg.physicsTime = cg.nextSnap->serverTime;
  470.     } else {
  471.         cg.predictedPlayerState = cg.snap->ps;
  472.         cg.physicsTime = cg.snap->serverTime;
  473.     }
  474.  
  475.     // run cmds
  476.     moved = qfalse;
  477.     for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
  478.         // get the command
  479.         trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
  480.  
  481.         // don't do anything if the time is before the snapshot player time
  482.         if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
  483.             continue;
  484.         }
  485.  
  486.         // don't do anything if the command was from a previous map_restart
  487.         if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
  488.             continue;
  489.         }
  490.  
  491.         // check for a prediction error from last frame
  492.         // on a lan, this will often be the exact value
  493.         // from the snapshot, but on a wan we will have
  494.         // to predict several commands to get to the point
  495.         // we want to compare
  496.         if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
  497.             vec3_t    delta;
  498.             float    len;
  499.  
  500.             if ( cg.thisFrameTeleport ) {
  501.                 // a teleport will not cause an error decay
  502.                 VectorClear( cg.predictedError );
  503.                 if ( cg_showmiss.integer ) {
  504.                     CG_Printf( "PredictionTeleport\n" );
  505.                 }
  506.                 cg.thisFrameTeleport = qfalse;
  507.             } else {
  508.                 vec3_t    adjusted;
  509.                 CG_AdjustPositionForMover( cg.predictedPlayerState.origin, 
  510.                     cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
  511.  
  512.                 VectorSubtract( oldPlayerState.origin, adjusted, delta );
  513.                 len = VectorLength( delta );
  514.                 if ( len > 0.1 ) {
  515.                     if ( cg_showmiss.integer ) {
  516.                         CG_Printf("Prediction miss: %f\n", len);
  517.                     }
  518.                     if ( cg_errorDecay.integer ) {
  519.                         int        t;
  520.                         float    f;
  521.  
  522.                         t = cg.time - cg.predictedErrorTime;
  523.                         f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
  524.                         if ( f < 0 ) {
  525.                             f = 0;
  526.                         }
  527.                         if ( f > 0 && cg_showmiss.integer ) {
  528.                             CG_Printf("Double prediction decay: %f\n", f);
  529.                         }
  530.                         VectorScale( cg.predictedError, f, cg.predictedError );
  531.                     } else {
  532.                         VectorClear( cg.predictedError );
  533.                     }
  534.                     VectorAdd( delta, cg.predictedError, cg.predictedError );
  535.                     cg.predictedErrorTime = cg.oldTime;
  536.                 }
  537.             }
  538.         }
  539.  
  540.         // don't predict gauntlet firing, which is only supposed to happen
  541.         // when it actually inflicts damage
  542.         cg_pmove.gauntletHit = qfalse;
  543.  
  544.         Pmove (&cg_pmove);
  545.  
  546.         moved = qtrue;
  547.  
  548.         // add push trigger movement effects
  549.         CG_TouchTriggerPrediction();
  550.     }
  551.  
  552.     if ( cg_showmiss.integer > 1 ) {
  553.         CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
  554.     }
  555.  
  556.     if ( !moved ) {
  557.         if ( cg_showmiss.integer ) {
  558.             CG_Printf( "not moved\n" );
  559.         }
  560.         return;
  561.     }
  562.  
  563.     // adjust for the movement of the groundentity
  564.     CG_AdjustPositionForMover( cg.predictedPlayerState.origin, 
  565.         cg.predictedPlayerState.groundEntityNum, 
  566.         cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
  567.  
  568.     // fire events and other transition triggered things
  569.     CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
  570. }
  571.  
  572.  
  573.