Skip to content

Gameplay messages

Programmer · reference · No code

XenoCore announces changes through Lyra's Gameplay Message Router: a sender broadcasts a payload struct on a gameplay-tag channel, and any number of listeners receive it without knowing who sent it. This is how the HUD, menus and quests stay up to date. For the idea behind it, see Events and messages.

To listen from a Blueprint, use Lyra's Listen for Gameplay Messages latent node, set Channel to the tag and Payload Type to the struct below. From C++, use UGameplayMessageSubsystem::Get(this).RegisterListener(...) and keep the returned handle so you can unregister in EndPlay or NativeDestruct. Every payload struct is BlueprintType.

Channels

Channel Payload Sent by Sent when
XenoCore.Inventory.Message.Changed FXenoCoreInventoryChangedMessage UXenoCoreInventoryStatics (every add, remove and consume it performs); UXenoCoreInventoryWatchSubsystem for a change made with Lyra's own inventory functions, one frame later The party bag gains or loses items
XenoCore.Equipment.Message.SlotChanged FXenoCoreEquipmentSlotChangedMessage UXenoCoreEquipmentComponent A character's slot is equipped, swapped or emptied
XenoCore.Party.Message.Changed FXenoCorePartyChangedMessage UXenoCorePartyComponent only The roster, the active party or the leader changes
XenoCore.Party.Message.TacticChanged FXenoCoreTacticChangedMessage UXenoCorePartyComponent only A party tactic changes, for the whole party or one member
XenoCore.Party.Message.Wiped FXenoCorePartyWipedMessage UXenoCorePartyComponent only Twice per party wipe: when every active member is down, and when the party has respawned
XenoCore.PartyGauge.Message.Changed FXenoCorePartyGaugeChangedMessage UXenoCorePartyGaugeComponent only The Party Gauge gains or loses points, with the reason
XenoCore.PartyGauge.Message.Refused FXenoCorePartyGaugeChangedMessage UXenoCorePartyGaugeComponent (Notify Cannot Afford) The player asked for bars the gauge does not hold, such as a revive with the gauge short. Nothing changed
XenoCore.Progression.Message.Changed FXenoCoreProgressionChangedMessage UXenoCoreProgressionComponent only EXP is banked, a level is gained, or gold changes
XenoCore.Progression.Message.LevelUp FXenoCoreLevelUpMessage UXenoCoreProgressionComponent Once per award that raised at least one level, after the Changed message
XenoCore.Skills.Message.SkillLearnt FXenoCoreSkillLearntMessage UXenoCoreProgressionComponent A character learns a skill
XenoCore.Quest.Message.Changed FXenoCoreQuestChangedMessage UXenoCoreQuestComponent only Any quest is offered, accepted, declined, progressed or turned in
XenoCore.Quest.Message.TurnedIn FXenoCoreQuestTurnedInMessage UXenoCoreQuestComponent Once, when a quest is handed in, carrying the payout
XenoCore.Enemy.Message.Defeated FXenoCoreEnemyDefeatedMessage AXenoCoreEnemyCharacter An enemy's death starts (the same moment EXP and its chest are awarded)
XenoCore.Loot.Message.ChestOpened FXenoCoreChestOpenedMessage AXenoCoreTreasureChest A chest is opened and its contents rolled
XenoCore.Collectable.Message.Collected FXenoCoreCollectableCollectedMessage AXenoCoreCollectableOrb A collectable orb is picked up and its item banked
XenoCore.Targeting.Message.TargetChanged FXenoCoreTargetChangedMessage UXenoCoreGameplayAbility_TargetMode The locked target changes, including to none when the lock ends
XenoCore.Battle.Message.Notification FXenoCoreBattleNotification UXenoCoreBattleNotifySubsystem (the Notify node) Battle text should appear over an actor: miss, break, a buff name
XenoCore.Battle.Message.Won FXenoCoreBattleWonMessage UXenoCoreBattleVictorySubsystem only A battle is won (the last fighting enemy fell with the party in battle), as the fanfare starts and the party sheathes
XenoCore.Voice.Message.Spoke FXenoCoreVoiceSpokeMessage UXenoCoreBattleVoiceSubsystem A party member starts a voice line
XenoCore.Time.Message.PhaseChanged FXenoCoreTimeChangedMessage UXenoCoreTimeOfDaySubsystem The clock enters Morning, Day, Evening or Night
XenoCore.Time.Message.HourBlockChanged FXenoCoreTimeChangedMessage UXenoCoreTimeOfDaySubsystem The clock enters a new three-hour block
XenoCore.Time.Message.Jumped FXenoCoreTimeChangedMessage UXenoCoreTimeOfDaySubsystem The time was set (Change Time, a load, a console command) rather than reached
XenoCore.Weather.Message.Changed FXenoCoreWeatherChangedMessage UXenoCoreWeatherSubsystem The weather changes

Sources: the BroadcastMessage calls in these files under Source/XenoCoreRuntime/Private/ (search the file for BroadcastMessage): XenoCoreInventoryStatics.cpp, XenoCoreInventoryWatchSubsystem.cpp, XenoCoreEquipmentComponent.cpp, XenoCorePartyComponent.cpp, XenoCorePartyGaugeComponent.cpp, XenoCoreProgressionComponent.cpp, XenoCoreProgressionComponent_Skills.cpp, XenoCoreQuestComponent.cpp, XenoCoreEnemyCharacter.cpp, XenoCoreTreasureChest.cpp, XenoCoreCollectableOrb.cpp, XenoCoreTargetModeAbility.cpp, XenoCoreBattleNotifySubsystem.cpp, XenoCoreBattleVictorySubsystem.cpp, XenoCoreBattleVoiceSubsystem.cpp, XenoCoreTimeOfDaySubsystem.cpp and XenoCoreWeatherSubsystem.cpp.

Payloads

FXenoCoreInventoryChangedMessage

Field Type Meaning
Owner AActor* The bag's owner: the player controller
ItemDef TSubclassOf<ULyraInventoryItemDefinition> The item that changed
NewCount int32 How many the party holds after the change
Delta int32 Positive when gained, negative when spent

FXenoCoreEquipmentSlotChangedMessage

Field Type Meaning
Owner AActor* The pawn whose loadout changed
Slot EXenoCoreEquipSlot Which slot
Item ULyraInventoryItemInstance* What is in the slot now; null when it was emptied

FXenoCorePartyChangedMessage

Field Type Meaning
OwningController AController* The controller whose party changed
ActiveCount int32 How many characters are active now

FXenoCoreTacticChangedMessage

Field Type Meaning
OwningController AController* The controller whose party it is
Member UXenoCorePartyMemberDefinition* The member whose own order changed; null for a whole-party change
Tactic EXenoCoreTactic Which tactic
Value int32 The new value. For a member, INDEX_NONE means the order was handed back to the party's

FXenoCorePartyWipedMessage

Field Type Meaning
OwningController AController* The controller whose party was wiped
Phase EXenoCorePartyWipePhase Defeated: every active member is down and the fade to black is about to start. Respawned: the party stands again at full health and the fade back in has started
RespawnTransform FTransform Where the party is sent. Already final at Defeated, so a UI can name the place before the fade

FXenoCorePartyGaugeChangedMessage

Used by both Party Gauge channels. On Refused, the old and new points are equal.

Field Type Meaning
OldPoints float Points before the change
NewPoints float Points after it
MaxPoints float The whole gauge (300 by default)
PointsPerBar float One bar (100 by default)
Reason FGameplayTag Why: a XenoCore.PartyGauge.Reason.* tag. Empty for the out-of-battle drain

FXenoCoreProgressionChangedMessage

Field Type Meaning
OwningController AController* The controller whose party progressed
LevelledCount int32 How many characters levelled in this award
ExperienceAwarded int32 The EXP this award was worth

FXenoCoreLevelUpMessage

Field Type Meaning
OwningController AController* The controller whose party levelled
Levelled TArray<FXenoCoreLevelUpEntry> One entry per character that levelled: Member, LevelBefore, LevelAfter

FXenoCoreSkillLearntMessage

Field Type Meaning
Member UXenoCorePartyMemberDefinition* Who learnt it
Branch FName The skill branch
Index int32 Position in the branch, 0 to 4, top to bottom
SkillName FText The skill's display name

FXenoCoreQuestChangedMessage

Field Type Meaning
OwningController AController* The controller whose quests moved

This message says only that something changed. Listeners re-read the quest component for the details.

FXenoCoreQuestTurnedInMessage

Field Type Meaning
Quest UXenoCoreQuestDefinition* The quest handed in
QuestTitle FText Its title, copied at the time
Gold int32 Gold paid
Experience int32 EXP paid
Items TArray<TSubclassOf<ULyraInventoryItemDefinition>> Items handed over

This one carries the payout because it cannot be re-read afterwards: a moment later the gold is part of a running total and the items may already be spent.

FXenoCoreEnemyDefeatedMessage

Field Type Meaning
EnemyClass TSubclassOf<AActor> What died. Kill objectives match it with is child of, so an objective can name a base class.
DisplayName FText The enemy's name as shown on its target badge. Empty if the enemy has none authored
Level int32 The enemy's level

FXenoCoreChestOpenedMessage

Field Type Meaning
Chest AActor* The chest
Tier EXenoCoreChestTier Wooden, Silver or Gold
Offered TArray<TSubclassOf<ULyraInventoryItemDefinition>> What the chest offers. Nothing is in the bag yet: the loot panel lets the player take or leave it.

FXenoCoreCollectableCollectedMessage

Field Type Meaning
ItemDef TSubclassOf<ULyraInventoryItemDefinition> What was picked up. Never null: a refused pickup sends nothing.
Instance ULyraInventoryItemInstance* The instance that entered the bag
Orb AActor* The orb

FXenoCoreTargetChangedMessage

Field Type Meaning
Seeker AActor* The pawn doing the targeting
NewTarget AActor* What is now selected; null when the lock ends
OldTarget AActor* What was selected before

FXenoCoreBattleNotification

Field Type Meaning
Target AActor* Whose head the text appears over
Text FText The text
Colour FLinearColor Its colour
Scale float Draw size

Send your own with the Notify node (XenoCore › Battle). It broadcasts on this channel, so anything else listening (a combat log, a tutorial) sees your text too.

FXenoCoreBattleWonMessage

Field Type Meaning
Celebrants TArray<ACharacter*> Every living party body told to sheathe and celebrate

FXenoCoreVoiceSpokeMessage

Field Type Meaning
Speaker AActor* Who is speaking
Category FGameplayTag The line's XenoCore.Voice.* category
Take FXenoCoreVoiceTake The take being played
Expression, ExpressionWeight FName, float The face the line asks for
Subtitle FText The subtitle text
Duration float How long the line lasts, in seconds

FXenoCoreTimeChangedMessage

Used by all three time channels.

Field Type Meaning
Minutes float Minutes since midnight now
OldPhase, NewPhase EXenoCoreTimePhase Morning, Day, Evening or Night, before and after
HourBlock int32 The three-hour block now
bJumped bool The time was set rather than reached; lighting snaps instead of blending

FXenoCoreWeatherChangedMessage

Field Type Meaning
OldWeather, NewWeather FGameplayTag The weather before and after
bInstant bool The change snaps rather than blends

Who listens

Channel Listeners in C++
Inventory.Message.Changed UXenoCoreQuestComponent (re-counts collection quests); also a console self-test on UXenoCoreEquipmentComponent
Equipment.Message.SlotChanged UXenoCoreStatBlockBase (stat panels)
Party.Message.Changed UXenoCorePartyMemberPlateBase (HUD plates)
Party.Message.Wiped None. Yours to use, for a defeat card or a "returned to..." line
PartyGauge.Message.Changed UXenoCorePartyGaugeWidget (the gauge readout)
PartyGauge.Message.Refused UXenoCorePartyGaugeWidget (shakes and flashes red)
Progression.Message.Changed UXenoCorePlayerPlateBase (HUD plates)
Progression.Message.LevelUp UXenoCoreLevelUpBannerBase
Quest.Message.Changed UXenoCoreQuestLogBase, UXenoCoreQuestTrackerBase
Quest.Message.TurnedIn UXenoCoreQuestRewardBase
Enemy.Message.Defeated UXenoCoreQuestComponent (kill objectives)
Loot.Message.ChestOpened UXenoCoreLootPopupSubsystem (opens the loot panel)
Collectable.Message.Collected UXenoCoreItemBadgeBase
Battle.Message.Notification UXenoCoreBattleNotifySubsystem (draws the text)
Battle.Message.Won AXenoCoreAreaMusic (fades the battle track), UXenoCoreBattleVoiceSubsystem (victory lines)
Weather.Message.Changed AXenoCoreEnvironmentDirector (lights, sky and rain)
Party.Message.TacticChanged, Voice.Message.Spoke, Time.Message.* None in C++. Yours to use

No shipped Blueprint listens to a XenoCore channel; all listeners are the C++ bases above. XenoCore also listens to one Lyra channel: UXenoCoreDamageNumberSubsystem draws taken-damage and heal numbers from Lyra's damage message.

Rules and traps

Fails silently: Lyra's own inventory message never fires here

Lyra's Lyra.Inventory.Message.StackChanged is only sent from network-replication callbacks. XenoCore is single-player, so it never arrives. Listen to XenoCore.Inventory.Message.Changed instead.

Changing the bag behind XenoCore's back

UXenoCoreInventoryStatics (the XenoCore › Inventory nodes) sends the inventory message directly. A change made through Lyra's inventory manager is noticed by UXenoCoreInventoryWatchSubsystem, which sends the same message for it one frame later and logs it to LogXenoBagWatch. So listeners still hear it, but a frame late, and with none of the statics' protections (carry caps, never removing a worn item). The message's Owner is then the controller that owns the bag.

Screens should re-read, not accumulate

Several messages carry only "something changed". Treat every message as a prompt to re-read the owning component, never as a delta to add up. A running total drifts the first time a change arrives without a message.

  • Add your own channel rather than reusing one: each XenoCore channel has one sender by design, so listeners can trust where it came from. Declare the tag in your own tag file and your own payload struct.
  • Unregister in EndPlay or NativeDestruct. A widget that is pooled and re-shown should register once, not on every show.