This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/cl_pred.c

251 lines
6.3 KiB
C

//=======================================================================
// Copyright XashXT Group 2008 ©
// cl_pred.c - client movement prediction
//=======================================================================
#include "common.h"
#include "client.h"
#include "matrix_lib.h"
#include "const.h"
#include "pm_local.h"
#include "net_encode.h"
#define MAX_FORWARD 6
qboolean CL_IsPredicted( void )
{
cl_entity_t *player = CL_GetLocalPlayer();
if( !player )
return false;
if( !cl.frame.valid )
return false;
if( cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= CL_UPDATE_BACKUP - 1 )
return false;
if( !cl_predict->integer )
return false;
return true;
}
void CL_PreRunCmd( cl_entity_t *clent, usercmd_t *ucmd )
{
clgame.pmove->runfuncs = false;
clgame.dllFuncs.pfnCmdStart( clent, clgame.pmove->runfuncs );
}
/*
===========
CL_PostRunCmd
Done after running a player command.
===========
*/
void CL_PostRunCmd( cl_entity_t *clent, usercmd_t *ucmd )
{
if( !clent ) return;
clgame.pmove->runfuncs = false; // all next calls ignore footstep sounds
clgame.dllFuncs.pfnCmdEnd( clent, ucmd, cl.random_seed );
}
/*
===================
CL_CheckPredictionError
===================
*/
void CL_CheckPredictionError( void )
{
int frame;
vec3_t delta;
cl_entity_t *player;
float flen;
if( !CL_IsPredicted( )) return;
player = CL_GetLocalPlayer();
if( !player ) return;
// calculate the last usercmd_t we sent that the server has processed
frame = cls.netchan.incoming_acknowledged;
frame &= CL_UPDATE_MASK;
// compare what the server returned with what we had predicted it to be
VectorSubtract( player->curstate.origin, cl.predicted_origins[frame], delta );
// save the prediction error for interpolation
flen = fabs( delta[0] ) + fabs( delta[1] ) + fabs( delta[2] );
if( flen > 80 )
{
// a teleport or something
VectorClear( cl.prediction_error );
}
else
{
if( cl_showmiss->integer && flen > 0.1f ) Msg( "prediction miss: %g\n", flen );
VectorCopy( player->curstate.origin, cl.predicted_origins[frame] );
// save for error itnerpolation
VectorCopy( delta, cl.prediction_error );
}
}
/*
===============
CL_SetIdealPitch
===============
*/
void CL_SetIdealPitch( cl_entity_t *ent )
{
float angleval, sinval, cosval;
pmtrace_t tr;
vec3_t top, bottom;
float z[MAX_FORWARD];
int i, j;
int step, dir, steps;
if( !( cl.frame.clientdata.flags & FL_ONGROUND ))
return;
angleval = ent->angles[YAW] * M_PI * 2 / 360;
com.sincos( angleval, &sinval, &cosval );
for( i = 0; i < MAX_FORWARD; i++ )
{
top[0] = ent->origin[0] + cosval * (i + 3) * 12;
top[1] = ent->origin[1] + sinval * (i + 3) * 12;
top[2] = ent->origin[2] + cl.frame.clientdata.view_ofs[2];
bottom[0] = top[0];
bottom[1] = top[1];
bottom[2] = top[2] - 160;
// skip any monsters (only world and brush models)
tr = PM_PlayerTrace( clgame.pmove, top, bottom, PM_STUDIO_IGNORE, 2, -1, NULL );
if( tr.allsolid ) return; // looking at a wall, leave ideal the way is was
if( tr.fraction == 1.0f )
return; // near a dropoff
z[i] = top[2] + tr.fraction * (bottom[2] - top[2]);
}
dir = 0;
steps = 0;
for( j = 1; j < i; j++ )
{
step = z[j] - z[j-1];
if( step > -ON_EPSILON && step < ON_EPSILON )
continue;
if( dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ))
return; // mixed changes
steps++;
dir = step;
}
if( !dir )
{
cl.refdef.idealpitch = 0;
return;
}
if( steps < 2 ) return;
cl.refdef.idealpitch = -dir * cl_idealpitchscale->value;
}
/*
=================
CL_PredictMovement
Sets cl.predicted_origin and cl.predicted_angles
=================
*/
void CL_PredictMovement( void )
{
int frame;
int ack, current;
cl_entity_t *player, *viewent;
clientdata_t *cd;
usercmd_t *cmd;
if( cls.state != ca_active ) return;
if( cl.refdef.paused || cls.key_dest == key_menu ) return;
player = CL_GetLocalPlayer ();
viewent = CL_GetEntityByIndex( cl.refdef.viewentity );
cd = &cl.frame.clientdata;
CL_SetIdealPitch( player );
if( cls.demoplayback && viewent )
{
// restore viewangles from angles
cl.refdef.cl_viewangles[PITCH] = -viewent->angles[PITCH] * 3;
cl.refdef.cl_viewangles[YAW] = viewent->angles[YAW];
cl.refdef.cl_viewangles[ROLL] = 0; // roll will be computed in view.cpp
}
// unpredicted pure angled values converted into axis
AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up );
if( 1 )//// disabled for now!!!!!!!!!!!!!!!!!!!!!!!!! ///////!CL_IsPredicted( ))
{
cmd = cl.refdef.cmd; // use current command
// run commands even if client predicting is disabled - client expected it
CL_PreRunCmd( player, cmd );
VectorCopy( cl.refdef.cl_viewangles, cl.predicted_angles );
VectorCopy( cd->view_ofs, cl.predicted_viewofs );
CL_PostRunCmd( player, cmd );
return;
}
#if 0
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 )
MsgDev( D_ERROR, "CL_Predict: exceeded CMD_BACKUP\n" );
return;
}
// setup initial pmove state
// FIXME!!!!...
// VectorCopy( player->v.movedir, clgame.pmove->movedir );
VectorCopy( cd->origin, clgame.pmove->origin );
VectorCopy( cd->velocity, clgame.pmove->velocity );
VectorCopy( player->curstate.basevelocity, clgame.pmove->basevelocity );
clgame.pmove->flWaterJumpTime = cd->waterjumptime;
clgame.pmove->onground = (edict_t *)CL_GetEntityByIndex( player->curstate.onground );
clgame.pmove->usehull = (player->curstate.flags & FL_DUCKING) ? 1 : 0; // reset hull
// run frames
while( ++ack < current )
{
frame = ack & CL_UPDATE_MASK;
cmd = &cl.cmds[frame];
CL_PreRunCmd( player, cmd );
CL_RunCmd( player, cmd );
CL_PostRunCmd( player, cmd );
// save for debug checking
VectorCopy( clgame.pmove->origin, cl.predicted_origins[frame] );
}
// copy results out for rendering
VectorCopy( player->v.view_ofs, cl.predicted_viewofs );
VectorCopy( clgame.pmove->origin, cl.predicted_origin );
VectorCopy( clgame.pmove->angles, cl.predicted_angles );
VectorCopy( clgame.pmove->velocity, cl.predicted_velocity );
#endif
}