> For the complete documentation index, see [llms.txt](https://dante-3.gitbook.io/dante-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dante-3.gitbook.io/dante-docs/modular-experience-system/architecture.md).

# Architecture

Internal architecture and loading pipeline mechanics of the Modular Experience System.

***

## Module Dependency Graph

```
                    ┌──────────┐
                    │  Engine  │
                    │ Modules  │
                    └────┬─────┘
                         │
            ┌────────────┼───────────────┐
            │            │               │
   ┌────────▼───┐  ┌─────▼────┐  ┌──────▼──────────┐
   │ Modular    │  │ Modular  │  │ GameFeatures    │
   │ Gameplay   │  │ Loading  │  │ (Engine Plugin) │
   │ (Engine)   │  │ Screen   │  └──────┬──────────┘
   └────┬───────┘  └─────┬────┘         │
        │                │              │
   ┌────▼───────────┐    │              │
   │ Modular        │    │              │
   │ Experience     │    │              │
   │ Framework      │    │              │
   └────┬───────────┘    │              │
        │                │              │
   ┌────▼────────────────▼──────────────▼──┐
   │     ModularExperienceSystem (Core)    │
   │  ├─ GameplayTags                      │
   │  └─ DeveloperSettings                 │
   └────┬──────────────────────────────────┘
        │
   ┌────▼──────────────────────┐
   │ ModularExperienceSystem   │
   │ Editor                    │
   │  ├─ UnrealEd, Kismet     │
   │  ├─ AssetTools            │
   │  └─ PropertyEditor        │
   └───────────────────────────┘
```

### Dependency Details

| Module                            | Public Dependencies                                                     | Private Dependencies                                                                                                                             |
| --------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **ModularExperienceFramework**    | Core                                                                    | CoreUObject, Engine, ModularGameplay, AIModule                                                                                                   |
| **ModularLoadingScreen**          | Core                                                                    | CoreUObject, Engine, Slate, SlateCore, InputCore, PreLoadScreen, RenderCore, DeveloperSettings, UMG                                              |
| **ModularExperienceSystem**       | Core, ModularLoadingScreen, ModularGameplay, GameFeatures, GameplayTags | CoreUObject, Engine, Slate, SlateCore, UMG, ModularExperienceFramework, DeveloperSettings                                                        |
| **ModularExperienceSystemEditor** | Core                                                                    | UnrealEd, CoreUObject, Engine, Slate, SlateCore, Kismet, AssetTools, AssetDefinition, PropertyEditor, DeveloperSettings, ModularExperienceSystem |
| **ModularStartupLoadingScreen**   | Core                                                                    | CoreUObject, Engine, Slate, SlateCore, MoviePlayer, PreLoadScreen, DeveloperSettings                                                             |

***

## Experience Loading Pipeline

Experience loading is performed by a **sequential state machine** managed by `UModularExperienceManagerComponent`:

```
                    ┌──────────┐
                    │ Unloaded │
                    └────┬─────┘
                         │ ChangeCurrentExperience()
                         │ or TryAutoResolveExperience()
                         ▼
                    ┌──────────┐
                    │ Loading  │  ── Asset bundle async load
                    └────┬─────┘
                         │ OnExperienceBundlesLoaded()
                         ▼
              ┌─────────────────────┐
              │ LoadingParentChain  │  ── Recursive loading of parent experiences
              └──────────┬──────────┘
                         │ OnParentChainLoaded()
                         ▼
              ┌─────────────────────┐
              │  ExecutingActions   │  ── Activating actions sequentially from root to leaf
              └──────────┬──────────┘
                         │ All actions activated
                         ▼
                    ┌──────────┐
                    │  Loaded  │  ── OnExperienceLoaded delegate fires
                    └────┬─────┘
                         │ EndPlay
                         ▼
                  ┌──────────────┐
                  │ Deactivating │  ── Actions deactivated in reverse order
                  └──────┬───────┘
                         │
                         ▼
                    ┌──────────┐
                    │ Unloaded │
                    └──────────┘
```

### Pipeline Steps

1. **Bundle Async Load** — The Experience Definition asset and its dependencies are loaded asynchronously
2. **Parent Chain Load** — `ParentExperience` is followed recursively (max 16 depth, cyclic dependency protection)
3. **Action Collection** — All actions across the chain are flattened in root-first order
4. **Action Execution** — Each action is activated sequentially via `OnGameFeatureActivating`
5. **Loaded** — The `OnExperienceLoaded` delegate fires, and the loading screen is dismissed

### Loading Screen Integration

`UModularExperienceManagerComponent` implements `IModularLoadingProcessInterface`. Throughout the pipeline, `ShouldShowLoadingScreen()` returns true, so `UModularLoadingScreenManager` automatically displays the loading screen.

***

## Auto Resolve Priority

`TryAutoResolveExperience()` searches for the experience in the following priority order:

| Priority | Source                      | Description                                                |
| -------- | --------------------------- | ---------------------------------------------------------- |
| 1        | Developer Settings Override | `UMES_DeveloperSettings::ExperienceOverride` (editor only) |
| 2        | URL Options                 | `?Experience=ModularExperienceDefinition:AssetName`        |
| 3        | Command Line                | `-Experience=ModularExperienceDefinition:AssetName`        |
| 4        | WorldSettings               | `AMES_WorldSettings::DefaultGameplayExperience`            |

***

## Auto Setup Mechanism

When `bAutoSetup` is enabled, `UModularExperienceSubsystem::OnWorldBeginPlay()`:

1. **Checks GameState** — Dynamically adds `UModularExperienceManagerComponent` if it doesn't exist
2. **Scans actors** — GameState, all PlayerControllers, PlayerStates, Pawns, and HUDs
3. **Receiver check** — Checks whether each actor already derives from an `AMES_` base class or from `ModularGameplayActors`
4. **Registers** — Registers non-modular actors with `GameFrameworkComponentManager::AddGameFrameworkComponentReceiver()` and sends the `GameActorReady` event
5. **Cleanup** — All registered receivers are cleaned up in `Deinitialize()`

Thanks to this mechanism, even default Unreal actors derived from `AGameStateBase` can receive GameFeatureAction component injection.

***

## Parent Experience Chain

Experiences can be combined through inheritance chains:

```
B_BaseExperience              (base settings: default pawn, controller)
  └── B_ShooterExperience      (weapon system, UI, HUD)
        └── B_TeamShooter       (team settings, scoreboard)
```

Loading order:

1. `B_BaseExperience` actions are activated
2. `B_ShooterExperience` actions are activated
3. `B_TeamShooter` actions are activated

During deactivation, **reverse order** is applied (leaf → root).

### Safety Checks

* Maximum chain depth: **16**
* Cyclic dependency protection is present
* Each experience in the chain is processed only **once**

***

## GameFrameworkComponentManager Pattern

This pattern is the cornerstone of Lyra and MES. Actors register themselves as "receivers" during `PreInitializeComponents()`. Actions like `GameFeatureAction_AddComponents` add components to the target actor class — but not directly, instead through the **GameFrameworkComponentManager**.

```
Actor (PreInitializeComponents)
  │
  ▼ AddGameFrameworkComponentReceiver(this)
  │
  ▼ GameFrameworkComponentManager
  │   ├── "Are there pending components for this class?"
  │   ├── Yes → Spawn and attach the component
  │   └── No  → Record it, will be added when the action arrives
  │
  ▼ BeginPlay
  │   └── SendGameFrameworkComponentExtensionEvent(NAME_GameActorReady)
  │
  ▼ EndPlay
      └── RemoveGameFrameworkComponentReceiver(this)
```

This enables **runtime component injection** into any actor **without compile-time dependencies**.
