mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Fully implemented ConVar class so we could statically construct all SDK convars, this avoids a level of indirection, and allows for creating ConVar's everywhere in the project. This patch also removed the settings tab of the ImGui server browser, as it has threading issues, while it technically never caused a crash yet, it has been removed as there was no point keeping it vs the work required to make it thread save (it only managed 2 convars which are perfectly manageable through cfg's or the in-game console). Also temporarily disabled the creation of ConVar's in the mod system due to a memory leak, we would allocate and register a convar based on details parsed out of a mod file definition, but never unregister and free it.
289 lines
9.2 KiB
C++
289 lines
9.2 KiB
C++
//======== Copyright (c) Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//===========================================================================//
|
|
#include "core/stdafx.h"
|
|
#include "common/protocol.h"
|
|
#include "game/shared/shareddefs.h"
|
|
#include "game/shared/usercmd.h"
|
|
#include "game/server/movehelper_server.h"
|
|
#include "gameinterface.h"
|
|
#include "player.h"
|
|
|
|
#include "engine/server/server.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: executes a null command for this player
|
|
//------------------------------------------------------------------------------
|
|
void CPlayer::RunNullCommand(void)
|
|
{
|
|
CUserCmd cmd;
|
|
|
|
float flOldFrameTime = (*g_pGlobals)->m_flFrameTime;
|
|
float flOldCurTime = (*g_pGlobals)->m_flCurTime;
|
|
|
|
cmd.frametime = flOldFrameTime;
|
|
cmd.command_time = flOldCurTime;
|
|
|
|
pl.fixangle = FIXANGLE_NONE;
|
|
EyeAngles(&cmd.viewangles);
|
|
|
|
SetTimeBase((*g_pGlobals)->m_flCurTime);
|
|
MoveHelperServer()->SetHost(this);
|
|
|
|
PlayerRunCommand(&cmd, MoveHelperServer());
|
|
SetLastUserCommand(&cmd);
|
|
|
|
(*g_pGlobals)->m_flFrameTime = flOldFrameTime;
|
|
(*g_pGlobals)->m_flCurTime = flOldCurTime;
|
|
|
|
MoveHelperServer()->SetHost(NULL);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: gets the eye angles of this player
|
|
// Input : *pAngles -
|
|
// Output : QAngle*
|
|
//------------------------------------------------------------------------------
|
|
QAngle* CPlayer::EyeAngles(QAngle* pAngles)
|
|
{
|
|
return CPlayer__EyeAngles(this, pAngles);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: sets the time base for this player
|
|
// Input : flTimeBase -
|
|
//------------------------------------------------------------------------------
|
|
inline void CPlayer::SetTimeBase(float flTimeBase)
|
|
{
|
|
float flTime = float(TIME_TO_TICKS(flTimeBase));
|
|
|
|
if (flTime < 0.0f)
|
|
flTime = 0.0f;
|
|
|
|
SetLastUCmdSimulationRemainderTime(flTime);
|
|
|
|
float flSimulationTime = flTimeBase - m_lastUCmdSimulationRemainderTime * (*g_pGlobals)->m_flTickInterval;
|
|
if (flSimulationTime >= 0.0f)
|
|
{
|
|
flTime = flSimulationTime;
|
|
}
|
|
|
|
SetTotalExtraClientCmdTimeAttempted(flTime);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: sets the last user cmd simulation remainder time
|
|
// Input : flRemainderTime -
|
|
//------------------------------------------------------------------------------
|
|
void CPlayer::SetLastUCmdSimulationRemainderTime(float flRemainderTime)
|
|
{
|
|
if (m_lastUCmdSimulationRemainderTime != flRemainderTime)
|
|
{
|
|
edict_t nEdict = NetworkProp()->GetEdict();
|
|
if (nEdict != FL_EDICT_INVALID)
|
|
{
|
|
_InterlockedOr16((SHORT*)(*g_pGlobals)->m_pEdicts + nEdict + 32, 0x200u);
|
|
}
|
|
|
|
m_lastUCmdSimulationRemainderTime = flRemainderTime;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: sets the total extra client cmd time attempted
|
|
// Input : flAttemptedTime -
|
|
//------------------------------------------------------------------------------
|
|
void CPlayer::SetTotalExtraClientCmdTimeAttempted(float flAttemptedTime)
|
|
{
|
|
if (m_totalExtraClientCmdTimeAttempted != flAttemptedTime)
|
|
{
|
|
edict_t nEdict = NetworkProp()->GetEdict();
|
|
if (nEdict != FL_EDICT_INVALID)
|
|
{
|
|
_InterlockedOr16((SHORT*)(*g_pGlobals)->m_pEdicts + nEdict + 32, 0x200u);
|
|
}
|
|
|
|
m_totalExtraClientCmdTimeAttempted = 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 -
|
|
// numCmds -
|
|
// totalCmds -
|
|
// droppedPackets -
|
|
// paused -
|
|
//------------------------------------------------------------------------------
|
|
// 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.");
|
|
|
|
void CPlayer::ProcessUserCmds(CUserCmd* cmds, int numCmds, int totalCmds,
|
|
int droppedPackets, bool paused)
|
|
{
|
|
if (totalCmds <= 0)
|
|
return;
|
|
|
|
CUserCmd* lastCmd = &m_Commands[MAX_QUEUED_COMMANDS_PROCESS];
|
|
|
|
for (int i = totalCmds - 1; i >= 0; i--)
|
|
{
|
|
CUserCmd* cmd = &cmds[i];
|
|
const int commandNumber = cmd->command_number;
|
|
|
|
if (commandNumber <= m_latestCommandQueued)
|
|
continue;
|
|
|
|
m_latestCommandQueued = commandNumber;
|
|
const int lastCommandNumber = lastCmd->command_number;
|
|
|
|
if (lastCommandNumber == MAX_QUEUED_COMMANDS_PROCESS)
|
|
return;
|
|
|
|
if (sv_unlag_clamp.GetBool())
|
|
ClampUnlag(cmd);
|
|
|
|
CUserCmd* queuedCmd = &m_Commands[lastCommandNumber];
|
|
queuedCmd->Copy(cmd);
|
|
|
|
if (++lastCmd->command_number > player_userCmdsQueueWarning->GetInt())
|
|
{
|
|
const float curTime = float(Plat_FloatTime());
|
|
|
|
if ((curTime - m_lastCommandCountWarnTime) > 0.5f)
|
|
m_lastCommandCountWarnTime = curTime;
|
|
}
|
|
}
|
|
|
|
lastCmd->tick_count += droppedPackets;
|
|
m_bGamePaused = paused;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: runs user command for this player
|
|
// Input : *pUserCmd -
|
|
// *pMover -
|
|
//------------------------------------------------------------------------------
|
|
void CPlayer::PlayerRunCommand(CUserCmd* pUserCmd, IMoveHelper* pMover)
|
|
{
|
|
CPlayer__PlayerRunCommand(this, pUserCmd, pMover);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: stores off a user command
|
|
// Input : *pUserCmd -
|
|
//------------------------------------------------------------------------------
|
|
void CPlayer::SetLastUserCommand(CUserCmd* pUserCmd)
|
|
{
|
|
m_LastCmd.Copy(pUserCmd);
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
CC_CreateFakePlayer_f
|
|
|
|
Creates a fake player
|
|
on the server
|
|
=====================
|
|
*/
|
|
static void CC_CreateFakePlayer_f(const CCommand& args)
|
|
{
|
|
if (!g_pServer->IsActive())
|
|
return;
|
|
|
|
if (args.ArgC() < 3)
|
|
{
|
|
Msg(eDLL_T::SERVER, "usage 'sv_addbot': name(string) teamid(int)\n");
|
|
return;
|
|
}
|
|
|
|
const int numPlayers = g_pServer->GetNumClients();
|
|
|
|
// Already at max, don't create.
|
|
if (numPlayers >= g_ServerGlobalVariables->m_nMaxClients)
|
|
return;
|
|
|
|
const char* playerName = args.Arg(1);
|
|
|
|
int teamNum = atoi(args.Arg(2));
|
|
const int maxTeams = int(g_pServer->GetMaxTeams()) + 1;
|
|
|
|
// Clamp team count, going above the limit will
|
|
// cause a crash. Going below 0 means that the
|
|
// engine will assign the bot to the last team.
|
|
if (teamNum > maxTeams)
|
|
teamNum = maxTeams;
|
|
|
|
g_pEngineServer->LockNetworkStringTables(true);
|
|
|
|
const edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum);
|
|
g_pServerGameClients->ClientFullyConnect(nHandle, false);
|
|
|
|
g_pEngineServer->LockNetworkStringTables(false);
|
|
}
|
|
|
|
static ConCommand sv_addbot("sv_addbot", CC_CreateFakePlayer_f, "Creates a bot on the server", FCVAR_RELEASE);
|