diff options
Diffstat (limited to '')
| -rw-r--r-- | CONTEXT.md | 3 | ||||
| -rw-r--r-- | src/esp.cpp | 22 |
2 files changed, 21 insertions, 4 deletions
| @@ -286,6 +286,9 @@ vocabulary / decisions. | |||
| 286 | - Only `item_item_crate` and `item_beacon_crate` are tagged as supply crates. | 286 | - Only `item_item_crate` and `item_beacon_crate` are tagged as supply crates. |
| 287 | Other breakable crates are intentionally ignored; crate chunk debris is | 287 | Other breakable crates are intentionally ignored; crate chunk debris is |
| 288 | skipped. | 288 | skipped. |
| 289 | - Client `CPhysicsProp` entities often have `m_nModelIndex == 0`, including | ||
| 290 | item crates. The item scan falls back to the server entity's model index | ||
| 291 | (`server_model_index`) to recover the model name. | ||
| 289 | 292 | ||
| 290 | ## Roadmap / TODO | 293 | ## Roadmap / TODO |
| 291 | 294 | ||
diff --git a/src/esp.cpp b/src/esp.cpp index 2fb5d1b..ec3e94b 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -100,10 +100,9 @@ static const char *entity_class_name(void *net, void **out_cc) { | |||
| 100 | 100 | ||
| 101 | // m_nModelIndex -> IVModelInfoClient(006)::GetModel/GetModelName. | 101 | // m_nModelIndex -> IVModelInfoClient(006)::GetModel/GetModelName. |
| 102 | // Itanium ABI: two dtor slots, so GetModel=2, GetModelName=4. | 102 | // Itanium ABI: two dtor slots, so GetModel=2, GetModelName=4. |
| 103 | static const char *entity_model_name(void *ent) { | 103 | static const char *model_name_from_index(int modelindex) { |
| 104 | if (!g_iface.modelinfo || g_net.modelindex < 0) return nullptr; | 104 | if (!g_iface.modelinfo || modelindex <= 0) |
| 105 | int modelindex = *(int *)((uintptr_t)ent + g_net.modelindex); | 105 | return nullptr; |
| 106 | if (modelindex <= 0) return nullptr; | ||
| 107 | const void *model = | 106 | const void *model = |
| 108 | vfunc<GetModelFn>(g_iface.modelinfo, 2)(g_iface.modelinfo, modelindex); | 107 | vfunc<GetModelFn>(g_iface.modelinfo, 2)(g_iface.modelinfo, modelindex); |
| 109 | if (!model) | 108 | if (!model) |
| @@ -111,6 +110,12 @@ static const char *entity_model_name(void *ent) { | |||
| 111 | return vfunc<GetModelNameFn>(g_iface.modelinfo, 4)(g_iface.modelinfo, model); | 110 | return vfunc<GetModelNameFn>(g_iface.modelinfo, 4)(g_iface.modelinfo, model); |
| 112 | } | 111 | } |
| 113 | 112 | ||
| 113 | static const char *entity_model_name(void *ent) { | ||
| 114 | if (!g_iface.modelinfo || g_net.modelindex < 0) return nullptr; | ||
| 115 | int modelindex = *(int *)((uintptr_t)ent + g_net.modelindex); | ||
| 116 | return model_name_from_index(modelindex); | ||
| 117 | } | ||
| 118 | |||
| 114 | // HL2 SP: generic NPCs (combine, metrocop, zombie, citizen, antlion, ...) all | 119 | // HL2 SP: generic NPCs (combine, metrocop, zombie, citizen, antlion, ...) all |
| 115 | // use the single client class "CAI_BaseNPC" — only special NPCs register their | 120 | // use the single client class "CAI_BaseNPC" — only special NPCs register their |
| 116 | // own class names (CNPC_Manhack, CNPC_Strider, CNPC_CombineGunship, ...). | 121 | // own class names (CNPC_Manhack, CNPC_Strider, CNPC_CombineGunship, ...). |
| @@ -1629,6 +1634,7 @@ static void items_collect(int local_idx) { | |||
| 1629 | g_nitems = 0; | 1634 | g_nitems = 0; |
| 1630 | if (!g_iface.entitylist || g_net.origin < 0 || g_net.modelindex < 0) | 1635 | if (!g_iface.entitylist || g_net.origin < 0 || g_net.modelindex < 0) |
| 1631 | return; | 1636 | return; |
| 1637 | resolve_server_netvars(); | ||
| 1632 | 1638 | ||
| 1633 | using Fn = int (*)(void *); | 1639 | using Fn = int (*)(void *); |
| 1634 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); | 1640 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); |
| @@ -1664,6 +1670,14 @@ static void items_collect(int local_idx) { | |||
| 1664 | continue; | 1670 | continue; |
| 1665 | const char *cls = entity_class_name(net, nullptr); | 1671 | const char *cls = entity_class_name(net, nullptr); |
| 1666 | const char *model = entity_model_name(ent); | 1672 | const char *model = entity_model_name(ent); |
| 1673 | // CPhysicsProp's client m_nModelIndex is often 0 (e.g. item_item_crate); | ||
| 1674 | // fall back to the server entity's model index, which is set in Spawn(). | ||
| 1675 | if ((!model || !*model) && g_iface.engineserver) { | ||
| 1676 | void *sbase = nullptr; | ||
| 1677 | server_entity_health(idx, nullptr, nullptr, &sbase); | ||
| 1678 | if (sbase) | ||
| 1679 | model = model_name_from_index(server_model_index(sbase)); | ||
| 1680 | } | ||
| 1667 | char label[128]; | 1681 | char label[128]; |
| 1668 | int kind = classify_item(model, cls, label, sizeof(label)); | 1682 | int kind = classify_item(model, cls, label, sizeof(label)); |
| 1669 | 1683 | ||
