feat(vfx): bind effects to live animated poses
This commit is contained in:
parent
96ddfdf175
commit
542dcfc384
41 changed files with 3246 additions and 741 deletions
|
|
@ -75,6 +75,31 @@ public sealed class ParticleSystem : IParticleSystem
|
|||
return SpawnEmitter(desc, anchor, rot, attachedObjectId, attachedPartIndex, renderPass);
|
||||
}
|
||||
|
||||
public bool TrySpawnEmitterById(
|
||||
uint emitterId,
|
||||
Vector3 anchor,
|
||||
Quaternion? rot,
|
||||
uint attachedObjectId,
|
||||
int attachedPartIndex,
|
||||
ParticleRenderPass renderPass,
|
||||
out int handle)
|
||||
{
|
||||
if (!_registry.TryGet(emitterId, out EmitterDesc? desc))
|
||||
{
|
||||
handle = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
handle = SpawnEmitter(
|
||||
desc,
|
||||
anchor,
|
||||
rot,
|
||||
attachedObjectId,
|
||||
attachedPartIndex,
|
||||
renderPass);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void PlayScript(uint scriptId, uint targetObjectId, float modifier = 1f)
|
||||
{
|
||||
// Full PhysicsScript scheduling lives in PhysicsScriptRunner.
|
||||
|
|
@ -90,6 +115,12 @@ public sealed class ParticleSystem : IParticleSystem
|
|||
{
|
||||
for (int i = 0; i < em.Particles.Length; i++)
|
||||
em.Particles[i].Alive = false;
|
||||
// Retail DestroyParticleEmitter removes the table entry now; it
|
||||
// does not wait for the next update. This is also required for a
|
||||
// hard-stopped emitter whose cell-less simulation is paused.
|
||||
_byHandle.Remove(handle);
|
||||
_handleOrder.Remove(handle);
|
||||
EmitterDied?.Invoke(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,10 +138,50 @@ public sealed class ParticleSystem : IParticleSystem
|
|||
if (!_byHandle.TryGetValue(handle, out var em))
|
||||
return;
|
||||
em.AnchorPos = anchor;
|
||||
if (!em.SimulationEnabled)
|
||||
em.LastEmitOffset = anchor;
|
||||
if (rot.HasValue)
|
||||
em.AnchorRot = rot.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes only render presentation. Logical lifetime is unaffected.
|
||||
/// </summary>
|
||||
public void SetEmitterPresentationVisible(int handle, bool visible)
|
||||
{
|
||||
if (_byHandle.TryGetValue(handle, out ParticleEmitter? emitter))
|
||||
emitter.PresentationVisible = visible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies retail's in-cell update gate without ending emitter ownership.
|
||||
/// Retail retains absolute creation timestamps while cell-less; the next
|
||||
/// update observes the elapsed wall-clock interval and expires old state.
|
||||
/// Only acdream's legacy rate accumulator is rebased to prevent a synthetic
|
||||
/// multi-particle catch-up burst that retail's one-shot emission path lacks.
|
||||
/// </summary>
|
||||
public void SetEmitterSimulationEnabled(int handle, bool enabled)
|
||||
{
|
||||
if (!_byHandle.TryGetValue(handle, out ParticleEmitter? emitter)
|
||||
|| emitter.SimulationEnabled == enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
emitter.SimulationEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (emitter.Desc.Birthrate <= 0f && emitter.Desc.EmitRate > 0f)
|
||||
{
|
||||
emitter.LastEmitTime = _time;
|
||||
emitter.EmittedAccumulator = 0f;
|
||||
}
|
||||
emitter.SimulationEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>True when the given handle still maps to a live emitter.</summary>
|
||||
public bool IsEmitterAlive(int handle) => _byHandle.ContainsKey(handle);
|
||||
|
||||
|
|
@ -136,6 +207,8 @@ public sealed class ParticleSystem : IParticleSystem
|
|||
int handle = _handleOrder[i];
|
||||
if (!_byHandle.TryGetValue(handle, out var em))
|
||||
continue;
|
||||
if (!em.SimulationEnabled)
|
||||
continue;
|
||||
|
||||
AdvanceEmitter(em);
|
||||
int live = CountAlive(em);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue