acdream/src/AcDream.App/Input
Erik d233f81dce feat(session): the in-world logoff — LogOut animation, reverse wormhole, live return to character select
Retires AD-74 (Exit to Character Selection 'behaves as Exit Game') and
files AD-110 (the composed handoff edge) — register rows in this commit.

Retail derivation (named decomp):
- gmGamePlayUI::UseTime @0x004EA3A0: confirmed Yes drains into
  CPlayerSystem::LogOffCharacter(0) when grounded (transient_state &
  CONTACT); the grounded three-way branch now also covers the
  indicator-bar end-session control (it was Options-only).
- CPlayerSystem::LogOffCharacter @0x00563520: SaveToServer FIRST (the
  existing pre-logoff flush hook), then RequestLogOff @0x00562DD0:
  'Logging off...' chat (type 0), 0xF653 via Proto_UI::LogOffCharacter
  @0x00546A20, logOffRequestTime = now + 3.0 (+20.0 when
  IsPlayerKiller @0x0058C910 — PWD bits 0x20|0x2000000), and
  CommandInterpreter::HandleLogOff @0x006B3330 -> Disable.
- The log-off ANIMATION is server-driven: ACE broadcasts
  MotionCommand.LogOut (0x1000011E, Player.cs:596 SendMotionAsCommands)
  and it plays on the local player through the existing inbound
  unpack_movement funnel during the 3 s hold — retail plays nothing
  locally; Disable() is the whole client-side effect.
- gmSmartBoxUI::UseTime @0x004D6E64: hold elapsed ->
  BeginTeleportAnimation(TAS_WORLD_FADE_OUT) @0x004D6E83 (enter cue
  @0x004D638E, unconditional) -> TunnelFadeIn -> Tunnel. The tunnel
  plays the SAME forward 40 fps animation; nothing renders backwards,
  and NO exit cue ever fires on logout (the char-select swap preempts
  the TunnelContinue/FadeOut tail).
- Inbound 0xF653 echo (dispatch case 3 @0x0055C963) ->
  ExecuteLogOff @0x0055D780: world teardown with the LOGON CONNECTION
  KEPT (ExitWorldDisconnect @0x00541E00 removes every connection
  except logonRecID_ — one connection against ACE) and
  Proto_UI::SetEventCounter(0) @0x00541E79; the fresh CharacterList in
  the same batch re-shows character management (gmGamePlayUI::Update
  @0x004E9CD0 -> QueueUIMode(0x1000000a)). ACE mirrors it:
  SendFinalLogOffMessages (Session.cs:249) sends 0xF653 + CharacterList
  + ServerName >=6 s after the request and leaves the session
  AuthConnected — a second EnterWorld needs no re-handshake.

Implementation:
- RuntimeWorldTransitState: the canonical logout lifecycle
  (Requested/PresentationActive/Confirmed, retail 3 s/+20 s holds,
  cancel/reset/ownership convergence).
- WorldSession: RequestCharacterLogOff (non-blocking 0xF653),
  IsCharacterLogOffConfirmed, ReturnToCharacterSelect (InWorld ->
  InCharacterSelect + game-action sequence reset; transport untouched).
- LiveSessionController: BeginCharacterLogOff (flush-first request) and
  CompleteCharacterLogOff — the return-to-selection transaction
  (ReconnectCore minus the transport swap: retire the world
  generation's routes, host reset, state flip, fresh generation
  re-bind, roster re-applied from the pushed CharacterList; failures
  degrade to the full StopCore teardown).
- RuntimeLocalPlayerMovementState.DisableCommandInterpreter +
  DispatcherMovementInputSource gate: retail's Disable() — held keys
  produce no movement while the server LogOut motion plays; cleared by
  the generation reset.
- LocalPlayerTeleportController: the logout pump as the third arm of
  the one wormhole machine (request/hold/wormhole/confirmed handoff;
  teleport starts refused during logout; the handoff runs the session
  transaction whose world reset retires the tunnel as the fresh
  selection state re-shows the character screen).
- UI: both end-session surfaces share the retail three-way grounded
  gate and now run the REAL flow; Options' Exit Game keeps the app
  exit (window close -> the existing graceful-shutdown logoff).

Tests: +5 transit lifecycle, +4 session transaction, +7 logout pump.
Runtime 1756/0 (baseline 1747), App live-DAT 5523/3 (baseline 5512/3
+ 11 this round), Core.Net 1004/0, full solution green (0 failures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 14:02:40 +02:00
..
CameraPointerInputController.cs refactor(app): compose session and player startup 2026-07-22 18:28:32 +02:00
DispatcherCameraInputSource.cs refactor(input): own pointer and callback lifetime 2026-07-22 11:59:33 +02:00
DispatcherMovementInputSource.cs feat(session): the in-world logoff — LogOut animation, reverse wormhole, live return to character select 2026-08-17 14:02:40 +02:00
GameplayInputActionRouter.cs feat(runtime): define borrowed views commands and ordered events 2026-07-25 19:08:42 +02:00
GameplayInputCommandController.cs refactor(settings): OP9 — retire the dead F11 settings surface + fully-superseded GameplaySettings 2026-08-11 13:18:53 +02:00
GameplayInputFrameController.cs refactor(runtime): own combat and magic intent 2026-07-26 11:56:40 +02:00
InputCaptureSources.cs feat(render): Campaign V slice V11 commit 1 - delete ImGui, Studio, and the DevTools frontend 2026-07-28 23:56:04 +02:00
LocalPlayerAnimationController.cs refactor(app): key live projections by runtime identity 2026-07-25 21:50:58 +02:00
LocalPlayerFrameRuntime.cs feat(headless): complete deterministic bot command parity 2026-07-27 08:23:36 +02:00
LocalPlayerProjectionController.cs Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
LocalPlayerRuntimeState.cs feat(headless): hydrate isolated collision worlds 2026-07-27 09:25:58 +02:00
MouseLookController.cs fix(input): focus loss no longer faults on an unpublished movement controller (#356) 2026-08-09 12:02:38 +02:00
MovementTruthDiagnosticController.cs refactor(runtime): close simulation ownership 2026-07-26 15:53:31 +02:00
PlayerModeAutoEntry.cs feat(runtime): C3c - production placement cutover: both hosts on the residence conductors (routes 1+8) 2026-08-02 18:10:33 +02:00
PlayerModeController.cs feat(world): the login wormhole — every world entry runs retail's portal-space presentation with sound (TS-28 narrowed) 2026-08-17 10:51:33 +02:00
QuiescentInputContext.cs refactor(app): compose settings and developer tools 2026-07-22 16:11:34 +02:00
RetailLocalPlayerFrameController.cs Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
RetainedUiGameplayBinding.cs refactor(input): own gameplay action routing 2026-07-22 12:43:05 +02:00
SilkKeyboardSource.cs Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
SilkMouseSource.cs Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00