mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-10 14:42:13 +00:00
Update VR-Inputs extension. Should now be more resilient against impulse loss, should also report better ping times.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5966 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
0fd629f2d2
commit
e90a0b3945
7 changed files with 432 additions and 235 deletions
|
@ -34,9 +34,10 @@ static cvar_t cl_movement = CVARD("cl_movement","1", "Specifies whether to send
|
|||
|
||||
cvar_t cl_nodelta = CVAR("cl_nodelta","0");
|
||||
|
||||
cvar_t cl_c2sdupe = CVAR("cl_c2sdupe", "0");
|
||||
cvar_t cl_c2sdupe = CVARD("cl_c2sdupe", "0", "Send duplicate copies of packets to the server. This avoids extra latency caused by packetloss, but could also make the problem worse.");
|
||||
cvar_t cl_c2spps = CVARD("cl_c2spps", "0", "Reduces outgoing packet rates by dropping up to a third of outgoing packets.");
|
||||
cvar_t cl_c2sImpulseBackup = CVARD("cl_c2sImpulseBackup","3", "Prevents the cl_c2spps setting from dropping redundant packets that contain impulses, in an attempt to keep impulses more reliable.");
|
||||
static cvar_t cl_c2sMaxRedundancy = CVARD("cl_c2sMaxRedundancy","5", "This is the maximum number of input frames to send in each input packet. Values greater than 1 provide redundancy and avoid prediction misses, though you might find cl_c2sdupe provides equivelent result and at lower latency. It is locked at 3 for vanilla quakeworld, and locked at 1 for vanilla netquake.");
|
||||
cvar_t cl_netfps = CVARD("cl_netfps", "150", "Send up to this many packets to the server per second. The rate used is also limited by the server which usually forces a cap to this setting of 77. Low packet rates can result in extra extrapolation to try to hide the resulting latencies.");
|
||||
cvar_t cl_sparemsec = CVARCD("cl_sparemsec", "10", CL_SpareMsec_Callback, "Allows the 'banking' of a little extra time, so that one slow frame will not delay the timing of the following frame so much.");
|
||||
cvar_t cl_queueimpulses = CVARD("cl_queueimpulses", "0", "Queues unsent impulses instead of replacing them. This avoids the need for extra wait commands (and the timing issues of such commands), but potentially increases latency and can cause scripts to be desynced with regard to buttons and impulses.");
|
||||
|
@ -1213,6 +1214,82 @@ static void CL_FinishMove (usercmd_t *cmd, int pnum)
|
|||
cmd->impulse = 0;
|
||||
}
|
||||
|
||||
|
||||
static qboolean CLFTE_SendVRCmd (sizebuf_t *buf, unsigned int seats)
|
||||
{
|
||||
//compute the delay between receiving the frame we're acking and when we're sending the new frame
|
||||
unsigned int cldelay = (realtime - cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK].receivedtime)*10000; //this is to report actual network latency instead of just reporting our packet rate (framerates may still be a factor).
|
||||
unsigned int lost = CL_CalcNet(r_netgraph.value); //report packetloss
|
||||
unsigned int flags = 0;
|
||||
unsigned int first = cl.ackedmovesequence+1; //no point resending that which has already been acked.
|
||||
unsigned int last = cl.movesequence+1; //we want to ignore moveseq itself
|
||||
unsigned int frame, seat, count, i;
|
||||
const usercmd_t *from, *to;
|
||||
qboolean dontdrop = false;
|
||||
if (first > last)
|
||||
first = last-1;
|
||||
if (first < last-(countof(cl.outframes)-2))
|
||||
first = last-(countof(cl.outframes)-2);
|
||||
if (first < 1)
|
||||
first = 1;
|
||||
if (last < first)
|
||||
count = 0;
|
||||
else
|
||||
count = last-first;
|
||||
if (count > max(1,cl_c2sMaxRedundancy.ival))
|
||||
count = max(1,cl_c2sMaxRedundancy.ival);
|
||||
if (cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK].receivedtime<0)
|
||||
cldelay = 0; //erk?
|
||||
|
||||
MSG_WriteByte (buf, clcfte_move);
|
||||
|
||||
#ifdef NQPROT
|
||||
if (cls.protocol == CP_NETQUAKE) //nq uses fully separate packet+movement sequences (unlike qw).
|
||||
MSG_WriteShort(buf, (last-1)&0xffff);
|
||||
#endif
|
||||
|
||||
if (seats!=1)
|
||||
flags |= VRM_SEATS;
|
||||
if (lost)
|
||||
flags |= VRM_LOSS;
|
||||
if (cldelay)
|
||||
flags |= VRM_DELAY;
|
||||
if (count!=3)
|
||||
flags |= VRM_FRAMES;
|
||||
if (cl.numackframes)
|
||||
flags |= VRM_ACKS;
|
||||
MSG_WriteUInt64 (buf, flags);
|
||||
|
||||
if (flags & VRM_SEATS)
|
||||
MSG_WriteUInt64 (buf, seats);
|
||||
if (flags & VRM_FRAMES)
|
||||
MSG_WriteUInt64 (buf, count);
|
||||
if (flags & VRM_LOSS)
|
||||
MSG_WriteByte (buf, (qbyte)lost);
|
||||
if (flags & VRM_DELAY)
|
||||
MSG_WriteByte (buf, bound(0,cldelay,255)); //a byte should always be enough for any framerate above 40.
|
||||
if (flags & VRM_ACKS)
|
||||
{
|
||||
MSG_WriteUInt64(buf, cl.numackframes);
|
||||
for (i = 0; i < cl.numackframes; i++)
|
||||
MSG_WriteLong(buf, cl.ackframes[i]);
|
||||
cl.numackframes = 0;
|
||||
}
|
||||
|
||||
from = &nullcmd;
|
||||
for (seat = 0; seat < seats; seat++)
|
||||
for (frame = last-count; frame < last; frame++)
|
||||
{
|
||||
to = &cl.outframes[frame&UPDATE_MASK].cmd[seat];
|
||||
MSGFTE_WriteDeltaUsercmd (buf, from, to);
|
||||
if (to->impulse && (int)(last-frame)>=cl_c2sImpulseBackup.ival)
|
||||
dontdrop = true;
|
||||
from = to;
|
||||
}
|
||||
return dontdrop;
|
||||
}
|
||||
|
||||
|
||||
void CL_UpdatePrydonCursor(usercmd_t *from, int pnum)
|
||||
{
|
||||
int hit;
|
||||
|
@ -1318,10 +1395,6 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf)
|
|||
else if (cls.fteprotocolextensions2 & PEXT2_PREDINFO)
|
||||
MSG_WriteShort(buf, cl.movesequence&0xffff);
|
||||
|
||||
if (cls.fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
MSGFTE_WriteDeltaUsercmd(buf, &nullcmd, cmd);
|
||||
else
|
||||
{
|
||||
MSG_WriteFloat (buf, cmd->fservertime); // use latest time. because ping reports!
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
|
@ -1371,7 +1444,6 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf)
|
|||
MSG_WriteFloat (buf, cmd->cursor_impact[2]);
|
||||
MSG_WriteEntity (buf, cmd->cursor_entitynumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QDECL Name_Callback(struct cvar_s *var, char *oldvalue)
|
||||
|
@ -1411,14 +1483,18 @@ void CLNQ_SendCmd(sizebuf_t *buf)
|
|||
CL_ClearPendingCommands();
|
||||
|
||||
//inputs are only sent once we receive an entity.
|
||||
if (cls.fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
CLFTE_SendVRCmd(buf, (cls.signon != 4 || cls.state == ca_connected)?0:cl.splitclients);
|
||||
else
|
||||
{
|
||||
if (cls.signon == 4)
|
||||
{
|
||||
for (seat = 0; seat < cl.splitclients; seat++)
|
||||
{
|
||||
// send the unreliable message
|
||||
// if (independantphysics[seat].impulse && !cls.netchan.message.cursize)
|
||||
// CLNQ_SendMove (&cl.outframes[i].cmd[seat], seat, &cls.netchan.message);
|
||||
// else
|
||||
// if (independantphysics[seat].impulse && !cls.netchan.message.cursize)
|
||||
// CLNQ_SendMove (&cl.outframes[i].cmd[seat], seat, &cls.netchan.message);
|
||||
// else
|
||||
CLNQ_SendMove (&cl.outframes[i].cmd[seat], seat, buf);
|
||||
}
|
||||
}
|
||||
|
@ -1431,6 +1507,7 @@ void CLNQ_SendCmd(sizebuf_t *buf)
|
|||
MSG_WriteLong(buf, cl.ackframes[i]);
|
||||
}
|
||||
cl.numackframes = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void Name_Callback(struct cvar_s *var, char *oldvalue)
|
||||
|
@ -1924,6 +2001,10 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
|
|||
}
|
||||
CL_ClearPendingCommands();
|
||||
|
||||
if (cls.fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
dontdrop = CLFTE_SendVRCmd(buf, clientcount);
|
||||
else
|
||||
{
|
||||
cmd = &cl.outframes[curframe].cmd[0];
|
||||
if (cmd->cursor_screen[0] || cmd->cursor_screen[1] || cmd->cursor_entitynumber ||
|
||||
cmd->cursor_start[0] || cmd->cursor_start[1] || cmd->cursor_start[2] ||
|
||||
|
@ -1965,11 +2046,12 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
|
|||
firstsize = buf->cursize;
|
||||
}
|
||||
|
||||
// calculate a checksum over the move commands
|
||||
// calculate a checksum over the move commands
|
||||
|
||||
buf->data[checksumIndex] = COM_BlockSequenceCRCByte(
|
||||
buf->data + checksumIndex + 1, firstsize - checksumIndex - 1,
|
||||
seq_hash);
|
||||
}
|
||||
|
||||
// request delta compression of entities
|
||||
if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP-1)
|
||||
|
@ -2599,6 +2681,7 @@ void CL_InitInput (void)
|
|||
|
||||
Cvar_Register (&cl_c2sdupe, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_c2sImpulseBackup, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_c2sMaxRedundancy, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_c2spps, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_queueimpulses, inputnetworkcvargroup);
|
||||
Cvar_Register (&cl_netfps, inputnetworkcvargroup);
|
||||
|
|
|
@ -500,7 +500,7 @@ void CL_AckedInputFrame(int inseq, int outseq, qboolean worldstateokay)
|
|||
cls.latency += 0.001; // drift up, so correction are needed
|
||||
}
|
||||
|
||||
if (cl.inframes[inseq&UPDATE_MASK].invalid)
|
||||
if (cls.protocol != CP_NETQUAKE && cl.inframes[inseq&UPDATE_MASK].invalid)
|
||||
frame->latency = -4;
|
||||
|
||||
//and mark any missing ones as dropped
|
||||
|
|
|
@ -1674,9 +1674,6 @@ void MSGCL_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const userc
|
|||
MSGQ2_WriteDeltaUsercmd(buf, from, cmd);
|
||||
else
|
||||
#endif
|
||||
if (cls.fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
MSGFTE_WriteDeltaUsercmd(buf, from, cmd);
|
||||
else
|
||||
MSGQW_WriteDeltaUsercmd(buf, from, cmd);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -236,7 +236,7 @@ unsigned int Net_PextMask(unsigned int protover, qboolean fornq)
|
|||
if (fornq)
|
||||
{
|
||||
//only ones that are tested
|
||||
mask &= PEXT2_PRYDONCURSOR | PEXT2_VOICECHAT | PEXT2_SETANGLEDELTA | PEXT2_REPLACEMENTDELTAS | PEXT2_MAXPLAYERS | PEXT2_PREDINFO | PEXT2_NEWSIZEENCODING /*| PEXT2_VRINPUTS - FIXME: do we want multiple per packet, to cover packetloss?*/;
|
||||
mask &= PEXT2_PRYDONCURSOR | PEXT2_VOICECHAT | PEXT2_SETANGLEDELTA | PEXT2_REPLACEMENTDELTAS | PEXT2_MAXPLAYERS | PEXT2_PREDINFO | PEXT2_NEWSIZEENCODING | PEXT2_VRINPUTS;
|
||||
}
|
||||
// else
|
||||
// mask &= ~PEXT2_PREDINFO;
|
||||
|
|
|
@ -501,6 +501,13 @@ enum {
|
|||
#define clcfte_prydoncursor 82
|
||||
#define clcfte_voicechat 83
|
||||
#define clcfte_brushedit 84
|
||||
#define clcfte_move 85 //part of PEXT2_VRINPUTS. replaces clc_move+clcfte_prydoncursor+clcdp_ackframe
|
||||
|
||||
#define VRM_LOSS (1u<<0) //for server packetloss reports
|
||||
#define VRM_DELAY (1u<<1) //for server to compute lag properly.
|
||||
#define VRM_SEATS (1u<<2) //for splitscreen to work properly
|
||||
#define VRM_FRAMES (1u<<3) //number of input frames in this packet.
|
||||
#define VRM_ACKS (1u<<4) //number of sequence acks included in message.
|
||||
|
||||
//==============================================
|
||||
|
||||
|
|
|
@ -2783,8 +2783,9 @@ qboolean SV_SendClientDatagram (client_t *client)
|
|||
sentbytes = Netchan_Transmit (&client->netchan, msg.cursize, buf, SV_RateForClient(client));
|
||||
if (ISNQCLIENT(client))
|
||||
{
|
||||
client_frame_t *frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK];
|
||||
client_frame_t *frame = &client->frameunion.frames[outframeseq & UPDATE_MASK];
|
||||
frame->packetsizeout += sentbytes;
|
||||
frame->ping_time = -1;
|
||||
frame->senttime = realtime;
|
||||
}
|
||||
else if (ISQWCLIENT(client))
|
||||
|
|
|
@ -7931,6 +7931,124 @@ done:
|
|||
SV_ClientPrintf(host_client, PRINT_HIGH, "qcrequest \"%s\" not supported\n", fname);
|
||||
}
|
||||
|
||||
static double SVFTE_ExecuteClientMove(client_t *controller)
|
||||
{
|
||||
client_t *split = controller;
|
||||
unsigned int flags = MSG_ReadUInt64();
|
||||
unsigned int seats = (flags & VRM_SEATS)?MSG_ReadUInt64():1;
|
||||
unsigned int frames = (flags & VRM_FRAMES)?MSG_ReadUInt64():3;
|
||||
unsigned int loss = (flags & VRM_LOSS)?MSG_ReadByte():0;
|
||||
double delay = (flags & VRM_DELAY)?MSG_ReadByte()/10000.0:0; //networked as 10ths of a millisecond.
|
||||
unsigned int numacks = (flags & VRM_ACKS)?MSG_ReadUInt64():0;
|
||||
usercmd_t old;
|
||||
|
||||
unsigned int seat, frame, a;
|
||||
qboolean ran;
|
||||
|
||||
for (a = 0; a < numacks; a++)
|
||||
{
|
||||
controller->delta_sequence = MSG_ReadLong();
|
||||
if (controller->delta_sequence == -1)
|
||||
{
|
||||
unsigned int e;
|
||||
if (controller->pendingdeltabits)
|
||||
controller->pendingdeltabits[0] = UF_REMOVE;
|
||||
if (host_client->pendingcsqcbits)
|
||||
for (e = 1; e < host_client->max_net_ents; e++)
|
||||
if (host_client->pendingcsqcbits[e] & SENDFLAGS_PRESENT)
|
||||
host_client->pendingcsqcbits[e] |= SENDFLAGS_USABLE;
|
||||
}
|
||||
SV_AckEntityFrame(controller, controller->delta_sequence);
|
||||
}
|
||||
|
||||
for (seat = 0; seat < seats; seat++)
|
||||
{
|
||||
if (!split)
|
||||
{ //err, they sent too many seats... assume we kicked one.
|
||||
for (frame = 0; frame < frames; frame++)
|
||||
MSGFTE_ReadDeltaUsercmd(&nullcmd, &old);
|
||||
continue;
|
||||
}
|
||||
|
||||
host_client = split;
|
||||
sv_player = split->edict;
|
||||
|
||||
split->lossage = loss;
|
||||
split->localtime = loss;
|
||||
|
||||
//all sorts of reasons why we might not want to do physics here and now.
|
||||
split->isindependant = !(sv_nqplayerphysics.ival || split->state < cs_spawned || SV_PlayerPhysicsQC || sv.paused || !sv.world.worldmodel || sv.world.worldmodel->loadstate != MLS_LOADED);
|
||||
|
||||
ran = false;
|
||||
old = nullcmd;
|
||||
for (frame = 0; frame < frames; frame++)
|
||||
{
|
||||
MSGFTE_ReadDeltaUsercmd(&old, &split->lastcmd);
|
||||
old = split->lastcmd;
|
||||
|
||||
if (split->penalties & BAN_CRIPPLED)
|
||||
{
|
||||
split->lastcmd.forwardmove = 0;
|
||||
split->lastcmd.sidemove = 0;
|
||||
split->lastcmd.upmove = 0;
|
||||
}
|
||||
|
||||
if (split->state == cs_spawned)
|
||||
{
|
||||
if (split->lastcmd.impulse)
|
||||
split->edict->v->impulse = split->lastcmd.impulse;
|
||||
if (split->isindependant)
|
||||
{ //this protocol uses bigger timestamps instead of msecs
|
||||
unsigned int curtime = sv.time*1000;
|
||||
if (split->lastcmd.servertime < split->lastruncmd)
|
||||
{
|
||||
if (sv_showpredloss.ival)
|
||||
Con_Printf("%s: client jumped %u msecs backwards (anti speed cheat)\n", split->name, split->lastruncmd - split->lastcmd.servertime);
|
||||
}
|
||||
else if (split->lastruncmd < split->lastcmd.servertime)
|
||||
{
|
||||
if (split->lastcmd.servertime > curtime)
|
||||
{
|
||||
//from last map?... attempted speedcheat?
|
||||
if (sv_showpredloss.ival)
|
||||
Con_Printf("%s: client is %u msecs in the future (anti speed cheat)\n", split->name, split->lastcmd.servertime - curtime);
|
||||
split->lastcmd.servertime = curtime;
|
||||
}
|
||||
|
||||
if (!ran)
|
||||
{
|
||||
SV_PreRunCmd();
|
||||
ran=true;
|
||||
}
|
||||
|
||||
split->lastcmd.msec = split->lastcmd.servertime - split->lastruncmd;
|
||||
SV_RunCmd (&split->lastcmd, false);
|
||||
split->lastruncmd = split->lastcmd.servertime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_SetEntityButtons(split->edict, split->lastcmd.buttons);
|
||||
split->lastcmd.buttons = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ran)
|
||||
SV_PostRunCmd();
|
||||
|
||||
//for framerate calcs
|
||||
if (split->frameunion.frames)
|
||||
split->frameunion.frames[split->netchan.outgoing_sequence&UPDATE_MASK].move_msecs = split->lastcmd.msec;
|
||||
split->lastcmd.msec = 0;
|
||||
|
||||
split = split->controlled;
|
||||
}
|
||||
|
||||
host_client = controller;
|
||||
sv_player = host_client->edict;
|
||||
return delay;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ExecuteClientMessage
|
||||
|
@ -8053,6 +8171,9 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
cl->delta_sequence = MSG_ReadByte ();
|
||||
break;
|
||||
|
||||
case clcfte_move:
|
||||
frame->ping_time -= SVFTE_ExecuteClientMove(cl);
|
||||
break;
|
||||
case clc_move:
|
||||
if (split == cl)
|
||||
{
|
||||
|
@ -8069,14 +8190,6 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
if (split)
|
||||
split->lossage = cl->lossage;
|
||||
}
|
||||
if (cl->fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
{
|
||||
MSGFTE_ReadDeltaUsercmd (&nullcmd, &oldest);
|
||||
MSGFTE_ReadDeltaUsercmd (&oldest, &oldcmd);
|
||||
MSGFTE_ReadDeltaUsercmd (&oldcmd, &newcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
MSGQW_ReadDeltaUsercmd (&nullcmd, &oldest, PROTOCOL_VERSION_QW);
|
||||
oldest.fservertime = frame->laggedtime; //not very accurate, but our best guess.
|
||||
oldest.servertime = frame->laggedtime*1000; //not very accurate
|
||||
|
@ -8089,7 +8202,6 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
}
|
||||
MSGQW_ReadDeltaUsercmd (&oldest, &oldcmd, PROTOCOL_VERSION_QW);
|
||||
MSGQW_ReadDeltaUsercmd (&oldcmd, &newcmd, PROTOCOL_VERSION_QW);
|
||||
}
|
||||
if (!split)
|
||||
break; // either someone is trying to cheat, or they sent input commands for splitscreen clients they no longer own.
|
||||
|
||||
|
@ -8168,39 +8280,6 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
split->isindependant = true;
|
||||
SV_PreRunCmd();
|
||||
|
||||
if (cl->fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
{ //this protocol uses bigger timestamps instead of msecs
|
||||
usercmd_t *c;
|
||||
unsigned int curtime = sv.time*1000;
|
||||
if (newcmd.servertime < split->lastruncmd)
|
||||
{
|
||||
if (sv_showpredloss.ival)
|
||||
Con_Printf("%s: client jumped %u msecs backwards (anti speed cheat)\n", split->name, split->lastruncmd - newcmd.servertime);
|
||||
}
|
||||
else while (split->lastruncmd < newcmd.servertime)
|
||||
{
|
||||
//try to find the oldest (valid) command.
|
||||
if (split->lastruncmd < oldest.servertime)
|
||||
c = &oldest;
|
||||
else if (split->lastruncmd < oldcmd.servertime)
|
||||
c = &oldcmd;
|
||||
else
|
||||
c = &newcmd;
|
||||
|
||||
if (c->servertime > curtime)
|
||||
{
|
||||
if (sv_showpredloss.ival)
|
||||
Con_Printf("%s: client is %u msecs in the future (anti speed cheat)\n", split->name, c->servertime - curtime);
|
||||
break; //from last map?... attempted speedcheat?
|
||||
}
|
||||
|
||||
c->msec = c->servertime - split->lastruncmd;
|
||||
SV_RunCmd (c, false);
|
||||
split->lastruncmd = c->servertime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (net_drop < 20)
|
||||
{
|
||||
while (net_drop > 2)
|
||||
|
@ -8215,7 +8294,6 @@ void SV_ExecuteClientMessage (client_t *cl)
|
|||
}
|
||||
SV_RunCmd (&newcmd, false);
|
||||
host_client->lastruncmd = sv.time*1000;
|
||||
}
|
||||
|
||||
if (!SV_PlayerPhysicsQC || host_client->spectator)
|
||||
SV_PostRunCmd();
|
||||
|
@ -8542,13 +8620,6 @@ void SVNQ_ReadClientMove (qboolean forceangle16)
|
|||
else
|
||||
host_client->last_sequence = 0;
|
||||
|
||||
if (host_client->fteprotocolextensions2 & PEXT2_VRINPUTS)
|
||||
{ //this actually drops from 37 to 23 bytes (according to showpackets), so that's cool. obviously it goes up when vr inputs are actually networked...
|
||||
MSGFTE_ReadDeltaUsercmd(&nullcmd, &cmd);
|
||||
cmd.fservertime = cmd.servertime/1000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = nullcmd;
|
||||
|
||||
//read the time, woo... should be an ack of our serverside time.
|
||||
|
@ -8601,7 +8672,6 @@ void SVNQ_ReadClientMove (qboolean forceangle16)
|
|||
|
||||
//clear out extension buttons that are part of the protocol rather than actual buttons..
|
||||
cmd.buttons &= ~((1u<<30)|(1u<<31));
|
||||
}
|
||||
|
||||
//figure out ping
|
||||
frame->ping_time = sv.time - cmd.fservertime;
|
||||
|
@ -8784,6 +8854,45 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
|
|||
// cl->delta_sequence = MSG_ReadByte ();
|
||||
// break;
|
||||
|
||||
case clcfte_move:
|
||||
{
|
||||
int seq = (unsigned short)MSG_ReadShort ();
|
||||
|
||||
unsigned int oldservertime = cl->lastcmd.servertime;
|
||||
float delay = SVFTE_ExecuteClientMove(cl);
|
||||
client_frame_t *frame;
|
||||
|
||||
//this is the input sequence that we'll need to ack later (no
|
||||
if (seq < (host_client->last_sequence&0xffff))
|
||||
host_client->last_sequence += 0x10000; //wrapped
|
||||
host_client->last_sequence = (host_client->last_sequence&0xffff0000) | seq;
|
||||
|
||||
if (cl->lastsequence_acknowledged)
|
||||
{
|
||||
frame = &host_client->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
|
||||
if (frame->ping_time == -1)
|
||||
frame->ping_time = (realtime - frame->senttime) - delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame = &host_client->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
|
||||
frame->ping_time = (sv.time - cl->lastcmd.servertime/1000.0) - delay;
|
||||
}
|
||||
frame->move_msecs = cl->lastcmd.servertime - oldservertime;
|
||||
if (frame->ping_time*1000 > sv_minping.value+1)
|
||||
{
|
||||
host_client->delay -= 0.001;
|
||||
if (host_client->delay < 0)
|
||||
host_client->delay = 0;
|
||||
}
|
||||
if (frame->ping_time*1000 < sv_minping.value)
|
||||
{
|
||||
host_client->delay += 0.001;
|
||||
if (host_client->delay > 1)
|
||||
host_client->delay = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case clc_move: //bytes: 16(nq), 19(proquake/fitz), 56(dp7)
|
||||
if (cl->state != cs_spawned)
|
||||
return; //shouldn't be sending moves at this point. typically they're stale, left from the previous map. this results in crashes if the protocol is different.
|
||||
|
|
Loading…
Reference in a new issue