yquake2remaster/src/client/cl_prediction.c
Yamagi Burmeister e30f824944 Don't cast the array itself but it's content.
This was so broken... Casting the type of an array to silence a
warning... It worked on x86, of course. But gave a SIGBUS on ARM.
Do it right, cast / copy the content of the array into another
array of the correct type. Yeah.

This fixes issue #231.
2017-11-14 17:24:41 +00:00

317 lines
6.4 KiB
C

/*
* 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.
*
* =======================================================================
*
* This file implements interpolation between two frames. This is used
* to smooth down network play
*
* =======================================================================
*/
#include "header/client.h"
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;
}
/* calculate the last usercmd_t we sent that the server has processed */
frame = cls.netchan.incoming_acknowledged;
frame &= (CMD_BACKUP - 1);
/* compare what the server returned with what we had predicted it to be */
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]);
/* 80 world units */
if (len > 640)
{
/* a teleport or something */
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]);
}
VectorCopy(cl.frame.playerstate.pmove.origin,
cl.predicted_origins[frame]);
/* save for error itnerpolation */
for (i = 0; i < 3; i++)
{
cl.prediction_error[i] = delta[i] * 0.125f;
}
}
}
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)
{
continue;
}
if (ent->number == cl.playernum + 1)
{
continue;
}
if (ent->solid == 31)
{
/* special value for bmodel */
cmodel = cl.model_clip[ent->modelindex];
if (!cmodel)
{
continue;
}
headnode = cmodel->headnode;
angles = ent->angles;
}
else
{
/* encoded bbox */
x = 8 * (ent->solid & 31);
zd = 8 * ((ent->solid >> 5) & 31);
zu = 8 * ((ent->solid >> 10) & 63) - 32;
bmins[0] = bmins[1] = -(float)x;
bmaxs[0] = bmaxs[1] = (float)x;
bmins[2] = -(float)zd;
bmaxs[2] = (float)zu;
headnode = CM_HeadnodeForBox(bmins, bmaxs);
angles = vec3_origin; /* boxes don't rotate */
}
if (tr->allsolid)
{
return;
}
trace = CM_TransformedBoxTrace(start, end,
mins, maxs, headnode, MASK_PLAYERSOLID,
ent->origin, angles);
if (trace.allsolid || trace.startsolid ||
(trace.fraction < tr->fraction))
{
trace.ent = (struct edict_s *)ent;
if (tr->startsolid)
{
*tr = trace;
tr->startsolid = true;
}
else
{
*tr = trace;
}
}
else if (trace.startsolid)
{
tr->startsolid = true;
}
}
}
trace_t
CL_PMTrace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
{
trace_t t;
/* check against world */
t = CM_BoxTrace(start, end, mins, maxs, 0, MASK_PLAYERSOLID);
if (t.fraction < 1.0)
{
t.ent = (struct edict_s *)1;
}
/* check all other solid models */
CL_ClipMoveToEntities(start, mins, maxs, end, &t);
return t;
}
int
CL_PMpointcontents(vec3_t point)
{
int i;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
int contents;
contents = CM_PointContents(point, 0);
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 */
{
continue;
}
cmodel = cl.model_clip[ent->modelindex];
if (!cmodel)
{
continue;
}
contents |= CM_TransformedPointContents(point, cmodel->headnode,
ent->origin, ent->angles);
}
return contents;
}
/*
* Sets cl.predicted_origin and cl.predicted_angles
*/
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)
{
return;
}
if (cl_paused->value)
{
return;
}
if (!cl_predict->value ||
(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
{
/* just set angles */
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 */
if (current - ack >= CMD_BACKUP)
{
if (cl_showmiss->value)
{
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)
{
frame = ack & (CMD_BACKUP - 1);
cmd = &cl.cmds[frame];
// Ignore null entries
if (!cmd->msec)
{
continue;
}
pm.cmd = *cmd;
Pmove(&pm);
/* save for debug checking */
VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
}
step = pm.s.origin[2] - (int)(cl.predicted_origin[2] * 8);
VectorCopy(tmp, pm.s.velocity);
if (((step > 126 && step < 130))
&& !VectorCompare(tmp, vec3_origin)
&& (pm.s.pm_flags & PMF_ON_GROUND))
{
cl.predicted_step = step * 0.125f;
cl.predicted_step_time = cls.realtime - (int)(cls.nframetime * 500);
}
/* copy results out for rendering */
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;
VectorCopy(pm.viewangles, cl.predicted_angles);
}