Appearance
Loading screens and safe returns
Use Push Screen Async when a screen class is a soft reference. InterfaceForge uses Unreal's streamable manager and CommonUI stacks. It presents an honest asset-loading fraction, restores the previous interface on cancellation/failure, and prevents a late result from pushing into an ended player flow. It has no game-specific controller, inventory or Mass dependency.
The playable Outpost and Emberwatch interfaces use original layouts and artwork. Game Master's design stays exclusive to that game. Its asynchronous navigation workflow informed this feature; no reference code, widget tree, material or design was copied.
Working Blueprint recipe
Set up CommonGameViewportClient, IFNavigationInputData and keyboard Trigger Click as described in INSTALLATION.md. Create a root through the owning player's IFLocalPlayerSubsystem → Create Root.
In an IFScreen Widget Blueprint:
- From a button's On Button Base Clicked, call Get Root Layout.
- Add Push Screen Async (category InterfaceForge → Loading). Connect Root. Set Layer to Menu, HUD or Modal. Choose your IFScreen soft class reference in Screen Class. Supply its initial Data and a player-facing Title. Scope may be the controller, a retained flow object, or this screen; it is weak and optional.
- Ready supplies the initialized Screen. Perform any game-owned commit here. Failed supplies no screen and a readable Reason: show a dialog/notification and let the player retry or stay. Cancelled supplies no screen: leave the previous flow in place.
- The exposed Request output supports Cancel Loading, Get Load State, Get Load Progress, Get Loading Title, Get Loading Detail and Get Loading Screen. Do not implement one polling timer per widget.
flowchart LR
Click[On Button Base Clicked] --> Load[Push Screen Async]
Root[Get Root Layout] --> Load
Class[Soft IFScreen class + initial Data] --> Load
Load -->|Ready: Screen| Commit[Commit game-owned flow]
Load -->|Failed: Reason| Retry[Dialog: Try again / Stay here]
Load -->|Cancelled| Stay[Previous screen and focus]
Cancel[Cancel button / CommonUI Back] --> Request[Cancel Loading]
Request --> Stay
Expected result: the previous screen remains beneath a modal loading presentation. Its Cancel button gets navigation focus. A successful load pushes the supplied class and removes only its loading screen; failure/cancellation returns to the previous screen. Fast loads proceed after the required CommonUI transition, with no minimum duration or fabricated progress.
Actual saved graph: /Game/UI/Blueprint/WBP_AshenMainMenu, SettingsChoice's click → Push Screen Async, Layer Menu, soft class WBP_AshenSettings, Title “Opening settings”, Scope self. Failed → IFNotificationSubsystem → Post Notification, using Reason as Message. The saved settings screen opens its normal transaction on activation. Cancel settings restores preferences and the same menu. This graph compiles and is exercised through synthetic Slate input; see the verification record for device limits.
The menu's Begin action uses the public Request UI Action contract. Its separate Outpost/Pilgrimage adapter calls the same public async factory with the soft HUD class, and starts its demonstration state only on Ready. Failed uses the saved confirmation dialog with “Try again” / “Stay here”. This backend owns the flow commit and game data; none of it is required by the plugin. The direct Begin Expedition / Begin Journey methods are synchronous fixture/convenience paths; playable Begin navigation uses Request Begin Expedition / Request Begin Journey.
Replace the loading presentation
Create a Widget Blueprint derived from IFLoadingScreen and set it as your IFRootLayout Blueprint's Default Loading Class. No plugin source edit is needed. The saved WBP_ForgeLoading has an original centered, fitted surface, theme-aware typography/progress and the same custom WBP_ForgeActionButton as the menus. WBP_ForgeRoot and WBP_EmberRoot select it in their defaults.
For automatic binding, add optional named controls and enable Is Variable:
| Name | Type | Behavior |
|---|---|---|
| LoadingTitle | TextBlock or IFText | Public request title |
| LoadingDetail | TextBlock or IFText | Current loading/failure detail |
| LoadingProgress | IFProgressWidget | Engine asset fraction; choose Linear, Segmented or another public style |
| CancelButton | IFButton or a Blueprint child | Cancel Loading and initial navigation focus |
Use IFText/IFSurface/theme-aware progress for project typography, colors and scale. Fit/scroll the designer with ordinary ScaleBox, SizeBox, SafeZone and layout widgets. Do not hard-code a second user scale. The saved custom body and native fallback use fit-down behavior so enlarged text retains a reachable Cancel action.
For a different body, override On Loading Updated, read Get Loading Request and update your own controls. The parent event updates the optional named controls; call parent if retaining them. Your custom Cancel button calls Cancel Loading. CommonUI Back uses the same cancellation. If overriding Initialize Screen, call parent before accessing the request. The node also exposes On Loading Updated; it is a change signal, not a terminal completion.
Leaving Default Loading Class empty uses the native themed body. A custom ordinary IFScreen can instead compose a loading view with the exposed request; IFLoadingScreen is a convenience that retains Back and pointer-modal handling.
Lifetime, history and modal behavior
Only one request runs per root. A competing public request fails with a reason and leaves the current request untouched. Examples also reject repeated Begin actions while a request is pending.
The root retains the request; it registers with the game instance until one terminal output. Scope is weak; keep the scope alive elsewhere for the intended lifetime. Initial Data is retained until completion; a destroyed data actor cancels the request. The root and scope must remain valid when committing. Clearing the target layer or Modal, replacing those stacks, removing the loading screen through Remove Screen, or Remove Root cancels pending work. During clear/teardown, reentrant new requests are rejected.
Remove Screen removes the exact supplied screen without clearing unrelated history. A newer dialog can cover the loader; committing waits until the loader regains the settled foreground. Cancelling removes the loader and preserves the unrelated dialog. Close that dialog normally to return to the original menu. Do not call Deactivate Widget directly to cancel a custom loader: use Cancel Loading, CommonUI Back, or Remove Screen so the request is also ended.
Terminal status is set before removing presentation or broadcasting outputs, so repeated Cancel/Activate cannot send another completion. Loading/progress/lifetime checks use UI/core time and work while game time is paused. CommonUI owns focus restoration, routing and stack transitions; the normal input-presentation service also applies to loading screens/custom buttons.
Progress and limits
Progress measures the streamable class and its asset dependencies. Unreal can count failed assets as finished; Ready/Failed, not a value of 1, determines success. This is not map-travel, server-connection, shader compilation, download, or gameplay-generation progress. Keep those operations in their appropriate engine/game systems and supply a separate presentation adapter. This slice does not implement engine MoviePlayer pre-world loading or conceal blocking level travel behind a fake progress bar.
Soft references must be included by your cooking policy. The initial package omitted the example HUDs: native C++ path defaults did not establish cooked asset dependencies. The sample now provides /Game/UI/DA_ForgeInterfaceAssets, an engine Primary Asset Label with an explicit list of its23 owned Blueprint classes (22widgets and one world-presenter actor), Cook Rule = Always Cook, Priority1 and Apply Recursively. Its Asset Manager scan is enabled for the sample's /Game/UI directory with Is Editor Only = false; the label's Is Runtime Label is true. This policy belongs to the standalone example, not the UI plugin. It adds no broad project-wide cook directory or rule for a buyer's game.
In your project, add your own soft screens to an Asset Manager label/rules policy, or use an appropriate existing packaging policy. Configure Project Settings → Asset Manager → Primary Asset Types to Scan so labels intended to pull assets into a package are scanned with Is Editor Only=false. In the label's Explicit Blueprints, choose your screen classes and set Always Cook. Inspect your staged assets and run the packaged flow. A soft path resolving in the editor is insufficient. Unreal's asset management, cook rule and primary asset label documentation describes these engine controls.
If an asset is omitted, report Failed and give the player a return/retry route; do not start gameplay before Ready. Packaged outcomes and actual tested engine versions belong in Evidence/LOADING_RUNTIME.md. Physical controller/touch, split-screen and slow-storage stress remain distinct gates.
Unreal foundations: async action lifetime and streamable handle progress/cancellation. The implementation uses the installed engine APIs and respects CommonUI's transition lifecycle.