Skip to content

Profile System

PlatanoGames edited this page Feb 23, 2026 · 3 revisions

Profile System v2.0 — The Constitutional Court of Your Project

"Every subsystem in your game asks the same questions at startup: what platform am I on, how much memory do I get, should I enable this feature? If the answers live in twelve different places, you don't have configuration — you have archaeology."


The Problem

Platform-aware configuration in Unreal Engine is a solved problem in theory. In practice, it is a distributed disaster.

Consider what happens when you ship on PC and Switch simultaneously. Your audio system needs to know the concurrent sound budget. Your streaming system needs memory pool sizes. Your PSO cache needs shader limits. Your save system needs to know whether external writes are permitted.

Where do those answers live today?

  [DefaultEngine.ini]    [PlatformA.ini]    [C++ #if PLATFORM_SWITCH]
        |                      |                       |
        v                      v                       v
   Audio reads            Streaming reads         Save system reads
   from here              from here               from here
        |                      |                       |
        v                      v                       v
   "Max sounds: 128"     "Pool: 512 MB"         "No external writes"

Three different mechanisms. Three different file formats. Three different moments in the initialization timeline. No way to query "what is the current truth" from a single API call. No way to simulate "what if we were on Switch" without rebuilding the project.

This pattern has three failure modes, all of which ship in real products:

Scattered authority. One team configures audio budgets in an ini file. Another team hardcodes streaming limits in a header. A third team uses preprocessor defines for save system behavior. Nobody knows the full picture. Nobody can audit the full picture.

Stale overrides. Platform-specific ini files diverge from the base configuration over months. A change to the base is not propagated. The Switch build silently runs with a budget that was correct six months ago.

No simulation path. You cannot answer "what would my game look like on Switch" without deploying to Switch hardware or maintaining a parallel configuration set. Profiling sessions on PC tell you nothing about platform constraints because the constraints are baked into platform-specific code paths.

The root cause is that Unreal Engine gives you the tools to configure per-platform behavior, but no single system that composes those configurations into a resolved truth that every subsystem can query. The engine gives you bricks. You need a building code.


How PGX Solves It

PGX treats project configuration as a composed profile — a single resolved object that every subsystem in the framework can query through a uniform API.

The profile is not a settings file. It is a runtime-resolved document that combines five layers of configuration with platform overrides, applies deterministic merge rules, and exposes the result through a read-only query interface.

The Five-Layer Model

  +-------------------------------------------------------+
  |                 RESOLVED PROFILE                       |
  |  (read-only, queried by all 11+ subsystems)           |
  +-------------------------------------------------------+
       ^            ^            ^           ^          ^
       |            |            |           |          |
  +---------+ +-----------+ +--------+ +---------+ +----------+
  | Identity| |Capabilities| |Policies| | Budgets | | Features |
  +---------+ +-----------+ +--------+ +---------+ +----------+

Layer 1: Identity defines what the project IS. Project mode (game, simulation, tool, cinematic). Target platforms. Build context (development, testing, shipping). Restriction level (none, family, child). This layer is descriptive — it makes no decisions, it declares facts.

Layer 2: Capabilities defines what the project CAN DO. Ten boolean flags: persistent saves, external writes, persistent logs, hot reload, profiling, developer commands, analytics, virtual textures, ray tracing, nanite. These are not feature toggles — they are permissions. A capability set to false means no subsystem in the framework will attempt that operation, regardless of what individual system configurations say.

Layer 3: Policies defines HOW things operate. Persistence routing (local, cloud, custom). Security settings (encryption, signing, compression). These are behavioral directives that subsystems consume to select their operational mode.

Layer 4: Budgets defines resource ceilings. Nine numeric limits: maximum concurrent sounds, maximum save slots, shader cache budget, PSO pipeline budget, streaming pool in megabytes, RAM budget, VRAM budget, disk budget, and log disk budget. A value of zero means unlimited. These are hard caps that subsystems enforce — not suggestions.

Layer 5: Features defines rendering feature availability. Seven features (ray tracing, nanite, virtual textures, lumen, virtual shadow maps, world partition, hardware-accelerated features), each with a policy (allowed, fallback required, disallowed) and a flag indicating whether changing the policy requires an editor restart.

Platform Configuration (v2.0)

The base five-layer model describes the project's defaults. Platform Config assets describe per-platform overrides. Each platform config contains budget structs for every subsystem that enforces budgets.

  Base Profile DA
  +-------------------+
  | Identity          |   Platform Config: Switch
  | Capabilities      |   +-------------------------+
  | Policies          |   | Audio Budget: 32 sounds  |
  | Budgets: 128 snd  |   | Save Budget: 8 slots     |
  | Features          |   | PSO Budget: 500 shaders   |
  +-------------------+   | Streaming: 256 MB         |
          |                +-------------------------+
          |                           |
          v                           v
  +---------------------------------------------+
  |          RESOLUTION ENGINE                   |
  |  Capabilities: AND   (both must agree)       |
  |  Budgets: MIN        (most restrictive wins) |
  |  Features: RESTRICT  (disallowed > fallback) |
  +---------------------------------------------+
          |
          v
  +---------------------------------------------+
  |          RESOLVED PROFILE                    |
  |  Audio: 32 sounds (Switch override won)      |
  |  Save: 8 slots (Switch override won)         |
  |  Ray Tracing: Disallowed (Switch said no)    |
  +---------------------------------------------+

The resolution rules are deterministic and conservative:

  • Capabilities: AND merge. If the base allows saves and the platform allows saves, the result allows saves. If either says no, the result says no.
  • Budgets: MIN merge (non-zero wins). If the base says 128 sounds and the platform says 32, the result is 32. If one says 0 (unlimited) and the other says 32, the result is 32.
  • Features: Most Restrictive merge. Disallowed beats Fallback Required beats Allowed.

These rules guarantee that the resolved profile is always the most conservative interpretation of all inputs. No subsystem will ever exceed what any configuration layer permits.

Multi-Platform Resolution

When a project targets multiple platforms simultaneously (common during development), the profile resolves ALL target platform configs and applies the same merge rules across them.

  Target: PC + Switch + Mobile

  PC Config         Switch Config       Mobile Config
  128 sounds        32 sounds           16 sounds
  RT: Allowed       RT: Disallowed      RT: Disallowed
  2048 MB stream    256 MB stream       128 MB stream
       |                  |                   |
       +------------------+-------------------+
                          |
                    MIN / AND / RESTRICT
                          |
                          v
                  Resolved: 16 sounds
                  RT: Disallowed
                  Stream: 128 MB

The result is the intersection of all platforms. Developing against this profile means your game works on your weakest target by construction.

Shipping Lock

In shipping builds, the profile is locked at resolution time. No runtime code can modify it. Simulation APIs are stripped. The resolved profile becomes a compile-time constant for all practical purposes.

In editor and development builds, the full simulation API is available. You can override the active platform, build context, or individual budget values to test behavior under different constraints without modifying any assets.


Architecture (ASCII Diagram)

                        +---------------------------+
                        |    Profile Subsystem       |
                        |  (GameInstanceSubsystem)   |
                        |                            |
                        |  Init: AssetRegistry scan  |
                        |  -> Discover config DA     |
                        |  -> Discover platform DAs  |
                        |  -> Resolve composed       |
                        |  -> Notify subscribers     |
                        |  -> Lock if Shipping       |
                        +-------------+--------------+
                                      |
                    +-----------------+-----------------+
                    |                                   |
            +-------v--------+                 +--------v-------+
            | Config DA      |                 | Platform DA(s) |
            |                |                 |                 |
            | 5-layer base   |                 | Per-system      |
            | + platform     |                 | budget structs  |
            |   overrides    |                 | + trait flags   |
            | + build        |                 |                 |
            |   overrides    |                 | One per target  |
            +----------------+                 | platform        |
                                               +-----------------+
                                      |
                    +-----------------+-----------------+
                    |                 |                 |
            +-------v---+    +-------v---+    +--------v--+
            | Resolution|    | Simulation|    | Delegates  |
            | Engine    |    | (Editor)  |    |            |
            |           |    |           |    | Resolved   |
            | AND/MIN/  |    | Override  |    | Changed    |
            | RESTRICT  |    | platform  |    | PreChange  |
            |           |    | Override  |    |            |
            +-----------+    | build ctx |    +------------+
                             +-----------+
                                      |
            +-------------------------+-----------------------+
            |              |          |           |           |
      +-----v----+  +-----v---+ +---v-----+ +---v----+ +---v------+
      | Audio     |  | Save    | | PSO     | | Stream | | Loading  |
      | Budget:   |  | Budget: | | Budget: | | Budget:| | Budget:  |
      | sounds    |  | slots   | | shaders | | MB     | | RAM/VRAM |
      +----------+  +---------+ +---------+ +--------+ +----------+

Initialization Timeline

  Engine Start
      |
      v
  Profile.Initialize()          <-- FIRST subsystem to init
      |
      +-- AssetRegistry scan for config DA
      +-- AssetRegistry scan for platform DAs
      +-- Resolve base layers
      +-- Apply platform overrides (AND/MIN/RESTRICT)
      +-- Apply build overrides
      +-- Broadcast OnProfileResolved
      +-- If Shipping: lock
      |
      v
  GameFlow.Initialize()         <-- Can query profile
      |
      v
  Log.Initialize()              <-- Can query profile
      |
      v
  Save.Initialize()             <-- Enforces save budgets from profile
      |
      v
  PSO.Initialize()              <-- Enforces shader budgets from profile
      |
      v
  ... (remaining subsystems)    <-- All consume resolved profile

Profile initializes first by design. Every subsequent subsystem in the initialization chain can query the resolved profile during its own initialization. There is never a moment where a subsystem needs profile data and it is not yet available.


Capabilities

Five-Layer Configuration

Layer Content Example
Identity Project mode, target platforms, build context, restriction level "This is a Game targeting PC+Switch in Development mode"
Capabilities 10 boolean permissions "Allow saves, allow profiling, disallow external writes"
Policies Persistence backend, security settings "Use local saves with compression and checksums"
Budgets 9 numeric resource limits "128 max sounds, 16 save slots, 2048 MB streaming pool"
Features 7 render features with policy "Ray tracing: Allowed, Nanite: Fallback Required"

Resolution Rules

Data Type Merge Strategy Rationale
Booleans (Capabilities) AND Both sides must agree to enable
Integers (Budgets) MIN (non-zero) Most restrictive limit wins
Enums (Features) Most Restrictive Disallowed > Fallback > Allowed

Platform Budget Enforcement (v2.0)

Eleven subsystems read their budget constraints from the resolved profile and enforce them as hard caps:

Subsystem Budget Enforced
Audio Maximum concurrent sounds, channel count
Save Maximum save slots, disk budget
PSO Pipeline cache budget, shader limit
GameFlow Channel history depth
Loading RAM and VRAM allocation
LevelFlow Streaming pool size
Log Disk budget for persistent logs
MGOS Memory pool monitoring thresholds
Message Broadcast queue depth
EventHandler Execution history limit
Data Registry Cache size budget

Editor Simulation

Without modifying any asset, you can test:

  • "What if we were on Switch?" (override target platform)
  • "What if this were a Shipping build?" (override build context)
  • "What if we only had 256 MB streaming?" (override individual budget)

Simulation overrides apply on top of the resolved profile and broadcast change delegates, so every subsystem reacts in real time. Clear the simulation to return to the real resolved profile instantly.


Configuration

Configuration follows the framework's data-driven philosophy. The developer creates a Data Asset in the Content Browser, fills in properties, and the system auto-discovers it at initialization.

Setup Flow

  1. Content Browser > Right-click > PGX > Profile
     -> Creates a Project Profile Config asset

  2. Fill in the five layers in the Details panel
     -> Identity: set project mode, targets
     -> Capabilities: toggle boolean flags
     -> Policies: select persistence backend
     -> Budgets: set numeric limits (0 = unlimited)
     -> Features: set per-feature policy

  3. (Optional) Create Platform Config assets
     -> One per target platform
     -> Set per-system budget overrides

  4. Done. Profile auto-discovers via AssetRegistry.
     No registration. No initialization code. No setup.

Data Asset Structure

The Project Profile Config asset contains:

  • Base layers: The five-layer model (Identity, Capabilities, Policies, Budgets, Features)
  • Platform overrides: Per-platform adjustments applied after base resolution
  • Build overrides: Per-build-context adjustments (development vs testing vs shipping)

Platform Config assets (v2.0) are separate Data Assets, one per platform, containing budget structures for each enforcing subsystem. They are discovered independently via the Asset Registry.

Zero-Config Default

If no Profile Config asset exists in the project, the system operates with permissive defaults: all capabilities enabled, all budgets unlimited, all features allowed. This means the Profile system is backward compatible — adding it to an existing project changes nothing until you create and populate a config asset.

Project Settings

A Developer Settings entry under Project Settings provides:

  • Default config asset reference (override for auto-discovery)
  • Simulation defaults for editor testing
  • Debug verbosity for profile resolution logging

Editor Tooling

Profile Inspector (6 Panels)

The Profile Inspector is a dedicated editor tab with six visualization panels:

  +----------------------------------------------------------+
  |  PGX Profile Inspector                            [Pin]  |
  +----------------------------------------------------------+
  |                                                          |
  |  [Identity]  [Capabilities]  [Policies]                  |
  |                                                          |
  |  Project Mode: Game                                      |
  |  Targets: PC, Switch                                     |
  |  Build: Development                                      |
  |  Restriction: None                                       |
  |                                                          |
  +----------------------------------------------------------+
  |                                                          |
  |  [Budgets]  [Features]  [Platform Health]                |
  |                                                          |
  |  Sounds    128 ============================== [Override] |
  |  Slots      16 ========                       [Override] |
  |  Shaders  2048 ============================== [Override] |
  |  Stream    512 ===================            [Override] |
  |                                                          |
  +----------------------------------------------------------+
  |  Simulation: [Platform v] [Build v] [Clear] [Status]    |
  +----------------------------------------------------------+

Panel 1 — Identity: Project mode, active targets, build context, restriction level. Read-only display of resolved values.

Panel 2 — Capabilities: Ten boolean flags displayed as toggle indicators. Green for enabled, red for disabled. Shows the resolved value after AND merge.

Panel 3 — Policies: Persistence backend, security flags, compression settings. Displays the active policy configuration.

Panel 4 — Budgets: Nine resource limits with progress bars showing usage against budget. Per-subsystem breakdown.

Panel 5 — Features: Seven render features with color-coded policy status. Restart indicators for features that require editor restart to change.

Panel 6 — Platform Health Dashboard (v2.0): Aggregated view of all platform budgets across all target platforms. Shows which subsystems are within budget, which are approaching limits, and which would exceed limits on specific platforms.

Simulation Controls

The bottom bar of the inspector provides simulation controls:

  • Platform dropdown: Select any target platform to simulate
  • Build context dropdown: Select development/testing/shipping
  • Clear button: Remove all simulation overrides
  • Status indicator: Shows whether simulation is active and what overrides are applied

Simulation changes are instant. Every subsystem that listens to profile change delegates updates immediately.

Quick Access

The Profile Inspector is available from:

  • PGX Toolbar > Tools submenu
  • PGX Toolbar > Quick Access pin
  • PGX Hub dashboard card
  • System Observer subsystem list

Integration Points

For Subsystem Authors

Any subsystem that needs platform-aware behavior queries the Profile at initialization:

  1. During your subsystem's initialization, query the resolved profile for your relevant budgets and capabilities
  2. Subscribe to the change delegate if you need to react to runtime profile changes (editor simulation)
  3. Enforce budget limits as hard caps in your subsystem's operation

For Game Developers

The Profile system is transparent to game code. Game developers interact with it in two scenarios:

  1. Initial setup: Create the Profile Config and Platform Config assets, fill in values
  2. Platform testing: Use the simulation controls to verify behavior under different platform constraints

No game code needs to reference the Profile directly unless implementing custom budget enforcement beyond what the framework provides.

Delegate Notifications

The Profile broadcasts three delegate events:

Event When Use Case
Profile Resolved First resolution at startup Subsystem initialization
Profile Changed Any change (including simulation) Live reaction to config changes
Profile Pre-Change Before a change is applied Validation, cleanup

Interface Integration

An optional interface allows objects to declare themselves as profile-aware. Objects implementing this interface receive direct notification of profile changes without manual delegate subscription.


Why This Matters

The Profile system addresses a fundamental architectural problem: the gap between "the engine lets you configure per-platform behavior" and "your entire project actually behaves correctly on every platform."

Without a composed profile, every subsystem implements its own version of platform-aware configuration. Some use ini files. Some use defines. Some use runtime queries. The result is a project where no single person can answer "what are our resource limits on Switch?" without auditing a dozen files across a dozen systems.

With a composed profile:

  • One asset defines all platform budgets. One place to audit. One place to change.
  • One API answers all queries. No per-system configuration archaeology.
  • One simulation tests all platforms. No rebuilds, no device farms, no guesswork.
  • Deterministic resolution means the most conservative interpretation always wins. If something works in simulation, it works on hardware.

The Profile initializes first in the framework's boot sequence. By the time any subsystem asks "what is my budget?", the answer is already resolved, cached, and available. The question of authority — who decides what a subsystem is allowed to do — is answered once, at startup, and never again until the developer explicitly changes the profile.

This is the difference between a project that happens to work on multiple platforms and a project that is designed to work on multiple platforms from the first line of configuration.


Console Commands

Command Description
pgx.profile.status Print resolved profile summary (state, platform, build)
pgx.profile.dump Dump all five layers with current resolved values
pgx.profile.capability <name> Query a specific capability by name
pgx.profile.budget <name> Query a specific budget by name
pgx.profile.feature <name> Query a specific render feature by name
pgx.profile.simulate.platform <name> Simulate a target platform (editor only)
pgx.profile.simulate.build <context> Simulate a build context (editor only)
pgx.profile.simulate.clear Clear all simulation overrides (editor only)
pgx.profile.simulate.status Display current simulation override status

Blueprint Nodes (12)

Organized into three categories:

Category Nodes
Core Get Resolved Profile, Is Capability Enabled, Get Budget
Query Is Feature Allowed, Get Profile State, Is Profile Resolved, Get Persistence Backend
Advanced Simulate Platform, Simulate Build Context, Clear Simulation, Has Simulation Overrides, Get Active Targets

Resumen en Espanol

El sistema Profile es el "tribunal constitucional" del framework. Define que puede hacer tu proyecto, en que plataformas, con que limites de recursos, y con que politicas de operacion.

El problema: En UE5, la configuracion de plataforma esta dispersa en archivos ini, defines de C++, y hardcodes por sistema. No hay una unica fuente de verdad. No puedes simular "como se comportaria en Switch" sin recompilar.

La solucion: Un modelo de 5 capas (Identidad, Capacidades, Politicas, Presupuestos, Caracteristicas) que se resuelve en un perfil compuesto al arrancar. Reglas deterministas: AND para booleanos, MIN para presupuestos, la politica mas restrictiva para features. 11 subsistemas respetan los limites de plataforma.

v2.0 agrega Data Assets de configuracion por plataforma. Cada plataforma target tiene su propio asset con presupuestos especificos por subsistema. La resolucion multi-plataforma garantiza que el resultado es la interseccion mas conservadora de todos los targets.

En el editor: Inspector con 6 paneles, simulacion de plataforma en tiempo real (sin modificar assets), y Platform Health Dashboard para visualizar presupuestos. 9 comandos de consola y 12 nodos Blueprint.

Filosofia de diseno: Si funciona en simulacion, funciona en hardware. Un solo asset. Una sola API. Cero arqueologia de configuracion.

Clone this wiki locally