diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 01:13:09 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 01:13:09 +0100 |
| commit | b9d5965c0366fd7777c3627b9fbf89c8526ac0ec (patch) | |
| tree | 65a1213b902f2a3352ecc19dc76be396e80f63f3 | |
| parent | Skybox image: swap red/blue in the uploaded texture (diff) | |
| download | hl2h-b9d5965c0366fd7777c3627b9fbf89c8526ac0ec.tar.gz hl2h-b9d5965c0366fd7777c3627b9fbf89c8526ac0ec.zip | |
World tint: colour dynamic props through m_clrRender
Prop model materials (VertexLitGeneric) ignore IMaterial::ColorModulate: the
engine feeds StudioRender the per-entity render colour (m_clrRender) on every
draw, so the material-side tint never showed on crates and other props.
Resolve m_clrRender from DT_BaseEntity and, every 10 ms while World tint and
Props are enabled, write the prop colour into every entity whose model is
under models/props. Restore white once when disabled.
Diffstat (limited to '')
| -rw-r--r-- | src/esp.cpp | 49 | ||||
| -rw-r--r-- | src/hl2h.h | 2 | ||||
| -rw-r--r-- | src/menu.cpp | 1 | ||||
| -rw-r--r-- | src/netvars.cpp | 6 |
4 files changed, 56 insertions, 2 deletions
diff --git a/src/esp.cpp b/src/esp.cpp index 50d7b5d..9d041b0 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -1405,6 +1405,55 @@ bool triggerbot_apply(CUserCmd *cmd) { | |||
| 1405 | return false; | 1405 | return false; |
| 1406 | } | 1406 | } |
| 1407 | 1407 | ||
| 1408 | // Tints dynamic props by writing their client render colour. StudioRender | ||
| 1409 | // uses m_clrRender as the per-model colour modulation, which is why changing | ||
| 1410 | // the prop MATERIAL colour had no effect. | ||
| 1411 | void prop_tint_update() { | ||
| 1412 | static bool applied = false; | ||
| 1413 | static bool logged_missing = false; | ||
| 1414 | static bool logged_touched = false; | ||
| 1415 | bool on = feature_active(FEAT_WORLD_TINT) && g_tint_prop_on; | ||
| 1416 | if (!on && !applied) | ||
| 1417 | return; | ||
| 1418 | if (!g_iface.entitylist || g_net.clr_render < 0) { | ||
| 1419 | if (on && !logged_missing) { | ||
| 1420 | logged_missing = true; | ||
| 1421 | logf("prop tint: m_clrRender unavailable"); | ||
| 1422 | } | ||
| 1423 | return; | ||
| 1424 | } | ||
| 1425 | static double last = 0.0; | ||
| 1426 | double now = esp_now(); | ||
| 1427 | if (on && now - last < 0.01) | ||
| 1428 | return; | ||
| 1429 | last = now; | ||
| 1430 | |||
| 1431 | using Fn = int (*)(void *); | ||
| 1432 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); | ||
| 1433 | if (hi < 0 || hi > 4096) | ||
| 1434 | hi = 4096; | ||
| 1435 | uint32_t col = | ||
| 1436 | on ? ((uint32_t)g_tint_prop_rgb[0] | ((uint32_t)g_tint_prop_rgb[1] << 8) | | ||
| 1437 | ((uint32_t)g_tint_prop_rgb[2] << 16) | (255u << 24)) | ||
| 1438 | : 0xFFFFFFFFu; | ||
| 1439 | int touched = 0; | ||
| 1440 | for (int idx = 1; idx <= hi; idx++) { | ||
| 1441 | void *ent = entitylist_get(idx); | ||
| 1442 | if (!ent) | ||
| 1443 | continue; | ||
| 1444 | const char *model = entity_model_name(ent); | ||
| 1445 | if (!model || strncmp(model, "models/props", 12) != 0) | ||
| 1446 | continue; | ||
| 1447 | *(uint32_t *)((uintptr_t)ent + (uintptr_t)g_net.clr_render) = col; | ||
| 1448 | touched++; | ||
| 1449 | } | ||
| 1450 | applied = on; | ||
| 1451 | if (on && touched > 0 && !logged_touched) { | ||
| 1452 | logged_touched = true; | ||
| 1453 | logf("prop tint: %d prop entities", touched); | ||
| 1454 | } | ||
| 1455 | } | ||
| 1456 | |||
| 1408 | void esp_draw() { | 1457 | void esp_draw() { |
| 1409 | if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; | 1458 | if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; |
| 1410 | if (!g_scr_w) { | 1459 | if (!g_scr_w) { |
| @@ -96,6 +96,7 @@ struct NetVars { | |||
| 96 | int activeweapon = -1; // client m_hActiveWeapon handle | 96 | int activeweapon = -1; // client m_hActiveWeapon handle |
| 97 | int owner = -1; // client m_hOwnerEntity handle | 97 | int owner = -1; // client m_hOwnerEntity handle |
| 98 | int weapon_owner = -1; // client m_hOwner handle (C_BaseCombatWeapon) | 98 | int weapon_owner = -1; // client m_hOwner handle (C_BaseCombatWeapon) |
| 99 | int clr_render = -1; // client m_clrRender (entity render colour) | ||
| 99 | // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 | 100 | // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 |
| 100 | bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } | 101 | bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } |
| 101 | // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100. | 102 | // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100. |
| @@ -296,6 +297,7 @@ int engine_get_local_player(); | |||
| 296 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); | 297 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); |
| 297 | void esp_draw(); | 298 | void esp_draw(); |
| 298 | void esp_draw_items(); | 299 | void esp_draw_items(); |
| 300 | void prop_tint_update(); | ||
| 299 | bool world_to_screen(const Vector &w, float &sx, float &sy); | 301 | bool world_to_screen(const Vector &w, float &sx, float &sy); |
| 300 | void set_silent_restore(const QAngle &angles); | 302 | void set_silent_restore(const QAngle &angles); |
| 301 | bool is_visible(const Vector &eye, const Vector &point, | 303 | bool is_visible(const Vector &eye, const Vector &point, |
diff --git a/src/menu.cpp b/src/menu.cpp index 7ffc84a..0ce6c05 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -815,6 +815,7 @@ void outer_draw() { | |||
| 815 | poll_keyboard(); | 815 | poll_keyboard(); |
| 816 | fullbright_update(); | 816 | fullbright_update(); |
| 817 | world_tint_update(); | 817 | world_tint_update(); |
| 818 | prop_tint_update(); | ||
| 818 | fog_update(); | 819 | fog_update(); |
| 819 | gui_handle_input(); | 820 | gui_handle_input(); |
| 820 | // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open | 821 | // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open |
diff --git a/src/netvars.cpp b/src/netvars.cpp index 238af70..4578e52 100644 --- a/src/netvars.cpp +++ b/src/netvars.cpp | |||
| @@ -92,6 +92,8 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) { | |||
| 92 | } else if (strcmp(pname2, "m_hActiveWeapon") == 0 && | 92 | } else if (strcmp(pname2, "m_hActiveWeapon") == 0 && |
| 93 | g_net.activeweapon < 0) { | 93 | g_net.activeweapon < 0) { |
| 94 | g_net.activeweapon = (int)(base_off + (uint32_t)poff); | 94 | g_net.activeweapon = (int)(base_off + (uint32_t)poff); |
| 95 | } else if (strcmp(pname2, "m_clrRender") == 0 && g_net.clr_render < 0) { | ||
| 96 | g_net.clr_render = (int)(base_off + (uint32_t)poff); | ||
| 95 | } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { | 97 | } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { |
| 96 | g_net.teamnum = (int)(base_off + (uint32_t)poff); | 98 | g_net.teamnum = (int)(base_off + (uint32_t)poff); |
| 97 | } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { | 99 | } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { |
| @@ -273,9 +275,9 @@ void resolve_netvars() { | |||
| 273 | logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " | 275 | logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " |
| 274 | "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d " | 276 | "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d " |
| 275 | "modelindex=%d absvelocity=%d activeweapon=%d owner=%d " | 277 | "modelindex=%d absvelocity=%d activeweapon=%d owner=%d " |
| 276 | "weapon_owner=%d", | 278 | "weapon_owner=%d clr_render=%d", |
| 277 | g_net.flags, g_net.velocity, g_net.movetype, g_net.health, | 279 | g_net.flags, g_net.velocity, g_net.movetype, g_net.health, |
| 278 | g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, | 280 | g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, |
| 279 | g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex, | 281 | g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex, |
| 280 | g_net.absvelocity, g_net.activeweapon); | 282 | g_net.absvelocity, g_net.activeweapon, g_net.clr_render); |
| 281 | } | 283 | } |
