From 4b7dd1ca76ff0f97d53038ac9a11165f2fc68528 Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 3 Nov 2026 22:22:08 +0100 Subject: World: add Fullbright visual feature - New Visuals card with the usual Active + Bind; default off. Unbound+Active is always-on, a bind makes it hold-to-brighten. - Resolve VEngineCvar004 and set mat_fullbright 1/0 through FindVar (slot 12) and ConVar::SetValue(int) (slot 11), bypassing the console cheat gate. Fall back to ClientCmd if the cvar interface is unavailable. - Reapply after map loads/respawns and persist [fullbright] active/bind. - Log on/off; show an error toast if the cvar cannot be applied. --- src/hl2h.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'src/hl2h.cpp') diff --git a/src/hl2h.cpp b/src/hl2h.cpp index f95f6ed..ebb9b14 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp @@ -123,6 +123,42 @@ float getfov(const QAngle &my_view, const QAngle &aim_ang) { static int g_modified_logged = 0; +// VEngineCvar004 / ICvar vtable: IAppSystem has 5 slots, then +// AllocateDLLIdentifier, RegisterConCommand, UnregisterConCommand, +// UnregisterConCommands, GetCommandLineValue, FindCommandBase, +// FindCommandBase const, FindVar -> slot 12. +// ConCommandBase has two dtor slots, then IsCommand, IsFlagSet, AddFlags, +// GetName, GetHelpText, IsRegistered, GetDLLIdentifier; ConVar then adds +// SetValue(const char*), SetValue(float), SetValue(int) -> slot 11. +bool cvar_set_int(const char *name, int value) { + if (!name) + return false; + if (g_iface.cvar) { + using FindVarFn = void *(*)(void *, const char *); + void *var = vfunc(g_iface.cvar, 12)(g_iface.cvar, name); + if (var) { + using GetNameFn = const char *(*)(void *); + const char *got = vfunc(var, 5)(var); + if (got && strcmp(got, name) == 0) { + using SetIntFn = void (*)(void *, int); + vfunc(var, 11)(var, value); + return true; + } + } + } + // Fallback for an engine that does not expose VEngineCvar004: ClientCmd + // slot 7. Cheat-protected cvars may still be rejected. + if (g_iface.engine) { + char cmd[96]; + snprintf(cmd, sizeof(cmd), "%s %d", name, value); + using CmdFn = void (*)(void *, const char *); + vfunc(g_iface.engine, 7)(g_iface.engine, cmd); + logd("cvar: fallback command '%s'", cmd); + return true; + } + return false; +} + void note_modified(const CUserCmd *cmd, int flags, const float *vel) { // recompute usercmd CRC after modification fix_verified_crc(cmd->command_number, usercmd_checksum(cmd)); @@ -563,6 +599,7 @@ static void do_move(int seq, float frametime) { bones_clear(); aimbot_reset_lock(); silentaim_reset_lock(); + fullbright_invalidate(); } if (feature_active(FEAT_SPREAD)) { @@ -908,10 +945,36 @@ static void *setup_thread(void *) { g_iface.engineserver = ef("VEngineServer021", nullptr); g_iface.debugoverlay = ef("VDebugOverlay003", nullptr); g_iface.enginetrace = ef("EngineTraceClient003", nullptr); + static const char *cvar_names[] = {"VEngineCvar004", "VEngineCvar007", + "VEngineCvar003", "IVEngineCvar004", + nullptr}; + for (int i = 0; cvar_names[i] && !g_iface.cvar; i++) { + g_iface.cvar = ef(cvar_names[i], nullptr); + if (!g_iface.cvar) + g_iface.cvar = cf(cvar_names[i], nullptr); + } + if (!g_iface.cvar) { + size_t slash = g_engine.path.find_last_of('/'); + if (slash != std::string::npos) { + std::string path = + g_engine.path.substr(0, slash + 1) + "libvstdlib.so"; + void *h = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL); + if (!h) + h = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); + if (h) { + auto vf = (CreateInterfaceFn)dlsym(h, "CreateInterface"); + if (vf) { + for (int i = 0; cvar_names[i] && !g_iface.cvar; i++) + g_iface.cvar = vf(cvar_names[i], nullptr); + } + } + } + } logf("modelinfo: %p (VModelInfoClient006)", g_iface.modelinfo); logf("engineserver: %p (VEngineServer021), debugoverlay: %p, " "enginetrace: %p (EngineTraceClient003)", g_iface.engineserver, g_iface.debugoverlay, g_iface.enginetrace); + logf("cvar: %p (VEngineCvar004)", g_iface.cvar); resolve_netvars(); if (!g_net.ok()) -- cgit v1.2.3