diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 17:25:31 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 17:25:31 +0100 |
| commit | 710e8cc59557bc95ed74af8726ea13012fde50c3 (patch) | |
| tree | f1fd242c12d2ce5a939fbf1d3828e3546bc8f1cf /src/esp.cpp | |
| parent | Netvars: catch array element props and log the walk (diff) | |
| download | hl2h-710e8cc59557bc95ed74af8726ea13012fde50c3.tar.gz hl2h-710e8cc59557bc95ed74af8726ea13012fde50c3.zip | |
Items: read ammo and inventory from the server arrays
The client m_iAmmo/m_hMyWeapons recv props still do not resolve, but the
listen server has the same CBaseCombatCharacter arrays in its datamap. Resolve
m_iAmmo and m_hMyWeapons there:
- reserve ammo comes from server_player_ammo() when the client array is
missing, so full-ammo filtering works (RPG rockets at 3);
- the owned-weapon mask is filled from the server m_hMyWeapons[48] handles,
so fallen weapons count as ammo before the player equips them.
Widen the datamap field-size filter to 512 for the 192-byte handle array.
Diffstat (limited to '')
| -rw-r--r-- | src/esp.cpp | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/src/esp.cpp b/src/esp.cpp index 1d4a6a5..b4d3eee 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -2396,9 +2396,14 @@ static int ammo_max(int type) { | |||
| 2396 | } | 2396 | } |
| 2397 | 2397 | ||
| 2398 | static int local_ammo(void *local_ent, int type) { | 2398 | static int local_ammo(void *local_ent, int type) { |
| 2399 | if (!local_ent || g_net.ammo < 0 || type < 0 || type >= 32) | 2399 | if (type < 0 || type >= 32) |
| 2400 | return -1; | 2400 | return -1; |
| 2401 | return *(int *)((uintptr_t)local_ent + g_net.ammo + type * 4); | 2401 | if (local_ent && g_net.ammo >= 0) |
| 2402 | return *(int *)((uintptr_t)local_ent + g_net.ammo + type * 4); | ||
| 2403 | // Client array offset may not resolve; the listen-server player has the | ||
| 2404 | // same array in its datamap. | ||
| 2405 | int local = engine_get_local_player(); | ||
| 2406 | return local > 0 ? server_player_ammo(local, type) : -1; | ||
| 2402 | } | 2407 | } |
| 2403 | 2408 | ||
| 2404 | static int classify_item(const char *model, const char *cls, char *label, | 2409 | static int classify_item(const char *model, const char *cls, char *label, |
| @@ -2627,6 +2632,30 @@ static void items_collect(int local_idx) { | |||
| 2627 | if (wt > 0) | 2632 | if (wt > 0) |
| 2628 | owned_mask |= 1u << wt; | 2633 | owned_mask |= 1u << wt; |
| 2629 | } | 2634 | } |
| 2635 | // Server-side inventory, independent of the client recv-table arrays. | ||
| 2636 | if (g_iface.engineserver) { | ||
| 2637 | for (int slot = 0; slot < 48; slot++) { | ||
| 2638 | uint32_t h = server_player_weapon(local_idx, slot); | ||
| 2639 | if (!item_handle_valid(h)) | ||
| 2640 | continue; | ||
| 2641 | int wi = (int)(h & 0x7FF); | ||
| 2642 | if (wi <= 0 || wi > 4096) | ||
| 2643 | continue; | ||
| 2644 | void *wep = entitylist_get(wi); | ||
| 2645 | void *net = entity_networkable(wi); | ||
| 2646 | const char *wc = net ? entity_class_name(net, nullptr) : nullptr; | ||
| 2647 | const char *wm = wep ? entity_model_name(wep) : nullptr; | ||
| 2648 | if (!wm) { | ||
| 2649 | void *sb = nullptr; | ||
| 2650 | server_entity_health(wi, nullptr, nullptr, &sb); | ||
| 2651 | if (sb) | ||
| 2652 | wm = model_name_from_index(server_model_index(sb)); | ||
| 2653 | } | ||
| 2654 | int wt = weapon_type_id(wm, wc); | ||
| 2655 | if (wt > 0) | ||
| 2656 | owned_mask |= 1u << wt; | ||
| 2657 | } | ||
| 2658 | } | ||
| 2630 | bool owned_weapon[WT_COUNT] = {}; | 2659 | bool owned_weapon[WT_COUNT] = {}; |
| 2631 | for (int t = 1; t < WT_COUNT; t++) | 2660 | for (int t = 1; t < WT_COUNT; t++) |
| 2632 | owned_weapon[t] = (owned_mask & (1u << t)) != 0; | 2661 | owned_weapon[t] = (owned_mask & (1u << t)) != 0; |
