namespace AcDream.App.Net; using AcDream.App.World; using AcDream.Runtime; using AcDream.Runtime.Entities; /// /// Focused owner operations composed by the App host for one character-session /// reset. Mixed world/static registries are deliberately absent: their /// session-owned entries leave through canonical live-entity teardown. /// internal sealed class LiveSessionResetBindings { public required Action MouseCapture { get; init; } public required Action PlayerPresentation { get; init; } public required Action TeleportPresentation { get; init; } public required Action SessionDialogs { get; init; } public required Action SettingsCharacterContext { get; init; } public required Action EquippedChildren { get; init; } public required Action InteractionPresentation { get; init; } public required Action SelectionPresentation { get; init; } public required Action ParticleVisibility { get; init; } public required Action InboundEventFifo { get; init; } public required Action LiveLiveness { get; init; } public required Action RuntimeGeneration { get; init; } public required Action SessionIdentityPresentation { get; init; } public required Action NetworkEffects { get; init; } public required Action AnimationHookFrames { get; init; } public required Action LivePresentation { get; init; } public required Action RemoteMovementDiagnostics { get; init; } } /// /// The concrete, ordered character-session reset manifest. Retail /// CPlayerSystem::OnEndCharacterSession @ 0x00562870 calls End then /// Begin; ClientUISystem::OnEndCharacterSession @ 0x00564AD0 /// independently resets gameplay UI. App resource dependencies impose the /// exact projection-before-canonical-runtime order pinned here. /// internal static class LiveSessionResetManifest { public static LiveSessionResetPlan Create(LiveSessionResetBindings bindings) { ArgumentNullException.ThrowIfNull(bindings); return new LiveSessionResetPlan( [ new("mouse capture", bindings.MouseCapture), new("player presentation", bindings.PlayerPresentation), new("teleport presentation", bindings.TeleportPresentation), new("session dialogs", bindings.SessionDialogs), new("settings character context", bindings.SettingsCharacterContext), // Attachment projections own GL-backed registrations and must leave // before canonical live GUID records are released. new("equipped children", bindings.EquippedChildren), new("interaction presentation", bindings.InteractionPresentation), new("selection presentation", bindings.SelectionPresentation), new("particle visibility", bindings.ParticleVisibility), new("inbound event fifo", bindings.InboundEventFifo), new("live liveness", bindings.LiveLiveness), new("runtime generation", bindings.RuntimeGeneration), // Identity must remain A until live teardown has converged so // player-specific teardown can still classify the old record. new( "session identity presentation", bindings.SessionIdentityPresentation), // F754/F755 can precede CreateObject, so pending network effects // must clear even when no LiveEntityRecord was constructed. new("network effects", bindings.NetworkEffects), new("animation hook frames", bindings.AnimationHookFrames), new("live presentation", bindings.LivePresentation), new("remote movement diagnostics", bindings.RemoteMovementDiagnostics), ]); } } /// /// App's narrow borrowed projection acknowledgement for Runtime's canonical /// generation-reset transaction. It owns no reset cursor or entity identity. /// internal sealed class GraphicalRuntimeGenerationResetHost : IRuntimeGenerationResetHost { private readonly LiveEntityRuntime _entities; private readonly Action _drainRenderProjection; public GraphicalRuntimeGenerationResetHost( LiveEntityRuntime entities, Action drainRenderProjection) { _entities = entities ?? throw new ArgumentNullException(nameof(entities)); _drainRenderProjection = drainRenderProjection ?? throw new ArgumentNullException(nameof(drainRenderProjection)); } public void RetireEntityProjection( RuntimeEntityRecord entity) => _entities.RetireGenerationProjection(entity); public void DrainEntityProjectionBoundary() => _drainRenderProjection(); public void CompleteEntityProjectionRetirement() => _entities.CompleteGenerationProjectionRetirement(); }