Skip to content

Commit 9c3737d

Browse files
authored
Preserve m_pLod for IPL siblings sharing a single LOD entity (#4863)
#### Summary Stop vanilla `_LinkLods` from nulling `m_pLod` on shared-LOD IPL siblings. NOP the 7-byte store at `0x5B52F8`. #### Motivation When several high-detail buildings reference the same LOD instance (common for billboards like `BillBd3` 1260 / `LODbillbd03` 1266), `_LinkLods` clears `m_pLod` on every sibling except the last. The result is `LOD = 0` on most shared-LOD entities for the rest of the session, breaking `processLineOfSight` LOD model id, debug overlays, and any other code that reads `m_pLod` at runtime. The `numChildren` decrement two instructions earlier is kept, so the count still drops to 1 and the final sibling still triggers the per-model collision swap exactly once. Tunnel keep-LOD (`flag 0x20`), single-child collision sharing, and streamed IPL loads (`CIplStore::LoadIpl`) are untouched. Reported by SpeedyFolf. #### Test plan Static (IDA, gta_sa.exe 1.0 US, MD5 `667f799c4ba8c9e1054fccaea6d4259b`): * `m_pLod` offset confirmed at `+0x30` against the IPL parser's own write at `0x53835C` (`89 46 30`). * `_LinkLods` only callable from `CFileLoader::LoadScene` (`0x5B8A7F`). * Decompile after patch: `else` branch is just the `numChildren` decrement, with the `m_pLod = 0` store gone. * No other `mov dword ptr [reg+30h], 0` site re-introduces the nuller (rest are unrelated D3D/RW/libpng, or ctor/sentinel writes). In-game: 1. Stand near a cluster of `BillBd3` billboards. 2. `processLineOfSight` each and read the LOD model id. 3. Before patch: subset reports `0`, rest report `1266`. 4. After patch: all report `1266`. #### Checklist * [x] Your code should follow the [coding guidelines](https://wiki.multitheftauto.com/index.php?title=Coding_guidelines). * [x] Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.
1 parent 44e606a commit 9c3737d

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

Client/game_sa/CFileLoaderSA.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ void CFileLoaderSA::StaticSetHooks()
2626
HookInstall(0x5371F0, (DWORD)CFileLoader_LoadAtomicFile, 5);
2727
HookInstall(0x537150, (DWORD)CFileLoader_SetRelatedModelInfoCB, 5);
2828
HookInstall(0x538690, (DWORD)CFileLoader_LoadObjectInstance, 5);
29+
30+
// Preserve m_pLod for buildings sharing one LOD entity at scene-load time.
31+
// Vanilla _LinkLods (0x5B51E0) walks the IPL instance list and, when several
32+
// high-detail buildings reference the same LOD instance, deregisters all but
33+
// the last sibling by writing 0 to their m_pLod field at 0x5B52F8
34+
// (mov dword ptr [esi+30h], 0). The decrement of the LOD's numChildren a few
35+
// bytes earlier is what brings the count down to 1 so the final sibling can
36+
// pick up the shared-collision path; that is intentional and is left intact.
37+
// Nulling m_pLod is order-dependent and visibly strands many shared-LOD
38+
// billboards (e.g. BillBd3 / model 1260) with no LOD reference at runtime,
39+
// which breaks LOD-aware lookups (collision queries, processLineOfSight LOD
40+
// model id, etc.). NOPing the 7-byte store keeps every sibling linked while
41+
// the per-model collision swap still happens exactly once.
42+
MemSet((void*)0x5B52F8, 0x90, 7);
2943
}
3044

3145
CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(SFileObjectInstance* obj)

0 commit comments

Comments
 (0)