yquake2remaster/src/client/cl_prediction.c

316 lines
6.5 KiB
C
Raw Normal View History

/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
2010-06-18 16:36:15 +00:00
* =======================================================================
*
* This file implements interpolation between two frames. This is used
* to smooth down network play
*
* =======================================================================
*/
2009-03-03 13:43:32 +00:00
#include "header/client.h"
2012-07-22 13:34:45 +00:00
void
CL_CheckPredictionError(void)
{
int frame;
int delta[3];
int i;
int len;
if (!cl_predict->value ||
(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
{
return;
2012-07-22 13:34:45 +00:00
}
/* calculate the last usercmd_t we sent that the server has processed */
frame = cls.netchan.incoming_acknowledged;
2012-07-22 13:34:45 +00:00
frame &= (CMD_BACKUP - 1);
/* compare what the server returned with what we had predicted it to be */
2012-07-22 13:34:45 +00:00
VectorSubtract(cl.frame.playerstate.pmove.origin,
cl.predicted_origins[frame], delta);
/* save the prediction error for interpolation */
len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
2012-07-22 13:34:45 +00:00
/* 80 world units */
if (len > 640)
{
/* a teleport or something */
2012-07-22 13:34:45 +00:00
VectorClear(cl.prediction_error);
}
else
{
if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]))
{
Com_Printf("prediction miss on %i: %i\n", cl.frame.serverframe,
delta[0] + delta[1] + delta[2]);
}
2012-07-22 13:34:45 +00:00
VectorCopy(cl.frame.playerstate.pmove.origin,
cl.predicted_origins[frame]);
/* save for error itnerpolation */
2012-07-22 13:34:45 +00:00
for (i = 0; i < 3; i++)
{
cl.prediction_error[i] = delta[i] * 0.125f;
}
}
}
2012-07-22 13:34:45 +00:00
void
CL_ClipMoveToEntities(vec3_t start, vec3_t mins, vec3_t maxs,
vec3_t end, trace_t *tr)
{
int i, x, zd, zu;
trace_t trace;
int headnode;
float *angles;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
vec3_t bmins, bmaxs;
for (i = 0; i < cl.frame.num_entities; i++)
{
num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
ent = &cl_parse_entities[num];
if (!ent->solid)
2012-07-22 13:34:45 +00:00
{
continue;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (ent->number == cl.playernum + 1)
{
continue;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (ent->solid == 31)
{
/* special value for bmodel */
cmodel = cl.model_clip[ent->modelindex];
if (!cmodel)
2012-07-22 13:34:45 +00:00
{
continue;
2012-07-22 13:34:45 +00:00
}
headnode = cmodel->headnode;
angles = ent->angles;
2012-07-22 13:34:45 +00:00
}
else
{
/* encoded bbox */
2012-07-22 13:34:45 +00:00
x = 8 * (ent->solid & 31);
zd = 8 * ((ent->solid >> 5) & 31);
zu = 8 * ((ent->solid >> 10) & 63) - 32;
2009-03-02 19:27:04 +00:00
bmins[0] = bmins[1] = -(float)x;
bmaxs[0] = bmaxs[1] = (float)x;
bmins[2] = -(float)zd;
bmaxs[2] = (float)zu;
2012-07-22 13:34:45 +00:00
headnode = CM_HeadnodeForBox(bmins, bmaxs);
angles = vec3_origin; /* boxes don't rotate */
}
if (tr->allsolid)
2012-07-22 13:34:45 +00:00
{
return;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
trace = CM_TransformedBoxTrace(start, end,
mins, maxs, headnode, MASK_PLAYERSOLID,
ent->origin, angles);
if (trace.allsolid || trace.startsolid ||
2012-07-22 13:34:45 +00:00
(trace.fraction < tr->fraction))
{
trace.ent = (struct edict_s *)ent;
2012-07-22 13:34:45 +00:00
if (tr->startsolid)
{
*tr = trace;
tr->startsolid = true;
2012-07-22 13:34:45 +00:00
}
else
{
*tr = trace;
2012-07-22 13:34:45 +00:00
}
}
}
}
2012-07-22 13:34:45 +00:00
trace_t
CL_PMTrace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
{
trace_t t;
/* check against world */
2012-07-22 13:34:45 +00:00
t = CM_BoxTrace(start, end, mins, maxs, 0, MASK_PLAYERSOLID);
if (t.fraction < 1.0)
2012-07-22 13:34:45 +00:00
{
t.ent = (struct edict_s *)1;
2012-07-22 13:34:45 +00:00
}
/* check all other solid models */
2012-07-22 13:34:45 +00:00
CL_ClipMoveToEntities(start, mins, maxs, end, &t);
return t;
}
2012-07-22 13:34:45 +00:00
int
CL_PMpointcontents(vec3_t point)
{
int i;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
int contents;
2012-07-22 13:34:45 +00:00
contents = CM_PointContents(point, 0);
2012-07-22 13:34:45 +00:00
for (i = 0; i < cl.frame.num_entities; i++)
{
num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
ent = &cl_parse_entities[num];
if (ent->solid != 31) /* special value for bmodel */
2012-07-22 13:34:45 +00:00
{
continue;
2012-07-22 13:34:45 +00:00
}
cmodel = cl.model_clip[ent->modelindex];
if (!cmodel)
2012-07-22 13:34:45 +00:00
{
continue;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
contents |= CM_TransformedPointContents(point, cmodel->headnode,
ent->origin, ent->angles);
}
return contents;
}
/*
* Sets cl.predicted_origin and cl.predicted_angles
*/
2012-07-22 13:34:45 +00:00
void
CL_PredictMovement(void)
{
int ack, current;
int frame;
usercmd_t *cmd;
pmove_t pm;
int i;
int step;
vec3_t tmp;
if (cls.state != ca_active)
2012-07-22 13:34:45 +00:00
{
return;
2012-07-22 13:34:45 +00:00
}
if (cl_paused->value)
2012-07-22 13:34:45 +00:00
{
return;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (!cl_predict->value ||
(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
{
/* just set angles */
2012-07-22 13:34:45 +00:00
for (i = 0; i < 3; i++)
{
cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(
cl.frame.playerstate.pmove.delta_angles[i]);
}
return;
}
ack = cls.netchan.incoming_acknowledged;
current = cls.netchan.outgoing_sequence;
/* if we are too far out of date, just freeze */
2012-07-22 13:34:45 +00:00
if (current - ack >= CMD_BACKUP)
{
if (cl_showmiss->value)
2012-07-22 13:34:45 +00:00
{
Com_Printf("exceeded CMD_BACKUP\n");
}
return;
}
/* copy current state to pmove */
memset (&pm, 0, sizeof(pm));
pm.trace = CL_PMTrace;
pm.pointcontents = CL_PMpointcontents;
pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
pm.s = cl.frame.playerstate.pmove;
/* run frames */
while (++ack <= current)
2012-07-22 13:34:45 +00:00
{
frame = ack & (CMD_BACKUP - 1);
cmd = &cl.cmds[frame];
// Ignore null entries
if (!cmd->msec)
{
continue;
}
pm.cmd = *cmd;
2012-07-22 13:34:45 +00:00
Pmove(&pm);
/* save for debug checking */
2012-07-22 13:34:45 +00:00
VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
}
// step is used for movement prediction on stairs
// (so moving up/down stairs is smooth)
step = pm.s.origin[2] - (int)(cl.predicted_origin[2] * 8);
VectorCopy(pm.s.velocity, tmp);
if (((step > 62 && step < 66) || (step > 94 && step < 98) || (step > 126 && step < 130))
&& !VectorCompare(tmp, vec3_origin)
&& (pm.s.pm_flags & PMF_ON_GROUND))
2012-07-22 13:34:45 +00:00
{
2009-03-02 19:27:04 +00:00
cl.predicted_step = step * 0.125f;
cl.predicted_step_time = cls.realtime - (int)(cls.nframetime * 500);
}
/* copy results out for rendering */
2012-07-22 13:34:45 +00:00
cl.predicted_origin[0] = pm.s.origin[0] * 0.125f;
cl.predicted_origin[1] = pm.s.origin[1] * 0.125f;
cl.predicted_origin[2] = pm.s.origin[2] * 0.125f;
2012-07-22 13:34:45 +00:00
VectorCopy(pm.viewangles, cl.predicted_angles);
}
2012-07-22 13:34:45 +00:00