X157 Dev Notes

One simulant attempts to share insight with others.

Deep Dive: Lyra’s Shooter Mannequin

Lyra defines a “Shooter Mannequin” (B_Hero_ShooterMannequin) to be the base character for the Lyra project. This serves as both the player-controlled character and the AI-controlled character.

This documentation is current as of Lyra 5.1.

Note that I do not use B_Hero_ShooterMannequin in my game. That would require me to declare ShooterCore as a GFP dependency, which I do not wish to do. Instead, I have my own base character class that was constructed using B_Hero_ShooterMannequin as an example. Thus, even though I’m not using this, it is still very important to understand what Epic is doing with this class so I can pick and choose the pieces that are relevant to my game for my character.

Quick Links:


Primary Blueprint Overview: B_Hero_ShooterMannequin

This is the primary BP we are interested in. However, note that A LOT of functionality is implemented in the base classes, both the base BPs and the base C++. You need to understand ALL the base classes and interfaces if you are to fully understand B_Hero_ShooterMannequin.

B_Hero_ShooterMannequin BP Inheritance
ALyraCharacter C++ Inheritance

Controller-Injected C++ Component: B_PickRandomCharacter

In addition to the base classes, Lyra also injects a B_PickRandomCharacter component into every AController at runtime. For example see the B_ShooterGame_Elimination Experience Definition.

Thus, even though you won’t see this explicitly attached to the controller or pawn in code, at runtime this component WILL exist on the default Pawn controller.

This component is based on the C++ ULyraControllerComponent_CharacterParts.

This Controller Component acts in conjunction with the Pawn version of this component (ULyraPawnComponent_CharacterParts). If you are dealing with characters comprised of different parts, like Lyra, you will want to read the underlying C++ for both the controller AND pawn versions of this component. They’re two parts of the same system.

On Controller BeginPlay, a random body mesh is chosen (either Manny or Quinn) by the controller component and assigned to the Pawn. This is what makes the pawn randomly masculine or feminine in physical appearance and animation style.


Key Concept: Pawn Extension System

Lyra Characters are modularly constructed at runtime. For this reason there is no clearly defined initialization order. The character may have many optional components that depend on each other in different ways that change over time.

As a developer you don’t have any way to know which components will be injected at runtime, yet you must still allow for them to initialize correctly, each with their own dependencies, in whatever random order happens by chance at runtime.

Lyra solves this problem by implementing The ModularGameplay Plugin in the form of ULyraPawnExtensionComponent, which is a part of every ALyraCharacter.

Lyra Pawn Extension Component

ULyraPawnExtensionComponent is the implementation of the ModularGameplay Plugin’s IGameFrameworkInitStateInterface functionality on a Pawn.

Giving this component to an Actor allows the other components on that actor to share Init State updates with each other to satisfy runtime dependencies. The components can hook into Actor Init State Changed events broadcast by this component if/when they have runtime dependencies to satisfy.

Note that, though this is a component, there are some deep integrations in ALyraCharacter for things like, for example, calling ULyraPawnExtensionComponent🡒HandleControllerChanged from ALyraCharacter🡒PossessedBy. If you want a deep understanding of what this component is doing, make sure you read through ALyraCharacter as well.

OnRegister
BeginPlay
Pawn Extension Component 🡒 OnActorInitStateChanged
Pawn Extension Component :: CheckDefaultInitialization

This tells every component on the owner Actor that supports the IGameFrameworkInitStateInterface to try to initialize.

This gets spammed A LOT during initialization. This is a trigger that keeps getting executed until all components have initialized successfully or finally fail to initialize.

Debugging Tip

The interesting logs related to the Pawn Extension System are made by the ModularGameplay plugin’s IGameFrameworkInitStateInterface.

It logs to LogModularGameplay with a lot of Verbose log messages. Make sure you turn on Verbose viewing for that log if you are trying to understand the flow of code via logs.


Blueprint: B_Hero_ShooterMannequin

Components:

» AimAssistTarget (UAimAssistTargetComponent via ShooterCore GFP)

» PawnCosmeticsComponent (ULyraPawnComponent_CharacterParts)

Mesh Name Animation Style Body Style
Manny Masculine Medium
Quinn Feminine Medium

The actual Gameplay Tags defined are Cosmetic.AnimationStyle.* and Cosmetic.BodyStyle.*

Anywhere that you want to know if you have a masculine or feminine character, you can simply check the Pawn’s Tags to, for example, animate a feminine character differently than a masculine one.

Event Graph:

BeginPlay

Possessed

ULyraPawnComponent_CharacterParts.OnCharacterPartsChanged

ULyraHealthComponent.OnHealthChanged

Enhanced Input Action Triggers:

OnDeathFinished

OnReset

Set Emote Audio Component from BI Emote Sound Interface

Not sure what this is or what this does. Seems to be part of the emote system. Requires investigation.


Blueprint: B_Hero_Default

Components:

» LyraHero (ULyraHeroComponent)

Lyra Hero Component 🡒 OnActorInitStateChanged
Lyra Hero Component :: CheckDefaultInitialization

» AIPerceptionStimuliSource (UAIPerceptionStimuliSourceComponent)

» LyraContextEffect (ULyraContextEffectComponent)

Event Graph:

ULyraHealthComponent.OnDeathStarted

ULyraContextEffectComponent.AnimMotionEffect

Interesting Variables:


Blueprint: B_Character_Default

This is a very simple BP. It inherits from ALyraCharacter and:

Essentially this is telling the navigation system that AI need to path AROUND a B_Character_Default character rather than through it.