mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-25 21:31:18 +00:00
e818226c34
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.
240 lines
5.7 KiB
C
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");
|
|
}
|
|
|