diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-03 22:22:08 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-03 22:22:08 +0100 |
| commit | 4b7dd1ca76ff0f97d53038ac9a11165f2fc68528 (patch) | |
| tree | d30473e54ecbb18f14e54e7cf678e7e7dc1a2a52 | |
| parent | Vischeck: only glass materials are glass; log font/glass diagnostics (diff) | |
| download | hl2h-4b7dd1ca76ff0f97d53038ac9a11165f2fc68528.tar.gz hl2h-4b7dd1ca76ff0f97d53038ac9a11165f2fc68528.zip | |
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.
Diffstat (limited to '')
| -rw-r--r-- | CONTEXT.md | 14 | ||||
| -rw-r--r-- | src/gui.cpp | 3 | ||||
| -rw-r--r-- | src/hl2h.cpp | 63 | ||||
| -rw-r--r-- | src/hl2h.h | 9 | ||||
| -rw-r--r-- | src/menu.cpp | 10 |
5 files changed, 96 insertions, 3 deletions
| @@ -269,6 +269,20 @@ vocabulary / decisions. | |||
| 269 | assist deliberately writes only `m_vecAbsVelocity`; `SetAbsVelocity` syncs | 269 | assist deliberately writes only `m_vecAbsVelocity`; `SetAbsVelocity` syncs |
| 270 | `m_vecVelocity` after the command. | 270 | `m_vecVelocity` after the command. |
| 271 | 271 | ||
| 272 | ## World transformations | ||
| 273 | |||
| 274 | ### Fullbright | ||
| 275 | |||
| 276 | - Visuals card with the usual Active + Bind. Unbound and Active means always | ||
| 277 | on; a bind makes it a hold-to-brighten key. | ||
| 278 | - Applies the client `mat_fullbright` cvar to 1/0 through `VEngineCvar004` | ||
| 279 | (`FindVar` slot 12, `ConVar::SetValue(int)` slot 11), which bypasses the | ||
| 280 | console cheat gate. No server-side writes. | ||
| 281 | - Re-applied after map loads/respawns (`fullbright_invalidate` on local entity | ||
| 282 | change) and saved as `[fullbright] active/bind`. | ||
| 283 | - `fullbright: on/off` is logged; a missing cvar interface raises an error | ||
| 284 | toast instead of failing silently. | ||
| 285 | |||
| 272 | ## Logging | 286 | ## Logging |
| 273 | 287 | ||
| 274 | - `/tmp/hl2hake.log` is opened once at startup with `"w"` (so it only contains | 288 | - `/tmp/hl2hake.log` is opened once at startup with `"w"` (so it only contains |
diff --git a/src/gui.cpp b/src/gui.cpp index b02e88a..3f1651d 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -372,6 +372,9 @@ static void build_cards() { | |||
| 372 | 10000, &g_item_max_dist); | 372 | 10000, &g_item_max_dist); |
| 373 | g_ctrls[g_nctrl - 1].zero_unlimited = true; | 373 | g_ctrls[g_nctrl - 1].zero_unlimited = true; |
| 374 | 374 | ||
| 375 | add_card(2, &g_fullbright, "Fullbright", | ||
| 376 | "Ignore world lighting so dark areas are visible.", true); | ||
| 377 | |||
| 375 | int spread = add_card(3, &g_spread, "Spread control", | 378 | int spread = add_card(3, &g_spread, "Spread control", |
| 376 | "Choose a server shot seed that tightens the cone.", | 379 | "Choose a server shot seed that tightens the cone.", |
| 377 | true); | 380 | true); |
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) { | |||
| 123 | 123 | ||
| 124 | static int g_modified_logged = 0; | 124 | static int g_modified_logged = 0; |
| 125 | 125 | ||
| 126 | // VEngineCvar004 / ICvar vtable: IAppSystem has 5 slots, then | ||
| 127 | // AllocateDLLIdentifier, RegisterConCommand, UnregisterConCommand, | ||
| 128 | // UnregisterConCommands, GetCommandLineValue, FindCommandBase, | ||
| 129 | // FindCommandBase const, FindVar -> slot 12. | ||
| 130 | // ConCommandBase has two dtor slots, then IsCommand, IsFlagSet, AddFlags, | ||
| 131 | // GetName, GetHelpText, IsRegistered, GetDLLIdentifier; ConVar then adds | ||
| 132 | // SetValue(const char*), SetValue(float), SetValue(int) -> slot 11. | ||
| 133 | bool cvar_set_int(const char *name, int value) { | ||
| 134 | if (!name) | ||
| 135 | return false; | ||
| 136 | if (g_iface.cvar) { | ||
| 137 | using FindVarFn = void *(*)(void *, const char *); | ||
| 138 | void *var = vfunc<FindVarFn>(g_iface.cvar, 12)(g_iface.cvar, name); | ||
| 139 | if (var) { | ||
| 140 | using GetNameFn = const char *(*)(void *); | ||
| 141 | const char *got = vfunc<GetNameFn>(var, 5)(var); | ||
| 142 | if (got && strcmp(got, name) == 0) { | ||
| 143 | using SetIntFn = void (*)(void *, int); | ||
| 144 | vfunc<SetIntFn>(var, 11)(var, value); | ||
| 145 | return true; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | } | ||
| 149 | // Fallback for an engine that does not expose VEngineCvar004: ClientCmd | ||
| 150 | // slot 7. Cheat-protected cvars may still be rejected. | ||
| 151 | if (g_iface.engine) { | ||
| 152 | char cmd[96]; | ||
| 153 | snprintf(cmd, sizeof(cmd), "%s %d", name, value); | ||
| 154 | using CmdFn = void (*)(void *, const char *); | ||
| 155 | vfunc<CmdFn>(g_iface.engine, 7)(g_iface.engine, cmd); | ||
| 156 | logd("cvar: fallback command '%s'", cmd); | ||
| 157 | return true; | ||
| 158 | } | ||
| 159 | return false; | ||
| 160 | } | ||
| 161 | |||
| 126 | void note_modified(const CUserCmd *cmd, int flags, const float *vel) { | 162 | void note_modified(const CUserCmd *cmd, int flags, const float *vel) { |
| 127 | // recompute usercmd CRC after modification | 163 | // recompute usercmd CRC after modification |
| 128 | fix_verified_crc(cmd->command_number, usercmd_checksum(cmd)); | 164 | fix_verified_crc(cmd->command_number, usercmd_checksum(cmd)); |
| @@ -563,6 +599,7 @@ static void do_move(int seq, float frametime) { | |||
| 563 | bones_clear(); | 599 | bones_clear(); |
| 564 | aimbot_reset_lock(); | 600 | aimbot_reset_lock(); |
| 565 | silentaim_reset_lock(); | 601 | silentaim_reset_lock(); |
| 602 | fullbright_invalidate(); | ||
| 566 | } | 603 | } |
| 567 | 604 | ||
| 568 | if (feature_active(FEAT_SPREAD)) { | 605 | if (feature_active(FEAT_SPREAD)) { |
| @@ -908,10 +945,36 @@ static void *setup_thread(void *) { | |||
| 908 | g_iface.engineserver = ef("VEngineServer021", nullptr); | 945 | g_iface.engineserver = ef("VEngineServer021", nullptr); |
| 909 | g_iface.debugoverlay = ef("VDebugOverlay003", nullptr); | 946 | g_iface.debugoverlay = ef("VDebugOverlay003", nullptr); |
| 910 | g_iface.enginetrace = ef("EngineTraceClient003", nullptr); | 947 | g_iface.enginetrace = ef("EngineTraceClient003", nullptr); |
| 948 | static const char *cvar_names[] = {"VEngineCvar004", "VEngineCvar007", | ||
| 949 | "VEngineCvar003", "IVEngineCvar004", | ||
| 950 | nullptr}; | ||
| 951 | for (int i = 0; cvar_names[i] && !g_iface.cvar; i++) { | ||
| 952 | g_iface.cvar = ef(cvar_names[i], nullptr); | ||
| 953 | if (!g_iface.cvar) | ||
| 954 | g_iface.cvar = cf(cvar_names[i], nullptr); | ||
| 955 | } | ||
| 956 | if (!g_iface.cvar) { | ||
| 957 | size_t slash = g_engine.path.find_last_of('/'); | ||
| 958 | if (slash != std::string::npos) { | ||
| 959 | std::string path = | ||
| 960 | g_engine.path.substr(0, slash + 1) + "libvstdlib.so"; | ||
| 961 | void *h = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL); | ||
| 962 | if (!h) | ||
| 963 | h = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); | ||
| 964 | if (h) { | ||
| 965 | auto vf = (CreateInterfaceFn)dlsym(h, "CreateInterface"); | ||
| 966 | if (vf) { | ||
| 967 | for (int i = 0; cvar_names[i] && !g_iface.cvar; i++) | ||
| 968 | g_iface.cvar = vf(cvar_names[i], nullptr); | ||
| 969 | } | ||
| 970 | } | ||
| 971 | } | ||
| 972 | } | ||
| 911 | logf("modelinfo: %p (VModelInfoClient006)", g_iface.modelinfo); | 973 | logf("modelinfo: %p (VModelInfoClient006)", g_iface.modelinfo); |
| 912 | logf("engineserver: %p (VEngineServer021), debugoverlay: %p, " | 974 | logf("engineserver: %p (VEngineServer021), debugoverlay: %p, " |
| 913 | "enginetrace: %p (EngineTraceClient003)", | 975 | "enginetrace: %p (EngineTraceClient003)", |
| 914 | g_iface.engineserver, g_iface.debugoverlay, g_iface.enginetrace); | 976 | g_iface.engineserver, g_iface.debugoverlay, g_iface.enginetrace); |
| 977 | logf("cvar: %p (VEngineCvar004)", g_iface.cvar); | ||
| 915 | 978 | ||
| 916 | resolve_netvars(); | 979 | resolve_netvars(); |
| 917 | if (!g_net.ok()) | 980 | if (!g_net.ok()) |
| @@ -67,6 +67,7 @@ struct GameInterfaces { | |||
| 67 | void *engineserver = nullptr; // IVEngineServer021 (edict access, incl. server entities) | 67 | void *engineserver = nullptr; // IVEngineServer021 (edict access, incl. server entities) |
| 68 | void *debugoverlay = nullptr; // IVDebugOverlay003 (engine-accurate world->screen) | 68 | void *debugoverlay = nullptr; // IVDebugOverlay003 (engine-accurate world->screen) |
| 69 | void *enginetrace = nullptr; // EngineTraceClient003 (world vischeck) | 69 | void *enginetrace = nullptr; // EngineTraceClient003 (world vischeck) |
| 70 | void *cvar = nullptr; // VEngineCvar004 (mat_fullbright etc.) | ||
| 70 | }; | 71 | }; |
| 71 | extern GameInterfaces g_iface; | 72 | extern GameInterfaces g_iface; |
| 72 | 73 | ||
| @@ -176,7 +177,8 @@ enum FeatureId { | |||
| 176 | FEAT_MELEE = 7, | 177 | FEAT_MELEE = 7, |
| 177 | FEAT_SPREAD = 8, | 178 | FEAT_SPREAD = 8, |
| 178 | FEAT_ITEM_ESP = 9, | 179 | FEAT_ITEM_ESP = 9, |
| 179 | FEAT_COUNT = 10 | 180 | FEAT_FULLBRIGHT = 10, |
| 181 | FEAT_COUNT = 11 | ||
| 180 | }; | 182 | }; |
| 181 | enum EspOption { | 183 | enum EspOption { |
| 182 | ESP_OPT_SHOW_NEUTRAL = 0, | 184 | ESP_OPT_SHOW_NEUTRAL = 0, |
| @@ -208,7 +210,7 @@ struct FeatureState { | |||
| 208 | }; | 210 | }; |
| 209 | 211 | ||
| 210 | extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, | 212 | extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, |
| 211 | g_aimbot, g_triggerbot, g_silentaim, g_item_esp; | 213 | g_aimbot, g_triggerbot, g_silentaim, g_item_esp, g_fullbright; |
| 212 | extern bool g_bhop_autostrafe; | 214 | extern bool g_bhop_autostrafe; |
| 213 | extern bool g_jumpbug_assist; | 215 | extern bool g_jumpbug_assist; |
| 214 | extern bool g_spread_no_spread; | 216 | extern bool g_spread_no_spread; |
| @@ -243,6 +245,9 @@ void fix_verified_crc(int seq, uint32_t crc); | |||
| 243 | uint32_t usercmd_checksum(const CUserCmd *c); | 245 | uint32_t usercmd_checksum(const CUserCmd *c); |
| 244 | bool find_input_global(); | 246 | bool find_input_global(); |
| 245 | void resolve_netvars(); | 247 | void resolve_netvars(); |
| 248 | bool cvar_set_int(const char *name, int value); | ||
| 249 | void fullbright_update(); | ||
| 250 | void fullbright_invalidate(); | ||
| 246 | bool resolve_server_netvars(); | 251 | bool resolve_server_netvars(); |
| 247 | int server_entity_health(int idx, int *maxhealth, int *lifestate, void **base_out); | 252 | int server_entity_health(int idx, int *maxhealth, int *lifestate, void **base_out); |
| 248 | bool server_set_velocity_z(int idx, float vz); | 253 | bool server_set_velocity_z(int idx, float vz); |
diff --git a/src/menu.cpp b/src/menu.cpp index 2d4c660..0c022e4 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -45,6 +45,7 @@ FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in the GUI | |||
| 45 | FeatureState g_triggerbot{true, 603}; // default Mouse4 | 45 | FeatureState g_triggerbot{true, 603}; // default Mouse4 |
| 46 | FeatureState g_silentaim{true, 602}; // default Mouse3 | 46 | FeatureState g_silentaim{true, 602}; // default Mouse3 |
| 47 | FeatureState g_item_esp{true, 0}; // valuable item tags, always-on by default | 47 | FeatureState g_item_esp{true, 0}; // valuable item tags, always-on by default |
| 48 | FeatureState g_fullbright{false, 0}; // mat_fullbright world lighting | ||
| 48 | bool g_item_health = true; | 49 | bool g_item_health = true; |
| 49 | bool g_item_ammo = true; | 50 | bool g_item_ammo = true; |
| 50 | bool g_item_armor = true; | 51 | bool g_item_armor = true; |
| @@ -184,6 +185,8 @@ void config_save() { | |||
| 184 | g_triggerbot.bind); | 185 | g_triggerbot.bind); |
| 185 | fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active, | 186 | fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active, |
| 186 | g_silentaim.bind, g_silent_fov); | 187 | g_silentaim.bind, g_silent_fov); |
| 188 | fprintf(f, "[fullbright]\nactive=%d\nbind=%d\n", g_fullbright.active, | ||
| 189 | g_fullbright.bind); | ||
| 187 | fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n" | 190 | fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n" |
| 188 | "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n", | 191 | "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n", |
| 189 | g_item_esp.active, g_item_esp.bind, (int)g_item_health, | 192 | g_item_esp.active, g_item_esp.bind, (int)g_item_health, |
| @@ -235,6 +238,8 @@ static bool config_load() { | |||
| 235 | cur = &g_esp; | 238 | cur = &g_esp; |
| 236 | else if (strstr(line, "[items]")) | 239 | else if (strstr(line, "[items]")) |
| 237 | cur = &g_item_esp; | 240 | cur = &g_item_esp; |
| 241 | else if (strstr(line, "[fullbright]")) | ||
| 242 | cur = &g_fullbright; | ||
| 238 | else if (strstr(line, "[aimbot]")) | 243 | else if (strstr(line, "[aimbot]")) |
| 239 | cur = &g_aimbot; | 244 | cur = &g_aimbot; |
| 240 | else if (strstr(line, "[triggerbot]")) | 245 | else if (strstr(line, "[triggerbot]")) |
| @@ -372,6 +377,7 @@ void config_reset_defaults() { | |||
| 372 | for (int i = 0; i < ESP_OPT_COUNT; i++) | 377 | for (int i = 0; i < ESP_OPT_COUNT; i++) |
| 373 | g_esp_opt[i] = true; | 378 | g_esp_opt[i] = true; |
| 374 | g_item_esp = {true, 0}; | 379 | g_item_esp = {true, 0}; |
| 380 | g_fullbright = {false, 0}; | ||
| 375 | g_item_health = true; | 381 | g_item_health = true; |
| 376 | g_item_ammo = true; | 382 | g_item_ammo = true; |
| 377 | g_item_armor = true; | 383 | g_item_armor = true; |
| @@ -488,7 +494,8 @@ static bool key_held(int sc) { | |||
| 488 | static FeatureState *feature_state(int feature) { | 494 | static FeatureState *feature_state(int feature) { |
| 489 | static FeatureState *feats[FEAT_COUNT] = { | 495 | static FeatureState *feats[FEAT_COUNT] = { |
| 490 | &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot, | 496 | &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot, |
| 491 | &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_item_esp}; | 497 | &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_item_esp, |
| 498 | &g_fullbright}; | ||
| 492 | if (feature < 0 || feature >= FEAT_COUNT) | 499 | if (feature < 0 || feature >= FEAT_COUNT) |
| 493 | return nullptr; | 500 | return nullptr; |
| 494 | return feats[feature]; | 501 | return feats[feature]; |
| @@ -658,6 +665,7 @@ void draw_text_col(int x, int y, const char *text, int r, int g, int b) { | |||
| 658 | // PushMakeCurrent/PopMakeCurrent so they are submitted with a clean clip. | 665 | // PushMakeCurrent/PopMakeCurrent so they are submitted with a clean clip. |
| 659 | void outer_draw() { | 666 | void outer_draw() { |
| 660 | poll_keyboard(); | 667 | poll_keyboard(); |
| 668 | fullbright_update(); | ||
| 661 | gui_handle_input(); | 669 | gui_handle_input(); |
| 662 | // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open | 670 | // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open |
| 663 | static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; | 671 | static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; |
