Skip to content

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 Archetype spelling (FAbilityArchetypeDef, ArchetypeId). Same thing; the glossary in Design/README.md records 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 AbilityValidation core 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 ChanceAttribute cleared — a copied ChanceAttribute silently overrides BaseChance, 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:

  1. Pick an archetype from the catalog.
  2. Name the ability and choose a target folder (defaults to the row's DefaultFolder).
  3. 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 TagNamespaces becomes <Namespace>.CrashLanding — for a Leap that is Cooldown.CrashLanding and the asset tag Ability.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.ini on 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 because ImportText on an unregistered tag yields None — the baked-None bug the validator exists to catch.
  • Cue tags are deliberately NOT derived. A cue tag with no registered GameplayCueNotify produces a has no registered GameplayCue handler warning, 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.

Eternal.Ability.Stamp <ArchetypeId> <AssetName> [Folder=/Game/...] [Property=ValueText]...
  • ValueText is 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:

Eternal.Chain.Stamp Design/Chains/SunderingSlam.chain.md
  • 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 in GameplayTags.ini and written into link N's emit property (the catalog row's ChainEmitTagProperty) and link N+1's AbilityTriggers; every link's Asset Tags gain Ability.Chain.<ChainId>; a damage_type re-type lands in ReTypeDamageTag where 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 — the grantedAbilities array the carrying modifier definition (or kit) must grant atomically. The validators enforce completeness: a grant set with a dangling Event.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 AbilitySet primary 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 same KitValidation::ValidateKit checks 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 CharacterPreset primary 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's GrantedKits list. 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-paired BL_* 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 via Eternal.PlayPreset — this requires a PIE session booted from L_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:

  • None tags baked by the constructor-singleton pitfall — triggers and asset tags that a CDO constructor read from the empty native-tag singleton, ending up None.
  • Catalog-row required slots — the resolved row's RequiredTagSlots / RequiredClassSlots / NumericSlots become hard errors when unset.
  • Legacy input wiring on player-activated archetypes.
  • No montage route at all — neither a SkillMontages entry nor a valid ActionTag (warning; a hard error for AOE skills, whose AOE could then never spawn). SkillMontages lives 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>RecoveryBlockEffectClass is exempt while every paired <Resource>RecoveryBlock* duration is zero: ApplyRecoveryBlock early-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 / Electric are legal damage types; anything else on a *DamageTypeTag property (except the WeaponDamageTypeTag impact-VFX category) or in a DamageTypes map 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) with LaunchSound/FlightLoopSound/FlybySound all 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 / WhileInputHeld with no effective input tag); OnSpawn entries 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.