fix: await playout callbacks before refresh

This commit is contained in:
2026-07-11 05:03:31 +09:00
parent d8b9641a75
commit 3e3292b8a9
6 changed files with 358 additions and 32 deletions

View File

@@ -681,6 +681,144 @@ public sealed class DynamicK3dSessionTests
Assert.Equal(1, log.Names.Count(name => name == "Unload:5006"));
}
[Fact]
public async Task LifecycleCallbacks_SameNameReplacement_UnloadsOnlyAfterStopAll()
{
using var scenes = TemporarySceneDirectory.Create("5001.t2s");
var options = SceneOptions(scenes.Path, "5001");
var log = new FakeComLog();
var player = new FakePlayer(log);
var retiredScene = new FakeScene(log, "5001");
var activeScene = new FakeScene(log, "5001");
var scenesToLoad = new Queue<FakeScene>([retiredScene, activeScene]);
var engine = new FakeEngine(log, player, retiredScene)
{
SceneResolver = _ => scenesToLoad.Dequeue()
};
var activator = new FakeActivator(log, engine);
var callbacks = new RecordingEventHandlerFactory();
var releaser = new FakeReleaser(
log,
(retiredScene, "5001-retired"),
(activeScene, "5001-active"),
(player, "Player"),
(engine, "Engine"),
(callbacks.Handler, "EventHandler"));
await using var dispatcher = new StaDispatcher(capacity: 3);
await dispatcher.InvokeAsync(
() =>
{
using var session = new DynamicK3dSession(
activator,
releaser,
new InstalledK3dInteropMethodInvoker(),
callbacks);
session.Connect(options);
session.Prepare(SceneCue(options, "5001"), options.LayoutIndex);
session.Play(options.LayoutIndex);
callbacks.Fire("OnScenePlayed", 1, 9, options.LayoutIndex);
Assert.Equal(
0,
session.ProcessPendingCallbacks(options.LayoutIndex).UnloadedSceneCount);
session.Prepare(SceneCue(options, "5001"), options.LayoutIndex);
session.Play(options.LayoutIndex);
callbacks.Fire("OnScenePlayed", 1, 9, options.LayoutIndex);
Assert.Equal(
0,
session.ProcessPendingCallbacks(options.LayoutIndex).UnloadedSceneCount);
Assert.DoesNotContain("Unload:5001", log.Names);
Assert.Contains("Release:5001-retired", log.Names);
Assert.DoesNotContain("Release:5001-active", log.Names);
session.TakeOut(options.LayoutIndex, PlayoutTakeOutScope.All);
callbacks.Fire("OnStopAll", 1);
Assert.Equal(
1,
session.ProcessPendingCallbacks(options.LayoutIndex).UnloadedSceneCount);
Assert.Equal(1, log.Names.Count(name => name == "Unload:5001"));
Assert.Contains("Release:5001-active", log.Names);
session.Disconnect();
return true;
},
TimeSpan.FromSeconds(5),
CancellationToken.None);
Assert.Empty(scenesToLoad);
Assert.Equal(1, log.Names.Count(name => name == "Unload:5001"));
Assert.Equal(1, log.Names.Count(name => name == "Release:5001-retired"));
Assert.Equal(1, log.Names.Count(name => name == "Release:5001-active"));
}
[Fact]
public async Task LifecycleCallbacks_SameNameReplacement_IgnoresSceneNameCasing()
{
using var scenes = TemporarySceneDirectory.Create("SceneA.t2s");
var options = SceneOptions(scenes.Path, "SceneA");
var log = new FakeComLog();
var player = new FakePlayer(log);
var retiredScene = new FakeScene(log, "SceneA");
var activeScene = new FakeScene(log, "scenea");
var scenesToLoad = new Queue<FakeScene>([retiredScene, activeScene]);
var engine = new FakeEngine(log, player, retiredScene)
{
SceneResolver = _ => scenesToLoad.Dequeue()
};
var activator = new FakeActivator(log, engine);
var callbacks = new RecordingEventHandlerFactory();
var releaser = new FakeReleaser(
log,
(retiredScene, "SceneA-retired"),
(activeScene, "scenea-active"),
(player, "Player"),
(engine, "Engine"),
(callbacks.Handler, "EventHandler"));
await using var dispatcher = new StaDispatcher(capacity: 3);
await dispatcher.InvokeAsync(
() =>
{
using var session = new DynamicK3dSession(
activator,
releaser,
new InstalledK3dInteropMethodInvoker(),
callbacks);
session.Connect(options);
session.Prepare(SceneCue(options, "SceneA"), options.LayoutIndex);
session.Play(options.LayoutIndex);
callbacks.Fire("OnScenePlayed", 1, 9, options.LayoutIndex);
session.ProcessPendingCallbacks(options.LayoutIndex);
session.Prepare(SceneCue(options, "scenea"), options.LayoutIndex);
session.Play(options.LayoutIndex);
callbacks.Fire("OnScenePlayed", 1, 9, options.LayoutIndex);
Assert.Equal(
0,
session.ProcessPendingCallbacks(options.LayoutIndex).UnloadedSceneCount);
Assert.DoesNotContain("Unload:SceneA", log.Names);
Assert.Contains("Release:SceneA-retired", log.Names);
session.TakeOut(options.LayoutIndex, PlayoutTakeOutScope.All);
callbacks.Fire("OnStopAll", 1);
Assert.Equal(
1,
session.ProcessPendingCallbacks(options.LayoutIndex).UnloadedSceneCount);
session.Disconnect();
return true;
},
TimeSpan.FromSeconds(5),
CancellationToken.None);
Assert.Empty(scenesToLoad);
Assert.DoesNotContain("Unload:SceneA", log.Names);
Assert.Equal(1, log.Names.Count(name => name == "Unload:scenea"));
Assert.Equal(1, log.Names.Count(name => name == "Release:SceneA-retired"));
Assert.Equal(1, log.Names.Count(name => name == "Release:scenea-active"));
}
[Fact]
public async Task StopAllSuccess_ClearsInterruptedPlayBeforeDisconnect()
{