Understanding Lyra's Experience System
Lyra ships with a lot of moving parts. The ULyraExperienceDefinition is the central data asset that drives the whole game mode, but its role isn't immediately obvious from the class hierarchy. Here's a practical breakdown of how the system works, what connects to what, and how to extend it.
What the Experience System Does
Every Lyra map references an ULyraExperienceDefinition asset. When the game state loads this asset, it triggers a cascade of setup steps:
- The pawn data (
ULyraPawnData) is resolved - this defines which pawn class to spawn, which ability sets to grant, and which input config to use. - Action sets are applied - these add components to actors (useful for adding features like team assignment or respawn handling without subclassing).
- Ability sets are granted to the
UAbilitySystemComponenton thePlayerState.
The Deferred Init Problem
The most confusing part of Lyra's architecture is why ULyraHeroComponent::InitializePlayerInput() doesn't just run in BeginPlay. It runs inside CheckPawnReadyToInitialize(), which gates on:
- The pawn extension component being valid
- The controller being set
- The experience being fully loaded
This is important for dedicated servers: the experience asset is replicated as part of game state. If you set up input bindings before replication completes, the input config asset reference is null and the whole binding chain silently fails.
The fix is always to use the OnExperienceLoaded delegate:
ULyraExperienceManagerComponent* ExperienceComponent =
GameState->FindComponentByClass<ULyraExperienceManagerComponent>();
ExperienceComponent->CallOrRegister_OnExperienceLoaded(
FOnLyraExperienceLoaded::FDelegate::CreateUObject(
this, &AMyCharacter::OnExperienceLoaded));
Granting and Revoking Ability Sets
Ability sets use a handle pattern for clean revocation. Always store the handles:
FLyraAbilitySet_GrantedHandles GrantedHandles;
AbilitySet->GrantToAbilitySystem(ASC, &GrantedHandles, SourceObject);
// Later, on pawn death or experience switch:
GrantedHandles.TakeFromAbilitySystem(ASC);
Forgetting to revoke causes duplicate ability specs on respawn, which produces unpredictable activation behavior.
Adding a Custom Ability Set
- Create a
ULyraAbilitySetdata asset. - Add your
UGameplayAbilitysubclasses to the Granted Gameplay Abilities array. - Reference this asset in your
ULyraExperienceDefinitionunder Ability Sets to Grant.
That's it. Lyra's ULyraPawnData also has a direct Ability Sets array - use that for pawn-specific grants, and the experience-level array for global (per-map) grants.
What I Learned
- The Experience system is essentially a data-driven dependency injection framework for game features.
- Never bypass
CheckPawnReadyToInitialize- the guards are there because the initialization order is genuinely non-deterministic in multiplayer. - Ability set handles are a lightweight RAII pattern - treat them like smart pointers and store them wherever you store the thing that owns the granted abilities.
- Lyra's
ULyraGameFeatureAction_AddAbilitiesshows a clean pattern for adding abilities without subclassingULyraExperienceDefinition.