Skip to content

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

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

  1. Edit › Plugins › Add, choose Game Feature (with C++). Name it MyGameCore. It is created under Plugins/GameFeatures/MyGameCore.
  2. Open MyGameCore.uplugin and add XenoCore to its Plugins list:

    "Plugins": [
        { "Name": "XenoCore", "Enabled": true }
    ]
    
  3. Open Source/MyGameCoreRuntime/MyGameCoreRuntime.Build.cs and add the modules you build on:

    PublicDependencyModuleNames.AddRange(new string[]
    {
        "Core", "CoreUObject", "Engine",
        "XenoCoreRuntime", "LyraGame",
        "GameplayAbilities", "GameplayTags", "GameplayTasks",
    });
    

    Add CommonUI, UMG, SlateCore if you subclass a screen or HUD base.

  4. 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

  1. Build (editor closed). The Output Log on startup shows no errors from MyGameCore.
  2. Open Maps/L_XenoCore_Gym, Play, and give a character the new art.
  3. At full health the art is refused; below half health it fires, goes on cooldown and ends normally.
  4. 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.

Going further