# 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 `DoesImplementInterface` before 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 use `Game.` prefix
- All tags documented in `DA_GameTagRegistry`
- Never use `FName` or `FString` for 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.*
