Ability & Kit Authoring Tools¶
Summary: The toolchain that turns a paper ability design into a shipped, kit-composed, PIE-testable ability. Two editor tabs — the Ability Workshop (browse/create/validate single abilities) and the Kit Composer (compose abilities into kits and kits onto preset builds) — sit on a shared data spine: the Ability Archetype Catalog (what shapes are authorable) and a pair of validators that gate every ability and kit on save. The tools do plumbing only: montage, notifies, cues, and feel stay hand-work in the Blueprint editor.
Pipeline overview¶
Design/ paper one-pager AbilityArchetypeCatalog (DefaultGame.ini)
(.ability.md / .kit.md) rows: shape + authoring contract
│ │
│ human transcribes │ seeds create menus,
▼ ▼ contract, validators
┌──────────────────────┐ template asset ┌──────────────────────┐
│ Create wizard OR │──── duplicate ─────▶ │ new GA_ Blueprint │
│ Eternal.Ability. │ + stamp CDO slots │ (validator-green by │
│ Stamp (headless) │ │ construction) │
└──────────────────────┘ └──────────┬───────────┘
│ hand-finish in BP:
│ montage, notifies,
│ cues, feel constants
▼
┌─────────────────────────────┐
on every save / -run=DataValidation / │ UEternalAbilityValidator │
Workshop "Validate All" ─────────────▶│ (shared AbilityValidation) │
└──────────────┬──────────────┘
│ 0 errors
▼
┌──────────────────────┐ compose ┌──────────────────────┐ compose ┌────────────┐
│ Kit Composer: │ abilities │ Kit Composer: │ kits │ Preset │
│ Kits view │───────────▶│ Presets view │───────────▶│ → PIE via │
│ (UEternalAbilitySet)│ │ (GrantedKits order) │ │ PlayPreset │
└──────────┬───────────┘ └──────────┬───────────┘ └────────────┘
│ UEternalKitValidator (shared KitValidation), on save / CI / inline strips
└────────────────────────────────────────────┘
The catalog is the pivot: the wizard, the stamp command, the Workshop's Create menu, and the
validators all read the same rows. Adding a new authorable shape is a data edit, never an editor-code
edit — see 09_New_Ability_Archetype_Recipe.md.
Ability Archetype Catalog¶
UEternalAbilityArchetypeCatalog is a UDeveloperSettings (Project Settings > Game > Ability
Base Catalog), config-backed in Config/DefaultGame.ini rather than a .uasset so the rows
are text-diffable and testable headlessly without loading assets.
Terminology: every designer-facing string in the tools says "Ability Base" (the wizard's picker, the Workshop's New from Ability Base… entry, the Project Settings page) — the C++/config identifiers keep the historical
Archetypespelling (FAbilityArchetypeDef,ArchetypeId). Same thing; the glossary inDesign/README.mdrecords the ruling. This reference uses the config term where it names code, and the UI term where it quotes the UI.
Each FAbilityArchetypeDef row carries:
| Field | Purpose |
|---|---|
ArchetypeId |
Stable row identity; referenced by template assets and validation reports. |
DisplayName |
Label in the Workshop's Create New menu and the wizard's archetype picker. |
Description |
One or two sentences on what the archetype is for, shown as the dropdown tooltip. Required — it is the only thing telling a designer apart two similarly-named rows (AOE Damage vs AOE Skill). |
Category |
Workshop list grouping / filter bucket. |
BaseClass |
The shipped C++ base this archetype parameterizes. Rows exist only for shipped bases. |
DefaultFolder |
Content folder the Create dialog opens in. |
TemplateBP |
The TPL_<ArchetypeId> Blueprint the wizard/stamp duplicates. Editor-only, never resolved at runtime — its folder is excluded from cooks. |
bPlayerActivated |
When true, validators require the cost/cooldown contract fully wired. |
RequiredTagSlots |
FGameplayTag CDO properties that must be non-None to function. |
RequiredClassSlots |
Class-reference CDO properties (cost/damage/state GEs, actor classes) that must be non-null. |
NumericSlots |
FScalableFloat CDO properties the wizard stamps; contract-checked to resolve. |
TagNamespaces |
Tag slot → the namespace its per-ability tag is derived from. The wizard proposes <Namespace>.<AbilityShortName> and registers the tag if it doesn't exist. Keys must be declared RequiredTagSlots, or the pseudo-slot AssetTags. |
FindRowForClass returns the row whose BaseClass is the most-derived ancestor of a given
class, so an AOE-skill Blueprint never mis-buckets as a plain skill; a subclass row shadows its
parent's row automatically. Rows ship for every authorable shape today — weapon Skill, AOE Skill, Leap,
Projectile, Melee Attack, Combat, Enemy, Enemy AOE, AOE Damage, Pressure Release Nova, Aura, the proc family (On-Hit,
On-Damaged, On-Kill, Pressure Builder, Status Cascade), the movement/defense family (Dodge, Sprint,
Crouch, Block, Hit React), and Consumable.
The catalog is consumed by the wizard, the Workshop, and the validators — it is never resolved at
runtime. To ADD an archetype (a new C++ verb + row + template asset), follow
09_New_Ability_Archetype_Recipe.md; this document does not duplicate that recipe.
Ability Workshop tab¶
Open it from the editor toolbar's Ability Workshop button (Plugin Tools section) or via Window > Ability Workshop. It is a unified browser for GAS abilities, gameplay effects, and combat config:
- Left — asset browser. Category-grouped abilities and effects (categories come from the catalog
via
ClassifyAbility), with a search box and category filter. - Right — details. The selected asset's CDO in an
IDetailsView, plus related-asset links.
Toolbar actions:
- Validate All runs the shared
AbilityValidationcore over every discovered entry — the exact same checks the on-save validator runs — so you can sweep the whole fleet from one button. - Create New has exactly two entries: New from Ability Base… (guided) — the wizard, below — and a plain Gameplay Effect. The raw per-base create entries were removed (ruled 2026-07-09): they produced blank, validator-red subclasses, a strictly worse path than the wizard. The catalog rows populate the wizard's Ability Base picker, not the menu.
- Duplicate clones the selected asset. Duplicated procs have their
ChanceAttributecleared — a copiedChanceAttributesilently overridesBaseChance, so the duplicate would inherit the source's proc rate instead of its own.
Cross-tool jump-links (OpenAndFocusAbility) let Kit Composer rows and the ability picker focus a
specific ability in an already-open Workshop tab.
Create wizard¶
The wizard (SAbilityCreateWizard, launched from Create New) is a blocking modal:
- Pick an archetype from the catalog.
- Name the ability and choose a target folder (defaults to the row's
DefaultFolder). - Fill the row's required slots with pickers — tag slots (
RequiredTagSlots, plus the startup input tag and primary asset tag pseudo-slots), class slots (RequiredClassSlots), and numeric slots (NumericSlots). Tag pickers are namespace-filtered per slot (Input.*for input,Cooldown.*for cooldowns, and so on).
Pre-fill from the ability name¶
Naming the asset GA_CrashLanding fills in everything the name implies, so the common case needs no
further typing:
- Display name becomes
Crash Landing(AbilityName, what the skill tooltip shows). Typing your own stops the derivation. - Every tag slot in the row's
TagNamespacesbecomes<Namespace>.CrashLanding— for a Leap that isCooldown.CrashLandingand the asset tagAbility.Skill.CrashLanding. Picking a tag by hand for that slot stops the derivation for it. - Derived tags that don't exist yet are created in
Config/Tags/GameplayTags.inion Finish, before the stamp. The wizard names them under the slot list first — it is a write to a shared config file, not a silent side effect. This is what the old workflow's "the picker only shows tags that already exist, go register one first" detour existed for. Registration happens before stamping becauseImportTexton an unregistered tag yieldsNone— the baked-Nonebug the validator exists to catch. - Cue tags are deliberately NOT derived. A cue tag with no registered
GameplayCueNotifyproduces ahas no registered GameplayCue handlerwarning, so auto-filling one would manufacture the very warning wall the pre-fill exists to remove. Cue tags are authored with their notifies.
Every slot seeds from the template asset's CDO, and only the slots you actually edit (the "dirty"
set) get stamped. That distinction matters: an untouched FScalableFloat numeric slot keeps the
template's curve reference instead of collapsing to a flat literal value. A blocker line at the
bottom names the first unmet requirement (missing name, unset required slot, …) and gates the Finish
button. Below the slots, hand-finish reminders list the montage step (set SkillMontages on the new
ability) and the audio layers the archetype owes (windup / travel / impact per 09_Audio/02; the travel line appears only for
archetypes that spawn projectiles or AOE actors). On Finish the wizard duplicates the template,
reflection-stamps the dirty slots, saves, validates, and opens the new Blueprint for hand-finish.
Eternal.Ability.Stamp console command¶
The wizard's Finish path and this console command run the same stamp code
(AbilityTemplateStamp::StampFromTemplate). The command is the headless path — agents and
-run=pythonscript / -ExecCmds sessions author abilities through it.
ValueTextis UE ExportText syntax and must be space-free — the console tokenizer splits on spaces. Value shapes:- Gameplay tags:
CooldownTag=(TagName="Cooldown.CrashLanding") - Class references:
DamageEffectClass=/Game/Path/GE_Foo.GE_Foo_C - Scalable floats:
LeapDistance=(Value=8.0) - The asset-tags property is accepted under either engine spelling (
AssetTags/AbilityTags). - The console command stamps only what you pass it. Name-derived pre-fill and tag registration are wizard behavior; a headless caller states every field explicitly.
- It refuses to run during PIE (stop the session first) and never creates over an existing asset (in memory or on disk).
- On a hard failure it returns null. On a soft failure — the asset was created but a stamped field or
a validator check failed — it returns the created Blueprint with the errors attached, so you
hand-finish instead of losing the duplicated work. Every run logs a
(N errors, M warnings)summary; read the Output Log.
Eternal.Chain.Stamp console command¶
Stamps every link of a Chain Sheet (Design/Chains/*.chain.md — the one machine-parsed Design/
artifact) as GA assets through the same StampFromTemplate path:
- The frontmatter is the input; per-link
fields:values are human-friendly (plain tag names, bare numbers) — the stamp converts them to ExportText by property type and still enforces each archetype's contract-field gate. - Structural wiring is derived, never authored:
Event.Chain.<ChainId>.<N>connecting tags are registered inGameplayTags.iniand written into link N's emit property (the catalog row'sChainEmitTagProperty) and link N+1'sAbilityTriggers; every link's Asset Tags gainAbility.Chain.<ChainId>; adamage_typere-type lands inReTypeDamageTagwhere the archetype has one. - The structural rails (linear, ≤3 links, per-victim fan-out terminal-only, non-terminal archetypes must have an emit seam) are validated before any asset is created.
- A full stamp writes the bundle handoff
Tools/ChainBundles/<ChainId>.bundle.json— thegrantedAbilitiesarray the carrying modifier definition (or kit) must grant atomically. The validators enforce completeness: a grant set with a danglingEvent.Chain.*connector errors. - The sheet stays authoritative for chain structure; the stamp never overwrites an existing asset — delete a link's GA to re-stamp it. Feel (montage, notifies, cues, hazard GE choice) stays hand-work per link.
Rules and provenance semantics: Documentation/02_AbilitySystem/08_Chain_Semantics.md.
Kit Composer¶
Open it from the editor toolbar's Kit Composer button or Window > Kit Composer. Two views
behind one toolbar (SKitComposerTab); it is a sibling to Build Lab — equipment lives there, and the
Composer only cross-links to it.
Kits view — author UEternalAbilitySet kits¶
- Left — kit list. Discovered via the AssetManager
AbilitySetprimary asset type (from/Game/DataAssets/Kits), with search. - Right — kit editor (
SKitDetailsPanel). An Abilities section with per-row input slot, activation policy, role, and level editing; a Passive Effects section; an inline validation strip (the sameKitValidation::ValidateKitchecks the on-save validator runs); and a where-used footer listing presets and class info that reference the kit, with jump-links.
Edits mutate the kit asset directly and MarkPackageDirty per the editor-module data convention.
Presets view — compose kits onto a build¶
- Left — preset list. Discovered via the AssetManager
CharacterPresetprimary asset type (from/Game/DataAssets/Presets), with search. Presets are captured elsewhere (Eternal.ExportPreset); this panel only lists them. - Right — preset composition (
SPresetKitsPanel). Edits the preset'sGrantedKitslist. Grant order matters: grant runs class starter kit → preset kits → items, and an input-slot collision resolves last-granted-wins at runtime. Use Move Up / Move Down to order the kits. The class starter kit is shown read-only as grant-order context (it is granted before any preset kit). The preset's equipped items are shown read-only with an Edit in Build Lab jump that opens the preset's name-pairedBL_*loadout (offering to create it from the preset's equipped items — remnant state included — when it doesn't exist); gear edits flow back via Build Lab's Export to Preset... (gear-only merge by default). Send to PIE pushes the build viaEternal.PlayPreset— this requires a PIE session booted fromL_Default, because the command needs the main-menu controller.
The toolbar carries kit CRUD (create / duplicate / delete in the Kits view, duplicate in the Presets view), open-asset, refresh, and a Validate All that runs both the kit and preset checks.
Validators¶
Both validators are UEditorValidatorBase subclasses, auto-discovered by the editor validator
subsystem. Each holds no logic of its own — all checks live in a shared core namespace so the on-save
validator, the -run=DataValidation commandlet (headless; not yet invoked by any CI workflow —
B-1/B-2 in WorldSystemsScalingReview.plan.md), and the tools' inline strips run identical code. They
run strict fleet-wide: there is no grandfather list. A failing legacy asset gets fixed,
re-authored, or deleted.
AbilityValidation (abilities + gameplay effects) checks:
Nonetags baked by the constructor-singleton pitfall — triggers and asset tags that a CDO constructor read from the empty native-tag singleton, ending upNone.- Catalog-row required slots — the resolved row's
RequiredTagSlots/RequiredClassSlots/NumericSlotsbecome hard errors when unset. - Legacy input wiring on player-activated archetypes.
- No montage route at all — neither a
SkillMontagesentry nor a validActionTag(warning; a hard error for AOE skills, whose AOE could then never spawn).SkillMontageslives on the CDO so it is machine-checked. A weapon-table row for the ActionTag, and hit-event-notify presence, cannot be: those tables hang off the runtime avatar/weapon, so they stay a PIE check covered by the wizard's reminder. - AOE-skill spawn-path sanity (with the Leap exemption — leap AOEs fire at landing, not on activation).
- Null gameplay-effect class references on eternal abilities (warning). A
<Resource>RecoveryBlockEffectClassis exempt while every paired<Resource>RecoveryBlock*duration is zero:ApplyRecoveryBlockearly-returns on a non-positive duration, so a null class there means the feature is off, not broken. Warning on it unconditionally is what made every fresh stamp open on a wall of warnings. - Damage-type guardrail — only
Physical/Fire/Corruption/Electricare legal damage types; anything else on a*DamageTypeTagproperty (except theWeaponDamageTypeTagimpact-VFX category) or in aDamageTypesmap errors. - GameplayCue tags with no registered handler — a
GameplayCue.*tag that resolves to no cue notify (nothing would play). - Projectile travel audio — any ability carrying a
ProjectileConfig(player or enemy hierarchy) withLaunchSound/FlightLoopSound/FlybySoundall unset warns (the travel layer of the audio model,09_Audio/02). Windup is montage-side (AudioAudit); impact rides the weapon×surface matrix.
Environment-dependent checks (cue registry, native tags) silently degrade when their subsystem is unavailable rather than false-failing CI, and every check is crash-safe on partially-authored assets.
KitValidation (kits + preset kit-lists) checks:
- Kit asset: null ability / granted-effect entries; activated-without-input (
OnInput/WhileInputHeldwith no effective input tag);OnSpawnentries that still claim an input slot; duplicate input slots within the kit (the later entry silently unbinds the earlier at grant time); non-positive levels; and empty kits. - Preset kit-list: unresolvable / duplicate kit references; and cross-kit input-slot collisions in grant order — a collision between two preset kits is an error (a colliding build must never ship), while a preset kit claiming a class-starter-kit slot is a warning (replacing a class default is last-granted-wins working as intended, but it should be a visible choice). The preset check degrades to kits-only when no class info asset is resolvable.
The effective input slot a kit entry claims is its InputTagOverride when set, otherwise the ability
CDO's StartupInputTag (which the grant path binds unconditionally).
See also¶
Documentation/02_AbilitySystem/07_Ability_Kits.md— the runtime kit/grant system these tools author for.Documentation/11_Tools/09_New_Ability_Archetype_Recipe.md— how to add a new authorable archetype.Design/README.md— the paper-design intake (.ability.md/.kit.md) that feeds this pipeline.