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
|
|
@ -0,0 +1,77 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Composition;
|
||||
using AcDream.Core.Physics;
|
||||
using DatReaderWriter.Types;
|
||||
|
||||
namespace AcDream.App.Tests.Composition;
|
||||
|
||||
public sealed class AnimationHookRegistrationSetTests
|
||||
{
|
||||
[Fact]
|
||||
public void CleanupUnregistersInReverseAndNeverReplaysSuccessfulEdges()
|
||||
{
|
||||
var calls = new List<string>();
|
||||
var first = new Sink("first");
|
||||
var second = new Sink("second");
|
||||
var third = new Sink("third");
|
||||
bool failSecond = true;
|
||||
var registrations = new AnimationHookRegistrationSet(
|
||||
sink => calls.Add($"add:{((Sink)sink).Name}"),
|
||||
sink =>
|
||||
{
|
||||
string name = ((Sink)sink).Name;
|
||||
calls.Add($"remove:{name}");
|
||||
if (name == "second" && failSecond)
|
||||
throw new InvalidOperationException("synthetic removal failure");
|
||||
});
|
||||
registrations.Register(first);
|
||||
registrations.Register(second);
|
||||
registrations.Register(third);
|
||||
|
||||
Assert.Throws<AggregateException>(registrations.Dispose);
|
||||
Assert.False(registrations.IsCleanupComplete);
|
||||
failSecond = false;
|
||||
registrations.Dispose();
|
||||
registrations.Dispose();
|
||||
|
||||
Assert.True(registrations.IsCleanupComplete);
|
||||
Assert.Equal(
|
||||
[
|
||||
"add:first", "add:second", "add:third",
|
||||
"remove:third", "remove:second", "remove:first",
|
||||
"remove:second",
|
||||
],
|
||||
calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DuplicateRegistrationIsIdempotentAndClosedSetRejectsNewEdges()
|
||||
{
|
||||
int adds = 0;
|
||||
int removes = 0;
|
||||
var sink = new Sink("only");
|
||||
var registrations = new AnimationHookRegistrationSet(
|
||||
_ => adds++,
|
||||
_ => removes++);
|
||||
|
||||
registrations.Register(sink);
|
||||
registrations.Register(sink);
|
||||
registrations.Dispose();
|
||||
|
||||
Assert.Equal(1, adds);
|
||||
Assert.Equal(1, removes);
|
||||
Assert.Throws<ObjectDisposedException>(() =>
|
||||
registrations.Register(new Sink("late")));
|
||||
}
|
||||
|
||||
private sealed class Sink(string name) : IAnimationHookSink
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public void OnHook(
|
||||
uint entityId,
|
||||
Vector3 entityWorldPosition,
|
||||
AnimationHook hook)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue