refactor(app): compose content effects and audio startup
Move Phase-2 startup behind typed composition/publication boundaries, replace the GameWindow-capturing PhysicsScript gate with a focused deferred source, and own animation-hook registrations reversibly. Make OpenAL construction and teardown transactional so every device, context, source, and buffer prefix is retryable without replay.
This commit is contained in:
parent
1d51e35c14
commit
60a1698ce7
12 changed files with 1901 additions and 152 deletions
63
src/AcDream.App/Rendering/Vfx/EntityEffectAdvanceSource.cs
Normal file
63
src/AcDream.App/Rendering/Vfx/EntityEffectAdvanceSource.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
namespace AcDream.App.Rendering.Vfx;
|
||||
|
||||
internal interface IEntityEffectAdvanceSource
|
||||
{
|
||||
bool CanAdvanceOwner(uint ownerLocalId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focused late-binding edge between the Phase-2 PhysicsScript runner and the
|
||||
/// Phase-6 live effect authority. Before live presentation exists, scripts are
|
||||
/// unconstrained exactly as the former null-safe callback was; after binding,
|
||||
/// the canonical effect owner decides whether its current pose can advance.
|
||||
/// </summary>
|
||||
internal sealed class DeferredEntityEffectAdvanceSource : IEntityEffectAdvanceSource
|
||||
{
|
||||
private readonly object _gate = new();
|
||||
private IEntityEffectAdvanceSource? _target;
|
||||
private bool _deactivated;
|
||||
|
||||
public void Bind(IEntityEffectAdvanceSource target)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(target);
|
||||
lock (_gate)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_deactivated, this);
|
||||
if (_target is not null && !ReferenceEquals(_target, target))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Entity-effect script advancement is already bound.");
|
||||
}
|
||||
|
||||
_target = target;
|
||||
}
|
||||
}
|
||||
|
||||
public void Unbind(IEntityEffectAdvanceSource target)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(target);
|
||||
lock (_gate)
|
||||
{
|
||||
if (ReferenceEquals(_target, target))
|
||||
_target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
_deactivated = true;
|
||||
_target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanAdvanceOwner(uint ownerLocalId)
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
return _deactivated
|
||||
|| _target?.CanAdvanceOwner(ownerLocalId) != false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,8 @@ namespace AcDream.App.Rendering.Vfx;
|
|||
/// (<c>0x00513260</c>) and both <c>play_default_script</c> overloads
|
||||
/// (<c>0x005132B0</c>, <c>0x00513300</c>).
|
||||
/// </remarks>
|
||||
public sealed class EntityEffectController : IAnimationHookSink
|
||||
public sealed class EntityEffectController : IAnimationHookSink,
|
||||
IEntityEffectAdvanceSource
|
||||
{
|
||||
private readonly LiveEntityRuntime _liveEntities;
|
||||
private readonly PhysicsScriptRunner _runner;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue