2009-02-28 14:41:18 +00:00
|
|
|
/*
|
2010-06-18 14:25:50 +00:00
|
|
|
* Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
*
|
2010-07-13 18:19:42 +00:00
|
|
|
* 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.
|
2010-06-18 14:25:50 +00:00
|
|
|
*
|
2010-07-13 18:19:42 +00:00
|
|
|
* 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.
|
2010-06-18 14:25:50 +00:00
|
|
|
*
|
|
|
|
* See the GNU General Public License for more details.
|
|
|
|
*
|
2010-07-13 18:19:42 +00:00
|
|
|
* 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 14:25:50 +00:00
|
|
|
*
|
2010-06-18 16:36:15 +00:00
|
|
|
* =======================================================================
|
|
|
|
*
|
|
|
|
* This file implements interpolation between two frames. This is used
|
|
|
|
* to smooth down network play
|
|
|
|
*
|
|
|
|
* =======================================================================
|
2010-06-18 14:25:50 +00:00
|
|
|
*/
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2009-03-03 13:43:32 +00:00
|
|
|
#include "header/client.h"
|
2009-02-28 14:41:18 +00:00
|
|
|
|
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))
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* calculate the last usercmd_t we sent that the server has processed */
|
2009-02-28 14:41:18 +00:00
|
|
|
frame = cls.netchan.incoming_acknowledged;
|
2012-07-22 13:34:45 +00:00
|
|
|
frame &= (CMD_BACKUP - 1);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* 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);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* save the prediction error for interpolation */
|
2009-02-28 14:41:18 +00:00
|
|
|
len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
/* 80 world units */
|
|
|
|
if (len > 640)
|
|
|
|
{
|
2010-06-18 14:25:50 +00:00
|
|
|
/* 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]);
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
VectorCopy(cl.frame.playerstate.pmove.origin,
|
|
|
|
cl.predicted_origins[frame]);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
2009-02-28 14:41:18 +00:00
|
|
|
ent = &cl_parse_entities[num];
|
|
|
|
|
|
|
|
if (!ent->solid)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
if (ent->number == cl.playernum + 1)
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
if (ent->solid == 31)
|
|
|
|
{
|
2010-06-18 14:25:50 +00:00
|
|
|
/* special value for bmodel */
|
2009-02-28 14:41:18 +00:00
|
|
|
cmodel = cl.model_clip[ent->modelindex];
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!cmodel)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
headnode = cmodel->headnode;
|
|
|
|
angles = ent->angles;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-06-18 14:25:50 +00:00
|
|
|
/* 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-02-28 14:41:18 +00:00
|
|
|
|
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;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
headnode = CM_HeadnodeForBox(bmins, bmaxs);
|
2010-06-18 14:25:50 +00:00
|
|
|
angles = vec3_origin; /* boxes don't rotate */
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tr->allsolid)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
trace = CM_TransformedBoxTrace(start, end,
|
|
|
|
mins, maxs, headnode, MASK_PLAYERSOLID,
|
|
|
|
ent->origin, angles);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
if (trace.allsolid || trace.startsolid ||
|
2012-07-22 13:34:45 +00:00
|
|
|
(trace.fraction < tr->fraction))
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
trace.ent = (struct edict_s *)ent;
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
if (tr->startsolid)
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
*tr = trace;
|
|
|
|
tr->startsolid = true;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
*tr = trace;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-28 14:41:18 +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;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* check against world */
|
2012-07-22 13:34:45 +00:00
|
|
|
t = CM_BoxTrace(start, end, mins, maxs, 0, MASK_PLAYERSOLID);
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (t.fraction < 1.0)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
t.ent = (struct edict_s *)1;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* check all other solid models */
|
2012-07-22 13:34:45 +00:00
|
|
|
CL_ClipMoveToEntities(start, mins, maxs, end, &t);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
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;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
contents = CM_PointContents(point, 0);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
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);
|
2009-02-28 14:41:18 +00:00
|
|
|
ent = &cl_parse_entities[num];
|
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
if (ent->solid != 31) /* special value for bmodel */
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
cmodel = cl.model_clip[ent->modelindex];
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!cmodel)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
contents |= CM_TransformedPointContents(point, cmodel->headnode,
|
|
|
|
ent->origin, ent->angles);
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-06-18 14:25:50 +00:00
|
|
|
* 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;
|
2017-11-14 17:24:41 +00:00
|
|
|
vec3_t tmp;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
if (cls.state != ca_active)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
if (cl_paused->value)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
2012-07-22 13:34:45 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
if (!cl_predict->value ||
|
|
|
|
(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
|
|
|
|
{
|
2010-06-18 14:25:50 +00:00
|
|
|
/* 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]);
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-06-18 14:25:50 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ack = cls.netchan.incoming_acknowledged;
|
|
|
|
current = cls.netchan.outgoing_sequence;
|
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* if we are too far out of date, just freeze */
|
2012-07-22 13:34:45 +00:00
|
|
|
if (current - ack >= CMD_BACKUP)
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl_showmiss->value)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
|
|
|
Com_Printf("exceeded CMD_BACKUP\n");
|
|
|
|
}
|
2010-06-18 14:25:50 +00:00
|
|
|
|
|
|
|
return;
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* copy current state to pmove */
|
2016-08-04 15:36:42 +00:00
|
|
|
memset (&pm, 0, sizeof(pm));
|
2009-02-28 14:41:18 +00:00
|
|
|
pm.trace = CL_PMTrace;
|
|
|
|
pm.pointcontents = CL_PMpointcontents;
|
2016-08-04 15:36:42 +00:00
|
|
|
pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
|
2009-02-28 14:41:18 +00:00
|
|
|
pm.s = cl.frame.playerstate.pmove;
|
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* run frames */
|
2016-08-04 15:36:42 +00:00
|
|
|
while (++ack <= current)
|
2012-07-22 13:34:45 +00:00
|
|
|
{
|
|
|
|
frame = ack & (CMD_BACKUP - 1);
|
2009-02-28 14:41:18 +00:00
|
|
|
cmd = &cl.cmds[frame];
|
|
|
|
|
2016-08-04 15:36:42 +00:00
|
|
|
// Ignore null entries
|
|
|
|
if (!cmd->msec)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
pm.cmd = *cmd;
|
2012-07-22 13:34:45 +00:00
|
|
|
Pmove(&pm);
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* save for debug checking */
|
2012-07-22 13:34:45 +00:00
|
|
|
VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-22 15:09:17 +00:00
|
|
|
// step is used for movement prediction on stairs
|
|
|
|
// (so moving up/down stairs is smooth)
|
2016-08-14 10:45:16 +00:00
|
|
|
step = pm.s.origin[2] - (int)(cl.predicted_origin[2] * 8);
|
2018-02-07 18:02:13 +00:00
|
|
|
VectorCopy(pm.s.velocity, tmp);
|
2016-08-11 17:11:33 +00:00
|
|
|
|
2022-10-22 15:09:17 +00:00
|
|
|
if (((step > 62 && step < 66) || (step > 94 && step < 98) || (step > 126 && step < 130))
|
2017-11-14 17:24:41 +00:00
|
|
|
&& !VectorCompare(tmp, vec3_origin)
|
2016-08-17 19:03:36 +00:00
|
|
|
&& (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;
|
2016-08-14 10:45:16 +00:00
|
|
|
cl.predicted_step_time = cls.realtime - (int)(cls.nframetime * 500);
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-06-18 14:25:50 +00:00
|
|
|
/* 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;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2012-07-22 13:34:45 +00:00
|
|
|
VectorCopy(pm.viewangles, cl.predicted_angles);
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2012-07-22 13:34:45 +00:00
|
|
|
|