diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-03 22:03:01 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-03 22:03:01 +0100 |
| commit | 2e9373d530bca779b4070a79972f246ef41e4038 (patch) | |
| tree | cc263d92cdcf7c9befd29f36da3cf04ed0b3a7f4 /src/gui.cpp | |
| parent | Handles: use the 11-bit networked EHANDLE entity index (diff) | |
| download | hl2h-2e9373d530bca779b4070a79972f246ef41e4038.tar.gz hl2h-2e9373d530bca779b4070a79972f246ef41e4038.zip | |
GUI: recover invalid fonts; vischeck: props and bulletproof glass
- Validate the GUI font handles with GetTextSize and recreate them when the
local player entity or UI scale changes. Small scaled sizes fall back to the
proven 16 px size, and the failure log/toast is emitted once instead of every
frame. This fixes sessions where the menu rendered with no text after a
level transition.
- Rework visibility: trace with MASK_SHOT/TRACE_EVERYTHING while ignoring the
local player and target, so static props, crates and other NPCs block.
Non-solid glass and breakable-glass materials are skipped; solid non-break
glass (bulletproof) blocks. Fix CONTENTS_WINDOW 0x2 (was 0x4) in the masks.
- Pass self/target to is_visible from aimbot/silent/melee callers.
Diffstat (limited to '')
| -rw-r--r-- | src/gui.cpp | 106 |
1 files changed, 82 insertions, 24 deletions
diff --git a/src/gui.cpp b/src/gui.cpp index b512ef3..417860f 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -39,6 +39,8 @@ static unsigned long g_font_title = 0; | |||
| 39 | static int g_body_h = 15; | 39 | static int g_body_h = 15; |
| 40 | static int g_title_h = 20; | 40 | static int g_title_h = 20; |
| 41 | static float g_font_scale = 0.0f; | 41 | static float g_font_scale = 0.0f; |
| 42 | static void *g_font_local = (void *)-1; | ||
| 43 | static bool g_font_fail_logged = false; | ||
| 42 | static int g_scr_w = 0, g_scr_h = 0; | 44 | static int g_scr_w = 0, g_scr_h = 0; |
| 43 | 45 | ||
| 44 | static void s_color(int r, int g, int b, int a) { | 46 | static void s_color(int r, int g, int b, int a) { |
| @@ -485,41 +487,97 @@ bool gui_toasts_active() { | |||
| 485 | return active; | 487 | return active; |
| 486 | } | 488 | } |
| 487 | 489 | ||
| 488 | static void ensure_fonts() { | 490 | static bool font_valid(unsigned long f) { |
| 489 | if (g_font_body && fabsf(g_font_scale - g_scale) < 0.001f) | 491 | if (!f || !g_surface) |
| 490 | return; | 492 | return false; |
| 491 | g_font_scale = g_scale; | 493 | int w = 0, h = 0; |
| 492 | g_body_h = (int)(15.0f * g_scale + 0.5f); | 494 | s_text_size(f, L"M", w, h); |
| 493 | g_title_h = (int)(20.0f * g_scale + 0.5f); | 495 | return w > 0 && h > 0; |
| 494 | if (g_body_h < 11) g_body_h = 11; | 496 | } |
| 495 | if (g_title_h < 15) g_title_h = 15; | 497 | |
| 498 | static void gui_reset_fonts() { | ||
| 499 | g_font_body = 0; | ||
| 500 | g_font_title = 0; | ||
| 501 | g_font_scale = 0.0f; | ||
| 502 | } | ||
| 503 | |||
| 504 | static unsigned long create_gui_font(int tall) { | ||
| 496 | static const char *families[] = {"Liberation Sans", "DejaVu Sans", | 505 | static const char *families[] = {"Liberation Sans", "DejaVu Sans", |
| 497 | "Noto Sans", "Tahoma", "Verdana", "Arial", | 506 | "Noto Sans", "Tahoma", "Verdana", "Arial", |
| 498 | nullptr}; | 507 | nullptr}; |
| 508 | for (int i = 0; families[i]; i++) { | ||
| 509 | unsigned long f = s_create_font(); | ||
| 510 | if (!f) | ||
| 511 | break; | ||
| 512 | if (s_set_font(f, families[i], tall, 400, 0x400, 0x20, 0xFF) && | ||
| 513 | font_valid(f)) | ||
| 514 | return f; | ||
| 515 | } | ||
| 516 | return 0; | ||
| 517 | } | ||
| 518 | |||
| 519 | static void ensure_fonts() { | ||
| 520 | void *le = nullptr; | ||
| 521 | if (g_iface.engine && g_iface.entitylist) { | ||
| 522 | int local = engine_get_local_player(); | ||
| 523 | if (local > 0) | ||
| 524 | le = entitylist_get(local); | ||
| 525 | } | ||
| 526 | if (le != g_font_local) { | ||
| 527 | g_font_local = le; | ||
| 528 | gui_reset_fonts(); | ||
| 529 | } | ||
| 530 | |||
| 531 | bool scale_changed = fabsf(g_font_scale - g_scale) >= 0.001f; | ||
| 532 | if (g_font_body && g_font_title && !scale_changed && | ||
| 533 | font_valid(g_font_body) && font_valid(g_font_title)) | ||
| 534 | return; | ||
| 535 | // Level transitions can silently invalidate VGUI font handles. Recreate | ||
| 536 | // them instead of drawing invisible text. | ||
| 537 | if ((g_font_body && !font_valid(g_font_body)) || | ||
| 538 | (g_font_title && !font_valid(g_font_title))) | ||
| 539 | gui_reset_fonts(); | ||
| 540 | if (scale_changed) | ||
| 541 | gui_reset_fonts(); | ||
| 542 | |||
| 543 | g_font_scale = g_scale; | ||
| 544 | int req_body = (int)(15.0f * g_scale + 0.5f); | ||
| 545 | int req_title = (int)(20.0f * g_scale + 0.5f); | ||
| 546 | if (req_body < 11) req_body = 11; | ||
| 547 | if (req_title < 15) req_title = 15; | ||
| 548 | g_body_h = req_body; | ||
| 549 | g_title_h = req_title; | ||
| 550 | |||
| 551 | if (!g_font_body) | ||
| 552 | g_font_body = create_gui_font(g_body_h); | ||
| 553 | if (!g_font_title) | ||
| 554 | g_font_title = create_gui_font(g_title_h); | ||
| 555 | |||
| 556 | // Small scaled sizes can fail in the font manager; 16 px is the proven ESP | ||
| 557 | // size, so use it as a readable fallback. | ||
| 499 | if (!g_font_body) { | 558 | if (!g_font_body) { |
| 500 | for (int i = 0; families[i] && !g_font_body; i++) { | 559 | g_body_h = 16; |
| 501 | unsigned long f = s_create_font(); | 560 | g_font_body = create_gui_font(g_body_h); |
| 502 | if (!f) | ||
| 503 | break; | ||
| 504 | if (s_set_font(f, families[i], g_body_h, 400, 0x400, 0x20, 0xFF)) | ||
| 505 | g_font_body = f; | ||
| 506 | } | ||
| 507 | } | 561 | } |
| 508 | if (!g_font_title) { | 562 | if (!g_font_title) { |
| 509 | for (int i = 0; families[i] && !g_font_title; i++) { | 563 | g_title_h = 16; |
| 510 | unsigned long f = s_create_font(); | 564 | g_font_title = create_gui_font(g_title_h); |
| 511 | if (!f) | ||
| 512 | break; | ||
| 513 | if (s_set_font(f, families[i], g_title_h, 400, 0x400, 0x20, 0xFF)) | ||
| 514 | g_font_title = f; | ||
| 515 | } | ||
| 516 | } | 565 | } |
| 517 | if (!g_font_title) | 566 | if (!g_font_title) |
| 518 | g_font_title = g_font_body; | 567 | g_font_title = g_font_body; |
| 568 | |||
| 519 | if (!g_font_body) { | 569 | if (!g_font_body) { |
| 520 | logf("gui: no usable body font"); | 570 | if (!g_font_fail_logged) { |
| 521 | toastf(TOAST_ERROR, "No usable GUI font"); | 571 | g_font_fail_logged = true; |
| 572 | logf("gui: no usable body font"); | ||
| 573 | toastf(TOAST_ERROR, "No usable GUI font"); | ||
| 574 | } | ||
| 575 | return; | ||
| 522 | } | 576 | } |
| 577 | g_font_fail_logged = false; | ||
| 578 | if (g_body_h != req_body || g_title_h != req_title) | ||
| 579 | logd("gui: font fallback body=%d title=%d (requested %d/%d)", g_body_h, | ||
| 580 | g_title_h, req_body, req_title); | ||
| 523 | } | 581 | } |
| 524 | 582 | ||
| 525 | static int text_w(const char *s, int tall) { | 583 | static int text_w(const char *s, int tall) { |
