Server: simplify lagcomp clamping code and add technical notes

Clamp to +- sv_maxunlag delta from server time base. Also added notes to possibly rework the system in the future.
This commit is contained in:
Kawe Mazidjatari 2024-04-14 14:23:14 +02:00
parent c3f66e748f
commit 1fe74fe727

View File

@ -112,65 +112,6 @@ void CPlayer::SetTotalExtraClientCmdTimeAttempted(float flAttemptedTime)
}
}
//------------------------------------------------------------------------------
// Purpose: clamps the unlag amount to sv_unlag + clockdrift
// Input : *cmd -
//------------------------------------------------------------------------------
void CPlayer::ClampUnlag(CUserCmd* cmd)
{
const CClient* client = g_pServer->GetClient(GetEdict() - 1);
const CNetChan* chan = client->GetNetChan();
const float clockDriftMsecs = sv_clockcorrection_msecs->GetFloat() / 1000.0f;
const float maxUnlag = sv_maxunlag->GetFloat();
const float latencyAmount = Clamp(chan->GetLatency(FLOW_OUTGOING), 0.0f, maxUnlag);
const float serverTime = (*g_pGlobals)->m_flCurTime;
// Command issue time from client, note that this value can be altered
// from the client, and therefore be used to exploit lag compensation.
const float commandTime = cmd->command_time;
const float lastCommandTime = m_LastCmd.command_time;
const float commandDelta = fabs(commandTime - serverTime);
bool recomputeUnlag = false;
// Check delta first, otherwise player could set commandTime to a fixed
// time and circumvent the system, as commandTime < lastCommandTime or
// commandTime > localCurTime will always fail.
if (commandDelta > maxUnlag)
{
// Too much to unlag, clamp to max !!!
recomputeUnlag = true;
DevWarning(eDLL_T::SERVER, "%s: commandDelta( %f ) > maxUnlag( %f ) !!!\n",
__FUNCTION__, commandDelta, maxUnlag);
}
else if (commandTime < (lastCommandTime - clockDriftMsecs))
{
// Can never be lower than last !!!
recomputeUnlag = true;
DevWarning(eDLL_T::SERVER, "%s: cmd->command_time( %f ) < (m_LastCmd.command_time( %f ) - clockDriftMsecs( %f )) !!!\n",
__FUNCTION__, commandTime, lastCommandTime, clockDriftMsecs);
}
else if (commandTime > (serverTime + clockDriftMsecs))
{
// Too far in the future, clamp to max !!!
recomputeUnlag = true;
DevWarning(eDLL_T::SERVER, "%s: cmd->command_time( %f ) > (g_pGlobals->m_flCurTime( %f ) + clockDriftMsecs( %f )) !!!\n",
__FUNCTION__, commandTime, serverTime, clockDriftMsecs);
}
if (recomputeUnlag)
{
// Clamp it to server time minus latency. Note that it could still
// be lower than previous, hence the clamp on the recomputation.
float newCommandTime = Clamp(serverTime - latencyAmount, lastCommandTime, serverTime);
cmd->command_time = newCommandTime;
DevWarning(eDLL_T::SERVER, "%s: Clamped cmd->command_time( %f ) to %f !!!\n",
__FUNCTION__, commandTime, newCommandTime);
}
}
//------------------------------------------------------------------------------
// Purpose: processes user cmd's for this player
// Input : *cmds -
@ -182,7 +123,7 @@ void CPlayer::ClampUnlag(CUserCmd* cmd)
// TODO: this code is experimental and has reported problems from players with
// high latency, needs to be debugged or a different approach needs to be taken!
// Defaulted to OFF for now
static ConVar sv_unlag_clamp("sv_unlag_clamp", "0", FCVAR_RELEASE, "Clamp the difference between the current time and received command time to sv_maxunlag + sv_clockcorrection_msecs.");
static ConVar sv_unlag_clamp("sv_unlag_clamp", "0", FCVAR_RELEASE, "Clamp the difference between the current time and received command time to sv_maxunlag.");
void CPlayer::ProcessUserCmds(CUserCmd* cmds, int numCmds, int totalCmds,
int droppedPackets, bool paused)
@ -192,6 +133,9 @@ void CPlayer::ProcessUserCmds(CUserCmd* cmds, int numCmds, int totalCmds,
CUserCmd* lastCmd = &m_Commands[MAX_QUEUED_COMMANDS_PROCESS];
const float maxUnlag = sv_maxunlag->GetFloat();
const float currTime = (*g_pGlobals)->m_flCurTime;
for (int i = totalCmds - 1; i >= 0; i--)
{
CUserCmd* cmd = &cmds[i];
@ -206,8 +150,22 @@ void CPlayer::ProcessUserCmds(CUserCmd* cmds, int numCmds, int totalCmds,
if (lastCommandNumber == MAX_QUEUED_COMMANDS_PROCESS)
return;
// TODO: why are grenades not clamped to sv_maxunlag ???
// TODO: the command_time is set from the client itself in CInput::CreateMove
// to gpGlobals->curtime in the ucmd packet, perhaps just calculate it from
// the server based on ucmd ticks ???
//
// Possible solutions that need to be explored and worked out further:
//
// cmd->command_time = TICKS_TO_TIME(cmd->command_number + cmd->tick_count) // seems to be the closest, but also still manipulatable from the client.
// cmd->command_time = TICKS_TO_TIME(client->GetDeltaTick() + cmd->command_number) // delta tick is not necessarily the same as actual ucmd tick, and will be -1 on baseline request.
// cmd->command_time = TICKS_TO_TIME(m_lastUCmdSimulationRemainderTime) + m_totalExtraClientCmdTimeAttempted; // player timebase; also up to 100ms difference between orig sent value.
//
// ... reverse more ticks and floats in CClient since there seem to be a
// bunch still in the padded bytes, possibly one of them is what we could
// and should actually use to get the remote client time since ucmd was sent.
if (sv_unlag_clamp.GetBool())
ClampUnlag(cmd);
cmd->command_time = Min(Max(cmd->command_time, Max(currTime - maxUnlag, 0.0f)), currTime + maxUnlag);
CUserCmd* queuedCmd = &m_Commands[lastCommandNumber];
queuedCmd->Copy(cmd);