summaryrefslogtreecommitdiffstats
path: root/src/world.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-06 16:09:55 +0100
committersalmonik <salmonik@tuta.io>2026-11-06 16:09:55 +0100
commit33f5ed9ef58f26c6b3b52cf605dd4311d658a60d (patch)
treea97254872e465c9107b7ef19695ab56bb076d7e2 /src/world.cpp
parentItems: log the usable ammo table once (diff)
downloadhl2h-33f5ed9ef58f26c6b3b52cf605dd4311d658a60d.tar.gz
hl2h-33f5ed9ef58f26c6b3b52cf605dd4311d658a60d.zip
Fix audit findings: crash safety, correctness, rendering, performance
Crash/UB: - gate every hook behind an init-stage flag until config/surface/input are ready - publish module maps as immutable atomic snapshots instead of reallocating shared vectors under unlocked readers - validate the %ebp walk in the RandomSeed/RandomFloat hooks against the stack - bounds-check every RecvTable/RecvProp/string dereference with module_range() - preserve the Itanium vtable header when cloning (client, CInput, model render, studio render) - reject negative usercmd sequence numbers; guard config_load against a null section target; cap the bone parent walk; check mprotect; drop PROT_EXEC on the GOT patch; absorb server.so .bss tail Correctness: - filter dormant entities across ESP, aimbot, triggerbot, melee, items and projectiles (slot self-tested against the local player) - reset the server-health latch per map and only latch on valid model indices - bone cache sized for the 128-target scan; set valid=false on every failure; head_position keeps searching past an invalid bone - vischeck steps past glass by probing until clear, and ignores entities owned by the target (held weapons, bone followers) - aimbot: maxs no longer disables it, AABB-aware FOV prefilter, lock hysteresis, lead point re-checked for FOV and visibility - spread: seed hook arms on the no-spread toggle alone; engine toggle only controls the RandomFloat zeroing - resolve m_hOwnerEntity/m_hOwner; NPC lead velocity from the server entity - vector_angles pitch range, point_ground normal test, underwater jump+duck no longer skips combat, semi-auto press/release edge for synthetic fire - item/projectile markers and blast rings refresh origin per frame while discovery stays at 10 Hz; trajectory uses the real m_DmgRadius and honours the blast-radius toggle Rendering/GUI: - one overlay draw per engine frame (FRAME_RENDER_START boundary), fixing alpha stacking and the speed-graph flicker - clipped lines/outlines and ellipsised text instead of drawing past the content pane or shifting over neighbours - dropdown dismissal consumes the click; hover ignores hidden controls - chams: reset AlphaModulate, reference shared materials once, restore prop tint colour; fonts created once per handle - projection uses Source's 4:3 aspect scaling and roll; screen size refreshed each frame; FOV circle gated on the aim toggles, not the bind Performance: - TTL caches for NPC relation, friendly/neutral and damage class - model names memoised per model index - entity pointer -> index cache for the triggerbot (was a 4096-slot walk/tick) Build: - real Makefile with -MMD dependency tracking, debug/release objects and an always-relink rule; build.sh kept as a thin wrapper
Diffstat (limited to 'src/world.cpp')
-rw-r--r--src/world.cpp45
1 files changed, 42 insertions, 3 deletions
diff --git a/src/world.cpp b/src/world.cpp
index ea186b4..a0576ab 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -633,6 +633,10 @@ bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels,
633} 633}
634 634
635std::vector<unsigned char> g_sky_pixels; 635std::vector<unsigned char> g_sky_pixels;
636// Pristine copy of the decoded PNG. HDR compensation is applied to
637// g_sky_pixels in place, so without this the linearised/darkened bytes bled
638// into the next map when it used the LDR sky shader.
639std::vector<unsigned char> g_sky_pixels_src;
636int g_sky_px_w = 0, g_sky_px_h = 0; 640int g_sky_px_w = 0, g_sky_px_h = 0;
637 641
638// ITextureRegenerator has two virtuals: RegenerateTextureBits then Release. 642// ITextureRegenerator has two virtuals: RegenerateTextureBits then Release.
@@ -717,6 +721,28 @@ bool is_sky_material(const char *name, const char *group) {
717 strncmp(name, "skybox/", 7) == 0; 721 strncmp(name, "skybox/", 7) == 0;
718} 722}
719 723
724// ITexture reference counting (material system header order, matching the
725// slots already used here: SetTextureRegenerator = 12, Download = 13):
726// 10 = IncrementReferenceCount, 11 = DecrementReferenceCount
727// The engine owns the original textures; holding a reference keeps them valid
728// between "capture" and "restore" instead of leaving a dangling pointer.
729static void texture_addref(void *tex) {
730 if (!tex)
731 return;
732 using Fn = void (*)(void *);
733 vfunc<Fn>(tex, 10)(tex);
734}
735
736void release_sky_originals() {
737 for (auto &r : g_sky_orig) {
738 if (!r.texture)
739 continue;
740 using Fn = void (*)(void *);
741 vfunc<Fn>(r.texture, 11)(r.texture);
742 }
743 g_sky_orig.clear();
744}
745
720void record_orig(const char *material, const char *var, const char *value, 746void record_orig(const char *material, const char *var, const char *value,
721 void *texture) { 747 void *texture) {
722 if (!material || !var) 748 if (!material || !var)
@@ -725,6 +751,7 @@ void record_orig(const char *material, const char *var, const char *value,
725 if (r.material == material && r.var == var) 751 if (r.material == material && r.var == var)
726 return; 752 return;
727 } 753 }
754 texture_addref(texture);
728 g_sky_orig.push_back( 755 g_sky_orig.push_back(
729 {material, var, value ? value : "", texture}); 756 {material, var, value ? value : "", texture});
730} 757}
@@ -750,6 +777,10 @@ int apply_sky_texture() {
750 // where the materials are definitely loaded, and re-upload if needed. 777 // where the materials are definitely loaded, and re-upload if needed.
751 bool hdr = sky_uses_hdr_shader(); 778 bool hdr = sky_uses_hdr_shader();
752 if (hdr && !g_sky_compensated && !g_sky_pixels.empty()) { 779 if (hdr && !g_sky_compensated && !g_sky_pixels.empty()) {
780 // Always start from the untouched decode so repeated HDR passes cannot
781 // compound the gamma conversion.
782 if (!g_sky_pixels_src.empty())
783 g_sky_pixels = g_sky_pixels_src;
753 for (size_t i = 0; i + 3 < g_sky_pixels.size(); i += 4) { 784 for (size_t i = 0; i + 3 < g_sky_pixels.size(); i += 4) {
754 for (int c = 0; c < 3; c++) { 785 for (int c = 0; c < 3; c++) {
755 float v = (float)g_sky_pixels[i + (size_t)c] / 255.0f; 786 float v = (float)g_sky_pixels[i + (size_t)c] / 255.0f;
@@ -822,7 +853,7 @@ void restore_sky_texture() {
822 } 853 }
823 void *ms = material_system(); 854 void *ms = material_system();
824 if (!ms) { 855 if (!ms) {
825 g_sky_orig.clear(); 856 release_sky_originals();
826 g_sky_applied = false; 857 g_sky_applied = false;
827 return; 858 return;
828 } 859 }
@@ -833,7 +864,7 @@ void restore_sky_texture() {
833 auto count = vfunc<MatCalls::CountFn>(ms, MATSYS_GetNumMaterials); 864 auto count = vfunc<MatCalls::CountFn>(ms, MATSYS_GetNumMaterials);
834 int total = count(ms); 865 int total = count(ms);
835 if (total <= 0 || total > 200000) { 866 if (total <= 0 || total > 200000) {
836 g_sky_orig.clear(); 867 release_sky_originals();
837 g_sky_applied = false; 868 g_sky_applied = false;
838 return; 869 return;
839 } 870 }
@@ -866,7 +897,7 @@ void restore_sky_texture() {
866 vfunc<SetStrFn>(var, 5)(var, r.value.c_str()); 897 vfunc<SetStrFn>(var, 5)(var, r.value.c_str());
867 } 898 }
868 } 899 }
869 g_sky_orig.clear(); 900 release_sky_originals();
870 g_sky_applied = false; 901 g_sky_applied = false;
871} 902}
872 903
@@ -925,6 +956,7 @@ void load_sky_texture() {
925 return; 956 return;
926 } 957 }
927 g_sky_pixels.swap(pixels); 958 g_sky_pixels.swap(pixels);
959 g_sky_pixels_src = g_sky_pixels;
928 g_sky_px_w = w; 960 g_sky_px_w = w;
929 g_sky_px_h = h; 961 g_sky_px_h = h;
930 962
@@ -960,6 +992,13 @@ void skybox_invalidate() {
960 992
961void skybox_reload_image() { 993void skybox_reload_image() {
962 restore_sky_texture(); 994 restore_sky_texture();
995 // Detach the regenerator before dropping the handle: the old texture may
996 // outlive it and must not call back into a regenerator whose pixels were
997 // replaced.
998 if (g_sky_tex) {
999 using SetRegenFn = void (*)(void *, void *);
1000 vfunc<SetRegenFn>(g_sky_tex, 12)(g_sky_tex, nullptr);
1001 }
963 g_sky_tex = nullptr; 1002 g_sky_tex = nullptr;
964 g_sky_tex_tried = false; 1003 g_sky_tex_tried = false;
965 g_sky_reload = true; 1004 g_sky_reload = true;