mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-22 20:11:44 +00:00
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:
parent
8b4a282c47
commit
f810be4830
6 changed files with 103 additions and 83 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue