fix(vfx): classify hardwareless particle emitters once

This commit is contained in:
Erik 2026-07-27 00:03:31 +02:00
parent 921712f412
commit 5b3fb17775
8 changed files with 374 additions and 18 deletions

View file

@ -40,6 +40,7 @@ public sealed class ParticleHookSink : IAnimationHookSink
private readonly HashSet<uint> _examinationOwners = [];
private readonly HashSet<uint> _hiddenPresentationOwners = [];
private readonly HashSet<uint> _stoppingOwners = [];
private readonly HashSet<uint> _reportedEmitterResolutionFailures = [];
// Production pose registries publish actual root/part/cell changes. Only
// those owners are recomposed; static world emitters do no refresh work.
@ -417,11 +418,16 @@ public sealed class ParticleHookSink : IAnimationHookSink
partIndex,
renderPass,
visibilityPolicy,
out int handle))
out int handle,
out EmitterDescResolutionFailure failure))
{
DiagnosticSink?.Invoke(
$"ParticleEmitterInfo 0x{emitterInfoId:X8} for owner " +
$"0x{ownerLocalId:X8} was not found; no fallback was created.");
if (_reportedEmitterResolutionFailures.Add(emitterInfoId))
{
DiagnosticSink?.Invoke(FormatEmitterResolutionDiagnostic(
emitterInfoId,
ownerLocalId,
failure));
}
return;
}
_system.UpdateEmitterOwnerPosition(handle, ownerPosition);
@ -534,6 +540,26 @@ public sealed class ParticleHookSink : IAnimationHookSink
return true;
}
private static string FormatEmitterResolutionDiagnostic(
uint emitterInfoId,
uint ownerLocalId,
EmitterDescResolutionFailure failure) =>
failure.Kind switch
{
EmitterDescResolutionFailureKind.InvalidHardwareGfxObjId =>
$"ParticleEmitterInfo 0x{emitterInfoId:X8} has no retail " +
$"hardware GfxObj; ParticleEmitter::SetInfo skipped it " +
$"(first owner 0x{ownerLocalId:X8}).",
EmitterDescResolutionFailureKind.MissingHardwareGfxObj =>
$"ParticleEmitterInfo 0x{emitterInfoId:X8} references missing " +
$"retail hardware GfxObj 0x{failure.RelatedDatId:X8}; " +
$"ParticleEmitter::SetInfo skipped it " +
$"(first owner 0x{ownerLocalId:X8}).",
_ =>
$"ParticleEmitterInfo 0x{emitterInfoId:X8} for owner " +
$"0x{ownerLocalId:X8} was not found; no fallback was created.",
};
private readonly record struct EmitterBinding(
uint OwnerLocalId,
int PartIndex,