Add a mechanic by subclassing¶
Programmer · 1–2 h · C++
This page is for programmers
It needs Visual Studio and C++. If you are a designer wanting a variation on an existing
mechanic, you almost never need it: right-click the XenoCore Blueprint closest to what you want
(for example Battle/Arts/GA_XenoCore_TalentArt_Base) and choose Create Child Blueprint
Class, then change its Class Defaults. The recipes show this for Arts, enemies, NPCs and
screens. If a recipe cannot do what you need without C++, hand this page to a programmer.
Result: your own C++ module, in its own plugin, that builds on XenoCore's classes (here, a new kind of Art ability) without a single edit to XenoCore's source. A template update then replaces XenoCore and leaves your code alone.
Before you start¶
- Architecture overview: what lives in the plugin and why.
- A working C++ toolchain: Requirements.
- C++ classes lists every class with its header.
The rule¶
Don't edit XenoCore's source, and don't edit Lyra's. Add behaviour by subclassing, in a module you own. If a base class is missing a hook you need, that is a gap in the template: report it (Reporting bugs) rather than patching around it, and keep any unavoidable patch small and written down.
Two ways to subclass¶
| Blueprint child | C++ child | |
|---|---|---|
| Needs | Nothing | Your own C++ module |
| Good for | Content-shaped variation: different numbers, a different montage, a few extra graph nodes | New logic: overriding virtual functions, per-frame work, new properties with validation |
| Works on | Any class marked Blueprintable or Abstract-but-Blueprintable | Every public XenoCore class (they are all exported) |
Try a Blueprint child first. Most extension in the samples is Blueprint children of C++ bases:
GA_XenoCore_BackSlash is a Blueprint child of the C++ Art ability.
Which bases are built for extension¶
| Base | For | C++ child? |
|---|---|---|
UXenoCoreGameplayAbility_Art |
Arts. Data-driven by UXenoCoreArtDefinition; override ActivateAbility, CanActivateAbility, EndAbility, ApplyCooldown. BeginStrike and ApplyArtEffect are callable helpers. |
Yes |
UXenoCoreGameplayAbility_TalentArt, UXenoCoreTalentArtDefinition |
Talent Arts | Yes |
UXenoCoreGameplayAbility_AutoAttack, UXenoCoreGameplayAbility_TargetMode |
Auto-attack, target mode | Yes |
UXenoCoreGameplayAbility_Reaction and its children …_HitReact (flinch), …_DefenceReact (guard, evade, recoil) and …_KnockdownReact (…_ToppleReact, …_DazeReact) |
Reactions. Derive from the child closest to yours: Reaction itself holds only the shared machinery (direction, hold, follow-up), each child adds its own trigger and refusals |
Yes |
UXenoCoreStatusEffect |
Status effects (a Gameplay Effect with display data) | Yes |
UXenoCoreArtDefinition, the item fragments (UXenoCoreFragment_*) |
New data on arts and items | Yes |
UXenoCoreHudPlateBase |
Any HUD element that fades in and out; the player plate, party plates, target plate, quest tracker and banners derive from it | Yes |
UXenoCoreMerchantScreenBase |
A buy/sell/exchange screen; shop and trade derive from it | Yes |
UXenoCoreBootScreenBase (…LogoBootScreenBase, …MovieBootScreenBase, …ShaderBootScreenBase) |
Cards in the boot sequence; override ShouldShow, OnBootScreenShown, OnBootScreenLeaving |
Yes |
UXenoCoreConfirmPopupBase, UXenoCoreSaveScreenBase, UXenoCoreTitleScreenBase, quest log/offer/reward bases, UXenoCoreLootPopupBase, UXenoCoreStatBlockBase, UXenoCoreTutorialCardBase |
Menu screens and popups | Yes |
UXenoCoreMainMenuBase, UXenoCorePartyCardBase, UXenoCoreMenuEntryButton |
The main menu, its party cards and its entries | Yes |
AXenoCoreCombatantCharacter, AXenoCorePartyCharacter, AXenoCoreEnemyCharacter |
Characters. Enemies do not derive from the combatant base; see Enemies and AI | Yes |
AXenoCoreInteractableActor |
Doors, levers, signs: anything the player presses A on. See Add an interactable object | Yes |
UXenoCoreEquipmentComponent, UXenoCoreAnimInstance |
Equipment, animation Blueprints | Yes |
UXenoCoreStatSet, UXenoCoreDamageExecution, UXenoCoreMMC_EffectLevel |
Stats and the damage formula. The execution has no per-term hooks; see Add a stat to the damage formula | Yes |
UXenoCorePartyMemberDefinition, AXenoCorePartyMemberController, AXenoCoreEnemyController |
Party data, party AI, enemy AI | Yes |
AXenoCoreEnemySpawner |
A squad of field enemies; see Place enemies | Yes |
UXenoCoreMenuAction, UXenoCoreMenuCondition |
What a menu entry does, and when it shows. Normally Blueprint; see Add a menu screen | Yes |
IXenoCoreSaveParticipant, UXenoCoreSaveParticipantComponent |
Your own saved data. See Make a system save | Yes |
The StateTree tasks and conditions (FXenoCore*Task, FXenoCore*Condition) |
Enemy and party AI building blocks | Yes, and callable |
Every public class and struct in XenoCoreRuntime is exported with XENOCORERUNTIME_API, so a
C++ class in your own module can derive from it and call its functions. The only exceptions are
the module object and the two console-command cheat extensions (UXenoCoreSystemCheats,
UXenoCoreProgressionCheats), which are not meant to be extended. The three interfaces
(IXenoCoreAnimProfileProvider, IXenoCoreMapMarkerSource, IXenoCoreMenuButton) are exported
too; only their U halves are minimally exported, which is all implementing one needs.
Link error: \"unresolved external symbol\" on a Lyra class
Some of Lyra's own classes are not exported from LyraGame (for example
ULyraAnimInstance, ULyraButtonBase, ULyraGameplayAbility_FromEquipment,
ULyraGameplayAbility_Interact). A C++ class of yours that derives from one compiles and then
fails to link. XenoCore's bases never require one: each derives only from exported Lyra
classes. Derive a Blueprint from the Lyra class instead.
Steps¶
1. Create your plugin¶
- Edit › Plugins › Add, choose Game Feature (with C++). Name it
MyGameCore. It is created underPlugins/GameFeatures/MyGameCore. -
Open
MyGameCore.upluginand add XenoCore to its Plugins list:"Plugins": [ { "Name": "XenoCore", "Enabled": true } ] -
Open
Source/MyGameCoreRuntime/MyGameCoreRuntime.Build.csand add the modules you build on:PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "XenoCoreRuntime", "LyraGame", "GameplayAbilities", "GameplayTags", "GameplayTasks", });Add
CommonUI,UMG,SlateCoreif you subclass a screen or HUD base. -
Never add XenoCore's editor module (
XenoCoreEditor) to a runtime module's dependencies.
2. Switch your feature on¶
A Game Feature does nothing until an experience enables it. Open
Experiences/B_XenoCore_Experience and add MyGameCore to Game Features to Enable, beside
XenoCore. Note this change for template updates, or use a copy of the experience as your own.
3. Write the subclass¶
An art that can only be used while the user is below half health:
// MyGameArt_Desperation.h
#pragma once
#include "Arts/XenoCoreGameplayAbility_Art.h"
#include "MyGameArt_Desperation.generated.h"
UCLASS(Blueprintable)
class MYGAMECORERUNTIME_API UMyGameArt_Desperation : public UXenoCoreGameplayAbility_Art
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, Category = "MyGame|Art", meta = (ClampMin = "0", ClampMax = "1"))
float MaxHealthFraction = 0.5f;
protected:
virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags,
const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const override;
};
In the .cpp, call Super::CanActivateAbility(...) first and return false if it does; only then
add your test. Build with the editor closed.
Then, in the editor, create a Blueprint child of UMyGameArt_Desperation if you want one, and set
it as the Ability Class on an Art definition. See Create an attack art.
4. Follow the base-class rules¶
Always call Super
The Art base does range checks, cooldowns, movement locking and montage bookkeeping in its
overrides. Skipping Super skips all of it, often with no visible error until an art never
ends or never goes on cooldown.
Fails silently: a Blueprint array override replaces the C++ defaults
The bases fill tag lists in their constructors. For example, the Art base adds
Gameplay.MovementStopped and Status.XenoCore.ArtExecuting to Activation Owned Tags,
which is what roots the character and keeps flinches from interrupting. If a Blueprint child
edits that list at all, its list replaces the whole C++ one. Nothing warns. In a Blueprint
child, leave these lists alone or re-add every entry the base had. In a C++ child, append in
your constructor rather than assigning.
Don't change behaviour for other children
If you add a subclass between a XenoCore base and existing children, defer to Super for
anything that has not opted in to your new behaviour.
Test it¶
- Build (editor closed). The Output Log on startup shows no errors from
MyGameCore. - Open
Maps/L_XenoCore_Gym, Play, and give a character the new art. - At full health the art is refused; below half health it fires, goes on cooldown and ends normally.
- Replace the XenoCore plugin folder with a fresh copy of the same version. Your plugin still builds and the art still works.
If it doesn't work¶
Unresolved external symbol at link
The base is one of Lyra's unexported classes (see the warning above), or your Build.cs is
missing a module the base's header needs, such as GameplayAbilities or StateTreeModule.
My class doesn't appear in the class picker
Your Game Feature isn't enabled by the experience, or the class isn't Blueprintable.
The art freezes the character
An override returned without calling Super::EndAbility, so the movement-stop tag was never
removed.