Available on Fab

PSO Autopilot Manual

Welcome to PSO Autopilot. This plugin is a reliable, production-ready solution to Unreal Engine 5's notorious shader compilation stutter and lag.

The "Shader Compilation" plugins on various marketplaces attempt to solve stutter by brute-forcing the Engine—loading all of your project's assets into memory simultaneously. If you are building a massive 50GB open-world game, this simplistic approach guarantees catastrophic RAM spikes, completely frozen loading screens, and eventually, Out-Of-Memory (OOM) crashes on consoles or lower-end PCs.

PSO Autopilot is different. It was created from the ground up to orchestrate Unreal's native hardware pipeline asynchronously, managing memory, threads, driver caches, and startup sequencing with architectural precision.

๐Ÿ›ก๏ธ Robust Architecture

PSO Autopilot includes built-in safeguards like Blanket Scan Protection. If you accidentally clear your target directories, the plugin instantly aborts rather than attempting to scan your entire 100GB project folder, preventing massive Editor lockups.

Key Features at a Glance

  • Memory-safe batching — flat RAM throughout the entire warmup cycle
  • Time-sliced processing — 60fps loading screens with configurable frame budget
  • Explicit warmup roots — maps, blueprints, labels, and runtime-discovered assets can be queued directly
  • Dependency expansion — recursively pulls in referenced content instead of relying on a flat directory scan alone
  • Smart fingerprint caching — skip warmup entirely on subsequent launches
  • Editor-preview bypass — leave PIE/editor preview on Unreal's normal shader compilation path unless explicitly enabled
  • Level package preload — move more first-run startup cost under the loading screen before the destination level opens
  • Visible destination-map failures — missing cooked destination packages keep the loading widget visible with an actionable error instead of silently dropping the UI
  • Startup-flow drift validation — stale loader actors are detected before packaging when Simple Setup changes
  • Texture pre-heating — standard and Virtual Texture streaming before the loading screen drops
  • Full vertex-factory coverage — Local, Nanite, ParticleSprite, BeamTrail, and MeshParticle PSOs
  • Drop-in Boot Loader — zero-code loading screen with progress bar and level transition
  • Editable loading widget templates — the wizard can create /Game/PSOAutopilot/WBP_PSOAutopilotLoadingScreen plus _Minimal and _Telemetry project-side variants
  • Blueprint-friendly delegatesOnProgressUpdated and OnWarmupComplete
  • Editor-aware — filesystem timestamps detected so you never test stale shaders
  • Validated packaged demo flow — boot-level warmup, destination-map preload, and duplicate-warmup suppression in the bundled sample

๐Ÿ–ฅ๏ธ Supported Platforms

The plugin descriptor declares its runtime module for Win64, Mac, Linux, Android, and IOS, with the editor module limited to desktop (Win64 / Mac / Linux). The new per-platform performance overrides let you tune the warmup independently for each target. Win64 is the primary desktop target used for the bundled demo and the included validation tooling, and the plugin ships as source so each engine compiles it with its own per-platform toolchain.


Latest Feature Updates

This release improves the setup experience for real projects by making the startup flow, content targeting, and packaged-build diagnostics explicit. The manual examples below match the current wizard labels and Boot Loader Details panel.

๐Ÿš€ New in 1.3.2

This build adds per-platform performance overrides, a headless coverage commandlet with a one-command CI gate, and a phase-aware ETA on the loading screen. The cards below cover the setup-experience changes; jump to Per-Platform Overrides and Coverage & CI for the new tooling.

Per-Platform Overrides 1.3.2

Replace items-per-step, frame budget, memory cleanup, and the pipeline-cache wait on a named platform (Windows, Mac, Linux, Android, IOS). Consoles and mobile can run gentler tuning than desktop from the same project.

Coverage Commandlet 1.3.2

The headless PSOAutopilotCoverage commandlet prints a per-type warmable-asset report and fails the build with a non-zero exit code when discovery drops below a -MinAssets floor.

One-Command CI Gate 1.3.2

Scripts/Run-CI.ps1 chains build → automation tests → coverage gate and fails fast, so a content or cook regression is caught before it ships.

Phase-Aware ETA 1.3.2

Get Estimated Remaining Seconds surfaces a live remaining-time estimate, driven by the real PSOs-per-second drain rate during the engine pipeline-cache flush.

Clear Startup Roles

Loading Level is the tiny boot map that runs PSO Autopilot. Level To Open After Warmup is where players go next: main menu, hub, or gameplay.

Validator Coverage Preview

The Setup Wizard previews how much warmable content your folders resolve: worlds, Blueprints, widgets, meshes, materials, VFX, and other runtime assets.

Material-Heavy Warnings

If Content to Prepare is mostly material folders, the validator warns because materials alone rarely represent the final PSO combinations players will hit.

Actionable Packaged Logs

Runtime logs now print effective warmup settings, discovery breakdowns, dependency-expansion results, and low-coverage folder/asset samples.

Startup Flow Drift Guard

The validator now checks that the placed loader still matches Simple Setup: destination level, warmup seed, preload behavior, and BeginPlay warmup.

Visible Destination Errors

If the destination map is missing from the cooked package, the loading widget stays on screen and receives a clear error instead of fading out before failed travel.

Simple Setup Cleanup

Simple Setup now saves edits immediately and clears stale hidden Advanced explicit-warmup and package-preload arrays before applying the current simple snapshot.

Packaging Log Clarity

Shader autogen lines are normal Unreal cook setup. Unloadable plugin-content assets with old package versions need project-owned replacements or a resaved plugin package.

Illustrated Startup Model

The most common confusion is treating the destination field as "the gameplay map PSO Autopilot must scan." It is not. It is the level opened after the warmup completes. The warmup set comes from Content to Prepare, explicit assets, dependency expansion, Primary Asset Labels, and runtime registrations.

1. Loading Level Small boot map with the PSO Autopilot Loader and loading widget. This should be the packaged startup map for the standard flow.
2. Startup Preparation Scans Content to Prepare, explicit roots, runtime roots, and referenced content. Preloads packages and waits for PSO backlog when configured.
3. Level To Open After Warmup Main menu, hub, or first gameplay map. This is the destination, not the whole warmup set by itself.

๐Ÿงญ Menu-First Games Are Supported

If your game must show a main menu before players choose a gameplay map, configure the destination as your main menu. A valid flow is PSO_Level → MainmenuLevel → PlayerSelectedGameplayMap. Warm the likely gameplay/menu assets through Content to Prepare, explicit warmup assets, Primary Asset Labels, or RegisterRuntimeWarmupAsset(...).

๐Ÿšฆ Custom Startup Maps Are Outside the Warmup Window

If your flow is intro movie → PSO loading level → language menu → main menu, the PSO loading level should still be the first real gameplay map after the movie handoff. If you start in a language menu, account map, or splash map before PSO Autopilot, enable Allow Custom Startup Level deliberately and keep that pre-PSO map lightweight.

What Content to Prepare Should Look Like

PSOs are built from combinations of material, mesh type, vertex factory, render pass, render state, platform, and RHI. That is why material-only folders are useful but incomplete. Prefer folders and roots that represent what the player can actually see or load near startup.

Maps Main menu, first playable maps, loading/menu worlds, first-area sublevels.
Blueprints Characters, weapons, vehicles, enemies, pickups, interactables, startup actors.
Meshes Static meshes, skeletal meshes, Nanite assets, landscape/environment folders.
UI & VFX Widgets, UI materials, Niagara systems, particles, decals, first-frame effects.
Materials Only Useful as support, but usually too narrow because it misses mesh/pass/state combinations.
Runtime Choices Use Primary Asset Labels or explicit/runtime registration for cosmetics, loadouts, or save-data choices.

Validator Preview: What It Tells You

The Setup Wizard now adds a discovery preview row to the readiness card. Use it as a first-pass sanity check before packaging.

OK Preview: Content to Prepare resolves to 184 warmable assets across 6 folder(s):
  2 worlds, 41 blueprints, 9 widgets, 73 static meshes, 11 skeletal meshes, 33 materials, 8 VFX, 7 other.

Warning Content to Prepare is material-heavy (48 material assets, only 1 map/mesh/Blueprint/widget/VFX assets).
Warning Preview only found the Level To Open seed. Your folders may not be contributing warmable assets.

โš ๏ธ Folder Count Is Not Asset Count

Adding 48 folder entries does not mean the loading screen should process 48 items. The counter advances per discovered warmable asset inside those folders. If the packaged build shows only 1, that is often just the Level To Open seed, meaning the configured folders contributed no runtime-discoverable warmup assets.

Packaged Runtime Diagnostics

Development packaged logs now include enough information to diagnose whether the packaged build actually received your intended settings and whether the cooked AssetRegistry can see your content.

LogPSOAutopilot: Warmup settings: scanDirs=6 explicitAssets=1 queuedRuntimeRoots=1 configuredPreloadPackages=1 queuedPreloadPackages=1 expandDependencies=true dependencyDepth=1 waitForPipelineCache=true minPipelinePrecompiles=20 smartSkip=true
LogPSOAutopilot: Warmup asset discovery details: scanDirs=6 directoryAssets=0 configuredExplicitRoots=1 configuredExplicitAssets=1 runtimeRoots=1 runtimeAssets=1 seedPackages=1 expandedDependencyPackages=0 dependencyAssets=0
LogPSOAutopilot: Warning: Warmup only discovered seed asset(s). PSO coverage will be limited; configured Content to Prepare folders contributed 0 assets.
LogPSOAutopilot: Warning: Warmup scan folder sample: /Game/FirstPerson/UI, /Game/FirstPerson/Materials, /Game/Waterpark

๐Ÿงฏ CrashGUID Is Not a Crash by Itself

Unreal can print a Session CrashGUID near startup even on clean exits. A real crash log usually has Fatal error, Unhandled Exception, LowLevelFatalError, an assert/ensure that terminates, CrashReportClient activity, or a call stack near the end. Clean exits usually end with RequestExit(0), LogExit: Exiting, and Log file closed.


The 11 Pillars of PSO Autopilot

Our architecture is built upon the following pillars that make it unique in the Unreal ecosystem.

USP 1: Memory-Safe Chunking

Instead of loading thousands of assets simultaneously, PSO Autopilot utilizes Unreal's FStreamableManager to asynchronously stream your assets into memory in strictly controlled batches.

Once a batch is successfully compiled by the Engine's native FShaderPipelineCache, the plugin explicitly drops all asset references and requests a non-blocking Garbage Collection pass. Your RAM footprint remains completely flat throughout the entire process.

Load Batch
Async
Compile Shaders
Time-Sliced
Drop Refs & GC
Memory Cleared

USP 2: The Seamless Loading Screen

A frozen loading screen feels like a crash to a player. PSO Autopilot uses advanced C++ time-slicing within the Game Thread's Tick function. It processes Asset Registry queries and shader assignments for a strictly allocated timeframe per frame (e.g., 5.0 milliseconds).

If the time limit is reached, it yields execution back to the Engine. This guarantees that your loading screen videos, UI spinners, and progress bars remain buttery smooth at 60fps while intense compilation happens quietly in the background.

USP 3: Broader Real-Project Coverage

PSO Autopilot no longer depends on a single flat directory scan to find what needs warming. It can combine standard scan folders with ExplicitAssetsToWarm, AdditionalClassesToScan, runtime-queued assets, and recursive package dependency expansion.

This is what allows the plugin to warm content that is only reachable through maps, actor blueprints, soft references, Primary Asset Labels, or inherited component templates instead of missing those assets and hitching later during gameplay.

USP 4: Zero-Redundancy Boot (Smart Cache Hashing)

Players shouldn't have to wait for shaders they've already compiled. When a player boots your game for the second time, PSO Autopilot intelligently checks its generated MD5 fingerprint against the local config.

If the Pipeline State Objects (PSOs) for your project are already fully digested and stored on the user's hard drive, the plugin instantly skips the entire warmup sequence. A process that took two minutes on the first launch will take 0.05 seconds on all subsequent launches.

Current builds also handle fresh editor restarts correctly: a matched fingerprint skips the asset warmup immediately instead of being forced back into a full pass by a temporary pipeline-cache backlog.

Honest skip gates. The asset-set fingerprint can't directly observe GPU driver state, so the skip path is guarded by two safeguards. If the engine was launched with -clearPSODriverCache (or -clearShaderCache), Smart Skip is bypassed for that run; the driver's PSO cache is gone and the warmup must repopulate it. A second strict-mode check — Require Empty Precompile Queue under Advanced > Smart Skip — can also bypass Smart Skip whenever the engine still has PSOs pending compile, covering driver updates, fresh installs on new GPUs, and similar cases. Strict mode is off by default because on a healthy repeat boot the engine briefly has PSOs queued while it loads .upipelinecache (they compile near-instantly against the warm driver cache); enabling strict mode would treat that window as "cold" and flash the loading UI on every boot. Turn it on for extra defense at the cost of occasional false positives. The log line Smart cache skip not used. ... DriverCacheClearedFlag=true PrecompileQueueBlocks=... shows which gate fired.

โฑ๏ธ Editor Timestamping

During development (WITH_EDITOR), the Smart Cache hashing algorithm actually interrogates the physical filesystem modification timestamps of your materials. If you tweak a Material Graph and save it, PSO Autopilot detects the change and bypasses the cache skip, ensuring you never test with stale shaders.

USP 5: First-Run Startup Cost Shift

For projects where the worst hitch happens in the first seconds after launching gameplay, PSO Autopilot can now push more work into a controlled loading phase. A Boot Loader can register the destination map as a warmup seed, expand its dependency graph, and preload the target package before travel begins.

This does not make Unreal's level transition free, but it moves more first-run cost under the loading screen instead of letting it land on the player's first interactive frames. The bundled boot-flow sample also carries a handoff flag so the gameplay map does not accidentally start a second warmup pass.

USP 6: Visual Continuity (Texture Pre-Heating)

Solving shader stutter is only half the battle. If your textures and virtual landscapes pop in blurry after the loading screen drops, the immersion is still broken.

Because PSO Autopilot already safely loads your materials into memory, it now automatically interrogates them for their texture dependencies. It seamlessly issues high-priority streaming requests for standard Textures (forcing high-res Mips) and pre-pages Virtual Textures (RVT/SVT) directly into VRAM before allowing the loading screen to finish.

USP 7: True Autopilot (Adaptive Frame Pacing)

The plugin acts as a dynamic governor. It monitors real-time Game Thread and Render Thread execution times, automatically expanding the PSO budget on high-end hardware (like an RTX 4090) and aggressively throttling it down on constrained hardware (like a Steam Deck) to guarantee a buttery-smooth loading screen automatically.

USP 8: AAA Cinematic Handoff

Hide compilation seamlessly behind unskippable studio logos or intro cinematics (.mp4 files) using the new CinematicBootLoader. It orchestrates perfect timing handoffs: enabling a "Press Any Key to Skip" prompt if compilation finishes early, or crossfading to a fallback UI spinner if compilation outlasts the video.

USP 9: Spatial / World Partition Warmup

Eliminate traversal stutter in open-world games. Attach the PSOAutopilotSpatialComponent to your Player Pawn to scan the environment using an async radius sweep, automatically queueing upcoming actors for JIT warmup before the player reaches them.

USP 10: Just-In-Time (JIT) Micro-Warmups

Need to spawn a massive boss mid-game without freezing? The new Blueprint node Warmup Actor Class (Time-Sliced) allows surgical, non-blocking shader compilation during active gameplay.

USP 11: The "Bloat Finder" Profiler Dashboard

Instantly identify unoptimized materials. The plugin tracks the exact number of PSOs generated by each asset during validation runs. Open Window > Tools > PSO Autopilot Bloat Profiler to view a live, sortable dashboard of the "Top 10 Heaviest Assets" bottlenecking your startup time.


Quick Start Guide (Setup Wizard)

We've introduced a powerful Setup Wizard to make integration effortless. It includes a project-aware preflight validator, one-click simple setup, and an automatic readiness card with instant fix buttons. The wizard header shows the installed plugin version (for example PSO Autopilot v1.3.2) so you can confirm which build you are running.

  1. Open Unreal Engine, then go to Window > PSO Autopilot Startup Setup.
  2. In Simple Setup, choose your Loading Level, Level To Open After Warmup, Loading Widget, Content to Prepare, and a Performance Preset. Leave the Loading Level empty to let the wizard create one at /Game/PSOAutopilot/PSOAutopilot_Loading, or point it at an existing world asset. For the loading screen, the easiest editable path is the wizard-created template widget at /Game/PSOAutopilot/WBP_PSOAutopilotLoadingScreen (with _Minimal and _Telemetry sibling variants).
  3. Leave Editor Iteration Mode set to Use Unreal Editor Compilation for normal PIE iteration. Switch it to Run PSO Autopilot Warmup only when you specifically want to test the full startup warmup in editor preview.
  4. Click Validate PSO Autopilot Setup. The Wizard's Project-Aware Preflight Validator will scan your active project.
  5. Review the Automatic Readiness Card. It displays color-coded results (Green/Yellow/Red) for your setup.
  6. Use the inline Fix buttons to instantly resolve issues. Current builds add targeted cook folders, avoid adding the whole /Game root, can remove a stale root cook directory when detected, and can generate the editable loading-widget templates automatically.
  7. Click Create/Update Startup Flow to generate your loading level and drop in the PSO Autopilot Boot Loader automatically. Run it again whenever you change Loading Level, Level To Open After Warmup, Content to Prepare, preload flags, or startup behavior; the loading map stores a serialized loader actor and must be kept in sync.

๐Ÿ—‚๏ธ About the /Game/ path prefix

Throughout the wizard you will see paths like /Game/PSOAutopilot/PSOAutopilot_Loading. /Game/ is Unreal's name for your project's Content/ folder; it is not a literal folder named "Game". In the Content Browser sidebar, click the Content node (under All) to navigate there. The PSOAutopilot subfolder is created the moment you click one of the wizard's Create fix buttons; on a fresh install the path is just a default the wizard intends to create.

๐Ÿงช Editor Play Uses Unreal's Default Path by Default

With Editor Iteration Mode set to Use Unreal Editor Compilation, pressing Play in the editor immediately completes the PSO Autopilot flow and lets Unreal compile shaders normally for that PIE session. Packaged builds, Standalone Game, and -game validation still use the production warmup path.

โšก Minimum Viable Integration

The simplest Blueprint integration is Start PSO Autopilot Loading Flow. It registers Level To Open After Warmup, queues the level package to load before play, shows the loading widget, starts preparation, releases the retained preload, and opens the destination level.

๐Ÿงญ Recommended Production Flow

The best current integration is a dedicated loading level that prepares and loads Level To Open After Warmup before travel. This is the same flow used by the bundled /Game/Demo/Demo_BootFlow sample.

For the standard Simple Setup flow, the wizard now writes both GameDefaultMap and EditorStartupMap to the selected loading level. If Allow Custom Startup Level is off, a different startup map is a blocking validator error.

๐ŸŽจ Choose Your Loading Widget Path

Fastest editable route: use the wizard-created template widgets. They are normal project-owned UMG assets and no longer get runtime layout injected into the Designer tree.

Zero-design fallback: assign the exact native UPSOAutopilotLoadingScreenWidget class if you want the stock procedural loading screen.

Full control: use any UserWidget that implements PSOAutopilotLoadingScreenReceiver, or bind to the subsystem delegates manually if you want your own widget architecture.


Configuration Settings

PSO Autopilot exposes powerful variables to Project Settings > Plugins > PSO Autopilot so you can tailor the memory/performance balance precisely to your hardware targets. All settings are stored in DefaultGame.ini under [/Script/PSOAutopilot.PSOAutopilotSettings].

Targeting

SettingDefaultDescription
DirectoriesToScan (empty) Array of content directories to recursively scan (e.g., /Game/Weapons, /Game/VFX). Do not set to /Game/ alone in large projects—isolate your heavy visual folders. Can be left empty if you are relying entirely on ExplicitAssetsToWarm.
AdditionalClassesToScan (empty) By default the plugin scans for UMaterialInterface. Add extra asset classes here when your warmable content is rooted in other asset types (for example actor blueprints or custom asset classes that reference primitive components and materials).
ExplicitAssetsToWarm (empty) Explicit root assets to include even if they are not found by the directory scan. Use this for maps, actor blueprints, Primary Asset Labels, or any special startup assets that should seed the warmup graph.

โš ๏ธ Avoid Empty Path Entries

If your DefaultGame.ini contains +DirectoriesToScan=(Path=""), the empty string causes the Asset Registry filter to return zero results even when valid paths are also present. Remove any blank entries.

๐Ÿ“ฆ Do Not Always Cook the Whole Project

Use targeted warmup folders and targeted cook directories. Adding +DirectoriesToAlwaysCook=(Path="/Game") forces Unreal to cook the entire project and can make every package attempt look like a full recook after restart. The setup wizard now avoids adding that root entry and the validator can remove it when found.

๐ŸŽฏ What Content to Prepare Should Contain

Content to Prepare should point at runtime content that represents what players can see or load near startup: maps, menu/UI widgets, actor Blueprints, static meshes, skeletal meshes, VFX, environment folders, UI materials, and the material folders used by those assets.

Material folders alone are usually not enough because a PSO is the combination of material, mesh type, vertex factory, render state, render pass, platform, and RHI. If the validator says your setup is material-heavy, add the maps, meshes, Blueprints, widgets, and VFX that use those materials.

Coverage & Startup Cost Shift

SettingDefaultDescription
bExpandPackageDependencies true Recursively expands package dependencies from the discovered seed assets so maps, blueprints, labels, and other roots can pull in their referenced warmable content.
DependencyExpansionDepth 1 How many dependency hops to traverse beyond the original seed set. Increase this when a single map or blueprint leads to deeper chains of referenced warmable assets.
bIncludeSoftPackageReferences true Includes soft package references during dependency expansion so softly referenced content can be discovered before gameplay touches it.
bIncludeManagementReferences true Includes asset-manager and Primary Asset Label management references during dependency expansion.
PackagesToPreload (empty) Optional packages or assets to asynchronously preload before warmup completes. Use this to move more first-run map and package load cost under the loading screen.

Memory Management

SettingDefaultDescription
BatchSize 100 Number of assets loaded per batch. Lower to 50 for low-RAM targets (consoles, mobile). Higher values are faster but increase peak memory.
bGarbageCollectBetweenBatches true Request a GC pass after every batch is unloaded. Leave enabled for stable RAM. Disable only if warmup speed matters more than memory.

Performance (Seamless UI)

SettingDefaultDescription
MaxProcessingTimeMsPerFrame 5.0 Time budget (ms) for PSO processing per game-thread tick. A 60fps frame is 16.6ms—leaving 5ms gives the Engine 11.6ms for UI rendering. Increase up to ~10ms for faster warmup at the cost of choppier loading animations.

Per-Platform Performance Overrides 1.3.2

One project usually ships to very different hardware. A 32 GB desktop can afford a big batch size and frame budget; a console or phone wants gentler tuning so the loading screen stays smooth and memory stays flat. Instead of forking settings per platform, add a Per-Platform Performance Override under Advanced > Per-Platform. When the game runs on the named platform, its values are overlaid onto the effective warmup tuning before the run starts.

Base Tuning Project Settings > Performance Items / Step     100 Frame Budget   5.0 ms GC Between     On Min PSO Queue  50 + Override: Android Enabled • platform name matches Items / Step     50 Frame Budget   3.0 ms GC Between     Off Min PSO Queue  20 = Effective on Android What the warmup actually uses Items / Step     50 Frame Budget   3.0 ms GC Between     Off Min PSO Queue  20

Each entry is matched case-insensitively against the running platform's ini name. Overlay rules are deliberately strict so nothing changes by accident:

Enabled + matchesThe override's values replace the effective tuning on that platform.
DisabledIgnored entirely — keep a tuned override on the shelf without applying it.
Name doesn't matchIgnored — e.g. a Windows run skips an Android override and keeps Base Tuning.
FieldDefaultDescription
PlatformIniName (empty) Platform this override targets: Windows, Mac, Linux, Android, or IOS. Matched case-insensitively against the running platform.
bEnabled true When false the entry is skipped, so you can keep a configured override without applying it.
BatchSize (Items Per Step) 100 Content items loaded per step on this platform. Lower it on memory-constrained targets. Clamped 10–1000.
MaxProcessingTimeMsPerFrame 5.0 Per-frame game-thread budget (ms) for preparation on this platform. Clamped 0.5–33.0.
bGarbageCollectBetweenBatches true Whether to clean memory between steps on this platform.
MinPipelinePrecompilesToWait 50 Minimum engine pipeline-cache backlog that triggers the final wait on this platform. Clamped 0–100000.
MaxPipelineCacheWaitSeconds 120.0 Safety timeout for the engine pipeline-cache wait on this platform. Clamped 1.0–600.0.

๐Ÿงฌ Where the Overlay Happens

The override is applied while the runtime warmup snapshot is captured (the same place Simple-mode tuning is resolved), so it composes cleanly with presets and Simple Setup. It only touches the six performance fields above — content targeting, dependency expansion, and texture pre-heating are unchanged. A disabled or non-matching override is a no-op, so it is safe to leave platform entries configured for builds you are not currently making.

Editor Preview

SettingDefaultDescription
EditorIterationMode
SimpleEditorIterationMode
Use Unreal Editor Compilation Controls whether PSO Autopilot runs during PIE/editor preview. Use Unreal Editor Compilation is recommended for normal iteration and bypasses PSO Autopilot in editor Play. Run PSO Autopilot Warmup runs the full loading flow inside editor preview for validation. Packaged builds are unaffected by this editor-only mode. Legacy config keys bEnableInEditorPreview and bSimpleEnableInEditorPreview remain supported.

Visual Continuity (VRAM)

SettingDefaultDescription
bPreHeatTextureStreaming true Forces standard textures referenced by scanned materials to load their high-resolution mip levels into VRAM during the warmup cycle.
bPreHeatVirtualTextures true Sends predictive page-in requests for Virtual Textures (RVT/SVT) to prevent grey blocks on world load.

Validation & Minimum Duration

SettingDefaultDescription
bEnforceMinimumValidationDuration false When enabled, keeps the warmup in a hold state for a configurable time after all batches finish. Useful for stress-testing or demos where you want to observe the validation phase.
MinimumValidationDurationSeconds 0.0 The minimum total warmup duration in seconds (only applies when enforcement is enabled).
bAllowCustomStartupLevel false Suppresses the warning when the packaged project startup map is not the PSO Autopilot Loading Level. This does not run PSO Autopilot in that custom startup map and does not protect content shown before the loading level opens.

๐Ÿšฆ Allow Custom Startup Level Is a Risk Acknowledgement

Leave this off for the standard flow. Turn it on only when you intentionally show a lightweight language picker, account/login map, splash screen, or launcher handoff before PSO Autopilot. It only suppresses the startup-map validator error; it does not make PSO Autopilot run inside that earlier map.

If logs show PSO hitches before LogPSOAutopilot: Starting PSO Autopilot Warmup..., those hitches happened before the plugin had control. Move shader-heavy UI, meshes, materials, and animation into the PSO loading flow or keep the pre-PSO map minimal.


Coverage & CI 1.3.2

The Setup Wizard's discovery preview is great for interactive checks, but teams also want a headless, scriptable way to prove the warmup set is still healthy — so a content move, a renamed folder, or a cook-settings slip fails a build instead of quietly shipping a near-empty warmup. PSO Autopilot 1.3.2 adds a coverage commandlet and a one-command CI gate for exactly that.

The Coverage Commandlet

Run the PSOAutopilotCoverage commandlet from any installed engine. It resolves the configured warmup content through the asset registry, prints a per-type coverage report, and returns a non-zero exit code when the discovered asset count is below the -MinAssets floor — turning a content/cook regression into a red build.

UnrealEditor-Cmd.exe MyProject.uproject -run=PSOAutopilotCoverage -MinAssets=900

It reads the same Content to Prepare / Content Folders the runtime warmup uses (Simple or Advanced mode), so the report reflects what would actually be warmed. A passing run looks like this:

===== PSO Autopilot Coverage Report =====
Setup mode: Advanced
Folders scanned (1):
    /Game/DemoMaterials
Assets by type:
    MaterialInstanceConstant    1000
    Material                         1
Total unique warmable assets: 1001 (worlds/maps: 0)
=====================================
OK Coverage gate passed (1001 >= required 900). → exit 0

Drop the floor below what the project should resolve and the gate fails loudly with a non-zero exit code CI can detect:

Error Coverage gate FAILED: 1001 discovered assets is below the required minimum of 5000.
Commandlet->Main return this error code: 1exit 1

The One-Command CI Gate

For a complete pre-flight, Scripts/Run-CI.ps1 chains the three stages below and fails fast on the first one that fails, so the same script works locally before a commit or inside a CI runner.

1 · Build compile plugin (Rocket) 2 · Automation Tests PSOAutopilot.* · NullRHI 3 · Coverage Gate -MinAssets=N ✓  all pass → exit 0 ✗  any fail → exit 1 Stops at the first failed stage — no false-green from a stage that silently ran nothing.
# Full gate with the default coverage floor
.\Scripts\Run-CI.ps1 -MinAssets 900

# Reuse current binaries / skip stages while iterating
.\Scripts\Run-CI.ps1 -SkipBuild
.\Scripts\Run-CI.ps1 -TestFilter PSOAutopilot.Settings

๐Ÿ›ก๏ธ A Content-Regression Guard

Pick a -MinAssets floor a little under what your project should resolve today. If someone moves a content root, renames a folder, or drops it from the cook list, the discovered count craters and the gate turns red — before the build ships with a near-empty warmup. The commandlet's dedup/counting/threshold logic is itself unit-tested, so the gate you rely on is covered too.

๐Ÿ“ฆ Note on Distribution

The commandlet and CI script are development and validation tooling. They run against the editor/commandlet target; nothing here is required at runtime or shipped into a packaged game.


State Machine

Understanding the internal state machine helps you diagnose issues and integrate custom UI. PSO Autopilot transitions through these states sequentially:

Idle
Scanning
Fingerprinting
Preloading Packages
Loading Batch
Processing Batch
Streaming Textures
Unloading Batch
Waiting For GC
Delay Minimum Duration
Compiling Pipeline Cache
Finished

After scanning and fingerprinting, PSO Autopilot can optionally enter Preloading Packages before the first batch begins. The loop from Loading Batch through Waiting For GC then repeats for each chunk of assets. An optional Delay Minimum Duration demo hold can follow. Before completing, the machine can enter Compiling Pipeline Cache (the FlushingPipelineCache state) to keep the loading screen visible while the engine drains its remaining PSO backlog — this is the 0.95 → 1.00 progress band and where the phase-aware ETA reads the real PSOs-per-second drain rate. It then reaches Finished, fires OnWarmupComplete, persists the fingerprint when the run succeeded cleanly, and returns to Idle.

Editor Preview Bypass

When Editor Iteration Mode is set to Use Unreal Editor Compilation and the world is PIE, Editor, Editor Preview, or Game Preview, StartWarmup() completes immediately before calling FShaderPipelineCache::ResumeBatching(). This keeps normal editor Play sessions on Unreal's built-in shader compilation behavior while preserving the full PSO Autopilot path for packaged/runtime validation.

Batch Loop Details

Scanning — waits for the Asset Registry to be ready, then builds the warmup list from scan directories, explicit roots, runtime-queued roots, classes, and optional dependency expansion.

Fingerprinting — hashes the final discovered asset set plus key settings so cache-skip decisions reflect the real startup workload.

Preloading Packages — asynchronously loads any queued gameplay packages before the loading screen is allowed to finish.

Loading Batch — Uses FStreamableManager::RequestAsyncLoad to stream assets without blocking the game thread. A 60-second watchdog timer protects against stuck loads.

Processing Batch — Time-sliced PSO precaching via PrecachePSOs(). Covers Local, Nanite, ParticleSprite, BeamTrail, and MeshParticle vertex factories.

Streaming Textures — Calls SetForceMipLevelsToBeResident() on standard textures and UpdateResource() on Virtual Textures. A 30-second timeout prevents indefinite waits.

Unloading Batch — Releases all FStreamableHandle references and clears temporary component arrays.

Waiting For GC — If enabled, requests a full-purge Garbage Collection to reclaim memory before the next batch.

Delay Minimum Duration — optional demo hold state that keeps the loading UI visible for a minimum total runtime.

Compiling Pipeline Cache — optional final wait that holds the loading screen while the engine's FShaderPipelineCache drains its remaining PSO backlog. Only entered when the backlog exceeds Min PSO Queue To Wait, and bounded by Max Wait Seconds. The progress bar advances across the 0.95 → 1.00 band from the real compiled-vs-discovered PSO ratio.


UI & Blueprint Integration

The PSOAutopilotSubsystem provides robust Blueprint delegates and a drop-in loading screen actor to drive your UI.

PSO Autopilot Loader Actor Recommended

The APSOAutopilotBootLoader is the fastest way to add startup preparation to your game. Drop the PSO Autopilot Loader into your starting level (or, preferably, a dedicated loading level) and configure it from the Details panel—no C++ or Blueprint graph is required.

In the current sample flow, the loader can prepare the destination level before opening it, queue additional content, preload the destination package before travel, and then open Level To Open After Warmup only after startup preparation is complete.

PropertyDescription
Loading WidgetWidget class shown while PSO Autopilot prepares startup content. Use the wizard-created editable templates at /Game/PSOAutopilot/WBP_PSOAutopilotLoadingScreen plus _Minimal and _Telemetry, any branded UserWidget that implements PSOAutopilotLoadingScreenReceiver, or the exact native UPSOAutopilotLoadingScreenWidget if you want the stock fallback layout.
Level To Open After WarmupLevel opened after startup preparation finishes. This can be your main menu, hub, or first gameplay map.
Auto Open LevelAutomatically opens the level when warmup finishes. If false, you must handle the transition via the On Startup Preparation Finished event. Starting in 1.2.1, when this is off the loading widget is also left in the viewport so a Blueprint confirm-button flow can run without losing the widget — call Dismiss Loading Widget to tear it down. Useful when integrating with third-party async loading screen plugins.
Warm Level To Open Before OpeningIncludes Level To Open After Warmup as a warmup seed so referenced content can be prepared before the destination opens. Recommended: On.
Preload Level To Open PackageLoads the Level To Open After Warmup package before startup preparation completes so more first-run level-load cost happens under the loading widget. Recommended: On.
Auto StartAutomatically starts startup preparation when this loader begins play. Recommended: On.
Remove Loading Widget When ReadyRemoves the loading widget when startup preparation completes and the destination package has been verified. Ignored when Auto Open Level is off — in that case the widget stays so the Blueprint can drive the rest of the flow. Recommended: On.
Dismiss Loading Widget 1.2.1BlueprintCallable function on the loader. Call from your custom flow (e.g. after a confirm-button click) to remove the loading widget from the viewport without relying on a level transition to clear it.
Advanced ContentOptional specific content to prepare or load before play when important startup content is not reachable from Level To Open After Warmup.
Advanced OverridesPer-loader tuning for content folders, item count, and frame budget. Recommended: leave off unless this loader needs different behavior from Project Settings.
Debug / DemoDemo hold and force-run controls. Recommended: Off for shipped games.

๐Ÿ›Ž๏ธ Confirm-Button Flow Pattern 1.2.1

To show a "Press Start" or "Click to Continue" prompt after warmup completes instead of auto-opening Level To Open After Warmup:

  1. On the Boot Loader actor, uncheck Auto Open Level. (Leave Remove Loading Widget When Ready at its default; it is ignored while Auto Open Level is off.)
  2. In the loading widget, hide the confirm button by default and reveal it on the loader's On Startup Preparation Finished event.
  3. On the button's click handler, call Open Level (by Name) with your target map. Optionally call the loader's Dismiss Loading Widget function before the transition if you want the widget gone before the new level streams in.

Before 1.2.1 the widget was always removed at warmup-complete regardless of Auto Open Level, which broke this pattern in packaged builds (and silently broke it on the second run when smart-cache-skip completed warmup in the same frame the widget was created). 1.2.1 keeps the widget alive whenever Auto Open Level is off so Blueprint owns the rest of the flow cleanly.

๐Ÿ”„ Settings Snapshot & Restore

When bApplySettingsOverride is enabled, the PSO Autopilot Loader captures a snapshot of your Project Settings before applying overrides. The original values are automatically restored when startup preparation completes or when the actor is destroyed, so your runtime settings are never permanently altered.

๐Ÿ›ฃ๏ธ Boot-Flow Handoff

The bundled demo carries a travel option from the boot map to the gameplay map so the destination demo manager can intentionally skip a duplicate warmup pass. If you build your own boot-to-gameplay flow, follow the same rule: do not call StartWarmup() again on the destination map if the boot flow already completed the work.

One-Node Blueprint Flow

Use Start PSO Autopilot Loading Flow when you want the recommended Stage Zero-style Blueprint entry point without wiring every subsystem call manually.

InputDescription
Level To Open After WarmupDestination level to prepare, optionally preload, and open after startup preparation completes. This can be a main menu, hub, or gameplay map.
Loading WidgetWidget class shown during startup preparation. Use the wizard-created template widgets, any UserWidget that implements PSOAutopilotLoadingScreenReceiver, or the exact native fallback widget if you want the stock generated layout.
Warm Level To Open Before OpeningRegisters the destination level as content to prepare. Recommended: On.
Preload Level To Open PackageLoads the destination level package before travel so more first-run load cost happens under the loading widget. Recommended: On.
Remove Loading Widget When ReadyRemoves the loading widget before opening the destination level, after the destination package existence check passes. Recommended: On.
Ignore Previous RunsForces preparation even when smart skip would normally skip it. Recommended: Off outside testing.

One-Node Destination Guard

The one-node flow now checks that Level To Open After Warmup exists before cleanup and travel. If the destination is missing from the cooked build, the loading widget remains visible, receives a terminal error, and the log points to Packaging maps/cook settings.

Delegates

On Progress Updated

Fires continuously during startup preparation.

Overall Progress (Float): A normalized 0.0 to 1.0 value representing the total completion percentage. Bind this directly to a UMG ProgressBar.

Progress bands. The single 0.0–1.0 value is mapped into three sequential sub-bands so the bar stays meaningful end-to-end:

  • 0.00 → 0.85 — asset warmup (load + PSO precache batches).
  • 0.85 → 0.95 — Level To Open package preload (formerly a hardcoded 100%).
  • 0.95 → 1.00 — engine pipeline cache draining (the FlushingPipelineCache state). Only runs when there is real backlog. After -clearPSODriverCache, a driver update, or a fresh GPU install, this slice keeps the loading screen visible while Unreal compiles the remaining PSOs — instead of handing off to OpenLevel while pipelines are still compiling.

Current Status Message (String): Friendly live status text for the loading screen. Messages include: Finding startup assets..., Checking previous warmup..., Loading assets in safe batches..., Preparing shaders..., Preparing textures..., Preloading gameplay map... / destination package preload, and Ready.

Technical Status Message (String): Optional telemetry text available through Get Technical Status Message. Use it in a collapsible debug or telemetry panel when you want details like cache fingerprinting, batch counts, PSO task counts, package names, texture streaming counts, or the engine pipeline cache flush progress (e.g., Compiling engine pipeline cache: N of M PSOs remaining, X.Xs elapsed.).

ETA helpers. Two BlueprintPure getters let you surface a remaining-seconds estimate alongside the progress bar:

  • Get Estimated Remaining Seconds — returns a float. Negative values mean "no estimate yet" (very early in the run, idle, or right after a Smart Skip) so the ETA label can hide cleanly.
  • Has Estimated Remaining Seconds — convenience boolean for the visibility binding.

The estimator is phase-aware: during the engine pipeline cache flush it uses the real PSOs-per-second drain rate from FShaderPipelineCache; during the asset and preload phases it falls back to linear extrapolation from the current progress fraction. Values are cached internally for 0.25 s so a tick-bound widget binding does not jitter.

On Startup Preparation Complete

Fires exactly once when the entire process is finished or skipped because the content was already prepared. Bind this event to close your loading screen and transition to gameplay.

Custom UMG Widgets

PSO Autopilot now supports three clean loading-widget paths. Pick the lightest one that matches how much control you need.

PathBest ForHow It Behaves
Wizard Template
UPSOAutopilotEditableLoadingScreenWidget
You want a normal project-owned UMG asset that you can edit freely in the Designer.The plugin updates optional named widgets if they exist. Nothing is procedurally added to the widget tree at runtime.
Native Fallback
UPSOAutopilotLoadingScreenWidget
You want a zero-design stock loading screen and do not care about editing the layout in UMG.The exact native class procedurally builds the bundled dark-mode progress layout and updates it automatically.
Fully Custom
UserWidget + interface or delegates
You want complete branding freedom, your own graph architecture, or a non-template widget hierarchy.The Boot Loader and one-node flow auto-call PSOAutopilotLoadingScreenReceiver. Manual delegate binding still works when you want total control.

โœ‚๏ธ Editing the Wizard Widget Is Safe Now

You can keep only the progress bar and status text, delete the timer / spinner / summary widgets, and add your own layout around them. Current wizard templates do not require hidden dummy widgets to prevent a fallback rebuild.

๐Ÿงฉ Optional Named Bindings for Template Widgets

If a widget exists with one of these exact variable names, PSO Autopilot updates it automatically. If it does not exist, nothing breaks; that part of the UI is simply skipped.

Variable NameWidget TypeAuto-Updated With
WarmupProgressBarProgressBarOverall progress percent.
WarmupStatusTextTextBlockFriendly player-facing status text.
WarmupProgressSummaryTextTextBlockPhase-aware summary text such as asset counts, package preload counts, or PSO counts.
WarmupTimerTextTextBlockElapsed seconds.
SpinnerImageImageRotation and pulse animation.
WarmupTelemetryPanelBorderShow / hide state for the optional technical panel.
WarmupTelemetryTextTextBlockTechnical status / telemetry text.

Important: keep Is Variable enabled and preserve the exact variable name for any widget you want updated automatically.

๐Ÿง  Interface Contract for Fully Custom Widgets

If your widget implements PSOAutopilotLoadingScreenReceiver, the built-in flows call these functions automatically:

  • Apply Loading Progress — overall progress and friendly status text.
  • Apply Loading Progress Summary — phase-aware summary label under the bar.
  • Apply Loading Technical Status — optional telemetry / debug detail.
  • Apply Loading Telemetry Visibility — whether the technical panel should be visible.

This is the cleanest path when you already have your own loading-screen widget architecture and do not want to use the named-binding template base.

๐Ÿงฐ Ready-Made Templates

Use Tools > PSO Autopilot > Create/Open Loading Widget Templates or run Scripts/CreateEditableLoadingWidget.py to generate the default, minimal, and telemetry Widget Blueprint templates under /Game/PSOAutopilot. Each template includes a populated Designer tree and an editable Event Graph seeded with the expected parent calls.

Blueprint-Driven Loading Screen

You can also use the subsystem directly from any Blueprint. Get the subsystem reference, bind to OnProgressUpdated and OnWarmupComplete, then call StartWarmup(). This gives you complete control over when and how startup preparation runs.

// Blueprint pseudo-code
GameInstance -> GetSubsystem(PSOAutopilotSubsystem) -> subsystem
subsystem -> BindEvent(OnProgressUpdated) -> UpdateMyProgressBar
subsystem -> BindEvent(OnWarmupComplete) -> OpenLevel("MainMenu")
subsystem -> StartWarmup()

If you prefer the one-node flow or Boot Loader, keep this same widget but implement PSOAutopilotLoadingScreenReceiver so those built-in flows can push progress updates into it automatically.


Fingerprint & Caching

PSO Autopilot uses an MD5 fingerprint to determine whether warmup needs to run. Understanding this system helps avoid unnecessary re-warmups and diagnose cache-related issues.

How the Fingerprint Works

  1. Discovery: After scanning directories, explicit roots, class roots, runtime-queued roots, and optional dependency expansion, the plugin generates a fingerprint string from the final discovered asset set.
  2. Editor timestamps: In WITH_EDITOR builds, filesystem modification timestamps of source materials are mixed into the hash. This means saving a material automatically invalidates the cache.
  3. Settings participation: Dependency-expansion settings and engine version are mixed into the fingerprint so cache-skip decisions reflect the real startup configuration, not just the root paths.
  4. MD5 hashing: The fingerprint string is hashed to produce a compact, deterministic identifier.
  5. Cache check: On startup, the plugin compares this fingerprint against previously completed fingerprints stored in Saved/PSOAutopilotCache.ini.
  6. Skip or run: If the fingerprint matches a cached entry, the asset warmup is skipped and OnWarmupComplete fires immediately. This remains true after an Unreal restart even if the engine reports a temporary fresh-process pipeline-cache backlog.

Multi-Configuration Cache

PSO Autopilot stores up to 8 completed fingerprints simultaneously using an LRU (Least Recently Used) eviction policy. This means:

  • Different Boot Loaders scanning different directories won't invalidate each other's caches.
  • Switching between build configurations preserves prior warmup results.
  • When the 9th unique fingerprint completes, the oldest entry is evicted.

Cache Storage Location

Fingerprints are stored in Saved/PSOAutopilotCache.ini under the [PSOAutopilot] section as a comma-separated list in the CompletedFingerprints key. Current builds also read legacy cache entries from GameUserSettings.ini once, migrate them into the dedicated cache file, and then continue using PSOAutopilotCache.ini.

๐Ÿ—‚๏ธ Why the Dedicated Cache File Matters

Packaged Smart Cache persistence no longer depends on Unreal flushing GameUserSettings.ini. This makes repeat-launch cache hits much more reliable, especially in packaged builds where user-settings churn or crashes could previously wipe the warmup fingerprint.

Matched Cache Runs Complete Immediately

Smart-cache hits bypass asset loading, package preload, and demo minimum-duration holds. If a loader previously had debug flags such as bResetFingerprintOnBeginPlay enabled, re-running the setup wizard clears stale simple-setup debug overrides so cached launches do not accidentally become cold launches again.

โš ๏ธ ResetCachedWarmupFingerprint

Calling ResetCachedWarmupFingerprint() on the subsystem clears all cached fingerprints. The Boot Loader exposes this via the bResetFingerprintOnBeginPlay checkbox. Use it during development when you want to guarantee the warmup runs.

๐Ÿงช Fingerprints Are Only Stored for Clean Runs

If the warmup finishes with asset-load failures or package-preload failures, PSO Autopilot intentionally does not persist the fingerprint. This prevents a partially successful startup run from being incorrectly treated as fully cached on the next launch.


Marketplace Demo

PSO Autopilot now ships with a buyer-facing startup flow instead of requiring manual demo construction. The bundled content includes:

  • /Game/Demo/Demo_BootFlow — boot map and default project startup map
  • /Game/Demo/UI/WBP_LoadingScreen — loading screen used while startup content is prepared
  • /Game/Demo/Demo_PSOTorture — gameplay map opened after preparation
  • /Game/Demo/BP_BootLoader — placed PSO Autopilot Loader actor sample
  • /Game/Demo/UI/BP_PSOAutopilot_HUD — gameplay telemetry overlay with cold/cached run controls
  • /Game/DemoMaterials — 1000 material-instance stress assets

Demo Story

  1. If needed, regenerate the sample assets with Scripts/CreatePSOAutopilotDemo.py using Unreal's -ExecutePythonScript argument.
  2. Open /Game/Demo/Demo_BootFlow.
  3. Press Play, preferably in Standalone Game for behavior closest to runtime.
  4. The boot map shows WBP_LoadingScreen, warms /Game/DemoMaterials, preloads the gameplay map, and then opens /Game/Demo/Demo_PSOTorture.
  5. The gameplay map detects the boot-flow handoff and skips duplicate preparation, so you only pay the startup cost once.
  6. The small telemetry overlay lets you run a cold pass and then a cached pass. Cached passes clearly report Warmup skipped because cache matched.

Packaged Smoke-Test Proof

A live packaged smoke test warmed 1001 startup assets, preloaded /Game/Demo/Demo_PSOTorture during the loading screen, released the retained preload before travel, opened the gameplay map, and skipped the duplicate warmup on the destination map.

Packaged-Build Checklist

  1. Use /Game/Demo/Demo_BootFlow as GameDefaultMap.
  2. Add /Game/Demo/Demo_BootFlow and /Game/Demo/Demo_PSOTorture to the packaged maps list.
  3. Always cook /Game/Demo and /Game/DemoMaterials.
  4. Package a Development build with logs when evaluating the demo overlay; package Shipping when validating the production loader path.
  5. Launch the packaged game once for the cold run, then launch it again for the cached run.

Interpreting Packaged Progress

Do not judge packaged behavior from a single captured frame. The progress bar is intentionally phase-banded:

  • 0.00 → 0.85 — asset warmup and PSO precache batches.
  • 0.85 → 0.95 — Level To Open package preload.
  • 0.95 → 1.00 — final engine pipeline-cache flush, only when the remaining backlog is large enough to justify waiting.

If a packaged run shows only 0 or 1 processed items, jumps to 85%, then opens Level To Open almost immediately, that usually means the asset phase found little startup work or was skipped by the cache fingerprint, the level-package preload phase still ran, and the final engine PSO backlog was too small to hold the screen.

Use Get Current Progress Summary Text instead of raw percentages alone. It switches between asset counts, package-preload counts, pipeline-cache PSO counts, and cached-run states so the UI reflects the real phase.

Destination Maps Must Be Cooked Explicitly

For production projects, add the loading level and every map opened immediately after warmup to Project Settings > Packaging > List of maps to include in a packaged build. This includes language menus, main menus, hubs, and custom handoff maps. Blueprint string paths and manual OpenLevel calls are not always enough to create a cook reference.

Direct Gameplay-Map Validation

If you want to test the raw demo manager path without the boot flow, open /Game/Demo/Demo_PSOTorture directly. That path forces a validation run, resets the warmup fingerprint cache, points scanning at /Game/DemoMaterials, and holds the UI for a minimum visible duration.

๐Ÿ“ฆ Demo vs. Production

The PSOAutopilotDemoManager is designed for demonstrations and testing only. It temporarily overrides your Project Settings (batch size, frame budget, minimum duration) and restores them when done. It is automatically disabled in Shipping builds. For production use, use the APSOAutopilotBootLoader instead.

Fallback Widget

If no HUDClass is set on the Demo Manager, it automatically falls back to UPSOAutopilotDemoWidget's C++ fallback UI, which procedurally generates a compact telemetry panel with progress, timing, cold/cached controls, cache status, and a smooth spinner.

๐Ÿ› ๏ธ Regenerating the Sample

Run Unreal with Scripts/CreatePSOAutopilotDemo.py via -ExecutePythonScript if you want to rebuild or normalize the sample levels, demo materials, boot widget, and boot actor defaults.


Best Practices

Target Precisely

Add only the directories that contain materials your players will see during gameplay. Scanning /Game/ on a large project will waste time on audio, data tables, and other non-visual assets. Typical targets:

  • /Game/Characters — player and NPC materials
  • /Game/Weapons — weapon skins and attachments
  • /Game/Environment — world materials and foliage
  • /Game/VFX — particle and Niagara effects
  • /Game/UI — only if you have material-based UI effects

Directory roots are scanned recursively. If you add /Game/Weapons, PSO Autopilot also scans child folders such as /Game/Weapons/Materials, /Game/Weapons/Meshes, and deeper descendants automatically.

That recursion only covers subfolders under the root you chose. If important startup content lives outside that folder tree but is reachable through map, blueprint, label, or soft-reference dependencies, keep dependency expansion enabled instead of broadening the directory root unnecessarily.

For content that is rooted in maps, labels, or blueprints instead of plain folders, add those roots through ExplicitAssetsToWarm and enable dependency expansion instead of broadening your directory scan unnecessarily.

Tune Batch Size to Your Target Hardware

The default batch size of 100 works well for mid-range PCs with 16GB RAM. Adjust based on your target:

  • Console / Mobile (8GB or less): Batch size 25–50
  • Mid-range PC (16GB): Batch size 50–100
  • High-end PC (32GB+): Batch size 100–200

Monitor your peak memory using stat memory or an external profiler during the warmup cycle to find the sweet spot.

Use a Dedicated Loading Level

For the cleanest integration, create a minimal level that contains only a BP_BootLoader actor and a sky/background. Set LevelToOpenOnComplete to your main menu, hub, or gameplay level. This ensures:

  • The warmup runs before any gameplay assets compete for memory.
  • The player sees a polished loading screen, not a half-loaded world.
  • Level transition automatically handles cleanup of warmup resources.

Leave bRegisterLevelAsWarmupSeed and bPreloadLevelPackagesBeforeOpen enabled unless you have a specific reason to disable them. Those two switches are what let the boot flow warm and preload Level To Open before the destination opens.

After changing Simple Setup, rerun Create/Update Startup Flow. The validator now treats a stale loader actor as a setup error because packaged maps preserve the actor's serialized destination and handoff flags.

Cook Startup Maps Explicitly

Every startup travel target must exist in the packaged build. Add the PSO loading level, Level To Open After Warmup, and any language-menu/main-menu handoff maps to the packaged maps list, or cook the containing startup folder intentionally.

If logs show LoadPackage: SkipPackage: /Game/FirstPerson/UI/LanguageMenuLevel - The package to load does not exist on disk or in the loader, the fix is packaging, not shader settings: add that exact map or its folder to the cook list and rebuild the package.

Queue Dynamic Roots Before Warmup Starts

If some of your startup content is chosen dynamically at runtime, queue it before the warmup begins instead of hoping a broad scan catches it. Use RegisterRuntimeWarmupAsset(...), QueuePackagePreload(...), or the Boot Loader's begin-play overrides.

Test in Standalone Game Mode

The Editor handles PSOs differently than a deployed executable. For accurate results:

  • Use Standalone Game, -game mode, or a packaged Development build for production-like behavior.
  • Use -game mode: UnrealEditor.exe MyProject.uproject MyMap.umap -game -log -windowed
  • If you need to test inside PIE/editor preview, switch Editor Iteration Mode to Run PSO Autopilot Warmup first.
  • Watch the LogPSOAutopilot category in the output log for detailed telemetry.

Troubleshooting FAQ

Startup & Scanning

Q: The progress bar stays at 0% for a long time on boot.

A: Unreal Engine's Asset Registry initializes asynchronously in the background when the game boots. PSO Autopilot waits for this background scan to finish before querying assets to ensure none are missed. If your project is very large, this initial wait is normal. You can monitor progress in the log under LogPSOAutopilot: once the Asset Registry is ready, scanning begins immediately.

Q: The plugin instantly finishes and warns "DirectoriesToScan is empty!"

A: This is Blanket Scan Protection working as intended. If the targeting directories array is empty, the plugin aborts to prevent querying the entire Asset Registry. Add at least one targeted directory (e.g., /Game/Characters or /Game/VFX) in Project Settings > Plugins > PSO Autopilot > Directories To Scan.

Q: The scan finds 0 assets even though my directories are set correctly.

A: Check for these common causes:

1. Empty path entry: If DefaultGame.ini contains +DirectoriesToScan=(Path=""), this empty entry causes the Asset Registry filter to fail silently. Remove it.

2. Wrong path format: Paths must use the /Game/ prefix, not filesystem paths. Use /Game/Characters, not Content/Characters.

3. Asset Registry not ready: In -game mode, the background asset scan may not have started yet. Current builds handle this by kicking off an async full search and waiting until the registry is ready.

4. Your real roots are not directory-based: If the startup content is rooted in a map, blueprint, label, or dynamic runtime selection, add it through ExplicitAssetsToWarm or RegisterRuntimeWarmupAsset(...) rather than relying only on DirectoriesToScan.

5. PIE and packaged builds do not see identical content sets: PIE can enumerate uncooked editor content, while packaged builds only see cooked staged runtime content. A setup that looks rich in editor can still discover very little in a packaged build if the runtime roots are narrow or the real startup content is elsewhere.

6. Cook roots are not the same as processed counts: Seeing many folders under Additional Asset Directories to Cook proves those folders were staged for cooking, but the loading-screen counter still advances per discovered warmable asset, not per folder path.

Q: I added many material folders, but the packaged build only processes one asset.

A: Material folders are not the same as representative startup content. A PSO depends on the material and the mesh type, vertex factory, render pass, render state, platform, and RHI. If the packaged run only shows 1, that item is often just the Level To Open seed registered by the Boot Loader.

Use the Setup Wizard's discovery preview first. Then check packaged logs for Warmup settings:, Warmup asset discovery details:, Warmup only discovered seed asset(s), and Warmup scan folder sample:. If directory assets are zero, add runtime folders containing maps, meshes, Blueprints, widgets, VFX, and the assets that use the materials.

Q: Scanning is very slow in the Editor.

A: In Editor builds, PSO Autopilot queries filesystem modification timestamps for every discovered asset to build the fingerprint. This is necessary to detect material changes but adds I/O overhead. In packaged builds this step is skipped, and scanning is significantly faster. To speed up Editor iteration, narrow your DirectoriesToScan to only the folders you're actively working on.

Q: Pressing Play in the editor no longer runs the warmup. Is the plugin disabled?

A: Not globally. Current builds default Editor Iteration Mode to Use Unreal Editor Compilation, so PIE/editor preview uses Unreal's standard shader compilation path and PSO Autopilot completes immediately. Packaged builds and runtime validation still use the warmup. Switch the mode to Run PSO Autopilot Warmup when you want to test the full flow in PIE.

Shader Compilation

Q: I see "Compiling PSOs..." in the log, but no shaders are actually building.

A: Ensure your project is configured to generate shader caches. In DefaultEngine.ini, verify that bShareMaterialShaderCode=True is set under [/Script/Engine.RendererSettings]. Also test in a Packaged Build or -game mode—the Editor handles PSOs differently than a deployed executable.

Q: Which vertex factories does PSO Autopilot cover?

A: The plugin submits PSO precache requests for these vertex factory types:

Local Vertex Factory — Standard static meshes
Nanite Vertex Factory — Nanite-enabled meshes (UE 5.x)
Particle Sprite — GPU sprite particles
Beam/Trail — Beam and trail particle emitters
Mesh Particle — Mesh-based particle emitters

Skeletal mesh vertex factories are covered when the corresponding materials are scanned. Landscape and other specialized factories rely on the Engine's own PSO collection at draw time.

Memory & Performance

Q: My loading screen stutters or drops below 60fps during warmup.

A: The MaxProcessingTimeMsPerFrame setting controls how much game-thread time the plugin uses per frame. The default of 5.0ms should leave ~11.6ms for rendering at 60fps. If you're still seeing hitches:

1. Lower MaxProcessingTimeMsPerFrame to 2.0–3.0ms.

2. Reduce BatchSize—smaller batches mean less per-frame work.

3. Check if other systems (level streaming, audio loading) are competing for the game thread.

Q: RAM usage spikes during warmup. How do I reduce peak memory?

A: Three levers control memory usage:

1. Reduce BatchSize — Fewer assets loaded simultaneously means lower peak RAM. Try 25–50 for constrained platforms.

2. Enable GC Between Batches — Ensure bGarbageCollectBetweenBatches is true. The plugin performs a full-purge GC after each batch to aggressively reclaim memory.

3. Target fewer directories — Only scan folders with materials the player will actually see. Reducing total asset count is the most effective way to lower peak memory.

4. Be selective with package preloadPackagesToPreload and bPreloadLevelPackagesBeforeOpen intentionally move more work into startup, which can also increase temporary memory pressure. Preload only the packages that materially improve first-run smoothness.

Q: The warmup takes too long. How can I speed it up?

A: Warmup speed is a tradeoff with memory and UI smoothness:

1. Increase BatchSize to 150–200 (if RAM allows).

2. Increase MaxProcessingTimeMsPerFrame to 8–10ms (loading animations may be slightly choppier).

3. Disable texture pre-heating if visual pop-in is acceptable: set bPreHeatTextureStreaming and bPreHeatVirtualTextures to false.

4. Narrow your scan targets to only critical directories.

Q: I saw a D3D12RHI uniform buffer crash during a huge warmup. What changed?

A: Current builds throttle active PSO precache requests during time-sliced batch processing. This prevents very large material sets from flooding the renderer with unchecked background PSO work. If you still hit renderer instability, reduce BatchSize, narrow scan folders, and test with a Development packaged build log.

Q: Does a Session CrashGUID mean PSO Autopilot crashed?

A: No. Unreal often prints a Session CrashGUID during startup so crash reporting has an ID ready if the process fails later. That line alone is not crash evidence.

A real crash usually has a fatal marker near the end of the log: Fatal error, Unhandled Exception, LowLevelFatalError, an assert/ensure that terminates, CrashReportClient activity, or a call stack. A clean exit normally ends with RequestExit(0), LogExit: Exiting, and Log file closed.

Texture Streaming

Q: The log shows "Texture streaming timed out." Is this a problem?

A: The plugin imposes a 30-second timeout on the texture streaming phase per batch. If some textures haven't finished streaming by then, the plugin advances to the next batch rather than waiting indefinitely. This is a safety mechanism. If you see this frequently:

1. Your batch size may be too large for your I/O bandwidth. Reduce BatchSize.

2. Virtual Textures with very large page tables may need more time. The timeout is generous enough for most projects.

3. The textures will still stream in during gameplay—this timeout just means they weren't fully resident before the loading screen dropped.

Q: Textures still pop in blurry after the loading screen finishes.

A: Ensure both bPreHeatTextureStreaming and bPreHeatVirtualTextures are enabled in Project Settings. If the issue persists:

1. The materials causing pop-in may be outside your scanned directories. Add their parent folders to DirectoriesToScan.

2. Texture streaming may have timed out (see above). Check the log for timeout warnings.

3. If using World Partition or level streaming, textures in streamed sub-levels are not covered by PSO Autopilot's pre-heat—they are managed by Unreal's runtime streaming system.

Fingerprint & Cache

Q: The warmup runs every time I launch, even though nothing changed.

A: The fingerprint may be changing between launches. Common causes:

1. Editor timestamp drift: In Editor/PIE, filesystem timestamps are included in the fingerprint. If your source control or build system touches file modification dates, the hash changes. This does not happen in packaged builds.

2. The dedicated cache file is not being written: Current builds persist fingerprints to Saved/PSOAutopilotCache.ini. If that file cannot be created or updated, the cache is lost. Check that the file and its parent Saved/ directory are writable.

3. bResetFingerprintOnBeginPlay is enabled: The Boot Loader or Demo Manager may be forcing a reset. Check the actor's properties. Re-running the setup wizard clears stale simple-setup demo/debug overrides on existing loader actors.

4. The previous run had warnings: Fingerprints are only stored for clean runs. Asset-load or package-preload failures intentionally force a fresh attempt next time.

Q: I changed some materials but the warmup was skipped. Stale cache?

A: In Editor builds, PSO Autopilot includes filesystem timestamps in the fingerprint, so saving a material should invalidate the cache. If it doesn't:

1. Verify the changed material is inside one of your DirectoriesToScan directories.

2. The material may be a Material Instance whose parent hasn't changed. Re-save the parent material to force a new timestamp.

3. If the changed content is only reachable through a map, blueprint, label, or soft reference, make sure that root is still represented in the discovered warmup set. The fingerprint now keys off the final discovered asset list, not just the raw directory list.

4. As a workaround, enable bResetFingerprintOnBeginPlay on your Boot Loader during development to always force the warmup.

Q: How do I manually clear the fingerprint cache?

A: Two methods:

1. At runtime: Call ResetCachedWarmupFingerprint() on the PSOAutopilotSubsystem before starting the warmup.

2. Manually: Open Saved/PSOAutopilotCache.ini and delete the [PSOAutopilot] section, or remove the file entirely.

Q: I have multiple Boot Loaders with different scan directories. Will they conflict?

A: No. PSO Autopilot stores up to 8 unique fingerprints using LRU eviction. Each Boot Loader generates its own fingerprint based on its scan configuration, and they are independently cached. The 9th unique fingerprint will evict the oldest entry.

Boot Loader

Q: The Boot Loader warns "LevelToOpenOnComplete was not found."

A: The level name you entered does not match any package available to the current runtime. The Boot Loader validates the level before attempting the transition to prevent crashes and silent failed travel. Check that:

1. The level name matches exactly (case-sensitive on some platforms).

2. The level is included in your packaged build's list of maps (Project Settings > Packaging > List of maps to include).

3. You're using the long package name (for example /Game/MainMenu/MainMenu), not a filesystem path.

Current builds check FPackageName::DoesPackageExist(...) before removing the loading widget or calling OpenLevel. If the destination is missing, the widget stays visible and the log points to Maps to Cook or Additional Asset Directories to Cook.

Q: Warmup completed, the loading UI faded out, and nothing opened.

A: That pattern usually means the destination package was missing from the cooked build. Older builds could remove the widget before the final travel failed, which made the issue look like PSO Autopilot silently finished. Current builds retain the widget and display a terminal error.

Look for a log line like LoadPackage: SkipPackage: /Game/FirstPerson/UI/LanguageMenuLevel - The package to load does not exist on disk or in the loader. Add that exact map to packaged maps, or add the containing folder to Additional Asset Directories to Cook, then rebuild.

The one-node Start PSO Autopilot Loading Flow uses the same destination guard, so a missing destination package is reported visibly there too.

Q: Why does the gameplay map not start a second warmup after the boot map finishes?

A: That is the intended sample behavior. The boot-flow path hands off a travel option to the gameplay map, and the bundled demo manager checks that flag and skips duplicate warmup work. This prevents the startup cost from being paid twice.

Q: The loading widget doesn't appear.

A: Check the following:

1. Ensure a valid Player Controller exists. The Boot Loader requires a local player controller to create widgets.

2. If using a custom LoadingScreenClass, verify it's a valid Widget Blueprint that compiles without errors. The setup wizard's editable default should live at /Game/PSOAutopilot/WBP_PSOAutopilotLoadingScreen, with optional _Minimal and _Telemetry siblings.

3. Check the output log for LogPSOAutopilot messages—the Boot Loader logs whether widget creation succeeded or failed.

Q: The folder only contains the loading map, but Play shows a C++ loading widget. Why?

A: Older setup data could point directly at the native UPSOAutopilotLoadingScreenWidget fallback instead of a project-owned UMG asset. Run the setup wizard and use the loading-widget fix or Create/Update Startup Flow. Current builds create and assign editable Widget Blueprint templates at /Game/PSOAutopilot/WBP_PSOAutopilotLoadingScreen plus _Minimal and _Telemetry.

Q: How do I edit the wizard-created widget without breaking it?

A: Open one of the wizard templates — usually /Game/PSOAutopilot/WBP_PSOAutopilotLoadingScreen or the lighter _Minimal variant — and edit it like a normal Widget Blueprint. Current builds no longer rebuild the layout at runtime for these assets.

Keep Is Variable enabled and preserve the exact variable name only for the elements you want updated automatically, such as WarmupProgressBar and WarmupStatusText. You can safely delete the spinner, timer, summary, or telemetry widgets if you do not want them.

Q: I want a completely custom branded loading widget. How do I still get auto-updates?

A: Use any UserWidget that implements PSOAutopilotLoadingScreenReceiver. The Boot Loader and Start PSO Autopilot Loading Flow now call that interface automatically. If you prefer, you can skip the interface and bind to OnProgressUpdated / OnWarmupComplete manually.

Q: My Project Settings get permanently changed after using the Boot Loader.

A: This should not happen. The Boot Loader captures a snapshot of your settings before applying overrides and restores them when warmup completes or when the actor is destroyed. If settings appear stuck:

1. Check if the game crashed before RestoreSettingsOverrides() ran. In that case, the CDO may have been modified but the INI file was not overwritten.

2. Restart the Editor to reload settings from DefaultGame.ini.

3. Verify that bApplySettingsOverride is actually enabled—if it's false, no snapshot is taken and nothing is restored.

Batch Processing

Q: The log shows "Batch load timed out." What happened?

A: A 60-second watchdog timer protects against stuck async loads. If an FStreamableManager::RequestAsyncLoad call doesn't complete within 60 seconds, the plugin cancels the load, marks the batch as failed, and advances to the next batch. Causes include:

1. Corrupted or excessively large assets that take too long to load.

2. Disk I/O contention (e.g., antivirus scanning, another application thrashing the disk).

3. The assets have external dependencies that trigger cascading loads. This is rare but can happen with deeply nested Blueprint references.

The warmup will continue with remaining batches. Failed batches are counted and reported in the completion log.

Q: The warmup completes but reports some failed batches. Should I worry?

A: A small number of failed batches (1–2 out of many) is usually harmless—those specific materials may have compilation issues unrelated to PSO Autopilot. The shaders for those materials will be compiled on-demand at draw time (with a potential micro-stutter). If many batches fail, investigate the assets in those batches for corruption or unsupported material features.

Integration & Platform

Q: Unreal keeps cooking almost everything after I restart the editor. What should I check?

A: Check Project Settings > Packaging > Additional Asset Directories to Cook and your config for +DirectoriesToAlwaysCook=(Path="/Game"). That root entry tells Unreal to always cook the whole project. Current setup-wizard fixes avoid adding it and can remove it; use specific folders such as /Game/Demo, /Game/DemoMaterials, or your real startup content folders instead.

Q: Packaging says plugin content is unloadable because the package version is too old.

A: A warning like Package is unloadable: .../Plugins/Marketplace/PSOAutopilot.../Content/... Reason: Version is too old. Min Version: 214, Package Version: 0 means Unreal cannot deserialize that bundled asset for the current engine. It is a cook-time asset compatibility problem, not a PSO Autopilot runtime warmup.

Use the wizard-created project-owned assets under /Game/PSOAutopilot for normal project setup. For plugin distribution, resave or rebuild the plugin content in the target Unreal version, or remove invalid bundled sample assets from the package.

Q: Can I call StartWarmup() from C++ instead of using the Boot Loader?

A: Yes. Get the subsystem from your GameInstance and call StartWarmup() directly:

UGameInstance* GI = UGameplayStatics::GetGameInstance(this);
UPSOAutopilotSubsystem* PSO = GI->GetSubsystem<UPSOAutopilotSubsystem>();
PSO->OnWarmupComplete.AddDynamic(this, &AMyActor::OnWarmupDone);
PSO->StartWarmup();

Q: What platforms does the current packaged release support?

A: The current packaged marketplace build is validated and configured for Win64. The underlying code is portable Unreal C++, but only Win64 is exposed in the released plugin descriptor and packaging profiles for this version.

Q: Is the plugin safe to use in Shipping builds?

A: Yes. The core subsystem (UPSOAutopilotSubsystem) and Boot Loader (APSOAutopilotBootLoader) work in all build configurations including Shipping. The Demo Manager (APSOAutopilotDemoManager) is automatically disabled in Shipping builds via a compile-time guard.

Q: Can I run the warmup in a background thread instead of the game thread?

A: No. PSO precaching (PrecachePSOs) must happen on the game thread because it interacts with the rendering subsystem and material proxies. This is an Unreal Engine requirement, not a PSO Autopilot limitation. The time-slicing architecture ensures the game thread is only occupied for a configurable number of milliseconds per frame, keeping your UI responsive.

Logging & Debugging

Q: How do I enable detailed logging?

A: All PSO Autopilot messages use the LogPSOAutopilot log category. To see them:

1. In-Editor: Open the Output Log and filter by LogPSOAutopilot.

2. In -game mode: Add -log to your launch arguments to open the log window.

3. In packaged builds: Add -log or check the saved log file in Saved/Logs/.

The plugin logs state transitions, batch progress, asset counts, fingerprint values, timing data, and any warnings or errors.

Q: Is "Compiling shader autogen file: AutogenShaderHeaders.ush" PSO Autopilot starting during packaging?

A: No. Lines such as Using Local Shader Compiler with 17 workers, Compiling shader autogen file: .../Intermediate/ShaderAutogen/.../AutogenShaderHeaders.ush, and Autogen file is unchanged, skipping write are normal Unreal shader-cook setup. PSO Autopilot starts at runtime when the packaged game reaches the loader, the one-node loading flow, or your custom call to start warmup.

Use LogPSOAutopilot: Starting PSO Autopilot Warmup... as the marker for the plugin's runtime phase.

Q: The log shows "IsWarmupRunning() is true, ignoring StartWarmup call."

A: You called StartWarmup() while a warmup is already in progress. The plugin guards against re-entrant calls. Wait for OnWarmupComplete to fire before starting another warmup, or check IsWarmupRunning() before calling.

Q: The warmup seems stuck in "Processing Batch" for a very long time.

A: This state is time-sliced, so it only runs for MaxProcessingTimeMsPerFrame per tick. If you have thousands of materials with complex shader permutations, this phase can take minutes. Check the log for the PSO remaining count—if it's decreasing, the plugin is working normally. If it's truly stuck at a fixed number, there may be a shader compilation issue with a specific material. Try reducing your scan scope to isolate the problematic asset.

Copyright © 2026 GregOrigin. All Rights Reserved.