Make input_servertime available to ssqc too, so it can guage the player's latency more accurately.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5908 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-06-21 13:46:52 +00:00
parent 8b4a282c47
commit f810be4830
6 changed files with 103 additions and 83 deletions

View file

@ -906,40 +906,10 @@ void CL_PredictEntityMovement(entity_state_t *estate, float age)
} }
} }
/* float CL_GetPredictionRealtime(playerview_t *pv)
==============
CL_PredictMove
==============
*/
void CL_PredictMovePNum (int seat)
{ {
//when this is called, the entity states have been interpolated. float simtime;
//interpolation state should be updated to match prediction state, so entities move correctly in mirrors/portals. //these are to make svc_viewentity work better
//this entire function is pure convolouted bollocks.
struct {
int frame;
double time;
player_state_t *state;
usercmd_t *cmd;
} from, to;
playerview_t *pv = &cl.playerview[seat];
int i;
float f;
outframe_t *backdate;
player_state_t framebuf[2]; //need two framebufs so we can interpolate between two states.
static player_state_t nullstate;
int oldphysent;
double simtime; //this is server time if nopred is set (lerp-only), and local time if we're predicting
extern cvar_t cl_netfps;
lerpents_t *le;
qboolean nopred;
qboolean lerpangles = false;
int trackent;
qboolean cam_nowlocked = false;
usercmd_t indcmd;
//these are to make svc_viewentity work better
float netfps = cl_netfps.value; float netfps = cl_netfps.value;
if (!netfps) if (!netfps)
@ -978,6 +948,43 @@ void CL_PredictMovePNum (int seat)
simtime -= cls.latency; //push back when playing demos. simtime -= cls.latency; //push back when playing demos.
simtime += bound(-0.5, cl_predict_timenudge.value, 0.5); simtime += bound(-0.5, cl_predict_timenudge.value, 0.5);
return simtime;
}
/*
==============
CL_PredictMove
==============
*/
void CL_PredictMovePNum (int seat)
{
//when this is called, the entity states have been interpolated.
//interpolation state should be updated to match prediction state, so entities move correctly in mirrors/portals.
//this entire function is pure convolouted bollocks.
struct {
int frame;
double time;
player_state_t *state;
usercmd_t *cmd;
} from, to;
playerview_t *pv = &cl.playerview[seat];
int i;
float f;
outframe_t *backdate;
player_state_t framebuf[2]; //need two framebufs so we can interpolate between two states.
static player_state_t nullstate;
int oldphysent;
double simtime; //this is server time if nopred is set (lerp-only), and local time if we're predicting
extern cvar_t cl_netfps;
lerpents_t *le;
qboolean nopred;
qboolean lerpangles = false;
int trackent;
qboolean cam_nowlocked = false;
usercmd_t indcmd;
simtime = CL_GetPredictionRealtime(pv);
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD); pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
if (!pv->spectator && (pv->cam_state != CAM_FREECAM || pv->cam_spec_track != -1)) //just in case if (!pv->spectator && (pv->cam_state != CAM_FREECAM || pv->cam_spec_track != -1)) //just in case

View file

@ -3941,6 +3941,8 @@ static void cs_get_input_state (usercmd_t *cmd)
cmd->fservertime = *csqcg.input_servertime; cmd->fservertime = *csqcg.input_servertime;
cmd->servertime = *csqcg.input_servertime*1000; cmd->servertime = *csqcg.input_servertime*1000;
} }
if (csqcg.input_clienttime)
cmd->fclienttime = *csqcg.input_clienttime;
if (csqcg.input_cursor_screen) if (csqcg.input_cursor_screen)
Vector2Copy(csqcg.input_cursor_screen, cmd->cursor_screen); Vector2Copy(csqcg.input_cursor_screen, cmd->cursor_screen);

View file

@ -1454,21 +1454,21 @@ void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const user
if (bits & UC_FORWARD) if (bits & UC_FORWARD)
{ {
if (bits & UC_BIGMOVES) if (bits & UC_BIGMOVES)
MSG_WriteShort(buf, cmd->forwardmove); MSG_WriteInt64(buf, cmd->forwardmove);
else else
MSG_WriteChar(buf, cmd->forwardmove/5); MSG_WriteChar(buf, cmd->forwardmove/5);
} }
if (bits & UC_RIGHT) if (bits & UC_RIGHT)
{ {
if (bits & UC_BIGMOVES) if (bits & UC_BIGMOVES)
MSG_WriteShort(buf, cmd->sidemove); MSG_WriteInt64(buf, cmd->sidemove);
else else
MSG_WriteChar(buf, cmd->sidemove/5); MSG_WriteChar(buf, cmd->sidemove/5);
} }
if (bits & UC_UP) if (bits & UC_UP)
{ {
if (bits & UC_BIGMOVES) if (bits & UC_BIGMOVES)
MSG_WriteShort(buf, cmd->upmove); MSG_WriteInt64(buf, cmd->upmove);
else else
MSG_WriteChar(buf, cmd->upmove/5); MSG_WriteChar(buf, cmd->upmove/5);
} }
@ -1548,6 +1548,7 @@ void MSGFTE_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *cmd)
} }
*cmd = *from; *cmd = *from;
cmd->servertime = from->servertime+MSG_ReadUInt64(); cmd->servertime = from->servertime+MSG_ReadUInt64();
cmd->fservertime = cmd->servertime/1000.0;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
if (bits & (UC_ANGLE1<<i)) if (bits & (UC_ANGLE1<<i))
@ -1561,21 +1562,21 @@ void MSGFTE_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *cmd)
if (bits & UC_FORWARD) if (bits & UC_FORWARD)
{ {
if (bits & UC_BIGMOVES) if (bits & UC_BIGMOVES)
cmd->forwardmove = MSG_ReadShort(); cmd->forwardmove = MSG_ReadInt64();
else else
cmd->forwardmove = MSG_ReadChar()*5; cmd->forwardmove = MSG_ReadChar()*5;
} }
if (bits & UC_RIGHT) if (bits & UC_RIGHT)
{ {
if (bits & UC_BIGMOVES) if (bits & UC_BIGMOVES)
cmd->sidemove = MSG_ReadShort(); cmd->sidemove = MSG_ReadInt64();
else else
cmd->sidemove = MSG_ReadChar()*5; cmd->sidemove = MSG_ReadChar()*5;
} }
if (bits & UC_UP) if (bits & UC_UP)
{ {
if (bits & UC_BIGMOVES) if (bits & UC_BIGMOVES)
cmd->upmove = MSG_ReadShort(); cmd->upmove = MSG_ReadInt64();
else else
cmd->upmove = MSG_ReadChar()*5; cmd->upmove = MSG_ReadChar()*5;
} }

View file

@ -1008,6 +1008,7 @@ void PR_LoadGlabalStruct(qboolean muted)
globalvec (false, input_right_angles) \ globalvec (false, input_right_angles) \
globalvec (false, input_right_velocity) \ globalvec (false, input_right_velocity) \
globalvec (false, input_right_avelocity) \ globalvec (false, input_right_avelocity) \
globalfloat (false, input_servertime) \
\ \
globalint (false, serverid) \ globalint (false, serverid) \
globalvec (false, global_gravitydir) \ globalvec (false, global_gravitydir) \
@ -10321,6 +10322,10 @@ static void SV_SetSSQCInputs(usercmd_t *ucmd)
(pr_global_struct->input_movevalues)[1] = ucmd->sidemove; (pr_global_struct->input_movevalues)[1] = ucmd->sidemove;
(pr_global_struct->input_movevalues)[2] = ucmd->upmove; (pr_global_struct->input_movevalues)[2] = ucmd->upmove;
} }
if (pr_global_ptrs->input_servertime)
pr_global_struct->input_servertime = ucmd->fservertime;
if (pr_global_ptrs->input_clienttime)
pr_global_struct->input_clienttime = ucmd->fclienttime;
if (pr_global_ptrs->input_buttons) if (pr_global_ptrs->input_buttons)
pr_global_struct->input_buttons = ucmd->buttons; pr_global_struct->input_buttons = ucmd->buttons;
if (pr_global_ptrs->input_weapon) if (pr_global_ptrs->input_weapon)
@ -10462,6 +10467,7 @@ qboolean SV_RunFullQCMovement(client_t *client, usercmd_t *ucmd)
} }
//prethink should be consistant with what the engine normally does //prethink should be consistant with what the engine normally does
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, client->edict); pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, client->edict);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->PlayerPreThink); PR_ExecuteProgram (svprogfuncs, pr_global_struct->PlayerPreThink);
WPhys_RunThink (&sv.world, (wedict_t*)client->edict); WPhys_RunThink (&sv.world, (wedict_t*)client->edict);
@ -12706,6 +12712,8 @@ void PR_DumpPlatform_f(void)
{"end_sys_fields", "void", QW|NQ|CS|MENU}, {"end_sys_fields", "void", QW|NQ|CS|MENU},
{"time", "float", MENU, D("The current local time. Increases while paused.")}, {"time", "float", MENU, D("The current local time. Increases while paused.")},
{"input_servertime", "float", QW|NQ|CS, D("Server's timestamp of the client's interpolation state.")},
// {"input_clienttime", "float", QW|NQ|CS, D("This is the timestamp that player prediction is simulating.")},
{"input_timelength", "float", QW|NQ}, {"input_timelength", "float", QW|NQ},
{"input_angles", "vector", QW|NQ, D("+x=DOWN")}, {"input_angles", "vector", QW|NQ, D("+x=DOWN")},
{"input_movevalues", "vector", QW|NQ}, {"input_movevalues", "vector", QW|NQ},

View file

@ -104,6 +104,8 @@ typedef struct nqglobalvars_s
pvec_t *physics_mode; pvec_t *physics_mode;
pvec_t *clientcommandframe; pvec_t *clientcommandframe;
pvec_t *input_servertime;
pvec_t *input_clienttime;
pvec_t *input_timelength; pvec_t *input_timelength;
pvec_t *input_impulse; pvec_t *input_impulse;
pvec3_t *input_angles; pvec3_t *input_angles;

View file

@ -7946,56 +7946,54 @@ void SV_ExecuteClientMessage (client_t *cl)
qbyte checksum, calculatedChecksum; qbyte checksum, calculatedChecksum;
int seq_hash; int seq_hash;
// calc ping time if (!cl->frameunion.frames)
if (cl->frameunion.frames)
{ //split screen doesn't always have frames.
frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged)
{
/*note that if there is packetloss, we can change a single frame's ping_time multiple times
this means that the 'ping' is more latency than ping times*/
if (frame->ping_time == -1 || !sv_ping_ignorepl.ival)
frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please
if (cl->spectator)
cl->delay = 0;
else
{
float diff = frame->ping_time*1000 - sv_minping.value;
if (fabs(diff) > 1)
{
//FIXME: we should use actual arrival times instead, so we don't get so much noise and seesawing.
diff = bound(-25, diff, 25); //don't swing wildly
cl->delay -= 0.001*(diff/25); //scale towards the ideal value
cl->delay = bound(0, cl->delay, 1); //but make sure things don't go crazy
}
}
if (cl->penalties & BAN_LAGGED)
if (cl->delay < 0.2)
cl->delay = 0.2;
}
if (sv_antilag.ival || !*sv_antilag.string)
{
#ifdef warningmsg
#pragma warningmsg("FIXME: make antilag optionally support non-player ents too")
#endif
cl->laggedents_count = sv.allocated_client_slots;
memcpy(cl->laggedents, frame->laggedplayer, sizeof(*cl->laggedents)*cl->laggedents_count);
cl->laggedents_time = frame->laggedtime;
cl->laggedents_frac = !*sv_antilag_frac.string?1:sv_antilag_frac.value;
}
else
cl->laggedents_count = 0;
}
else
{ {
Con_Printf("Server bug: No frames!\n"); Con_Printf("Server bug: No frames!\n");
cl->send_message = false; cl->send_message = false;
return; //shouldn't happen... return; //shouldn't happen...
} }
// calc ping time
frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged)
{
/*note that if there is packetloss, we can change a single frame's ping_time multiple times
this means that the 'ping' is more latency than ping times*/
if (frame->ping_time == -1 || !sv_ping_ignorepl.ival)
frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please
if (cl->spectator)
cl->delay = 0;
else
{
float diff = frame->ping_time*1000 - sv_minping.value;
if (fabs(diff) > 1)
{
//FIXME: we should use actual arrival times instead, so we don't get so much noise and seesawing.
diff = bound(-25, diff, 25); //don't swing wildly
cl->delay -= 0.001*(diff/25); //scale towards the ideal value
cl->delay = bound(0, cl->delay, 1); //but make sure things don't go crazy
}
}
if (cl->penalties & BAN_LAGGED)
if (cl->delay < 0.2)
cl->delay = 0.2;
}
if (sv_antilag.ival || !*sv_antilag.string)
{
#ifdef warningmsg
#pragma warningmsg("FIXME: make antilag optionally support non-player ents too")
#endif
cl->laggedents_count = sv.allocated_client_slots;
memcpy(cl->laggedents, frame->laggedplayer, sizeof(*cl->laggedents)*cl->laggedents_count);
cl->laggedents_time = frame->laggedtime;
cl->laggedents_frac = !*sv_antilag_frac.string?1:sv_antilag_frac.value;
}
else
cl->laggedents_count = 0;
// make sure the reply sequence number matches the incoming // make sure the reply sequence number matches the incoming
// sequence number // sequence number
if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence) if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
@ -8076,6 +8074,8 @@ void SV_ExecuteClientMessage (client_t *cl)
else else
{ {
MSGQW_ReadDeltaUsercmd (&nullcmd, &oldest, PROTOCOL_VERSION_QW); 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
Vector2Copy(split->lastcmd.cursor_screen, oldest.cursor_screen); Vector2Copy(split->lastcmd.cursor_screen, oldest.cursor_screen);
VectorCopy(split->lastcmd.cursor_start, oldest.cursor_start); VectorCopy(split->lastcmd.cursor_start, oldest.cursor_start);
VectorCopy(split->lastcmd.cursor_impact, oldest.cursor_impact); VectorCopy(split->lastcmd.cursor_impact, oldest.cursor_impact);