Move canonical per-session teardown into one retryable Runtime transaction, reduce App reset to projection acknowledgements, and prove the same GameRuntime graph through deterministic no-window lifecycle, gameplay, portal, fault, reconnect, and isolation gates.\n\nCo-authored-by: Codex <noreply@openai.com>
108 lines
4.9 KiB
C#
108 lines
4.9 KiB
C#
namespace AcDream.App.Net;
|
|
|
|
using AcDream.App.World;
|
|
using AcDream.Runtime;
|
|
using AcDream.Runtime.Entities;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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<RuntimeGenerationToken> RuntimeGeneration { get; init; }
|
|
public required Action<RuntimeGenerationToken> SessionIdentityPresentation
|
|
{ get; init; }
|
|
public required Action RemoteTeleport { 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; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The concrete, ordered character-session reset manifest. Retail
|
|
/// <c>CPlayerSystem::OnEndCharacterSession @ 0x00562870</c> calls End then
|
|
/// Begin; <c>ClientUISystem::OnEndCharacterSession @ 0x00564AD0</c>
|
|
/// independently resets gameplay UI. App resource dependencies impose the
|
|
/// exact projection-before-canonical-runtime order pinned here.
|
|
/// </summary>
|
|
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),
|
|
new("remote teleport", bindings.RemoteTeleport),
|
|
// 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),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// App's narrow borrowed projection acknowledgement for Runtime's canonical
|
|
/// generation-reset transaction. It owns no reset cursor or entity identity.
|
|
/// </summary>
|
|
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();
|
|
}
|