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();
}