- Updated references from GI_GameTagRegistry to DA_GameTagRegistry in architecture overview and implementation patterns documentation. - Added new Blueprint specification for GI_StarterGameInstance, detailing its purpose, configuration, and integration pattern. - Introduced DA_GameTagRegistry Blueprint specification, centralizing GameplayTag management and providing functions for tag validation and logging. - Created documentation for the Starter GameInstance, outlining its role in the project setup and how other systems can integrate with it.
12 KiB
Common UE5 Blueprint Implementation Patterns
Purpose: This document catalogs the recurring Blueprint implementation patterns used throughout the framework. When implementing a blueprint spec into an actual UE5 Blueprint asset, reference these patterns for consistent, correct implementation.
Pattern 1: Interface-First Communication
When to Use: Any time System A needs to call a function on System B without knowing System B's concrete class.
Blueprint Implementation:
[System A Blueprint]
TargetActor = GetOwner() // or any actor reference
bImplements = DoesImplementInterface(TargetActor, I_Interactable)
Branch(bImplements)
True → Call I_Interactable::ExecuteInteraction(TargetActor, Self)
False → Return / Log Warning
Framework Examples: BPC_InteractionDetector → I_Interactable, SS_SaveManager → I_Persistable, Weapons → I_Damageable
Key Rules:
- Always check
DoesImplementInterfacebefore calling - Never cast to concrete class — use the interface
- Default return values (false/0.0f/empty) handle missing implementations gracefully
Pattern 2: Event Dispatcher Binding (UI Display)
When to Use: Any system that needs to react to state changes in another system.
Blueprint Implementation:
[HUD Widget Blueprint — Event Construct]
PlayerPawn = GetOwningPlayerPawn()
HealthComponent = PlayerPawn.FindComponentByClass(BPC_HealthSystem)
Bind Event to HealthComponent.OnHealthChanged
→ Custom Event: OnHealthChangedHandler(OldHealth, NewHealth, Delta)
→ ProgressBar.SetPercent(NewHealth / MaxHealth)
[HUD Widget Blueprint — Event Destruct]
Unbind Event from HealthComponent.OnHealthChanged
Framework Examples: WBP_HUDController binds to OnHealthChanged, GS_CoreGameState binds to OnGamePhaseChanged
Key Rules:
- Always unbind in Event Destruct to prevent dangling references
- Never use Event Tick for polling — always bind to dispatchers
- Normalize values (0.0-1.0) before sending to UI for smooth interpolation
Pattern 3: Subsystem Lookup (Global Service Resolution)
When to Use: Any system that needs a global service (save, audio, UI, input).
Blueprint Implementation:
[Any Blueprint]
GameInstance = GetGameInstance()
Cast to GI_GameFramework → Framework
SubsystemRef = Framework.GetSubsystem(Tag) // or FL_GameUtilities.GetSubsystemSafe()
IsValid(SubsystemRef)?
True → Call Subsystem function
False → Log warning, return gracefully
Framework Examples: Any system calling SS_SaveManager.Save(), SS_AudioManager.PlaySound()
Key Rules:
- Always use
FL_GameUtilities.GetSubsystemSafe()— returns null instead of crashing - Check validity of the returned subsystem before calling functions
- Subsystems are singletons — no need to cache, just look up when needed
Pattern 4: Data Asset Configuration
When to Use: Any system that needs configurable data (item stats, weapon balance, encounter rules).
Blueprint Implementation:
[Component Configuration]
Variable: ItemData
Type: DA_ItemData (Object Reference → Primary Data Asset)
Instance Editable: ✓
Expose on Spawn: ✓
Category: "Config"
[Runtime Usage]
ItemData.ItemTag → GameplayTag
ItemData.DisplayName → Text for UI
ItemData.Weight → Float for carry capacity
ItemData.StackLimit → Integer for stack management
Framework Examples: All systems that reference DA_* Data Assets
Key Rules:
- Data Assets are read-only at runtime — never modify them
- Use Soft Object References for async loading large Data Asset collections
- Register Data Assets with Primary Asset Manager for streaming support
Pattern 5: Timer-Based Ticks (Not Event Tick)
When to Use: Any repeating operation that doesn't need per-frame precision (regen, decay, scan).
Blueprint Implementation:
[BeginPlay]
Set Timer by Event
Event: RegenTick
Time: 0.1 (seconds)
Looping: ✓
[Custom Event: RegenTick]
CurrentStamina = Min(MaxStamina, CurrentStamina + RegenRate * 0.1)
Fire OnStaminaChanged
If CurrentStamina >= MaxStamina:
Clear Timer (RegenTimerHandle)
Framework Examples: BPC_HealthSystem regen, BPC_StaminaSystem drain, BPC_StressSystem decay, BPC_InteractionDetector scan
Key Rules:
- Use 0.1s intervals for smooth but performant updates
- Store timer handles and clear them on component destroy
- Never use Event Tick unless absolutely necessary (physics, camera)
Pattern 6: State Machine with Enum Switch
When to Use: Any system that has distinct, mutually exclusive states.
Blueprint Implementation:
[Function: SetState(NewState)]
OldState = CurrentState
Switch on NewState:
Case StateA:
// StateA setup logic
Case StateB:
// StateB setup logic
Case StateC:
// StateC setup logic
CurrentState = NewState
Fire OnStateChanged(OldState, NewState)
Framework Examples: BP_DoorActor (Closed/Opening/Open/Closing/Locked/Barricaded), BP_WeaponBase (Holstered/Equipping/Ready/Firing/Reloading), BPC_AIStateMachine (Patrol/Search/Combat/Flee)
Key Rules:
- Store previous state for transition detection
- Fire dispatcher on every state change
- Block operations that don't make sense in current state
Pattern 7: Validation Before Action
When to Use: Any function that modifies state and can fail.
Blueprint Implementation:
[Function: AddItem(ItemData, Quantity)]
// Validate
FreeSlot = FindFreeSlot()
If FreeSlot < 0:
Fire OnInventoryFull
Return E_InventoryOperationResult::InventoryFull
OverWeight = CheckWeight(ItemData.Weight * Quantity)
If OverWeight:
Return E_InventoryOperationResult::WeightCapacityExceeded
// Execute
SetSlot(FreeSlot, ItemData, Quantity)
RecalculateWeight()
Fire OnItemAdded
Return E_InventoryOperationResult::Success
Framework Examples: BPC_InventorySystem.AddItem, BPC_StaminaSystem.DrainStamina, BPC_HidingSystem.EnterHideSpot
Key Rules:
- Validate ALL conditions before making ANY changes
- Return descriptive result codes, not just true/false
- Fire error dispatchers with human-readable failure reasons
Pattern 8: RepNotify for Networked State
When to Use: Any replicated variable that needs local effects when changed remotely.
Blueprint Implementation:
[Variable]
CurrentHealth: Float
Replication: RepNotify
OnRep Function: OnRep_CurrentHealth
[Function: OnRep_CurrentHealth]
Fire OnHealthChanged (with cached old value)
// This runs on clients when server changes the value
// Local effects (UI update, effects) fire here
Framework Examples: All replicated variables in GS_CoreGameState, BPC_InventorySystem.Slots
Key Rules:
- RepNotify fires on clients, NOT on server (server handles effects in the setter)
- Cache old value before replication to use in OnRep
- Single-player games can ignore replication entirely — framework is SP-first
Pattern 9: Tag-Driven Filtering
When to Use: Any time you need to filter or categorize (items, interactions, states, narrative).
Blueprint Implementation:
[Function: HasTag(Actor, Tag)]
TagContainer = Actor.GetGameplayTagContainer() // or via interface
Return TagContainer.HasTag(Tag)
[Function: FindItemsByTag(Tag)]
FilteredArray = []
For Each Slot in Inventory.Slots:
If Slot.Entry.ItemData.ItemTag.MatchesTag(Tag):
Add to FilteredArray
Return FilteredArray
Framework Examples: Every system — tags replace booleans and strings everywhere
Key Rules:
- Framework tags use
Framework.prefix; project tags useGame.prefix - All tags documented in
DA_GameTagRegistry - Never use
FNameorFStringfor state — always GameplayTags
Pattern 10: Linked Actor Notifications
When to Use: When one actor's state change should trigger other actors (door opens → lights turn on).
Blueprint Implementation:
[Variable: LinkedActors]
Type: Array of Actor
Instance Editable: ✓
Category: "Connections"
[On Door Opened]
For Each LinkedActor in LinkedActors:
bImplements = DoesImplementInterface(LinkedActor, I_Toggleable)
If bImplements:
Call I_Toggleable::SetState(LinkedActor, True)
Framework Examples: BP_DoorActor notifying lights/traps, BP_PuzzleDeviceActor unlocking connected doors
Key Rules:
- Use interfaces (I_Toggleable, I_Adjustable) for linked actor communication
- Designer sets LinkedActors in editor — no code changes needed
- Order of linked actor notification may matter — test edge cases
Quick Reference: Which Pattern for What?
| Need | Pattern |
|---|---|
| Call a function on unknown actor type | Pattern 1: Interface-First |
| React to another system's state change | Pattern 2: Dispatcher Binding |
| Access global services (save, audio, UI) | Pattern 3: Subsystem Lookup |
| Configure system behavior without code | Pattern 4: Data Asset |
| Repeating operation at interval | Pattern 5: Timer-Based Tick |
| Manage mutually exclusive states | Pattern 6: State Machine |
| Operation that can fail | Pattern 7: Validation Before Action |
| Network state synchronization | Pattern 8: RepNotify |
| Filter/categorize by type | Pattern 9: Tag-Driven Filtering |
| Chain reactions between actors | Pattern 10: Linked Actor Notifications |
Multiplayer Networking Patterns
Pattern 11: Server Authority Gate
When to Use: Every function that modifies replicated state.
Blueprint Implementation:
[Function: ApplyDamage(DamageEvent)]
Switch HasAuthority
Authority:
→ Execute authoritative logic (damage calc, health modification)
→ Fire dispatchers
Remote:
→ Return (client cannot modify replicated state directly)
→ Client calls Server_ RPC to request the change
Key Rule: Never modify a replicated variable without HasAuthority() check.
Pattern 12: Server RPC Wrapper
When to Use: Client needs to request a state change from the server.
Blueprint Implementation:
[Client Event Graph — Input: Interact pressed]
→ Call Server_Interact(TargetActor) // RPC: Run on Server, Reliable
[Server RPC: Server_Interact(TargetActor)]
Switch HasAuthority
Authority:
→ Validate distance, conditions
→ Call I_Interactable.Execute_OnInteract(TargetActor, Instigator)
→ State changes replicate automatically
Naming: All Server RPCs prefixed with Server_.
Pattern 13: OnRep Dispatcher Relay
When to Use: Any replicated variable that should trigger the same effects as single-player.
Blueprint Implementation:
[Variable: CurrentHealth]
Replication: Replicated Using OnRep_CurrentHealth
[Function: OnRep_CurrentHealth]
→ Broadcast OnHealthChanged(OldHealth, CurrentHealth, Delta)
→ UI, audio, effects react exactly as in single-player path
→ No multiplayer-specific code in consumer systems
Key Rule: OnRep_ fires the SAME dispatcher the SP mutation code fires. Zero consumer changes needed.
Pattern 14: Client Prediction with Correction
When to Use: Actions that need instant feedback (firing, using items, interacting).
Blueprint Implementation:
[Client: Input → Fire pressed]
→ Client prediction: play fire animation, muzzle flash, reduce ammo display
→ Call Server_StartFire()
[Server: Server_StartFire()]
→ Validate weapon state, ammo, cooldown
→ If valid: execute authoritative fire logic, consume ammo
→ If invalid: log warning, return (client will be corrected via OnRep)
[Client: OnRep_Ammo]
→ If server count matches client prediction: no visible change
→ If different: correct ammo display, stop fire animation
Pattern 15: Multicast for Cosmetic Events
When to Use: Server needs to trigger a cosmetic-only event on all clients.
Blueprint Implementation:
[Server: Explosion triggered]
→ Multicast_PlayExplosionFX(Location, Radius)
→ All clients play VFX, SFX, camera shake locally
→ No replication of individual particles
Key Rule: Multicast is for cosmetic only — never use for state changes. State changes replicate via variable RepNotify.
Implementation Patterns v1.0 — Reference when building blueprint specs into UE5 Blueprint assets.