#include "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;
frame = cls.netchan.incoming_acknowledged;
frame &= (CMD_BACKUP - 1);
VectorSubtract(cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
if(len > 640) { 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]);
for(i = 0; i < 3; i++)
cl.prediction_error[i] = delta[i] * 0.125;
}
}
void CL_ClipMoveToEntities(int cmodel_index, 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->cmodel_index != cmodel_index)
continue;
if(ent->solid == 31) { cmodel = cl.cmodel_clip[ent->modelindex - 1][ent->modelindex2];
if(!cmodel)
continue;
headnode = cmodel->headnode;
angles = ent->angles;
} else { x = 8 * (ent->solid & 31);
zd = 8 * ((ent->solid >> 5) & 31);
zu = 8 * ((ent->solid >> 10) & 63) - 32;
bmins[0] = bmins[1] = -x;
bmaxs[0] = bmaxs[1] = x;
bmins[2] = -zd;
bmaxs[2] = zu;
headnode = CM_HeadnodeForBox(cmodel_index, bmins, bmaxs);
angles = vec3_origin; }
if(tr->allsolid)
return;
trace =
CM_TransformedBoxTrace(cmodel_index, 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(int cmodel_index, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) {
trace_t t;
t = CM_BoxTrace(cmodel_index, start, end, mins, maxs, 0, MASK_PLAYERSOLID);
if(t.fraction < 1.0)
t.ent = (struct edict_s *)1;
CL_ClipMoveToEntities(cmodel_index, start, mins, maxs, end, &t);
return t;
}
int CL_PMpointcontents(int cmodel_index, vec3_t point) {
int i;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
int contents;
contents = CM_PointContents(cmodel_index, 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->cmodel_index != cmodel_index)
continue;
if(ent->solid != 31) continue;
cmodel = cl.cmodel_clip[ent->modelindex - 1][ent->modelindex2];
if(!cmodel)
continue;
contents |= CM_TransformedPointContents(cmodel_index, point, cmodel->headnode, ent->origin, ent->angles);
}
return contents;
}
void CL_PredictMovement(void) {
int ack, current;
int frame;
int oldframe;
usercmd_t *cmd;
pmove_t pm;
int i;
int step;
int oldz;
if(cls.state != ca_active)
return;
if(cl_paused->value)
return;
if(!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)) { 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(current - ack >= CMD_BACKUP) {
if(cl_showmiss->value)
Com_Printf("exceeded CMD_BACKUP\n");
return;
}
memset(&pm, 0, sizeof(pm));
pm.cmodel_index = cl.frame.playerstate.cmodel_index;
pm.trace = CL_PMTrace;
pm.pointcontents = CL_PMpointcontents;
pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
pm.s = cl.frame.playerstate.pmove;
frame = 0;
while(++ack < current) {
frame = ack & (CMD_BACKUP - 1);
cmd = &cl.cmds[frame];
pm.cmd = *cmd;
Pmove(&pm);
VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
}
oldframe = (ack - 2) & (CMD_BACKUP - 1);
oldz = cl.predicted_origins[oldframe][2];
step = pm.s.origin[2] - oldz;
if(step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND)) {
cl.predicted_step = step * 0.125;
cl.predicted_step_time = cls.realtime - cls.frametime * 500;
}
cl.predicted_origin[0] = pm.s.origin[0] * 0.125;
cl.predicted_origin[1] = pm.s.origin[1] * 0.125;
cl.predicted_origin[2] = pm.s.origin[2] * 0.125;
VectorCopy(pm.viewangles, cl.predicted_angles);
}