File: client\cl_pred.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 
   21 #include "client.h"
   22 
   23 
   24 /*
   25 ===================
   26 CL_CheckPredictionError
   27 ===================
   28 */
   29 void CL_CheckPredictionError (void)
   30 {
   31         int             frame;
   32         int             delta[3];
   33         int             i;
   34         int             len;
   35 
   36         if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
   37                 return;
   38 
   39         // calculate the last usercmd_t we sent that the server has processed
   40         frame = cls.netchan.incoming_acknowledged;
   41         frame &= (CMD_BACKUP-1);
   42 
   43         // compare what the server returned with what we had predicted it to be
   44         VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
   45 
   46         // save the prediction error for interpolation
   47         len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
   48         if (len > 640)  // 80 world units
   49         {       // a teleport or something
   50                 VectorClear (cl.prediction_error);
   51         }
   52         else
   53         {
   54                 if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
   55                         Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe, 
   56                         delta[0] + delta[1] + delta[2]);
   57 
   58                 VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
   59 
   60                 // save for error itnerpolation
   61                 for (i=0 ; i<3 ; i++)
   62                         cl.prediction_error[i] = delta[i]*0.125;
   63         }
   64 }
   65 
   66 
   67 /*
   68 ====================
   69 CL_ClipMoveToEntities
   70 
   71 ====================
   72 */
   73 void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
   74 {
   75         int                     i, x, zd, zu;
   76         trace_t         trace;
   77         int                     headnode;
   78         float           *angles;
   79         entity_state_t  *ent;
   80         int                     num;
   81         cmodel_t                *cmodel;
   82         vec3_t          bmins, bmaxs;
   83 
   84         for (i=0 ; i<cl.frame.num_entities ; i++)
   85         {
   86                 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
   87                 ent = &cl_parse_entities[num];
   88 
   89                 if (!ent->solid)
   90                         continue;
   91 
   92                 if (ent->number == cl.playernum+1)
   93                         continue;
   94 
   95                 if (ent->solid == 31)
   96                 {       // special value for bmodel
   97                         cmodel = cl.model_clip[ent->modelindex];
   98                         if (!cmodel)
   99                                 continue;
  100                         headnode = cmodel->headnode;
  101                         angles = ent->angles;
  102                 }
  103                 else
  104                 {       // encoded bbox
  105                         x = 8*(ent->solid & 31);
  106                         zd = 8*((ent->solid>>5) & 31);
  107                         zu = 8*((ent->solid>>10) & 63) - 32;
  108 
  109                         bmins[0] = bmins[1] = -x;
  110                         bmaxs[0] = bmaxs[1] = x;
  111                         bmins[2] = -zd;
  112                         bmaxs[2] = zu;
  113 
  114                         headnode = CM_HeadnodeForBox (bmins, bmaxs);
  115                         angles = vec3_origin;   // boxes don't rotate
  116                 }
  117 
  118                 if (tr->allsolid)
  119                         return;
  120 
  121                 trace = CM_TransformedBoxTrace (start, end,
  122                         mins, maxs, headnode,  MASK_PLAYERSOLID,
  123                         ent->origin, angles);
  124 
  125                 if (trace.allsolid || trace.startsolid ||
  126                 trace.fraction < tr->fraction)
  127                 {
  128                         trace.ent = (struct edict_s *)ent;
  129                         if (tr->startsolid)
  130                         {
  131                                 *tr = trace;
  132                                 tr->startsolid = true;
  133                         }
  134                         else
  135                                 *tr = trace;
  136                 }
  137                 else if (trace.startsolid)
  138                         tr->startsolid = true;
  139         }
  140 }
  141 
  142 
  143 /*
  144 ================
  145 CL_PMTrace
  146 ================
  147 */
  148 trace_t         CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
  149 {
  150         trace_t t;
  151 
  152         // check against world
  153         t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
  154         if (t.fraction < 1.0)
  155                 t.ent = (struct edict_s *)1;
  156 
  157         // check all other solid models
  158         CL_ClipMoveToEntities (start, mins, maxs, end, &t);
  159 
  160         return t;
  161 }
  162 
  163 int             CL_PMpointcontents (vec3_t point)
  164 {
  165         int                     i;
  166         entity_state_t  *ent;
  167         int                     num;
  168         cmodel_t                *cmodel;
  169         int                     contents;
  170 
  171         contents = CM_PointContents (point, 0);
  172 
  173         for (i=0 ; i<cl.frame.num_entities ; i++)
  174         {
  175                 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
  176                 ent = &cl_parse_entities[num];
  177 
  178                 if (ent->solid != 31) // special value for bmodel
  179                         continue;
  180 
  181                 cmodel = cl.model_clip[ent->modelindex];
  182                 if (!cmodel)
  183                         continue;
  184 
  185                 contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
  186         }
  187 
  188         return contents;
  189 }
  190 
  191 
  192 /*
  193 =================
  194 CL_PredictMovement
  195 
  196 Sets cl.predicted_origin and cl.predicted_angles
  197 =================
  198 */
  199 void CL_PredictMovement (void)
  200 {
  201         int                     ack, current;
  202         int                     frame;
  203         int                     oldframe;
  204         usercmd_t       *cmd;
  205         pmove_t         pm;
  206         int                     i;
  207         int                     step;
  208         int                     oldz;
  209 
  210         if (cls.state != ca_active)
  211                 return;
  212 
  213         if (cl_paused->value)
  214                 return;
  215 
  216         if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
  217         {       // just set angles
  218                 for (i=0 ; i<3 ; i++)
  219                 {
  220                         cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
  221                 }
  222                 return;
  223         }
  224 
  225         ack = cls.netchan.incoming_acknowledged;
  226         current = cls.netchan.outgoing_sequence;
  227 
  228         // if we are too far out of date, just freeze
  229         if (current - ack >= CMD_BACKUP)
  230         {
  231                 if (cl_showmiss->value)
  232                         Com_Printf ("exceeded CMD_BACKUP\n");
  233                 return; 
  234         }
  235 
  236         // copy current state to pmove
  237         memset (&pm, 0, sizeof(pm));
  238         pm.trace = CL_PMTrace;
  239         pm.pointcontents = CL_PMpointcontents;
  240 
  241         pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
  242 
  243         pm.s = cl.frame.playerstate.pmove;
  244 
  245 //      SCR_DebugGraph (current - ack - 1, 0);
  246 
  247         frame = 0;
  248 
  249         // run frames
  250         while (++ack < current)
  251         {
  252                 frame = ack & (CMD_BACKUP-1);
  253                 cmd = &cl.cmds[frame];
  254 
  255                 pm.cmd = *cmd;
  256                 Pmove (&pm);
  257 
  258                 // save for debug checking
  259                 VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
  260         }
  261 
  262         oldframe = (ack-2) & (CMD_BACKUP-1);
  263         oldz = cl.predicted_origins[oldframe][2];
  264         step = pm.s.origin[2] - oldz;
  265         if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
  266         {
  267                 cl.predicted_step = step * 0.125;
  268                 cl.predicted_step_time = cls.realtime - cls.frametime * 500;
  269         }
  270 
  271 
  272         // copy results out for rendering
  273         cl.predicted_origin[0] = pm.s.origin[0]*0.125;
  274         cl.predicted_origin[1] = pm.s.origin[1]*0.125;
  275         cl.predicted_origin[2] = pm.s.origin[2]*0.125;
  276 
  277         VectorCopy (pm.viewangles, cl.predicted_angles);
  278 }
  279