diff options
Diffstat (limited to '')
| -rw-r--r-- | FIX_PLAN.md | 13 | ||||
| -rw-r--r-- | src/studio.cpp | 24 |
2 files changed, 33 insertions, 4 deletions
diff --git a/FIX_PLAN.md b/FIX_PLAN.md index e4e149e..2c84122 100644 --- a/FIX_PLAN.md +++ b/FIX_PLAN.md | |||
| @@ -778,6 +778,16 @@ Caches are cleared by `esp_reset_session()` on map change/respawn. The ESP scan | |||
| 778 | itself is unchanged: projection only happens for the handful of entities that | 778 | itself is unchanged: projection only happens for the handful of entities that |
| 779 | survive the class/life/friendly filters, not for every entity. | 779 | survive the class/life/friendly filters, not for every entity. |
| 780 | 780 | ||
| 781 | ### Batch 5 — chams shadow passes | ||
| 782 | |||
| 783 | `IVModelRender::ForcedMaterialOverride` (slot 1) is now hooked as well, purely | ||
| 784 | to track the engine's current forced material. `DrawModelExecute` skips chams | ||
| 785 | when an override is already active, so shadow-depth and reflection passes draw | ||
| 786 | with their own material instead of being substituted with chams and then having | ||
| 787 | the engine's override cleared for every model drawn afterwards. This is the fix | ||
| 788 | for the corruption described in P2-6; it needs an in-game check because it | ||
| 789 | relies on the engine always going through the vtable for that call. | ||
| 790 | |||
| 781 | ### Known remaining work | 791 | ### Known remaining work |
| 782 | 792 | ||
| 783 | Deliberately deferred, with reasons: | 793 | Deliberately deferred, with reasons: |
| @@ -787,9 +797,6 @@ Deliberately deferred, with reasons: | |||
| 787 | slot plus a way to get the networkable from a raw entity pointer, or a | 797 | slot plus a way to get the networkable from a raw entity pointer, or a |
| 788 | cached pointer→index map. Not worth the risk for a hot path that fires a few | 798 | cached pointer→index map. Not worth the risk for a hot path that fires a few |
| 789 | times per second. | 799 | times per second. |
| 790 | - **P2-6 shadow-depth `ForcedMaterialOverride`** — requires reading the | ||
| 791 | engine's current override, which VEngineModel016 does not expose. Needs an | ||
| 792 | alternative detection (draw flags in `DrawModelState_t`) validated in-game. | ||
| 793 | - **P3-2 declarative settings table** — large rewrite of `config_save`, | 800 | - **P3-2 declarative settings table** — large rewrite of `config_save`, |
| 794 | `config_load`, `config_reset_defaults` and `build_cards`. It can regress | 801 | `config_load`, `config_reset_defaults` and `build_cards`. It can regress |
| 795 | config persistence, so it should follow an in-game pass. | 802 | config persistence, so it should follow an in-game pass. |
diff --git a/src/studio.cpp b/src/studio.cpp index 69a2e07..8b0a710 100644 --- a/src/studio.cpp +++ b/src/studio.cpp | |||
| @@ -212,6 +212,20 @@ ModelExecFn g_orig_model_exec = nullptr; | |||
| 212 | ForceOverrideFn g_force_override = nullptr; | 212 | ForceOverrideFn g_force_override = nullptr; |
| 213 | void *g_style_mats[8] = {}; | 213 | void *g_style_mats[8] = {}; |
| 214 | 214 | ||
| 215 | // The engine forces a material for special passes (shadow depth, reflections) | ||
| 216 | // and clears it again. Without tracking that, the chams pass could not tell | ||
| 217 | // "no override" from "engine override in progress": it hijacked the shadow pass | ||
| 218 | // with chams materials and then cleared the engine's override for every model | ||
| 219 | // drawn afterwards. | ||
| 220 | static ForceOverrideFn g_real_force_override = nullptr; | ||
| 221 | static void *g_current_override = nullptr; | ||
| 222 | |||
| 223 | static void hkdForceOverride(void *self, void *mat, int type) { | ||
| 224 | g_current_override = mat; | ||
| 225 | if (g_real_force_override) | ||
| 226 | g_real_force_override(self, mat, type); | ||
| 227 | } | ||
| 228 | |||
| 215 | const char *chams_material_name(int idx) { | 229 | const char *chams_material_name(int idx) { |
| 216 | switch (idx) { | 230 | switch (idx) { |
| 217 | case 1: return "debug/debugwireframe"; | 231 | case 1: return "debug/debugwireframe"; |
| @@ -330,6 +344,12 @@ void hkdModelExecute(void *self, const void *state, const void *info, | |||
| 330 | g_orig_model_exec(self, state, info, bone); | 344 | g_orig_model_exec(self, state, info, bone); |
| 331 | return; | 345 | return; |
| 332 | } | 346 | } |
| 347 | // Shadow-depth/reflection passes arrive with a material already forced. Let | ||
| 348 | // them draw normally instead of substituting chams. | ||
| 349 | if (g_current_override) { | ||
| 350 | g_orig_model_exec(self, state, info, bone); | ||
| 351 | return; | ||
| 352 | } | ||
| 333 | if (feature_active(FEAT_CHAMS) && info && g_force_override) { | 353 | if (feature_active(FEAT_CHAMS) && info && g_force_override) { |
| 334 | // ModelRenderInfo_t::entity_index is at 0x30 on 32-bit. | 354 | // ModelRenderInfo_t::entity_index is at 0x30 on 32-bit. |
| 335 | int idx = *(const int *)((const char *)info + 0x30); | 355 | int idx = *(const int *)((const char *)info + 0x30); |
| @@ -568,7 +588,8 @@ void chams_init() { | |||
| 568 | logf("chams: model render has no vtable"); | 588 | logf("chams: model render has no vtable"); |
| 569 | return; | 589 | return; |
| 570 | } | 590 | } |
| 571 | g_force_override = (ForceOverrideFn)vt[1]; | 591 | g_real_force_override = (ForceOverrideFn)vt[1]; |
| 592 | g_force_override = g_real_force_override; | ||
| 572 | g_orig_model_exec = (ModelExecFn)vt[19]; | 593 | g_orig_model_exec = (ModelExecFn)vt[19]; |
| 573 | if (!mod_engine().contains((uintptr_t)g_force_override) || | 594 | if (!mod_engine().contains((uintptr_t)g_force_override) || |
| 574 | !mod_engine().contains((uintptr_t)g_orig_model_exec)) { | 595 | !mod_engine().contains((uintptr_t)g_orig_model_exec)) { |
| @@ -581,6 +602,7 @@ void chams_init() { | |||
| 581 | logf("chams: vtable clone failed"); | 602 | logf("chams: vtable clone failed"); |
| 582 | return; | 603 | return; |
| 583 | } | 604 | } |
| 605 | nvt[1] = (void *)&hkdForceOverride; // track engine-forced passes | ||
| 584 | nvt[19] = (void *)&hkdModelExecute; | 606 | nvt[19] = (void *)&hkdModelExecute; |
| 585 | g_modelrender = g_iface.modelrender; | 607 | g_modelrender = g_iface.modelrender; |
| 586 | *(void ***)g_modelrender = nvt; | 608 | *(void ***)g_modelrender = nvt; |
