quakeforge-old/qw_client/cl_pred.c
Joseph Carter e818226c34 This SHOULD allow Mega2K to work whenever it gets released. View offsets
are done (sorry if this steps on your toes with the view.c merge Deek) and
I'm almost positive flymode will now work.  Even though view offset is
done, it won't.

The reason for this is that cl.stats[STAT_FLYMODE] is pretty much going to
ALWAYS be 0 on a standard server.  Since 0 tells us that we're not flying,
this is fine.  cl.stats[STAT_VIEWHEIGHT] is also going to be 0, but it
should be 22 for normal views.  I could always assume this value is an
offset from 22, but that just seems lame to me.  I'll either do it anyway
or we'll have to find a good opportunity in the connect cycle to set the
cl.qfserver qboolean to true.

I'm thinking about using an info key value for this, but we'd be better
served I think by coordinating with QSG to up the protocol version across
all engines.
2000-03-11 21:29:48 +00:00

240 lines
5.7 KiB
C

/*
cl_pred.c
Copyright (C) 1996-1997 Id Software, Inc.
Portions Copyright (C) 1999,2000 Nelson Rush.
Copyright (C) 1999,2000 contributors of the QuakeForge project
Please see the file "AUTHORS" for a list of contributors
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.
*/
#include <qtypes.h>
#include <quakedef.h>
#include <winquake.h>
#include <cvar.h>
#include <client.h>
#include <console.h>
#include <mathlib.h>
cvar_t *cl_nopred;
cvar_t *cl_pushlatency;
extern frame_t *view_frame;
/*
CL_NudgePosition
If pmove.origin is in a solid position,
try nudging slightly on all axis to
allow for the cut precision of the net coordinates
*/
void
CL_NudgePosition (void)
{
vec3_t base;
int x, y;
if (PM_HullPointContents (&cl.model_precache[1]->hulls[1], 0,
pmove.origin) == CONTENTS_EMPTY)
return;
VectorCopy (pmove.origin, base);
for (x=-1 ; x<=1 ; x++)
{
for (y=-1 ; y<=1 ; y++)
{
pmove.origin[0] = base[0] + x * 1.0/8;
pmove.origin[1] = base[1] + y * 1.0/8;
if (PM_HullPointContents (&cl.model_precache[1]->hulls[1], 0, pmove.origin) == CONTENTS_EMPTY)
return;
}
}
Con_DPrintf ("CL_NudgePosition: stuck\n");
}
/*
CL_PredictUsercmd
*/
void
CL_PredictUsercmd (player_state_t *from, player_state_t *to, usercmd_t *u,
qboolean spectator)
{
// split up very long moves
if (u->msec > 50)
{
player_state_t temp;
usercmd_t split;
split = *u;
split.msec /= 2;
CL_PredictUsercmd (from, &temp, &split, spectator);
CL_PredictUsercmd (&temp, to, &split, spectator);
return;
}
VectorCopy (from->origin, pmove.origin);
// VectorCopy (from->viewangles, pmove.angles);
VectorCopy (u->angles, pmove.angles);
VectorCopy (from->velocity, pmove.velocity);
pmove.oldbuttons = from->oldbuttons;
pmove.waterjumptime = from->waterjumptime;
pmove.dead = cl.stats[STAT_HEALTH] <= 0;
pmove.spectator = spectator;
pmove.flying = cl.stats[STAT_FLYMODE];
pmove.cmd = *u;
PlayerMove ();
//for (i=0 ; i<3 ; i++)
//pmove.origin[i] = ((int)(pmove.origin[i]*8))*0.125;
to->waterjumptime = pmove.waterjumptime;
to->oldbuttons = pmove.cmd.buttons;
VectorCopy (pmove.origin, to->origin);
VectorCopy (pmove.angles, to->viewangles);
VectorCopy (pmove.velocity, to->velocity);
to->onground = onground;
to->weaponframe = from->weaponframe;
}
/*
CL_PredictMove
*/
void
CL_PredictMove (void)
{
int i;
float f;
frame_t *from, *to = NULL;
int oldphysent;
if (cl_pushlatency->value > 0)
Cvar_Set ("pushlatency", "0");
if (cl.paused)
return;
cl.time = realtime - cls.latency - cl_pushlatency->value*0.001;
if (cl.time > realtime)
cl.time = realtime;
if (cl.intermission)
return;
if (!cl.validsequence)
return;
if (cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= UPDATE_BACKUP-1)
return;
VectorCopy (cl.viewangles, cl.simangles);
// this is the last frame received from the server
from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
// we can now render a frame
if (cls.state == ca_onserver)
{ // first update is the final signon stage
char text[1024];
cls.state = ca_active;
snprintf(text, sizeof(text), "QuakeWorld: %s", cls.servername);
#ifdef _WIN32
SetWindowText (mainwindow, text);
#endif
}
if (cl_nopred->value)
{
VectorCopy (from->playerstate[cl.playernum].velocity, cl.simvel);
VectorCopy (from->playerstate[cl.playernum].origin, cl.simorg);
return;
}
// predict forward until cl.time <= to->senttime
oldphysent = pmove.numphysent;
CL_SetSolidPlayers (cl.playernum);
// to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
for (i=1 ; i<UPDATE_BACKUP-1 && cls.netchan.incoming_sequence+i <
cls.netchan.outgoing_sequence; i++)
{
to = &cl.frames[(cls.netchan.incoming_sequence+i)
& UPDATE_MASK];
CL_PredictUsercmd (&from->playerstate[cl.playernum],
&to->playerstate[cl.playernum], &to->cmd,
cl.spectator);
if (to->senttime >= cl.time)
break;
from = to;
}
pmove.numphysent = oldphysent;
if (i == UPDATE_BACKUP-1 || !to)
return; // net hasn't deliver packets in a long time...
// now interpolate some fraction of the final frame
if (to->senttime == from->senttime)
f = 0;
else
{
f = (cl.time - from->senttime) / (to->senttime
- from->senttime);
f = max(0, min(f, 1));
}
for (i=0 ; i<3 ; i++)
if ( fabs(from->playerstate[cl.playernum].origin[i]
- to->playerstate[cl.playernum].origin[i])
> 128)
{ // teleported, so don't lerp
VectorCopy (to->playerstate[cl.playernum].velocity,
cl.simvel);
VectorCopy (to->playerstate[cl.playernum].origin,
cl.simorg);
return;
}
for (i=0 ; i<3 ; i++)
{
cl.simorg[i] = from->playerstate[cl.playernum].origin[i]
+ f*(to->playerstate[cl.playernum].origin[i]
- from->playerstate[cl.playernum].origin[i]);
cl.simvel[i] = from->playerstate[cl.playernum].velocity[i]
+ f*(to->playerstate[cl.playernum].velocity[i]
- from->playerstate[cl.playernum].velocity[i]);
}
}
/*
CL_InitPrediction
*/
void
CL_InitPrediction (void)
{
cl_pushlatency = Cvar_Get ("cl_pushlatency","0",CVAR_NONE,"None");
cl_nopred = Cvar_Get ("cl_nopred","0",CVAR_NONE,"None");
}