refactor(runtime): cut graphical host over to canonical root
Make every App composition phase borrow one GameRuntime, retire the duplicate view/event adapters, and dispose the root only after its graphical borrowers release. This preserves synchronous UI commands while giving shutdown one exact ownership ledger. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
ecb9f79444
commit
ce41efb9e5
29 changed files with 613 additions and 778 deletions
|
|
@ -17,6 +17,7 @@ using AcDream.App.World;
|
|||
using AcDream.Content;
|
||||
using AcDream.Core.Audio;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.Runtime.Session;
|
||||
|
|
@ -62,7 +63,7 @@ internal sealed record IngressShutdownRoots(
|
|||
// Keeps failed physical UI bindings alive through native-window release.
|
||||
UiHost? RetainedUiHost,
|
||||
DevToolsCompositionOwner? DevTools,
|
||||
LiveSessionController? LiveSession,
|
||||
GameRuntime Runtime,
|
||||
RuntimeSettingsController Settings,
|
||||
DispatcherMovementInputSource MovementInput,
|
||||
DispatcherCameraInputSource CameraInput,
|
||||
|
|
@ -83,12 +84,8 @@ internal sealed record LiveShutdownRoots(
|
|||
LandblockStreamer? Streamer,
|
||||
EquippedChildRenderController? EquippedChildren,
|
||||
LiveEntityRuntime? LiveEntities,
|
||||
RuntimeEntityObjectLifetime EntityObjects,
|
||||
RuntimeInventoryState Inventory,
|
||||
RuntimeCharacterState Character,
|
||||
RuntimeCommunicationState Communication,
|
||||
RuntimeActionState Actions,
|
||||
RuntimeLocalPlayerMovementState Movement,
|
||||
GameRuntime Runtime,
|
||||
IDisposable RuntimeHostLease,
|
||||
RenderSceneShadowRuntime? RenderSceneShadow,
|
||||
LivePresentationRuntimeBindings? PresentationBindings,
|
||||
DeferredEntityEffectAdvanceSource EffectAdvance,
|
||||
|
|
@ -352,7 +349,7 @@ internal static class GameWindowShutdownManifest
|
|||
Hard("keyboard source", () => ingress.KeyboardSource?.Deactivate()),
|
||||
Hard("retained UI input", ingress.RetailUi.QuiesceInput),
|
||||
Hard("developer tools input", () => ingress.DevTools?.DeactivateInput()),
|
||||
Hard("live session", () => DisposeLiveSession(ingress.LiveSession)),
|
||||
Hard("game runtime session", ingress.Runtime.StopSession),
|
||||
]),
|
||||
new ResourceShutdownStage("physical ingress cleanup",
|
||||
[
|
||||
|
|
@ -391,24 +388,6 @@ internal static class GameWindowShutdownManifest
|
|||
"shadow render scene",
|
||||
() => live.RenderSceneShadow?.Dispose()),
|
||||
]),
|
||||
new ResourceShutdownStage("runtime entity/object stream",
|
||||
[
|
||||
Hard(
|
||||
"runtime local movement state",
|
||||
live.Movement.Dispose),
|
||||
Hard(
|
||||
"runtime action state",
|
||||
live.Actions.Dispose),
|
||||
Hard(
|
||||
"runtime character state",
|
||||
live.Character.Dispose),
|
||||
Hard(
|
||||
"runtime inventory state",
|
||||
live.Inventory.Dispose),
|
||||
Hard(
|
||||
"runtime entity/object lifetime",
|
||||
live.EntityObjects.Dispose),
|
||||
]),
|
||||
new ResourceShutdownStage("effect dispatch edges",
|
||||
[
|
||||
Hard("live-presentation bindings", () => live.PresentationBindings?.Dispose()),
|
||||
|
|
@ -456,9 +435,10 @@ internal static class GameWindowShutdownManifest
|
|||
Hard("sky", () => render.Sky?.Dispose()),
|
||||
Hard("particles", () => render.Particles?.Dispose()),
|
||||
]),
|
||||
new ResourceShutdownStage("runtime communication state",
|
||||
new ResourceShutdownStage("game runtime root",
|
||||
[
|
||||
Hard("communication owner", live.Communication.Dispose),
|
||||
Hard("graphical runtime host lease", live.RuntimeHostLease.Dispose),
|
||||
Hard("game runtime", () => DisposeGameRuntime(live.Runtime)),
|
||||
]),
|
||||
new ResourceShutdownStage("shared texture owners",
|
||||
[
|
||||
|
|
@ -515,15 +495,14 @@ internal static class GameWindowShutdownManifest
|
|||
private static ResourceShutdownOperation Soft(string name, Action action) =>
|
||||
new(name, action, ResourceShutdownOperationPolicy.ReportAndContinue);
|
||||
|
||||
private static void DisposeLiveSession(LiveSessionController? controller)
|
||||
private static void DisposeGameRuntime(GameRuntime runtime)
|
||||
{
|
||||
if (controller is null)
|
||||
return;
|
||||
controller.Dispose();
|
||||
if (!controller.IsDisposalComplete)
|
||||
runtime.Dispose();
|
||||
GameRuntimeOwnershipSnapshot ownership = runtime.CaptureOwnership();
|
||||
if (!ownership.IsConverged)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Live-session disposal was deferred by a reentrant lifecycle callback.");
|
||||
"The canonical game runtime did not converge after disposal.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue