From b212e8e13835cfdc4849a61c1b57146bd0312a29 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 28 Oct 2026 13:02:26 +0100 Subject: Melee: surface weapon state across maps; reset stale caches - Map transitions often leave a non-crowbar weapon active, so the killbot silently does nothing. Log every active-weapon change as a normal `melee: active ... crowbar=0/1` line and toast once suggesting the crowbar. - Recover the crowbar model from the server entity when the client weapon model index is missing/0 after a map change. - Clear the bone cache and aim/silent locks when the local player entity changes (map load/respawn) so stale entity/model data cannot poison melee target selection. --- CONTEXT.md | 6 ++++++ src/bones.cpp | 13 +++++++++++++ src/esp.cpp | 19 ++++++++++++++++++- src/hl2h.cpp | 9 +++++++++ src/hl2h.h | 1 + 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/CONTEXT.md b/CONTEXT.md index a9e34d8..a9b85b9 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -190,6 +190,12 @@ vocabulary / decisions. client `m_hActiveWeapon` handle is used first; if it is missing, the authoritative server `m_hActiveWeapon` handle (0x824) is used to get the weapon entity index. +- Map transitions often switch the active weapon away from the crowbar. The + state change is logged as `melee: active ... crowbar=0/1` (normal log), and + a one-time toast says to equip the crowbar. If the client weapon model is + missing/0, the server model index is used to recognize it. +- Bone caches and aim locks are cleared when the local player entity changes + (map load/respawn). - Crowbar range is `CROWBAR_RANGE` 75 units from `Weapon_ShootPosition`. The selector computes the closest point on each hostile NPC's AABB to the eye, rejects anything farther than 75, sorts by that distance, and picks the diff --git a/src/bones.cpp b/src/bones.cpp index 0df13f2..c777067 100644 --- a/src/bones.cpp +++ b/src/bones.cpp @@ -509,6 +509,19 @@ bool head_position(int idx, Vector &out) { // Collect world-space aim points for the selected hit groups (HITGROUP_*). // Group 1 (head) uses head_position for its bone fallback; other groups are // the hitbox centers. The caller picks the point nearest to the crosshair. +void bones_clear() { + for (auto &e : g_entries) { + e.ent = nullptr; + e.valid = false; + e.hdr = nullptr; + e.count = 0; + e.stamp = 0.0; + } + g_next = 0; + g_logged = 0; + g_renderable_warned = false; +} + int aim_points(int idx, unsigned group_mask, Vector *out, int max) { if (!out || max <= 0) return 0; diff --git a/src/esp.cpp b/src/esp.cpp index 06bafaf..a0d84dd 100644 --- a/src/esp.cpp +++ b/src/esp.cpp @@ -873,6 +873,8 @@ bool melee_weapon_active(void *local_ent) { if (!local_ent) return false; int local = engine_get_local_player(); + if (g_iface.engineserver) + resolve_server_netvars(); auto check = [&](int idx, const char **cls_out, const char **model_out) -> bool { @@ -882,6 +884,14 @@ bool melee_weapon_active(void *local_ent) { void *net = entity_networkable(idx); const char *cls = net ? entity_class_name(net, nullptr) : nullptr; const char *model = wep ? entity_model_name(wep) : nullptr; + // Client weapon models can be missing/0 after a map change; recover the + // server model index so the crowbar is still recognized. + if ((!model || !*model) && g_iface.engineserver) { + void *sbase = nullptr; + server_entity_health(idx, nullptr, nullptr, &sbase); + if (sbase) + model = model_name_from_index(server_model_index(sbase)); + } *cls_out = cls; *model_out = model; return (cls && strstr(cls, "Crowbar")) || @@ -916,8 +926,15 @@ bool melee_weapon_active(void *local_ent) { if (idx != last_idx || crowbar != last_crowbar) { last_idx = idx; last_crowbar = crowbar; - logd("melee: active idx=%d cls=%s model=%s crowbar=%d", idx, + logf("melee: active idx=%d cls=%s model=%s crowbar=%d", idx, cls ? cls : "?", model ? model : "?", (int)crowbar); + if (!crowbar) { + static bool warned = false; + if (!warned) { + warned = true; + toastf(TOAST_WARN, "Melee killbot: equip the crowbar"); + } + } } return crowbar; } diff --git a/src/hl2h.cpp b/src/hl2h.cpp index 4f5673f..f95f6ed 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp @@ -556,6 +556,15 @@ static void do_move(int seq, float frametime) { if (!ent) return; + // New map / respawn: drop stale bone caches and target locks. + static void *last_local_ent = nullptr; + if (ent != last_local_ent) { + last_local_ent = ent; + bones_clear(); + aimbot_reset_lock(); + silentaim_reset_lock(); + } + if (feature_active(FEAT_SPREAD)) { resolve_server_netvars(); void *srv = nullptr; diff --git a/src/hl2h.h b/src/hl2h.h index 9b4fa8a..9c0440f 100644 --- a/src/hl2h.h +++ b/src/hl2h.h @@ -286,6 +286,7 @@ bool bone_is_skeleton_core(int idx, int bone); int bone_nearest_core_parent(int idx, int bone); bool bones_is_humanoid(int idx); bool hitbox_center(int idx, const char *hitbox_name, Vector &out); +void bones_clear(); bool head_position(int idx, Vector &out); int aim_points(int idx, unsigned group_mask, Vector *out, int max); -- cgit v1.2.3