Character Pipeline

All CrimsonCore characters share a common init-state machine driven by UCrimsonPawnExtensionComponent. No actor hardcodes attribute sets in its constructor — they are always granted dynamically via UCrimsonAbilitySet data assets.

Init-state machine

StateGate conditionWhat triggers it
SpawnedAlways — set immediately on spawnActor is created and components initialize
DataAvailablePawnData is set (replicated from PlayerState or injected by GameMode)UCrimsonPawnExtensionComponent::SetPawnData() called
DataInitializedAll sibling components have also reached DataAvailableEach component calls CheckDefaultInitialization()
GameplayReadyASC is initialized and the pawn is possessedUCrimsonHeroComponent or NPC controller completes setup

Attribute set grant order

Attribute sets must be granted before any component that reads from them is initialized. The rule is strict: grant first, initialize health component second.

ActorWhen sets are grantedWhen health component initializes
ACrimsonPlayerStateSetPawnData() — after experience loadsN/A — PlayerState has no health component; the pawn's health component reads this ASC
ACrimsonNPCBaseSetNPCData() — called by spawner after spawnEnd of SetNPCData()
ACrimsonSummonBaseInitializeSummon() — on possession by summon controllerEnd of InitializeSummon()
ACrimsonCharacter (player pawn)UCrimsonHeroComponent::InitializeAbilitySystem()Inside UCrimsonHeroComponent
UCrimsonHealthSet must be in the ability set
Every UCrimsonAbilitySet used by NPCs or summons must include UCrimsonHealthSet under Granted Attributes. Without it, UCrimsonHealthComponent will log an error and skip initialization — the actor will be unkillable.

NPC object pool

When ACrimsonNPCBase::DeactivateForPooling() is called, the health component is uninitialized before ability set handles are torn down. This prevents stale delegate callbacks from firing on a pooled actor. On reactivation, SetNPCData() re-grants the sets and re-initializes the health component.

Per-actor attribute defaults

To give a specific NPC different starting health without a separate Gameplay Effect, use the DefaultValues array on FCrimsonAbilitySet_AttributeSet in CrimsonCommon:

text
DA_AbilitySet_Goblin_Boss
GrantedAttributes[0].AttributeSet = UCrimsonHealthSet
GrantedAttributes[0].DefaultValues[0].Attribute = UCrimsonHealthSet.MaxHealth
GrantedAttributes[0].DefaultValues[0].Value = 500
GrantedAttributes[0].DefaultValues[1].Attribute = UCrimsonHealthSet.Health
GrantedAttributes[0].DefaultValues[1].Value = 500
Order matters
Set MaxHealth before Health in the DefaultValues array so the health component reads the correct cap when it initializes immediately after the grant.