summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 17:41:53 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 17:41:53 +0100
commitf4616119c64ddcaa14cf10727e7aba4a3e64910f (patch)
tree2cb68ab8dfde040a6fd1baa0e77039fba32019a4 /src
parentItems/projectiles: ammo diagnostics, dispensers, launched RPG (diff)
downloadhl2h-f4616119c64ddcaa14cf10727e7aba4a3e64910f.tar.gz
hl2h-f4616119c64ddcaa14cf10727e7aba4a3e64910f.zip
Items: skip the CNetworkArray length header for m_iAmmo/m_hMyWeapons
The datamap offset points at the array length header, so every ammo count was read one type early. That made the RPG slot read the buckshot count (30) and permanently exceed the 3-rocket cap, which is why RPG pickups never showed and grenades/AR2/weapon ammo never hid. Read the elements 4 bytes after the field offset.
Diffstat (limited to '')
-rw-r--r--src/server.cpp9
1 files changed, 6 insertions, 3 deletions
diff --git a/src/server.cpp b/src/server.cpp
index af0a8ff..09d198a 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -482,7 +482,9 @@ float server_grenade_radius(int idx) {
482 return *(float *)((uintptr_t)base + g_srv_grenade_radius); 482 return *(float *)((uintptr_t)base + g_srv_grenade_radius);
483} 483}
484 484
485// Server-side CBaseCombatCharacter::m_iAmmo array (reserve ammo). 485// Server-side CBaseCombatCharacter::m_iAmmo array (reserve ammo). The datamap
486// offset points at the CNetworkArray length header; the elements start 4 bytes
487// later (confirmed by the shifted current/max table).
486int server_player_ammo(int idx, int type) { 488int server_player_ammo(int idx, int type) {
487 if (!g_srv_ready || g_srv_ammo < 0 || type < 0 || type >= 32) 489 if (!g_srv_ready || g_srv_ammo < 0 || type < 0 || type >= 32)
488 return -1; 490 return -1;
@@ -490,10 +492,11 @@ int server_player_ammo(int idx, int type) {
490 server_entity_health(idx, nullptr, nullptr, &base); 492 server_entity_health(idx, nullptr, nullptr, &base);
491 if (!base) 493 if (!base)
492 return -1; 494 return -1;
493 return *(int *)((uintptr_t)base + g_srv_ammo + type * 4); 495 return *(int *)((uintptr_t)base + g_srv_ammo + 4 + type * 4);
494} 496}
495 497
496// Server-side m_hMyWeapons[48] handle for one inventory slot (0 if empty). 498// Server-side m_hMyWeapons[48] handle for one inventory slot (0 if empty).
499// Same 4-byte CNetworkArray header as m_iAmmo.
497uint32_t server_player_weapon(int idx, int slot) { 500uint32_t server_player_weapon(int idx, int slot) {
498 if (!g_srv_ready || g_srv_myweapons < 0 || slot < 0 || slot >= 48) 501 if (!g_srv_ready || g_srv_myweapons < 0 || slot < 0 || slot >= 48)
499 return 0; 502 return 0;
@@ -501,7 +504,7 @@ uint32_t server_player_weapon(int idx, int slot) {
501 server_entity_health(idx, nullptr, nullptr, &base); 504 server_entity_health(idx, nullptr, nullptr, &base);
502 if (!base) 505 if (!base)
503 return 0; 506 return 0;
504 return *(uint32_t *)((uintptr_t)base + g_srv_myweapons + slot * 4); 507 return *(uint32_t *)((uintptr_t)base + g_srv_myweapons + 4 + slot * 4);
505} 508}
506 509
507// Entity index of the player's active weapon from the authoritative server 510// Entity index of the player's active weapon from the authoritative server