Skip to content

Naming and semantic conventions

Stable namespace

Use Berta.* for ordinary catalog vocabulary and GameplayCue.Berta.* for native Gameplay Cues. The cue root comes first because GAS cue tools and handlers operate in that hierarchy. Keep the approved spelling and PascalCase segments, including AI, UI, MainHand, OffHand, CounterAttack, and LockOn. Dots separate semantic levels; they are not underscores or display punctuation.

Namespaced identifiers are intentionally longer than many generic GAS or Lyra examples. They distinguish ownership in a shared global dictionary and reduce collisions between project, engine sample, and third-party vocabularies. The hierarchy is not a module path, UObject path, asset name, faction system, or network channel. Do not copy an entire sample vocabulary just to reuse a small concept.

Choose nouns or capability names for identifiers, current conditions for State/Status, and completed occurrences for Event where appropriate. Existing approved names remain canonical even when another grammatical form might be equally reasonable. Improve explanations instead of silently renaming a stable identifier.

Registered versus owned

The dictionary establishes that a name exists and makes it selectable. Runtime ownership belongs to a concrete container or provider. An ASC owns tags through GAS mechanisms; an inventory object may store a plain container. These are distinct stores. Registering Berta.State.Life.Dead does not make every actor dead. Assigning Berta.Ability.Movement.Jump to an ability's Asset Tags does not add it to the character's owned tags.

A local FGameplayTagContainer has no automatic authority, replication, duration, or count semantics. Decide which system exposes it and who may update it. Do not assume arbitrary actor tag variables are automatically discoverable by GAS; use the native ASC or an explicitly implemented tag provider as appropriate.

Hierarchical matching is directional

Suppose a container contains only Berta.Ability.Combat.Attack.Light:

Query Result Reason
HasTag(Light) true The exact child is present
HasTag(Attack) true The stored child satisfies a broader parent query
HasTagExact(Attack) false The parent was not explicitly added to that container
HasTagExact(Light) true Exact identity is present
HasTag(Heavy) false A sibling is not implied

Here Light, Attack, and Heavy refer to the fully qualified entries in the Ability reference. FGameplayTag::MatchesTag follows the same child-to-parent direction. A container holding only the parent does not satisfy a query for a child. Granting a parent never grants every descendant.

Unreal builds hierarchy nodes for missing ancestors. The approved catalog also explicitly declares some parents, notably Berta.Ability.Combat.Attack and Berta.Cooldown.Combat.Attack, because they are useful first-class concepts. The validator counts only INI rows, not those implicit nodes. An implicit parent is available for hierarchy queries but has no dedicated approved declaration/comment in this catalog.

Use exact matching for exact identity or when sibling/parent equivalence would be unsafe. Use hierarchical matching deliberately for groups such as all attack variants. Empty All/Any queries have native logical behavior; do not assume an empty selection means the same thing for both operations. Define empty-filter policy at the calling boundary.

Semantic boundaries

Concept Example Separate from
Ability identity Berta.Ability.Movement.Jump Input, current movement, and cue execution
Current condition Berta.State.Life.Dead Berta.Event.Life.Died, the transition occurrence
Damage type Berta.Damage.Type.Elemental.Fire Berta.Status.Burning, the recipient condition
Cosmetic feedback GameplayCue.Berta.Status.Burning Authoritative damage and condition state
Potential restriction Berta.Cooldown.Movement.Dash Ability identity and actual timer/effect implementation
Resource concept Berta.Resource.Health Numeric Gameplay Attribute or current value
Input intent Berta.Input.Movement.Jump Enhanced Input Action binding and ability grant
Object type Berta.Weapon.Type.Rifle Weapon condition, character condition, and AI role
Relation predicate Berta.Targeting.Relation.Enemy Intrinsic faction identity
Surface classification Berta.World.Surface.Metal Native Physical Material or physical-surface enum
Persistent quest outcome Berta.Quest.State.Completed Berta.Event.Quest.Completed, its announcement

The State and Status entries explain overlapping cases individually. InAir, Jumping, and Falling can overlap. Idle can coexist with Grounded. Slowed does not select Walking. A regeneration passive can remain granted without a current Regenerating condition. Shielded does not hold a Shield amount. Rooted, Stunned, and InputLocked require separate restriction policies. HitConfirmed and HitReceived describe contact; DamageDealt and DamageReceived describe resolved damage.

Do not claim a family is globally mutually exclusive. A project may enforce one life-state selection, one current weapon phase, or one camera policy when that invariant helps its design. Optional objectives, concurrent status conditions, weapon classifications, and overlapping world zones demonstrate why blanket exclusivity would be wrong. Document exclusivity next to the actual project owner and test its transitions.

Compose dimensions

Describe a projectile fire hit on the head using three existing dimensions: Berta.Damage.Source.Projectile, Berta.Damage.Type.Elemental.Fire, and Berta.Damage.HitZone.Head. Retain numeric magnitude and hit data in the actual payload. Do not create a new identifier for each damage-type/source/body-part combination.

Likewise combine Berta.Item.Type.Weapon, Berta.Item.Rarity.Rare, and Berta.Weapon.Type.Rifle on appropriate item metadata. A slot label describes equipment position; it does not replace the item identity or instance handle. Use project identifiers for individual quests, items, factions, and seats rather than expanding a reusable vocabulary into every content record.

Controlled extension and collisions

Search the full catalog and project sources for equivalent meaning before adding a tag. Prefer project-specific namespaces such as MyGame.* for mechanics and content belonging to one game. Do not redeclare existing Berta names in project config or native C++ declarations just to make them visible. Different sources can contribute the same dictionary name, obscuring ownership and comments even when runtime matching still seems to work.

Inspect source basenames as well as tag names, including enabled third-party plugins. A new semantic collision should lead to a documented mapping or project integration decision; never reinterpret or rename the approved vocabulary silently. Stable names are serialized API. Use the migration guide for changes that affect existing references.