#include <ComposableCameraContextStack.h>
Inherits:
UObject
Camera context stack — the macro-level orchestrator.
Manages a LIFO stack of camera evaluation contexts, each owning its own Director and EvaluationTree. This is the first tier in the two-tier camera architecture:
-
Tier 1 (this): Context stack for switching between camera "modes" (gameplay, UI, cinematic).
-
Tier 2: Evaluation tree within each context for transitions between cameras of the same mode.
Contexts are identified by FName and defined in project settings. The stack is strict LIFO: new contexts push on top, popping removes from top (or by name).
Auto-pop: when the active context's running camera is transient and finishes, the context is automatically popped. The camera itself drives lifecycle, not the context.
Inter-context transitions use a reference leaf node in the evaluation tree: the new context's tree gets a reference leaf that evaluates the previous context's Director live, enabling smooth blending between contexts.
Popped contexts with transitions enter a "pending destruction" state: their Director stays alive and is evaluated through the reference leaf during the transition. Once the transition finishes, the pending context's cameras are destroyed and the entry is removed.
Public Methods¶
| Return | Name | Description |
|---|---|---|
UComposableCameraContextStack |
||
UComposableCameraDirector * |
EnsureContext |
Ensure a context with the given name exists on the stack. If already present, returns its Director. If not, pushes a new context on top (LIFO) and returns its Director. |
void |
PopContext |
Pop a specific context by name. If the context is the active (top) context and a transition is available, the pop is animated: the previous context resumes with a transition from the popped context's Director. If the context is not the active one, it is removed immediately. Cannot pop the base (bottom) context if it is the last one remaining. |
void |
PopActiveContext |
Pop the active (top) context. Used by TerminateCurrentCamera. Cannot pop the base context if it is the last one remaining. |
int32 |
GetStackDepth const inline |
Get the number of contexts on the stack. |
UComposableCameraDirector * |
GetActiveDirector const |
Get the active (top) context's Director. Returns nullptr if the stack is empty. |
UComposableCameraDirector * |
GetDirectorForContext const |
Get the Director for a specific context by name. Returns nullptr if not on the stack. |
AComposableCameraCameraBase * |
GetRunningCamera const |
Get the active context's running camera. Returns nullptr if the stack is empty. |
FName |
GetActiveContextName const |
Get the active context's name. Returns NAME_None if the stack is empty. |
FComposableCameraPose |
Evaluate |
Evaluate the active context for this frame. Only the top context is ticked (unless a lower context is referenced by a reference leaf in the active context's tree, in which case it ticks through the reference). If the active context's running camera is transient and finished, auto-pops the context. |
void |
DemoteNonTopTransientContextsToPending |
After an inter-context activation, demote every non-top entry whose running camera is transient into PendingDestroyEntries, treating each one as an implicit pop whose cleanup is bound to ActivatingTransition. |
void |
BuildDebugSnapshot const |
Build a structured snapshot of the stack + each director's tree. The snapshot is the single source of truth for every debug consumer: the in-viewport 2D panel, the showdebug camera HUD, and any future dump command all format their text by walking this snapshot through [ComposableCameraDebug::AppendTreeNodeLine](../free-functions/Functions.md#appendtreenodeline). Contexts are emitted top → base (index 0 of OutSnapshot.Contexts = active/top) followed by all PendingDestroyEntries flagged bIsPendingDestroy = true. |
UComposableCameraContextStack¶
UComposableCameraContextStack(const FObjectInitializer & ObjectInitializer)
EnsureContext¶
UComposableCameraDirector * EnsureContext(AComposableCameraPlayerCameraManager * PlayerCameraManager, FName ContextName)
Ensure a context with the given name exists on the stack. If already present, returns its Director. If not, pushes a new context on top (LIFO) and returns its Director.
Parameters
-
PlayerCameraManagerThe owning player camera manager. -
ContextNameThe name identifying which context to ensure (must be in project settings).
Returns
The Director for the context. Returns nullptr if the name is not registered.
PopContext¶
void PopContext(FName ContextName, AComposableCameraPlayerCameraManager * PlayerCameraManager, UComposableCameraTransitionDataAsset * TransitionOverride, const FComposableCameraActivateParams & ActivationParams)
Pop a specific context by name. If the context is the active (top) context and a transition is available, the pop is animated: the previous context resumes with a transition from the popped context's Director. If the context is not the active one, it is removed immediately. Cannot pop the base (bottom) context if it is the last one remaining.
Parameters
-
ContextNameThe name of the context to pop. -
PlayerCameraManagerThe owning player camera manager (needed for camera creation during transition). -
TransitionOverrideOptional transition data asset. If nullptr, falls back to the resume camera's EnterTransition. -
ActivationParamsOptional activation params for the resume camera.
PopActiveContext¶
void PopActiveContext(AComposableCameraPlayerCameraManager * PlayerCameraManager, UComposableCameraTransitionDataAsset * TransitionOverride, const FComposableCameraActivateParams & ActivationParams)
Pop the active (top) context. Used by TerminateCurrentCamera. Cannot pop the base context if it is the last one remaining.
Parameters
-
PlayerCameraManagerThe owning player camera manager. -
TransitionOverrideOptional transition data asset override. -
ActivationParamsOptional activation params for the resume camera.
GetStackDepth¶
const inline
inline int32 GetStackDepth() const
Get the number of contexts on the stack.
GetActiveDirector¶
const
UComposableCameraDirector * GetActiveDirector() const
Get the active (top) context's Director. Returns nullptr if the stack is empty.
GetDirectorForContext¶
const
UComposableCameraDirector * GetDirectorForContext(FName ContextName) const
Get the Director for a specific context by name. Returns nullptr if not on the stack.
GetRunningCamera¶
const
AComposableCameraCameraBase * GetRunningCamera() const
Get the active context's running camera. Returns nullptr if the stack is empty.
GetActiveContextName¶
const
FName GetActiveContextName() const
Get the active context's name. Returns NAME_None if the stack is empty.
Evaluate¶
FComposableCameraPose Evaluate(float DeltaTime)
Evaluate the active context for this frame. Only the top context is ticked (unless a lower context is referenced by a reference leaf in the active context's tree, in which case it ticks through the reference). If the active context's running camera is transient and finished, auto-pops the context.
Returns
The final camera pose for this frame.
DemoteNonTopTransientContextsToPending¶
void DemoteNonTopTransientContextsToPending(UComposableCameraTransitionBase * ActivatingTransition)
After an inter-context activation, demote every non-top entry whose running camera is transient into PendingDestroyEntries, treating each one as an implicit pop whose cleanup is bound to ActivatingTransition.
Motivating scenario (the reason this exists):
-
Gameplay runs camera A.
-
Push Transient context with transient camera B (LifeTime 4s, transition 5s).
-
Mid-push-transition, the caller invokes ActivateCamera(A, Gameplay) to flip back to Gameplay.
EnsureContext(Gameplay)rearranges the stack to[Transient, Gameplay]— Transient drops off the top. -
With only-top-scans-for-auto-pop semantics, Transient is now permanently stuck on the stack: its camera B is no longer at the top so the auto-pop loop in
Evaluatenever inspects it, and its LifeTime expiring does not trigger any cleanup.
Fix: at the end of the inter-context activation that caused the demotion, call this method with the activation's blend transition. Each non-top entry with a transient RunningCamera is removed from Entries, inserted into PendingDestroyEntries, and a lambda is registered on ActivatingTransition->OnTransitionFinishesDelegate so its director is destroyed + the pending entry removed exactly when the blend resolves. Matches the semantics of an explicit PopContext for that context.
Why the delegate (instead of immediate destruction): the activation's new tree captures the Transient director's tree root as a RefLeaf snapshot. Destroying the transient camera immediately would leave the RefLeaf chain walking into PendingKill leaves during the blend — the same class of bug the PendingDestroyOldRoots defer fix addresses on the target-director side. The blend finish is the earliest moment the transient camera is reachable from no live tree.
Non-transient entries that happen to be below the top are left alone — they are the caller's responsibility (e.g. a UI context temporarily suspended behind gameplay stays suspended).
No-op if ActivatingTransition is null (camera-cut inter-context activation); in that case nothing is blending so any transient entry pushed below the top is destroyed immediately to match the single- frame semantics of a cut.
BuildDebugSnapshot¶
const
void BuildDebugSnapshot(FComposableCameraContextStackSnapshot & OutSnapshot) const
Build a structured snapshot of the stack + each director's tree. The snapshot is the single source of truth for every debug consumer: the in-viewport 2D panel, the showdebug camera HUD, and any future dump command all format their text by walking this snapshot through [ComposableCameraDebug::AppendTreeNodeLine](../free-functions/Functions.md#appendtreenodeline). Contexts are emitted top → base (index 0 of OutSnapshot.Contexts = active/top) followed by all PendingDestroyEntries flagged bIsPendingDestroy = true.
Public Static Methods¶
| Return | Name | Description |
|---|---|---|
void |
AddReferencedObjects static |
AddReferencedObjects¶
static
static void AddReferencedObjects(UObject * InThis, FReferenceCollector & Collector)
Private Attributes¶
| Return | Name | Description |
|---|---|---|
TArray< FComposableCameraContextEntry > |
Entries |
Stack entries in LIFO order (index 0 = base, Last() = active/top). |
TArray< FComposableCameraContextEntry > |
PendingDestroyEntries |
Contexts that have been popped but are kept alive during their pop transition. Their Directors are still evaluated via reference leaves in the resume context's tree. Cleaned up when the transition finishes. |
Entries¶
TArray< FComposableCameraContextEntry > Entries
Stack entries in LIFO order (index 0 = base, Last() = active/top).
PendingDestroyEntries¶
TArray< FComposableCameraContextEntry > PendingDestroyEntries
Contexts that have been popped but are kept alive during their pop transition. Their Directors are still evaluated via reference leaves in the resume context's tree. Cleaned up when the transition finishes.
Private Methods¶
| Return | Name | Description |
|---|---|---|
int32 |
FindContextIndex const |
Find the index of a context by name. Returns INDEX_NONE if not found. |
void |
PopActiveContextInternal |
Internal: execute a pop of the active context with optional transition. Handles the transition setup, pending destruction, and cleanup. |
FindContextIndex¶
const
int32 FindContextIndex(FName ContextName) const
Find the index of a context by name. Returns INDEX_NONE if not found.
PopActiveContextInternal¶
void PopActiveContextInternal(AComposableCameraPlayerCameraManager * PlayerCameraManager, UComposableCameraTransitionDataAsset * TransitionOverride, const FComposableCameraActivateParams & ActivationParams)
Internal: execute a pop of the active context with optional transition. Handles the transition setup, pending destruction, and cleanup.