2.8 KiB
Retail hardwareless particle-emitter resolution
Date: 2026-07-26
Oracle: matching Sept-2013 acclient.exe + acclient.pdb
Symptom
Dense scenes repeatedly logged that ParticleEmitterInfo records such as
0x320002D6 and 0x320003B6–0x320003B9 were “not found” for many different
owners. The records were present in the installed DAT, so the message was
misleading and each owner repeated the same failed resolution work.
Named-retail behavior
ParticleEmitter::SetInfo @ 0x0051CE90 begins with:
Destroy()
info = suppliedInfo
if info.hw_gfxobj_id == INVALID_DID:
Destroy()
return false
particleObject = makeParticleObject(info.max_particles, info.sorting_sphere)
...
ParticleEmitter::SetInfo(DataID) @ 0x0051D3C0 first loads the
ParticleEmitterInfo and delegates to the overload above.
ParticleManager::CreateParticleEmitter @ 0x0051B6C0 destroys the attempted
emitter when either SetInfo or parenting fails. Retail does not substitute
the software gfxobj_id for an absent hardware GfxObj.
Installed-DAT audit
The production DatCollection and EmitterDescRegistry were exercised
through ProjectileVfxAudit --emitters:
| Emitter | Record | Software GfxObj | Hardware GfxObj | Retail outcome |
|---|---|---|---|---|
0x320002D6 |
present/parsed | present | 0 |
skip |
0x320003B6 |
present/parsed | present | 0 |
skip |
0x320003B7 |
present/parsed | present | 0 |
skip |
0x320003B8 |
present/parsed | present | 0 |
skip |
0x320003B9 |
present/parsed | present | 0 |
skip |
These are authored hardwareless records, not missing DAT files.
Cross-reference
- ACViewer
ParticleEmitter.SetInforeturns false whenHWGfxObjID == 0. Its render initialization explicitly comments that this case is expected and skips the absent emitter. - WorldBuilder contains no contradictory live-client hardware-emitter fallback. Its particle code is an editor/rendering reference, while the retail client remains the behavior oracle.
Runtime contract
EmitterDescRegistry now stores either one resolved descriptor or one
classified negative result per DAT ID:
MissingEmitterInfo
InvalidHardwareGfxObjId
MissingHardwareGfxObj
The particle hook sink reports the first failure for each emitter DAT ID, not one line per owner. Hardwareless records say that retail skipped them rather than claiming the ParticleEmitterInfo was absent. No fallback asset or particle is fabricated.
Registration of an explicit runtime descriptor clears a cached negative result, preserving test/tool injection and future hot-reload behavior.
Conformance coverage
EmitterDescRegistry_NegativeCachesMissingDatAndRegisterClearsFailureEmitterDescRegistry_ClassifiesAndCachesAuthoredHardwarelessEmitterMissingEmitterAsset_ReportsOnlyOnceAcrossManyOwners