mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
* Only run '_DownloadPlaylists_f()' in the main thread, schedule for next frame if we aren't in the main thread. (this should fix crash cases related to disconnecting from the game). * Locked read/write to CBrowser members (thread for obtaining the server list is detached, but once the 'slow' post operation in this thread is complete, mutex lock is acquired (locking the render thread if the browser is active) to set the string members of CBrowser, this operation is very fast as we only set the string and the color after the http post operation (this never caused a crash, but the behavior without any lock mechanism is technically undefined regardless). * Obtain the host name dynamically from the ConVar 'pylon_matchmaking_hostname' (atomic operation). Initial approach was deleting the whole master server pointer just to construct a new httpclient object..
976 lines
30 KiB
C++
976 lines
30 KiB
C++
#include "core/stdafx.h"
|
|
#include "tier1/utlrbtree.h"
|
|
#include "tier1/cvar.h"
|
|
#include "tier1/IConVar.h"
|
|
#include "engine/sys_dll2.h"
|
|
#include "filesystem/filesystem.h"
|
|
#include "vstdlib/concommandhash.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ENGINE |
|
|
ConVar* single_frame_shutdown_for_reload = nullptr;
|
|
ConVar* old_gather_props = nullptr;
|
|
ConVar* enable_debug_overlays = nullptr;
|
|
ConVar* cm_unset_all_cmdquery = nullptr;
|
|
|
|
ConVar* staticProp_defaultBuildFrustum = nullptr;
|
|
ConVar* staticProp_no_fade_scalar = nullptr;
|
|
ConVar* staticProp_gather_size_weight = nullptr;
|
|
|
|
ConVar* model_defaultFadeDistScale = nullptr;
|
|
ConVar* model_defaultFadeDistMin = nullptr;
|
|
|
|
ConVar* hostname = nullptr;
|
|
ConVar* hostdesc = nullptr;
|
|
ConVar* hostip = nullptr;
|
|
ConVar* hostport = nullptr;
|
|
ConVar* host_hasIrreversibleShutdown = nullptr;
|
|
ConVar* mp_gamemode = nullptr;
|
|
|
|
ConVar* rcon_address = nullptr;
|
|
ConVar* rcon_password = nullptr;
|
|
|
|
ConVar* r_debug_overlay_nodecay = nullptr;
|
|
ConVar* r_debug_overlay_invisible = nullptr;
|
|
ConVar* r_debug_overlay_wireframe = nullptr;
|
|
ConVar* r_debug_overlay_zbuffer = nullptr;
|
|
ConVar* r_drawWorldMeshes = nullptr;
|
|
ConVar* r_drawWorldMeshesDepthOnly = nullptr;
|
|
ConVar* r_drawWorldMeshesDepthAtTheEnd = nullptr;
|
|
|
|
ConVar* stream_overlay = nullptr;
|
|
ConVar* stream_overlay_mode = nullptr;
|
|
//-----------------------------------------------------------------------------
|
|
// SERVER |
|
|
#ifndef CLIENT_DLL
|
|
ConVar* ai_ainDumpOnLoad = nullptr;
|
|
ConVar* ai_ainDebugConnect = nullptr;
|
|
ConVar* ai_script_nodes_draw = nullptr;
|
|
ConVar* ai_script_nodes_draw_range = nullptr;
|
|
|
|
ConVar* navmesh_always_reachable = nullptr;
|
|
ConVar* navmesh_debug_type = nullptr;
|
|
ConVar* navmesh_debug_tile_range = nullptr;
|
|
ConVar* navmesh_debug_camera_range = nullptr;
|
|
#ifndef DEDICATED
|
|
ConVar* navmesh_draw_bvtree = nullptr;
|
|
ConVar* navmesh_draw_portal = nullptr;
|
|
ConVar* navmesh_draw_polys = nullptr;
|
|
ConVar* navmesh_draw_poly_bounds = nullptr;
|
|
ConVar* navmesh_draw_poly_bounds_inner = nullptr;
|
|
#endif // !DEDICATED
|
|
|
|
ConVar* sv_showconnecting = nullptr;
|
|
ConVar* sv_pylonVisibility = nullptr;
|
|
ConVar* sv_pylonRefreshInterval = nullptr;
|
|
ConVar* sv_banlistRefreshInterval = nullptr;
|
|
ConVar* sv_statusRefreshInterval = nullptr;
|
|
|
|
#ifdef DEDICATED
|
|
ConVar* sv_rcon_debug = nullptr;
|
|
ConVar* sv_rcon_sendlogs = nullptr;
|
|
ConVar* sv_rcon_banpenalty = nullptr; // TODO
|
|
ConVar* sv_rcon_maxfailures = nullptr;
|
|
ConVar* sv_rcon_maxignores = nullptr;
|
|
ConVar* sv_rcon_maxsockets = nullptr;
|
|
ConVar* sv_rcon_whitelist_address = nullptr;
|
|
#endif // DEDICATED
|
|
#endif // !CLIENT_DLL
|
|
|
|
ConVar* sv_visualizetraces = nullptr;
|
|
#if !defined (GAMEDLL_S0) && !defined (GAMEDLL_S1)
|
|
ConVar* bhit_enable = nullptr;
|
|
ConVar* bhit_abs_origin = nullptr;
|
|
#endif // !GAMEDLL_S0 && !GAMEDLL_S1
|
|
//-----------------------------------------------------------------------------
|
|
// CLIENT |
|
|
#ifndef DEDICATED
|
|
ConVar* cl_rcon_request_sendlogs = nullptr;
|
|
|
|
ConVar* cl_drawconsoleoverlay = nullptr;
|
|
ConVar* cl_consoleoverlay_lines = nullptr;
|
|
ConVar* cl_consoleoverlay_invert_rect_x = nullptr;
|
|
ConVar* cl_consoleoverlay_invert_rect_y = nullptr;
|
|
ConVar* cl_consoleoverlay_offset_x = nullptr;
|
|
ConVar* cl_consoleoverlay_offset_y = nullptr;
|
|
|
|
ConVar* cl_conoverlay_script_server_clr = nullptr;
|
|
ConVar* cl_conoverlay_script_client_clr = nullptr;
|
|
ConVar* cl_conoverlay_script_ui_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_server_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_client_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_ui_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_engine_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_fs_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_rtech_clr = nullptr;
|
|
ConVar* cl_conoverlay_native_ms_clr = nullptr;
|
|
ConVar* cl_conoverlay_netcon_clr = nullptr;
|
|
ConVar* cl_conoverlay_common_clr = nullptr;
|
|
ConVar* cl_conoverlay_warning_clr = nullptr;
|
|
ConVar* cl_conoverlay_error_clr = nullptr;
|
|
|
|
ConVar* cl_showhoststats = nullptr;
|
|
ConVar* cl_hoststats_invert_rect_x = nullptr;
|
|
ConVar* cl_hoststats_invert_rect_y = nullptr;
|
|
ConVar* cl_hoststats_offset_x = nullptr;
|
|
ConVar* cl_hoststats_offset_y = nullptr;
|
|
|
|
ConVar* cl_showsimstats = nullptr;
|
|
ConVar* cl_simstats_invert_rect_x = nullptr;
|
|
ConVar* cl_simstats_invert_rect_y = nullptr;
|
|
ConVar* cl_simstats_offset_x = nullptr;
|
|
ConVar* cl_simstats_offset_y = nullptr;
|
|
|
|
ConVar* cl_showgpustats = nullptr;
|
|
ConVar* cl_gpustats_invert_rect_x = nullptr;
|
|
ConVar* cl_gpustats_invert_rect_y = nullptr;
|
|
ConVar* cl_gpustats_offset_x = nullptr;
|
|
ConVar* cl_gpustats_offset_y = nullptr;
|
|
|
|
ConVar* cl_showmaterialinfo = nullptr;
|
|
ConVar* cl_materialinfo_offset_x = nullptr;
|
|
ConVar* cl_materialinfo_offset_y = nullptr;
|
|
|
|
ConVar* cl_threaded_bone_setup = nullptr;
|
|
|
|
ConVar* con_max_size_logvector = nullptr;
|
|
ConVar* con_max_size_history = nullptr;
|
|
ConVar* con_suggestion_limit = nullptr;
|
|
ConVar* con_suggestion_showhelptext = nullptr;
|
|
ConVar* con_suggestion_showflags = nullptr;
|
|
ConVar* con_suggestion_flags_realtime = nullptr;
|
|
|
|
ConVar* origin_disconnectWhenOffline = nullptr;
|
|
#endif // !DEDICATED
|
|
//-----------------------------------------------------------------------------
|
|
// FILESYSTEM |
|
|
ConVar* fs_warning_level_sdk = nullptr;
|
|
ConVar* fs_show_warning_output = nullptr;
|
|
ConVar* fs_packedstore_entryblock_stats = nullptr;
|
|
ConVar* fs_packedstore_workspace = nullptr;
|
|
//-----------------------------------------------------------------------------
|
|
// MATERIALSYSTEM |
|
|
#ifndef DEDICATED
|
|
ConVar* mat_showdxoutput = nullptr;
|
|
#endif // !DEDICATED
|
|
//-----------------------------------------------------------------------------
|
|
// SQUIRREL |
|
|
ConVar* sq_showrsonloading = nullptr;
|
|
ConVar* sq_showscriptloading = nullptr;
|
|
ConVar* sq_showvmoutput = nullptr;
|
|
ConVar* sq_showvmwarning = nullptr;
|
|
//-----------------------------------------------------------------------------
|
|
// NETCHANNEL |
|
|
ConVar* net_tracePayload = nullptr;
|
|
ConVar* net_encryptionEnable = nullptr;
|
|
ConVar* net_useRandomKey = nullptr;
|
|
ConVar* net_usesocketsforloopback = nullptr;
|
|
ConVar* pylon_matchmaking_hostname = nullptr;
|
|
ConVar* pylon_host_update_interval = nullptr;
|
|
ConVar* pylon_showdebug = nullptr;
|
|
//-----------------------------------------------------------------------------
|
|
// RTECH API |
|
|
ConVar* rtech_debug = nullptr;
|
|
//-----------------------------------------------------------------------------
|
|
// RUI |
|
|
#ifndef DEDICATED
|
|
ConVar* rui_drawEnable = nullptr;
|
|
ConVar* rui_defaultDebugFontFace = nullptr;
|
|
#endif // !DEDICATED
|
|
|
|
struct ConVarFlags_t
|
|
{
|
|
int bit;
|
|
const char* desc;
|
|
const char* shortdesc;
|
|
};
|
|
|
|
#define CONVARFLAG( x, y ) { FCVAR_##x, #x, #y }
|
|
|
|
static ConVarFlags_t g_ConVarFlags[] =
|
|
{
|
|
CONVARFLAG(UNREGISTERED, "u" ),
|
|
CONVARFLAG(ARCHIVE, "a"),
|
|
CONVARFLAG(ARCHIVE_PLAYERPROFILE, "ap"),
|
|
CONVARFLAG(SPONLY, "sp"),
|
|
CONVARFLAG(GAMEDLL, "sv"),
|
|
CONVARFLAG(CHEAT, "cheat"),
|
|
CONVARFLAG(USERINFO, "user"),
|
|
CONVARFLAG(NOTIFY, "nf"),
|
|
CONVARFLAG(PROTECTED, "prot"),
|
|
CONVARFLAG(PRINTABLEONLY, "print"),
|
|
CONVARFLAG(UNLOGGED, "ulog"),
|
|
CONVARFLAG(NEVER_AS_STRING, "numeric"),
|
|
CONVARFLAG(REPLICATED, "rep"),
|
|
CONVARFLAG(DEMO, "demo"),
|
|
CONVARFLAG(DONTRECORD, "norecord"),
|
|
CONVARFLAG(SERVER_CAN_EXECUTE, "server_can_execute"),
|
|
CONVARFLAG(CLIENTCMD_CAN_EXECUTE, "clientcmd_can_execute"),
|
|
CONVARFLAG(CLIENTDLL, "cl"),
|
|
};
|
|
|
|
static void PrintListHeader(FileHandle_t& f)
|
|
{
|
|
char csvflagstr[1024];
|
|
|
|
csvflagstr[0] = 0;
|
|
|
|
int c = ARRAYSIZE(g_ConVarFlags);
|
|
for (int i = 0; i < c; ++i)
|
|
{
|
|
char csvf[64];
|
|
|
|
ConVarFlags_t& entry = g_ConVarFlags[i];
|
|
snprintf(csvf, sizeof(csvf), "\"%s\",", entry.desc);
|
|
strncat(csvflagstr, csvf, sizeof(csvflagstr));
|
|
}
|
|
|
|
FileSystem()->FPrintf(f, "\"%s\",\"%s\",%s,\"%s\"\n", "Name", "Value", csvflagstr, "Help Text");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *var -
|
|
// *f -
|
|
//-----------------------------------------------------------------------------
|
|
static void PrintCvar(ConVar* var, bool logging, FileHandle_t& fh)
|
|
{
|
|
char flagstr[128];
|
|
char csvflagstr[1024];
|
|
|
|
flagstr[0] = 0;
|
|
csvflagstr[0] = 0;
|
|
|
|
int c = ARRAYSIZE(g_ConVarFlags);
|
|
for (int i = 0; i < c; ++i)
|
|
{
|
|
char f[32];
|
|
char csvf[64];
|
|
|
|
ConVarFlags_t& entry = g_ConVarFlags[i];
|
|
if (var->IsFlagSet(entry.bit))
|
|
{
|
|
snprintf(f, sizeof(f), ", %s", entry.shortdesc);
|
|
strncat(flagstr, f, sizeof(flagstr));
|
|
snprintf(csvf, sizeof(csvf), "\"%s\",", entry.desc);
|
|
}
|
|
else
|
|
{
|
|
snprintf(csvf, sizeof(csvf), ",");
|
|
}
|
|
|
|
strncat(csvflagstr, csvf, sizeof(csvflagstr));
|
|
}
|
|
|
|
|
|
char valstr[32];
|
|
char tempbuff[512] = { 0 };
|
|
|
|
// Clean up integers
|
|
if (var->GetInt() == (int)var->GetFloat())
|
|
{
|
|
snprintf(valstr, sizeof(valstr), "%-8i", var->GetInt());
|
|
}
|
|
else
|
|
{
|
|
snprintf(valstr, sizeof(valstr), "%-8.3f", var->GetFloat());
|
|
}
|
|
|
|
// Print to console
|
|
DevMsg(eDLL_T::ENGINE, "%-40s : %-8s : %-16s : %s\n", var->GetName(), valstr, flagstr, StripTabsAndReturns(var->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
|
if (logging)
|
|
{
|
|
FileSystem()->FPrintf(fh, "\"%s\",\"%s\",%s,\"%s\"\n", var->GetName(), valstr, csvflagstr, StripQuotes(var->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input :
|
|
// Output :
|
|
//-----------------------------------------------------------------------------
|
|
static void PrintCommand(const ConCommand* cmd, bool logging, FileHandle_t& f)
|
|
{
|
|
// Print to console
|
|
char tempbuff[512] = { 0 };
|
|
DevMsg(eDLL_T::ENGINE, "%-40s : %-8s : %-16s : %s\n", cmd->GetName(), "cmd", "", StripTabsAndReturns(cmd->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
|
if (logging)
|
|
{
|
|
char emptyflags[256];
|
|
|
|
emptyflags[0] = 0;
|
|
|
|
int c = ARRAYSIZE(g_ConVarFlags);
|
|
for (int i = 0; i < c; ++i)
|
|
{
|
|
char csvf[64];
|
|
Q_snprintf(csvf, sizeof(csvf), ",");
|
|
Q_strncat(emptyflags, csvf, sizeof(emptyflags));
|
|
}
|
|
// Names staring with +/- need to be wrapped in single quotes
|
|
char name[256];
|
|
snprintf(name, sizeof(name), "%s", cmd->GetName());
|
|
if (name[0] == '+' || name[0] == '-')
|
|
{
|
|
snprintf(name, sizeof(name), "'%s'", cmd->GetName());
|
|
}
|
|
FileSystem()->FPrintf(f, "\"%s\",\"%s\",%s,\"%s\"\n", name, "cmd", emptyflags, StripQuotes(cmd->GetHelpText(), tempbuff, sizeof(tempbuff)));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input :
|
|
// Output : bool
|
|
//-----------------------------------------------------------------------------
|
|
static bool ConCommandBaseLessFunc(ConCommandBase* const& lhs, ConCommandBase* const& rhs)
|
|
{
|
|
const char* left = lhs->GetName();
|
|
const char* right = rhs->GetName();
|
|
|
|
if (*left == '-' || *left == '+')
|
|
left++;
|
|
if (*right == '-' || *right == '+')
|
|
right++;
|
|
|
|
return (Q_stricmp(left, right) < 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Singleton CCvarUtilities
|
|
//-----------------------------------------------------------------------------
|
|
static CCvarUtilities g_CvarUtilities;
|
|
CCvarUtilities* cv = &g_CvarUtilities;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input :
|
|
// Output : int
|
|
//-----------------------------------------------------------------------------
|
|
int CCvarUtilities::CountVariablesWithFlags(int flags)
|
|
{
|
|
int i = 0;
|
|
ConCommandBase* var;
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through cvars...
|
|
{
|
|
var = itint->Get();
|
|
if (!var->IsCommand())
|
|
{
|
|
if (var->IsFlagSet(flags))
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
MemAllocSingleton()->Free(itint);
|
|
return i;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Removes the FCVAR_DEVELOPMENTONLY flag from all cvars, making them accessible
|
|
//-----------------------------------------------------------------------------
|
|
void CCvarUtilities::EnableDevCvars()
|
|
{
|
|
// Loop through cvars...
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next())
|
|
{
|
|
// remove flag from all cvars
|
|
ConCommandBase* pCommandBase = itint->Get();
|
|
pCommandBase->RemoveFlags(FCVAR_DEVELOPMENTONLY);
|
|
}
|
|
|
|
MemAllocSingleton()->Free(itint);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : void CCvar::CvarList_f
|
|
//-----------------------------------------------------------------------------
|
|
void CCvarUtilities::CvarList(const CCommand& args)
|
|
{
|
|
ConCommandBase* var; // Temporary Pointer to cvars
|
|
int iArgs; // Argument count
|
|
const char* partial = NULL; // Partial cvar to search for...
|
|
// E.eg
|
|
int ipLen = 0; // Length of the partial cvar
|
|
|
|
FileHandle_t f = FILESYSTEM_INVALID_HANDLE; // FilePointer for logging
|
|
bool bLogging = false;
|
|
// Are we logging?
|
|
iArgs = args.ArgC(); // Get count
|
|
|
|
// Print usage?
|
|
if (iArgs == 2 && !Q_strcasecmp(args[1], "?"))
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "cvarlist: [log logfile] [ partial ]\n");
|
|
return;
|
|
}
|
|
|
|
if (!Q_strcasecmp(args[1], "log") && iArgs >= 3)
|
|
{
|
|
char fn[256];
|
|
Q_snprintf(fn, sizeof(fn), "%s", args[2]);
|
|
f = FileSystem()->Open(fn, "wb", nullptr, 0);
|
|
if (f)
|
|
{
|
|
bLogging = true;
|
|
}
|
|
else
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "Couldn't open '%s' for writing!\n", fn);
|
|
return;
|
|
}
|
|
|
|
if (iArgs == 4)
|
|
{
|
|
partial = args[3];
|
|
ipLen = Q_strlen(partial);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
partial = args[1];
|
|
ipLen = Q_strlen(partial);
|
|
}
|
|
|
|
// Banner
|
|
DevMsg(eDLL_T::ENGINE, "cvar list\n--------------\n");
|
|
|
|
CUtlRBTree< ConCommandBase* > sorted(0, 0, ConCommandBaseLessFunc);
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances.
|
|
{
|
|
var = itint->Get();
|
|
|
|
if (!var->IsFlagSet(FCVAR_DEVELOPMENTONLY) &&
|
|
!var->IsFlagSet(FCVAR_HIDDEN))
|
|
{
|
|
bool print = false;
|
|
|
|
if (partial) // Partial string searching?
|
|
{
|
|
if (!Q_strncasecmp(var->GetName(), partial, ipLen))
|
|
{
|
|
print = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print = true;
|
|
}
|
|
|
|
if (print)
|
|
{
|
|
sorted.Insert(var);
|
|
}
|
|
}
|
|
}
|
|
|
|
MemAllocSingleton()->Free(itint);
|
|
|
|
if (bLogging)
|
|
{
|
|
PrintListHeader(f);
|
|
}
|
|
for (int i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder(i))
|
|
{
|
|
var = sorted[i];
|
|
if (var->IsCommand())
|
|
{
|
|
PrintCommand((ConCommand*)var, bLogging, f);
|
|
}
|
|
else
|
|
{
|
|
PrintCvar((ConVar*)var, bLogging, f);
|
|
}
|
|
}
|
|
|
|
|
|
// Show total and syntax help...
|
|
if (partial && partial[0])
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "--------------\n%3i convars/concommands for [%s]\n", sorted.Count(), partial);
|
|
}
|
|
else
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "--------------\n%3i total convars/concommands\n", sorted.Count());
|
|
}
|
|
|
|
if (bLogging)
|
|
{
|
|
FileSystem()->Close(f);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCvarUtilities::CvarHelp(const CCommand& args)
|
|
{
|
|
const char* search;
|
|
ConCommandBase* var;
|
|
|
|
if (args.ArgC() != 2)
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "Usage: help <cvarname>\n");
|
|
return;
|
|
}
|
|
|
|
// Get name of var to find
|
|
search = args[1];
|
|
|
|
// Search for it
|
|
var = g_pCVar->FindCommandBase(search);
|
|
if (!var)
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "help: no cvar or command named %s\n", search);
|
|
return;
|
|
}
|
|
|
|
// Show info
|
|
ConVar_PrintDescription(var);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCvarUtilities::CvarDifferences(const CCommand& args)
|
|
{
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
|
int i = 0;
|
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances.
|
|
{
|
|
ConCommandBase* pCommandBase = itint->Get();
|
|
|
|
if (!pCommandBase->IsCommand() &&
|
|
!pCommandBase->IsFlagSet(FCVAR_HIDDEN))
|
|
{
|
|
ConVar* pConVar = reinterpret_cast<ConVar*>(pCommandBase);
|
|
|
|
if (V_strcmp(pConVar->GetString(), "FCVAR_NEVER_AS_STRING") != NULL)
|
|
{
|
|
if (V_stricmp(pConVar->GetString(), pConVar->GetDefault()) != NULL)
|
|
{
|
|
ConVar_PrintDescription(pConVar);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MemAllocSingleton()->Free(itint);
|
|
DevMsg(eDLL_T::ENGINE, "--------------\n%3i changed convars\n", i);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCvarUtilities::CvarFindFlags_f(const CCommand& args)
|
|
{
|
|
if (args.ArgC() < 2)
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "Usage: findflags <string>\n");
|
|
DevMsg(eDLL_T::ENGINE, "Available flags to search for: \n");
|
|
|
|
for (int i = 0; i < ARRAYSIZE(g_ConVarFlags); i++)
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, " - %s\n", g_ConVarFlags[i].desc);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Get substring to find
|
|
const char* search = args[1];
|
|
ConCommandBase* var;
|
|
|
|
// Loop through vars and print out findings
|
|
CCvar::CCVarIteratorInternal* itint = g_pCVar->FactoryInternalIterator();
|
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next())
|
|
{
|
|
var = itint->Get();
|
|
|
|
if (!var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || !var->IsFlagSet(FCVAR_HIDDEN))
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(g_ConVarFlags); i++)
|
|
{
|
|
if (var->IsFlagSet(g_ConVarFlags[i].bit))
|
|
{
|
|
if (V_stristr(g_ConVarFlags[i].desc, search))
|
|
{
|
|
ConVar_PrintDescription(var);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MemAllocSingleton()->Free(itint);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
int CCvarUtilities::CvarFindFlagsCompletionCallback(const char* partial, char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH])
|
|
{
|
|
int flagC = ARRAYSIZE(g_ConVarFlags);
|
|
char const* pcmd = "findflags ";
|
|
int len = Q_strlen(partial);
|
|
|
|
if (len < Q_strlen(pcmd))
|
|
{
|
|
int i = 0;
|
|
for (; i < MIN(flagC, COMMAND_COMPLETION_MAXITEMS); i++)
|
|
{
|
|
Q_snprintf(commands[i], sizeof(commands[i]), "%s %s", pcmd, g_ConVarFlags[i].desc);
|
|
Q_strlower(commands[i]);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
char const* pSub = partial + Q_strlen(pcmd);
|
|
int nSubLen = Q_strlen(pSub);
|
|
|
|
int values = 0;
|
|
for (int i = 0; i < flagC; ++i)
|
|
{
|
|
if (Q_strnicmp(g_ConVarFlags[i].desc, pSub, nSubLen))
|
|
continue;
|
|
|
|
Q_snprintf(commands[values], sizeof(commands[values]), "%s %s", pcmd, g_ConVarFlags[i].desc);
|
|
Q_strlower(commands[values]);
|
|
++values;
|
|
|
|
if (values >= COMMAND_COMPLETION_MAXITEMS)
|
|
break;
|
|
}
|
|
return values;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: registers input commands.
|
|
// Input : *pszCommandName -
|
|
//-----------------------------------------------------------------------------
|
|
ConCommandBase* CCvar::RegisterConCommand(ConCommandBase* pCommandToRemove)
|
|
{
|
|
const int index = 9;
|
|
return CallVFunc<ConCommandBase*>(index, this, pCommandToRemove);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: unregisters input commands.
|
|
// Input : *pszCommandName -
|
|
//-----------------------------------------------------------------------------
|
|
ConCommandBase* CCvar::UnregisterConCommand(ConCommandBase* pCommandToRemove)
|
|
{
|
|
const int index = 10;
|
|
return CallVFunc<ConCommandBase*>(index, this, pCommandToRemove);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: finds base commands.
|
|
// Input : *pszCommandName -
|
|
//-----------------------------------------------------------------------------
|
|
ConCommandBase* CCvar::FindCommandBase(const char* pszCommandName)
|
|
{
|
|
const int index = 14;
|
|
return CallVFunc<ConCommandBase*>(index, this, pszCommandName);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: finds ConVars.
|
|
// Input : *pszVarName -
|
|
//-----------------------------------------------------------------------------
|
|
ConVar* CCvar::FindVar(const char* pszVarName)
|
|
{
|
|
const int index = 16;
|
|
return CallVFunc<ConVar*>(index, this, pszVarName);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: finds ConCommands.
|
|
// Input : *pszCommandName -
|
|
//-----------------------------------------------------------------------------
|
|
ConCommand* CCvar::FindCommand(const char* pszCommandName)
|
|
{
|
|
const int index = 18;
|
|
return CallVFunc<ConCommand*>(index, this, pszCommandName);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCvar::CallGlobalChangeCallbacks(ConVar* pConVar, const char* pOldString)
|
|
{
|
|
const int index = 23;
|
|
CallVFunc<void>(index, this, pConVar, pOldString);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: deal with queued material system ConVars
|
|
//-----------------------------------------------------------------------------
|
|
bool CCvar::IsMaterialThreadSetAllowed(void)
|
|
{
|
|
const int index = 35;
|
|
return CallVFunc<bool>(index, this);
|
|
}
|
|
void CCvar::QueueMaterialThreadSetValue(ConVar* pConVar, float flValue)
|
|
{
|
|
const int index = 36;
|
|
CallVFunc<void>(index, this, pConVar, flValue);
|
|
}
|
|
void CCvar::QueueMaterialThreadSetValue(ConVar* pConVar, int nValue)
|
|
{
|
|
const int index = 37;
|
|
CallVFunc<void>(index, this, pConVar, nValue);
|
|
}
|
|
void CCvar::QueueMaterialThreadSetValue(ConVar* pConVar, const char* pValue)
|
|
{
|
|
const int index = 38;
|
|
CallVFunc<void>(index, this, pConVar, pValue);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: iterates over all ConVars
|
|
//-----------------------------------------------------------------------------
|
|
CCvar::CCVarIteratorInternal* CCvar::FactoryInternalIterator(void)
|
|
{
|
|
const int index = 41;
|
|
return CallVFunc<CCVarIteratorInternal*>(index, this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: returns all ConVars
|
|
//-----------------------------------------------------------------------------
|
|
unordered_map<string, ConCommandBase*> CCvar::DumpToMap(void)
|
|
{
|
|
stringstream ss;
|
|
CCVarIteratorInternal* itint = FactoryInternalIterator(); // Allocate new InternalIterator.
|
|
|
|
unordered_map<string, ConCommandBase*> allConVars;
|
|
|
|
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances.
|
|
{
|
|
ConCommandBase* pCommand = itint->Get();
|
|
const char* pszCommandName = pCommand->m_pszName;
|
|
allConVars[pszCommandName] = pCommand;
|
|
}
|
|
|
|
MemAllocSingleton()->Free(itint);
|
|
|
|
return allConVars;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
CCvar* g_pCVar = nullptr;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Console command hash data structure
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CConCommandHash()
|
|
{
|
|
Purge(true);
|
|
}
|
|
|
|
CConCommandHash::~CConCommandHash()
|
|
{
|
|
Purge(false);
|
|
}
|
|
|
|
void CConCommandHash::Purge(bool bReinitialize)
|
|
{
|
|
m_aBuckets.Purge();
|
|
m_aDataPool.Purge();
|
|
if (bReinitialize)
|
|
{
|
|
Init();
|
|
}
|
|
}
|
|
|
|
// Initialize.
|
|
void CConCommandHash::Init(void)
|
|
{
|
|
// kNUM_BUCKETS must be a power of two.
|
|
COMPILE_TIME_ASSERT((kNUM_BUCKETS & (kNUM_BUCKETS - 1)) == 0);
|
|
|
|
// Set the bucket size.
|
|
m_aBuckets.SetSize(kNUM_BUCKETS);
|
|
for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket)
|
|
{
|
|
m_aBuckets[iBucket] = m_aDataPool.InvalidIndex();
|
|
}
|
|
|
|
// Calculate the grow size.
|
|
int nGrowSize = 4 * kNUM_BUCKETS;
|
|
m_aDataPool.SetGrowSize(nGrowSize);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Insert data into the hash table given its key (unsigned int),
|
|
// WITH a check to see if the element already exists within the hash.
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CCommandHashHandle_t CConCommandHash::Insert(ConCommandBase* cmd)
|
|
{
|
|
// Check to see if that key already exists in the buckets (should be unique).
|
|
CCommandHashHandle_t hHash = Find(cmd);
|
|
if (hHash != InvalidHandle())
|
|
return hHash;
|
|
|
|
return FastInsert(cmd);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Insert data into the hash table given its key (unsigned int),
|
|
// WITHOUT a check to see if the element already exists within the hash.
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CCommandHashHandle_t CConCommandHash::FastInsert(ConCommandBase* cmd)
|
|
{
|
|
// Get a new element from the pool.
|
|
intptr_t iHashData = m_aDataPool.Alloc(true);
|
|
HashEntry_t* RESTRICT pHashData = &m_aDataPool[iHashData];
|
|
if (!pHashData)
|
|
return InvalidHandle();
|
|
|
|
HashKey_t key = Hash(cmd);
|
|
|
|
// Add data to new element.
|
|
pHashData->m_uiKey = key;
|
|
pHashData->m_Data = cmd;
|
|
|
|
// Link element.
|
|
int iBucket = key & kBUCKETMASK; // HashFuncs::Hash( uiKey, m_uiBucketMask );
|
|
m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData);
|
|
m_aBuckets[iBucket] = iHashData;
|
|
|
|
return iHashData;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Remove a given element from the hash.
|
|
//-----------------------------------------------------------------------------
|
|
void CConCommandHash::Remove(CCommandHashHandle_t hHash) RESTRICT
|
|
{
|
|
HashEntry_t* RESTRICT entry = &m_aDataPool[hHash];
|
|
HashKey_t iBucket = entry->m_uiKey & kBUCKETMASK;
|
|
if (m_aBuckets[iBucket] == hHash)
|
|
{
|
|
// It is a bucket head.
|
|
m_aBuckets[iBucket] = m_aDataPool.Next(hHash);
|
|
}
|
|
else
|
|
{
|
|
// Not a bucket head.
|
|
m_aDataPool.Unlink(hHash);
|
|
}
|
|
|
|
// Remove the element.
|
|
m_aDataPool.Remove(hHash);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Remove all elements from the hash
|
|
//-----------------------------------------------------------------------------
|
|
void CConCommandHash::RemoveAll(void)
|
|
{
|
|
m_aBuckets.RemoveAll();
|
|
m_aDataPool.RemoveAll();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Find hash entry corresponding to a string name
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const char* name, HashKey_t hashkey) const RESTRICT
|
|
{
|
|
// hash the "key" - get the correct hash table "bucket"
|
|
int iBucket = hashkey & kBUCKETMASK;
|
|
|
|
for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement))
|
|
{
|
|
const HashEntry_t& element = m_aDataPool[iElement];
|
|
if (element.m_uiKey == hashkey && // if hashes of strings match,
|
|
Q_stricmp(name, element.m_Data->GetName()) == 0) // then test the actual strings
|
|
{
|
|
return iElement;
|
|
}
|
|
}
|
|
|
|
// found nuffink
|
|
return InvalidHandle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Find a command in the hash.
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const ConCommandBase* cmd) const RESTRICT
|
|
{
|
|
// Set this #if to 1 if the assert at bottom starts whining --
|
|
// that indicates that a console command is being double-registered,
|
|
// or something similarly nonfatally bad. With this #if 1, we'll search
|
|
// by name instead of by pointer, which is more robust in the face
|
|
// of double registered commands, but obviously slower.
|
|
#if 0
|
|
return Find(cmd->GetName());
|
|
#else
|
|
HashKey_t hashkey = Hash(cmd);
|
|
int iBucket = hashkey & kBUCKETMASK;
|
|
|
|
// hunt through all entries in that bucket
|
|
for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement))
|
|
{
|
|
const HashEntry_t& element = m_aDataPool[iElement];
|
|
if (element.m_uiKey == hashkey && // if the hashes match...
|
|
element.m_Data == cmd) // and the pointers...
|
|
{
|
|
// in debug, test to make sure we don't have commands under the same name
|
|
// or something goofy like that
|
|
Assert(iElement == Find(cmd->GetName()),
|
|
"ConCommand %s had two entries in the hash!", cmd->GetName());
|
|
|
|
// return this element
|
|
return iElement;
|
|
}
|
|
}
|
|
|
|
// found nothing.
|
|
#ifdef DBGFLAG_ASSERT // double check against search by name
|
|
CCommandHashHandle_t dbghand = Find(cmd->GetName());
|
|
|
|
Assert(InvalidHandle() == dbghand,
|
|
"ConCommand %s couldn't be found by pointer, but was found by name!", cmd->GetName());
|
|
#endif
|
|
return InvalidHandle();
|
|
#endif
|
|
}
|
|
|
|
|
|
//#ifdef _DEBUG
|
|
// Dump a report to MSG
|
|
void CConCommandHash::Report(void)
|
|
{
|
|
DevMsg(eDLL_T::ENGINE, "Console command hash bucket load:\n");
|
|
int total = 0;
|
|
for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket)
|
|
{
|
|
int count = 0;
|
|
CCommandHashHandle_t iElement = m_aBuckets[iBucket]; // get the head of the bucket
|
|
while (iElement != m_aDataPool.InvalidIndex())
|
|
{
|
|
++count;
|
|
iElement = m_aDataPool.Next(iElement);
|
|
}
|
|
|
|
DevMsg(eDLL_T::ENGINE, "%d: %d\n", iBucket, count);
|
|
total += count;
|
|
}
|
|
|
|
DevMsg(eDLL_T::ENGINE, "\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS)));
|
|
}
|
|
//#endif
|