//=============================================================================// // // 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 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 end. ===================== */ 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 end radius . ===================== */ 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); }