r5sdk/r5dev/common/callback.cpp
Kawe Mazidjatari 6eee25a4e9 Engine: use dedicated convar to determine rcon server socket bind
Decoupled from net_usesocketforloopback since we actually don't want this to be tied with that of the game. Now it by default does not bind to the loopback socket unlike the game.
2024-06-01 11:43:08 +02:00

574 lines
15 KiB
C++

//=============================================================================//
//
// Purpose: Callback functions for ConVar's.
//
//=============================================================================//
#include "core/stdafx.h"
#include "core/init.h"
#include "windows/id3dx.h"
#include "tier0/fasttimer.h"
#include "tier1/cvar.h"
#include "tier1/fmtstr.h"
#include "engine/shared/shared_rcon.h"
#ifndef CLIENT_DLL
#include "engine/server/sv_rcon.h"
#endif // !CLIENT_DLL
#ifndef DEDICATED
#include "engine/client/cl_rcon.h"
#include "engine/client/cdll_engine_int.h"
#include "engine/client/clientstate.h"
#endif // !DEDICATED
#include "engine/client/client.h"
#include "engine/net.h"
#include "engine/host_cmd.h"
#include "engine/host_state.h"
#include "engine/enginetrace.h"
#ifndef CLIENT_DLL
#include "engine/server/server.h"
#endif // !CLIENT_DLL
#include "rtech/pak/pakencode.h"
#include "rtech/pak/pakdecode.h"
#include "rtech/pak/pakparse.h"
#include "rtech/pak/pakstate.h"
#include "rtech/pak/paktools.h"
#include "rtech/playlists/playlists.h"
#include "filesystem/basefilesystem.h"
#include "filesystem/filesystem.h"
#include "vpklib/packedstore.h"
#include "vscript/vscript.h"
#include "localize/localize.h"
#include "ebisusdk/EbisuSDK.h"
#ifndef DEDICATED
#include "geforce/reflex.h"
#include "gameui/IBrowser.h"
#include "gameui/IConsole.h"
#endif // !DEDICATED
#ifndef CLIENT_DLL
#include "networksystem/bansystem.h"
#endif // !CLIENT_DLL
#include "public/edict.h"
#include "public/worldsize.h"
#include "mathlib/crc32.h"
#include "mathlib/mathlib.h"
#include "common/completion.h"
#include "common/callback.h"
#ifndef DEDICATED
#include "materialsystem/cmaterialglue.h"
#endif // !DEDICATED
#include "public/bspflags.h"
#include "public/cmodel.h"
#include "public/idebugoverlay.h"
#include "public/localize/ilocalize.h"
#ifndef CLIENT_DLL
#include "game/server/detour_impl.h"
#include "game/server/gameinterface.h"
#endif // !CLIENT_DLL
#ifndef DEDICATED
#include "game/client/cliententitylist.h"
#include "game/client/viewrender.h"
#endif // !DEDICATED
/*
=====================
MP_GameMode_Changed_f
=====================
*/
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString)
{
v_SetupGamemode(mp_gamemode->GetString());
}
#ifndef CLIENT_DLL
/*
=====================
Host_Changelevel_f
Goes to a new map,
taking all clients along
=====================
*/
void Host_Changelevel_f(const CCommand& args)
{
const int argCount = args.ArgC();
if (argCount >= 2
&& IsOriginInitialized()
&& g_pServer->IsActive())
{
const char* levelName = args[1];
const char* landMarkName = argCount > 2 ? args[2] : "";
v_SetLaunchOptions(args);
v_HostState_ChangeLevelMP(levelName, landMarkName);
}
}
#endif // !CLIENT_DLL
// TODO: move this to 'packedstore.cpp' and move everything in that file to 'packetstorebuilder.cpp'
static ConVar fs_packedstore_workspace("fs_packedstore_workspace", "ship", FCVAR_DEVELOPMENTONLY, "Determines the current VPK workspace.");
static ConVar fs_packedstore_compression_level("fs_packedstore_compression_level", "default", FCVAR_DEVELOPMENTONLY, "Determines the VPK compression level.", "fastest faster default better uber");
static ConVar fs_packedstore_max_helper_threads("fs_packedstore_max_helper_threads", "-1", FCVAR_DEVELOPMENTONLY, "Max # of additional \"helper\" threads to create during compression.", true, -1, true, LZHAM_MAX_HELPER_THREADS, "Must range between [-1,LZHAM_MAX_HELPER_THREADS], where -1=max practical");
/*
=====================
VPK_Pack_f
Packs VPK files into
'PLATFORM' VPK directory.
=====================
*/
void VPK_Pack_f(const CCommand& args)
{
if (args.ArgC() < 4)
{
return;
}
const char* workspacePath = fs_packedstore_workspace.GetString();
if (!FileSystem()->IsDirectory(workspacePath, "PLATFORM"))
{
Error(eDLL_T::FS, NO_ERROR, "Workspace path \"%s\" doesn't exist!\n", workspacePath);
return;
}
VPKPair_t pair(args.Arg(1), args.Arg(2), args.Arg(3), NULL);
Msg(eDLL_T::FS, "*** Starting VPK build command for: '%s'\n", pair.m_DirName.String());
CFastTimer timer;
timer.Start();
CPackedStoreBuilder builder;
builder.InitLzEncoder(fs_packedstore_max_helper_threads.GetInt(), fs_packedstore_compression_level.GetString());
builder.PackStore(pair, workspacePath, "vpk/");
timer.End();
Msg(eDLL_T::FS, "*** Time elapsed: '%lf' seconds\n", timer.GetDuration().GetSeconds());
Msg(eDLL_T::FS, "\n");
}
/*
=====================
VPK_Unpack_f
Unpacks VPK files into
workspace directory.
=====================
*/
void VPK_Unpack_f(const CCommand& args)
{
if (args.ArgC() < 2)
{
return;
}
CUtlString fileName = args.Arg(1);
VPKDir_t vpk(fileName, (args.ArgC() > 2));
if (vpk.Failed())
{
Error(eDLL_T::FS, NO_ERROR, "Failed to parse directory tree file \"%s\"!\n", fileName.String());
return;
}
Msg(eDLL_T::FS, "*** Starting VPK extraction command for: '%s'\n", fileName.String());
CFastTimer timer;
timer.Start();
CPackedStoreBuilder builder;
builder.InitLzDecoder();
builder.UnpackStore(vpk, fs_packedstore_workspace.GetString());
timer.End();
Msg(eDLL_T::FS, "*** Time elapsed: '%lf' seconds\n", timer.GetDuration().GetSeconds());
Msg(eDLL_T::FS, "\n");
}
/*
=====================
VPK_Mount_f
Mounts input VPK file for
internal FileSystem usage
=====================
*/
void VPK_Mount_f(const CCommand& args)
{
if (args.ArgC() < 2)
{
return;
}
FileSystem()->MountVPKFile(args.Arg(1));
}
/*
=====================
VPK_Unmount_f
Unmounts input VPK file
and clears its cache
=====================
*/
void VPK_Unmount_f(const CCommand& args)
{
if (args.ArgC() < 2)
{
return;
}
FileSystem()->UnmountVPKFile(args.Arg(1));
}
void LanguageChanged_f(IConVar* pConVar, const char* pOldString)
{
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
{
const char* pNewString = pConVarRef->GetString();
if (strcmp(pOldString, pConVarRef->GetString()) == NULL)
return; // Same language.
if (!Localize_IsLanguageSupported(pNewString))
{
// if new text isn't valid but the old value is, reset the value
if (Localize_IsLanguageSupported(pOldString))
pNewString = pOldString;
else
{
// this shouldn't really happen, but if neither the old nor new values are valid, set to english
Assert(0);
pNewString = g_LanguageNames[0];
}
}
pConVarRef->SetValue(pNewString);
g_MasterServer.SetLanguage(pNewString);
}
}
#ifndef DEDICATED
/*
=====================
Mat_CrossHair_f
Print the material under the crosshair.
=====================
*/
void Mat_CrossHair_f(const CCommand& args)
{
CMaterialGlue* material = v_GetMaterialAtCrossHair();
if (material)
{
Msg(eDLL_T::MS, "______________________________________________________________\n");
Msg(eDLL_T::MS, "-+ Material --------------------------------------------------\n");
Msg(eDLL_T::MS, " |-- ADDR: '%llX'\n", material);
Msg(eDLL_T::MS, " |-- GUID: '%llX'\n", material->assetGuid);
Msg(eDLL_T::MS, " |-- Num Streaming Textures: '%d'\n", material->numStreamingTextureHandles);
Msg(eDLL_T::MS, " |-- Material width: '%d'\n", material->width);
Msg(eDLL_T::MS, " |-- Material height: '%d'\n", material->height);
Msg(eDLL_T::MS, " |-- Samplers: '%08X'\n", material->samplers);
std::function<void(CMaterialGlue*, const char*)> fnPrintChild = [](CMaterialGlue* material, const char* print)
{
Msg(eDLL_T::MS, " |-+\n");
Msg(eDLL_T::MS, " | |-+ Child material ----------------------------------------\n");
Msg(eDLL_T::MS, print, material);
Msg(eDLL_T::MS, " | |-- GUID: '%llX'\n", material->assetGuid);
Msg(eDLL_T::MS, " | |-- Material name: '%s'\n", material->name);
};
Msg(eDLL_T::MS, " |-- Material name: '%s'\n", material->name);
Msg(eDLL_T::MS, " |-- Material surface name 1: '%s'\n", material->surfaceProp);
Msg(eDLL_T::MS, " |-- Material surface name 2: '%s'\n", material->surfaceProp2);
Msg(eDLL_T::MS, " |-- DX buffer: '%llX'\n", material->dxBuffer);
Msg(eDLL_T::MS, " |-- DX buffer VFTable: '%llX'\n", material->unkD3DPointer);
material->depthShadowMaterial
? fnPrintChild(material->depthShadowMaterial, " | |-+ DepthShadow: '%llX'\n")
: Msg(eDLL_T::MS, " | |-+ DepthShadow: 'NULL'\n");
material->depthPrepassMaterial
? fnPrintChild(material->depthPrepassMaterial, " | |-+ DepthPrepass: '%llX'\n")
: Msg(eDLL_T::MS, " | |-+ DepthPrepass: 'NULL'\n");
material->depthVSMMaterial
? fnPrintChild(material->depthVSMMaterial, " | |-+ DepthVSM: '%llX'\n")
: Msg(eDLL_T::MS, " | |-+ DepthVSM: 'NULL'\n");
material->depthShadowTightMaterial
? fnPrintChild(material->depthShadowTightMaterial, " | |-+ DepthShadowTight: '%llX'\n")
: Msg(eDLL_T::MS, " | |-+ DepthShadowTight: 'NULL'\n");
material->colpassMaterial
? fnPrintChild(material->colpassMaterial, " | |-+ ColPass: '%llX'\n")
: Msg(eDLL_T::MS, " | |-+ ColPass: 'NULL'\n");
Msg(eDLL_T::MS, "-+ Texture GUID map ------------------------------------------\n");
Msg(eDLL_T::MS, " |-- Texture handles: '%llX'\n", material->textureHandles);
Msg(eDLL_T::MS, " |-- Streaming texture handles: '%llX'\n", material->streamingTextureHandles);
Msg(eDLL_T::MS, "--------------------------------------------------------------\n");
}
else
{
Msg(eDLL_T::MS, "%s: No material found >:(\n", __FUNCTION__);
}
}
/*
=====================
Line_f
Draws a line at
start<x1 y1 z1> end<x2 y2 z2>.
=====================
*/
void Line_f(const CCommand& args)
{
if (args.ArgC() != 7)
{
Msg(eDLL_T::CLIENT, "Usage 'line': start(vector) end(vector)\n");
return;
}
Vector3D start, end;
for (int i = 0; i < 3; ++i)
{
start[i] = float(atof(args[i + 1]));
end[i] = float(atof(args[i + 4]));
}
g_pDebugOverlay->AddLineOverlay(start, end, 255, 255, 0, !r_debug_draw_depth_test.GetBool(), 100);
}
/*
=====================
Sphere_f
Draws a sphere at origin(x1 y1 z1)
radius(float) theta(int) phi(int).
=====================
*/
void Sphere_f(const CCommand& args)
{
if (args.ArgC() != 7)
{
Msg(eDLL_T::CLIENT, "Usage 'sphere': origin(vector) radius(float) theta(int) phi(int)\n");
return;
}
Vector3D start;
for (int i = 0; i < 3; ++i)
{
start[i] = float(atof(args[i + 1]));
}
float radius = float(atof(args[4]));
int theta = atoi(args[5]);
int phi = atoi(args[6]);
g_pDebugOverlay->AddSphereOverlay(start, radius, theta, phi, 20, 210, 255, 0, 100);
}
/*
=====================
Capsule_f
Draws a capsule at start<x1 y1 z1>
end<x2 y2 z2> radius <x3 y3 z3>.
=====================
*/
void Capsule_f(const CCommand& args)
{
if (args.ArgC() != 10)
{
Msg(eDLL_T::CLIENT, "Usage 'capsule': start(vector) end(vector) radius(vector)\n");
return;
}
Vector3D start, end, radius;
for (int i = 0; i < 3; ++i)
{
start[i] = float(atof(args[i + 1]));
end[i] = float(atof(args[i + 4]));
radius[i] = float(atof(args[i + 7]));
}
g_pDebugOverlay->AddCapsuleOverlay(start, end, radius, { 0,0,0 }, { 0,0,0 }, 141, 233, 135, 0, 100);
}
#endif // !DEDICATED
// TODO: move to other file?
static ConVar bhit_depth_test("bhit_depth_test", "0", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Use depth test for bullet ray trace overlay");
static ConVar bhit_abs_origin("bhit_abs_origin", "1", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Draw entity's predicted abs origin upon bullet impact for trajectory debugging (requires 'r_visualizetraces' to be set!)");
/*
=====================
BHit_f
Bullet trajectory tracing
from shooter to target entity.
=====================
*/
void BHit_f(const CCommand& args)
{
#ifndef CLIENT_DLL // Stubbed to suppress server warnings as this is a GAMEDLL command!
if (args.ArgC() != 9)
return;
if (!bhit_enable->GetBool())
return;
if (sv_visualizetraces->GetBool())
{
Vector3D vecAbsStart;
Vector3D vecAbsEnd;
for (int i = 0; i < 3; ++i)
vecAbsStart[i] = float(atof(args[i + 4]));
QAngle vecBulletAngles;
for (int i = 0; i < 2; ++i)
vecBulletAngles[i] = float(atof(args[i + 7]));
vecBulletAngles.z = 180.f; // Flipped axis.
AngleVectors(vecBulletAngles, &vecAbsEnd);
vecAbsEnd.MulAdd(vecAbsStart, vecAbsEnd, MAX_COORD_RANGE);
Ray_t ray(vecAbsStart, vecAbsEnd);
trace_t trace;
g_pEngineTraceServer->TraceRay(ray, TRACE_MASK_NPCWORLDSTATIC, &trace);
g_pDebugOverlay->AddLineOverlay(trace.startpos, trace.endpos, 0, 255, 0, !bhit_depth_test.GetBool(), sv_visualizetraces_duration->GetFloat());
g_pDebugOverlay->AddLineOverlay(trace.endpos, vecAbsEnd, 255, 0, 0, !bhit_depth_test.GetBool(), sv_visualizetraces_duration->GetFloat());
}
#endif // !CLIENT_DLL
#ifndef DEDICATED
if (bhit_abs_origin.GetBool() && r_visualizetraces->GetBool())
{
const int iEnt = atoi(args[2]);
if (const IClientEntity* pEntity = g_pClientEntityList->GetClientEntity(iEnt))
{
g_pDebugOverlay->AddSphereOverlay( // Render a debug sphere at the client's predicted entity origin.
pEntity->GetAbsOrigin(), 10.f, 8, 6, 20, 60, 255, 0, r_visualizetraces_duration->GetFloat());
}
}
#endif // !DEDICATED
}
/*
=====================
CVHelp_f
Show help text for a
particular convar/concommand
=====================
*/
void CVHelp_f(const CCommand& args)
{
cv->CvarHelp(args);
}
/*
=====================
CVList_f
List all ConCommandBases
=====================
*/
void CVList_f(const CCommand& args)
{
cv->CvarList(args);
}
/*
=====================
CVDiff_f
List all ConVar's
who's values deviate
from default value
=====================
*/
void CVDiff_f(const CCommand& args)
{
cv->CvarDifferences(args);
}
/*
=====================
CVFlag_f
List all ConVar's
with specified flags
=====================
*/
void CVFlag_f(const CCommand& args)
{
cv->CvarFindFlags_f(args);
}
#ifndef DEDICATED
static double s_flScriptExecTimeBase = 0.0f;
static int s_nScriptExecCount = 0;
#endif // !DEDICATED
/*
=====================
Cmd_Exec_f
executes a cfg file
=====================
*/
#ifndef DEDICATED
static ConVar sv_quota_scriptExecsPerSecond("sv_quota_scriptExecsPerSecond", "3", FCVAR_REPLICATED | FCVAR_RELEASE,
"How many script executions per second clients are allowed to submit, 0 to disable the limitation thereof.", true, 0.f, false, 0.f);
#endif // !DEDICATED
void Cmd_Exec_f(const CCommand& args)
{
#ifndef DEDICATED
// Prevent users from running neo strafe commands and other quick hacks.
// TODO: when reBar becomes a thing, we should verify this function and
// flag users that patch them out.
if (g_pClientState->IsActive() && !ThreadInServerFrameThread())
{
const int execQuota = sv_quota_scriptExecsPerSecond.GetInt();
if (execQuota > 0)
{
const double flCurrentTime = Plat_FloatTime();
// Reset every second.
if ((flCurrentTime - s_flScriptExecTimeBase) > 1.0)
{
s_flScriptExecTimeBase = flCurrentTime;
s_nScriptExecCount = 0;
}
if (s_nScriptExecCount >= execQuota)
{
DevWarning(eDLL_T::ENGINE, "Client is simulating and exec count = %d of %d; dropped exec command: %s\n",
s_nScriptExecCount, execQuota, args.ArgS());
return;
}
s_nScriptExecCount++;
}
}
#endif // !DEDICATED
v__Cmd_Exec_f(args);
}
void VCallback::Detour(const bool bAttach) const
{
DetourSetup(&v__Cmd_Exec_f, &Cmd_Exec_f, bAttach);
}