TankUISubsystem Ready/Broadcast Flow¶
This doc summarizes how the multi-queue + flush pipeline works for widget controller readiness, including the split local vs simulated-proxy broadcasts.
Queues and meaning¶
PendingPlayerStates- Raw
PlayerStateAddedevents that arrive before the local player is ready. - Held so the local PlayerState can be identified and initialized first.
PendingPostNetInitPlayerStates- Remote PlayerStates that are not post-net-init yet (client only).
- Waits on
OnPostNetInitDelegate. PendingUniqueIdPlayerStates- Remote PlayerStates that do not yet have a replicated UniqueId.
- Waits on
OnUniqueIdReadyDelegate. PendingReadyBroadcastPlayerStates- Remote PlayerStates that are initialized (view models + controller ready),
but their
OnSimulatedProxyWidgetControllerReadybroadcast is deferred until the local player is ready.
Core flow¶
1) HandlePlayerStateAdded
- If local is not ready (bLocalReadyBroadcasted == false), the PlayerState
is queued in PendingPlayerStates and initialization returns early.
- Once local is ready, remotes can be initialized immediately.
2) ProcessPendingPlayerStates
- Called when the local PlayerState becomes known.
- Removes the local PlayerState from PendingPlayerStates.
- Initializes the local view models with bDeferReadyBroadcast = true.
3) InitializeViewModelsForPlayerStateInternal
- For local PlayerState:
- Calls TryBroadcastLocalReady (which gates on EOS readiness).
- Successful broadcast fires OnLocalWidgetControllerReady.
- For remote PlayerState:
- If local is not ready, it enqueues the PlayerState into
PendingReadyBroadcastPlayerStates and returns (also queues UniqueId
if needed).
- If local is ready, it broadcasts immediately via
OnSimulatedProxyWidgetControllerReady (or queues UniqueId if needed).
4) TryBroadcastLocalReady
- When local passes EOS readiness checks, it broadcasts local ready.
- Then it flushes:
- FlushPendingPlayerStates (initialize any queued remotes)
- FlushPendingReadyBroadcasts (emit deferred remote ready events)
5) FlushPendingReadyBroadcasts
- For each queued remote PlayerState:
- If still missing PostNetInit / UniqueId / or not initialized, it is re-queued.
- Otherwise it broadcasts OnSimulatedProxyWidgetControllerReady.
Why this defers remote ready¶
Remote PlayerStates can become valid before the local overlay/controller exists.
By deferring remote OnSimulatedProxyWidgetControllerReady until after local ready, the
first broadcast observed by UI systems is guaranteed to be local-ready, and
remote ready broadcasts are emitted after the local overlay controller exists.
HUD/Overlay Notes¶
ATankHUD::InitOverlayno longer creates the overlay controller; it expects one to already exist (typically created duringInitializeViewModelsForPlayerStateInternal).- UI extensions are registered against the LocalPlayer context, not PlayerState. This keeps bindings stable across travel but means widgets are pooled/reused.
- Because pooled widgets do not re-construct on reuse, refresh/rebind must happen in
OnUIDataApplied/OnActivated, not justNativeConstruct.