djcev.com

//

Git Repos / fte_dogmode / qc / cl_player.qc

Last update to this file was on 2024-03-24 at 02:40.

Show cl_player.qc

//==============================================================================
// CSQC PLAYER MOVEMENT & PREDICTION
//
// This is based on code by Eukara [1] and the CSQCTest code shipped with
// FTEQW [2].
//
// [1]: https://icculus.org/~marco/quakec/csqc/prediction.html
// [2]: https://sourceforge.net/p/fteqw/code/HEAD/tree/trunk/quakec/csqctest/src
//==============================================================================

//======================================================================
// constants
//======================================================================

#ifdef CSQC
const float PRED_ERRORTIME = 20; //
const float PRED_STEPTIME = 8;
#endif

//======================================================================
// forward declarations
//======================================================================

#ifdef CSQC
void(entity ent) PlayerResetPrediction;
void(entity ent, float endframe) PlayerRunMovement;
float() PlayerPreDraw;
static void() PlayerRemove;
void() PlayerNew;
void(float isnew) PlayerUpdate;
#endif

//------------------------------------------------------------------------------

#ifdef CSQC
//----------------------------------------------------------------------
// PlayerResetPrediction
// was Pred_ResetPlayerPrediction in CSQCTest cs/prediction.qc
//----------------------------------------------------------------------
void(entity e) PlayerResetPrediction =
{
e.origin = player_org;
e.velocity = player_vel;
e.flags = player_flags;
e.pmove_flags = player_pmove_flags;
e.doublejump_timer = player_doublejump_timer;

// +1 because the received frame has the move already done (server side)
pmove_frame = player_sequence + 1;

if (pmove_frame < clientcommandframe - 128)
// avoid an infinite loop
pmove_frame = clientcommandframe - 128;
};

//----------------------------------------------------------------------
// PlayerRunMovement
// was Pred_RunMovement in CSQCTest cs/prediction.qc
//----------------------------------------------------------------------
void(entity e, float endframe) PlayerRunMovement =
{
if (servercommandframe >= player_sequence + 63)
{
// we're meant to be updating the player faster than
// this. hopefully its just that we're throttled...

// you can comment out this block and the player will
// continue to be predicted locally. But its best to
// freeze them

// as a note we also hit this block when the console is
// down -- CEV

player_sequence = servercommandframe - 63;
return;
}

PlayerResetPrediction (e);

if (getstatf(STAT_HEALTH) <= 0)
{
// dead, so don't run prediction. :D
pmove_frame = clientcommandframe;
if (!getinputstate(pmove_frame - 1))
{
dprint ("PlayerRunMovement: no-op if statement?\n");
// no-op ? -- CEV
}
return;
}

/*
if (getinputstate(pmove_frame - 1))
// from CSQCTest; what is this doing? -- TODO CEV;
e.pmove_flags |= PMF_JUMP_HELD;
*/

while (pmove_frame <= endframe)
{
if (!getinputstate(pmove_frame))
{
// no input from client
// pmove_frame++;
break;
}

if (world_standardphysics)
// for testing
runstandardplayerphysics (e);
else
// for real
PM_Move (e);
pmove_frame++;
}

// add anything that was applied after (for low packet
// rate protocols)
// TODO CEV
input_angles = view_angles;
};

//----------------------------------------------------------------------
// PlayerPreDraw
// Incorporates Pred_UpdateLocalMovement from CSQCTest.
//----------------------------------------------------------------------
float() PlayerPreDraw =
{
local float viewheight;

if (self.entnum != player_localentnum)
{
self.renderflags = 0;
}
else
{
PlayerRunMovement (self, clientcommandframe);

if (self.origin_z >= player_step_oldz + 6 &&
self.origin_z < player_step_oldz + 24 &&
self.velocity_z == 0)
{
// evaluate out the remaining old step
if (player_steptime - time > 0)
player_step = (player_steptime - time) *
PRED_STEPTIME * player_step;
else
player_step = 0;

// work out the new step
player_step += (player_step_oldz - self.origin_z);
player_steptime = time + 1 / PRED_STEPTIME;
}
player_step_oldz = self.origin_z;

// allow the user to move the viewheight down 6 units so
// it's at +16, where projectiles come from.
viewheight = autocvar (v_viewheight, 0);
if (viewheight < -7)
viewheight = -7;
else if (viewheight > 7)
viewheight = 7;

view_origin = self.origin;
view_origin_z += getstatf (STAT_VIEWHEIGHT) + viewheight;

// correct the view position to compensate for any errors,
// slowly over time, 0.1 seconds.
if (pmove_errortime - time > 0)
{
dprint ("PlayerPreDraw: pmove error\n");
view_origin += (pmove_errortime - time) *
PRED_ERRORTIME * pmove_error;
}

if (player_steptime - time > 0)
view_origin_z += (player_steptime - time) *
PRED_STEPTIME * player_step;

if (self.lerptime)
self.lerpfrac = 1 - (time - self.lerptime) * 10;

self.renderflags |= RF_EXTERNALMODEL;
}

viewentity.angles = view_angles;
viewentity.origin = view_origin;

addentity (self);
return PREDRAW_NEXT;
};

//----------------------------------------------------------------------
// PlayerRemove
//----------------------------------------------------------------------
static void() PlayerRemove =
{
if (player_local == self)
player_local = world;

setmodel (self, "");
self.oldskin = "";
self.predraw = __NULL__;
};

//----------------------------------------------------------------------
// PlayerNew
//----------------------------------------------------------------------
void() PlayerNew =
{
self.classname = "player";
self.customphysics = sub_null;
// MASK_NORMAL ?
self.drawmask = MASK_ENGINE;
self.movetype = MOVETYPE_WALK;
self.predraw = PlayerPreDraw;
self.removefunc = PlayerRemove;
self.solid = SOLID_SLIDEBOX;
setmodel (self, "progs/player.mdl");
};

//----------------------------------------------------------------------
// PlayerUpdate
// called from CSQC_Ent_Update for CT_PLAYER entities
//----------------------------------------------------------------------
void(float isnew) PlayerUpdate =
{
local float f;

f = ReadByte ();
self.origin_x = ReadCoord ();
self.origin_y = ReadCoord ();
self.origin_z = ReadCoord ();
self.angles_x = ReadShort () / (32767 / 360);
self.angles_y = ReadShort () / (32767 / 360);
self.angles_z = ReadShort () / (32767 / 360);
self.velocity_x = ReadShort ();
self.velocity_y = ReadShort ();
self.velocity_z = ReadShort ();
self.effects = ReadFloat ();
self.flags = ReadFloat ();
self.pmove_flags = ReadFloat ();
self.doublejump_timer = ReadFloat ();

if (isnew && !(self.predraw))
PlayerNew ();

if (intermission)
{
// zero out velocity if in intermission -- CEV
world_gravity = 0.0f;
input_movevalues = '0 0 0';
self.velocity = '0 0 0';
viewentity.velocity = '0 0 0';
// viewentity.angles = self.angles;
// viewentity.origin = self.origin;
// setorigin (self, self.origin);
// setorigin (viewentity, viewentity.origin);
return;
}

if (f != self.frame || isnew)
{
self.frame2 = self.frame;
self.lerptime = time;
self.frame = f;
}

if (self.entnum == player_localentnum)
{
local vector o, v;
local float djt, gbt, pmflags, tempflags;

// this is us; save for later
player_local = self;
o = self.origin;
v = self.velocity;
djt = self.doublejump_timer;
tempflags = self.flags;
pmflags = self.pmove_flags;

// PlayerRunMovement calls ResetPrediction -- CEV
// PlayerResetPrediction (self);
PlayerRunMovement (self, servercommandframe + 1);

// TODO CEV ????
player_doublejump_timer = djt;
player_flags = tempflags;
player_pmove_flags = pmflags;
player_org = o;
player_vel = v;
player_sequence = servercommandframe;

if (autocvar(cg_noerror, TRUE))
{
pmove_error = '0 0 0';
pmove_errortime = time;
PlayerResetPrediction (self);
}
else
{
PlayerRunMovement (self, clientcommandframe);
o = self.origin;
// again: PlayerRunMovement calls ResetPrediction
// PlayerResetPrediction (self);
PlayerRunMovement (self, clientcommandframe);

if (vlen(o - self.origin) > 64)
{
// teleport
pmove_error = '0 0 0';
pmove_errortime = time;
}
else
{
pmove_error = (pmove_errortime - time) *
PRED_ERRORTIME * pmove_error +
(o - self.origin);
if (vlen(pmove_error) < 1)
pmove_error = '0 0 0';
pmove_errortime = time + 1 / PRED_ERRORTIME;
}
}
}

setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
self.oldframe = self.frame;
// setorigin (self, self.origin);
};
#endif

Return to the top of this page or return to the overview of this repo.

Log cl_player.qc

Date Commit Message Author + -
2024-03-24 2nd pass refactor, rework QC class structure cev +329  

Return to the top of this page or return to the overview of this repo.