Files
UE5-Modular-Game-Framework/docs/blueprints/02-player/09_BPC_StaminaSystem.md
Lefteris Notas 8bc731e5ae feat: Add multiplayer networking architecture and documentation updates
- Updated Master Blueprint Index to include Multiplayer Networking support.
- Added detailed Multiplayer Networking sections across all developer documentation (01-11).
- Introduced authority maps, key patterns, and RPC guidelines for each system.
- Established a comprehensive multiplayer networking architecture document outlining core principles, replication strategies, and anti-cheat considerations.
- Enhanced UI documentation to clarify local-only behavior and binding to replicated dispatchers.
- Implemented client prediction strategies and RPC naming conventions for consistency across the framework.
2026-05-19 17:15:57 +03:00

15 KiB

09 — Stamina System (BPC_StaminaSystem)

Purpose

Manages the player's stamina pool — drain during sprinting, jumping, and special actions; regeneration during idle/walking. Prevents action spamming by enforcing minimum stamina thresholds. Drives exhaustion VFX and audio cues.

Dependencies

  • Requires: GI_GameFramework (phase checks), FL_GameUtilities (tag queries)
  • Required By: BPC_MovementStateSystem (stamina affects max speed), WBP_HUD (stamina bar), BPC_PlayerMetricsTracker (exhaustion tracking)
  • Engine/Plugin Requirements: GameplayTags, Timers

Class Info

Property Value
Parent Class ActorComponent
Class Type Blueprint Component
Asset Path Content/Framework/Player/BPC_StaminaSystem
Implements Interfaces None

1. Enums

E_ExhaustionState

Value Description
Normal = 0 Full stamina operation
Low = 1 Below LowThreshold, heavy breathing, slightly reduced regen delay
Exhausted = 2 Below ExhaustedThreshold, cannot sprint, slow regen

E_StaminaActionType

Value Description
Sprint = 0 Continuous drain while sprinting
Jump = 1 One-time drain on jump
Climb = 2 Continuous drain while climbing
SpecialAttack = 3 One-time drain for strong melee
Dodge = 4 One-time drain for dodging
Environment = 5 Drain from external sources (cold, poison)

2. Structs

S_StaminaDrainRate

Field Type Description
ActionType E_StaminaActionType Which action this rate applies to
DrainPerSecond Float Stamina drained per second (continuous)
DrainFlat Float Stamina drained once per use (one-shot)
MinStamina Float Minimum stamina required to perform this action
CooldownAfterUse Float Seconds before this action can be used again

S_StaminaRegenSettings

Field Type Description
RegenRate Float Stamina recovered per second
RegenDelay Float Seconds after last drain before regen begins
ExhaustedRegenRate Float Slower recovery while exhausted
ExhaustedRegenDelay Float Longer delay while exhausted
RegenBlockedWhileMoving Boolean If true, regen pauses while moving above walk speed

3. Variables

Configuration (Instance Editable, Expose On Spawn)

Variable Type Default Category Description
MaxStamina Float 100.0 Stamina Config Maximum stamina pool
DefaultDrainRates Array<S_StaminaDrainRate> [] Stamina Config Base drain rates for each action type
RegenSettings S_StaminaRegenSettings (15.0, 2.0, 5.0, 4.0, true) Stamina Config Regeneration behaviour
LowThreshold Float 0.30 Stamina Config Fraction of MaxStamina for Low state
ExhaustedThreshold Float 0.10 Stamina Config Fraction of MaxStamina for Exhausted state
bCanExhaust Boolean true Stamina Config Allow exhaustion state

Internal (Private / Protected, No Expose)

Variable Type Default Category Description
CurrentStamina Float 100.0 Stamina State Current stamina pool
ExhaustionState E_ExhaustionState Normal Stamina State Current exhaustion tier
ActiveDrains Map<E_StaminaActionType, bool> {} Stamina State Which drains are currently active
RegenTimerHandle FTimerHandle - Stamina State Timer for regen ticks
DrainTimerHandle FTimerHandle - Stamina State Timer for continuous drain ticks
LastDrainTime Float 0.0 Stamina State World time of last stamina drain
bRegenBlocked Boolean false Stamina State True while external block is active
ActionCooldownTimers Map<E_StaminaActionType, FTimerHandle> {} Stamina State Per-action cooldown timers

Replicated (if multiplayer)

Variable Type Condition Description
CurrentStamina Float RepNotify Replicated with OnRep handler for UI updates
ExhaustionState E_ExhaustionState RepNotify Replicated exhaustion tier

4. Functions

Public Functions

DrainStaminaBoolean (success)

  • Description: Attempts to drain stamina for a specific action. Returns false if insufficient stamina or cooldown active.
  • Parameters:
    Param Type Description
    ActionType E_StaminaActionType Which action is being performed
    OverrideAmount Float If > 0, use this instead of the DrainRate config value
  • Blueprint Authority: Server (if MP), Any (single-player)
  • Flow:
    1. If ActionCooldownTimers contains ActionType and timer active: return false
    2. Look up S_StaminaDrainRate for ActionType
    3. RequiredStamina = DrainRate.MinStamina
    4. If CurrentStamina < RequiredStamina: return false
    5. DrainAmount = OverrideAmount > 0 ? OverrideAmount : DrainRate.DrainFlat
    6. CurrentStamina = FMath::Max(0, CurrentStamina - DrainAmount)
    7. Start cooldown timer for DrainRate.CooldownAfterUse
    8. Update ExhaustionState
    9. Reset regen delay, stop regen if running
    10. Fire OnStaminaDrained
    11. If ActionType is continuous: add to ActiveDrains
    12. Fire OnStaminaChanged
    13. Return true

StartContinuousDrainvoid

  • Description: Begins draining stamina per second for a continuous action.
  • Parameters:
    Param Type Description
    ActionType E_StaminaActionType Sprint, Climb, etc.
  • Flow:
    1. Add ActionType to ActiveDrains = true
    2. If DrainTimerHandle not active: start timer with interval 0.1 seconds
    3. Timer callback: apply (DrainRate.DrainPerSecond * 0.1) to CurrentStamina each tick
    4. If CurrentStamina <= 0: stop continuous drain, fire OnExhausted

StopContinuousDrainvoid

  • Parameters:
    Param Type Description
    ActionType E_StaminaActionType Action to stop draining for
  • Flow:
    1. Set ActiveDrains[ActionType] = false
    2. If no active drains remain: clear DrainTimerHandle
    3. Start regen delay timer

RestoreStaminaFloat (actual restored)

  • Description: Adds stamina up to MaxStamina.
  • Parameters:
    Param Type Description
    Amount Float Stamina to restore
    Tags GameplayTagContainer Context tags (e.g. Potion, Rest)
  • Flow:
    1. Previous = CurrentStamina
    2. CurrentStamina = FMath::Min(MaxStamina, CurrentStamina + Amount)
    3. Update ExhaustionState
    4. Fire OnStaminaRestored
    5. Fire OnStaminaChanged
    6. Return CurrentStamina - Previous

GetStaminaNormalisedFloat [0.0 - 1.0]

  • Flow: Return CurrentStamina / MaxStamina

CanAffordActionBoolean

  • Parameters:
    Param Type Description
    ActionType E_StaminaActionType Action to check
  • Flow:
    1. Look up MinStamina for this ActionType
    2. Return CurrentStamina >= MinStamina AND no active cooldown

SetMaxStaminavoid

  • Parameters:
    Param Type Description
    NewMax Float New maximum value
    bMaintainRatio Boolean Scale current stamina to maintain ratio
  • Flow:
    1. If bMaintainRatio: CurrentStamina = (CurrentStamina / MaxStamina) * NewMax
    2. Else: CurrentStamina = FMath::Min(CurrentStamina, NewMax)
    3. MaxStamina = NewMax
    4. Update ExhaustionState
    5. Fire OnStaminaChanged

BlockRegenvoid

  • Parameters:
    Param Type Description
    Duration Float Seconds to block regen
  • Flow:
    1. Set bRegenBlocked = true
    2. Start timer for Duration
    3. On timer end: bRegenBlocked = false

Protected / Private Functions

UpdateExhaustionStatevoid

  • Flow:
    1. Normalised = CurrentStamina / MaxStamina
    2. OldState = ExhaustionState
    3. If Normalised <= ExhaustedThreshold: NewState = Exhausted
    4. Else if Normalised <= LowThreshold: NewState = Low
    5. Else: NewState = Normal
    6. If NewState != OldState:
      • ExhaustionState = NewState
      • Fire OnExhaustionStateChanged
      • If NewState == Exhausted: fire OnExhausted

RegenTickvoid

  • Flow:
    1. If bRegenBlocked: return
    2. Rate = ExhaustionState == Exhausted ? RegenSettings.ExhaustedRegenRate : RegenSettings.RegenRate
    3. CurrentStamina = FMath::Min(MaxStamina, CurrentStamina + Rate * 0.1)
    4. Fire OnStaminaChanged
    5. If CurrentStamina >= MaxStamina: stop regen timer, fire OnStaminaFullyRestored

OnMovementStateChanged (listener)void

  • Flow:
    1. Get movement mode from character
    2. If RegenSettings.RegenBlockedWhileMoving and movement speed > walk:
      • Pause regen timer
    3. Else: resume regen timer if conditions met

5. Event Dispatchers

Dispatcher Parameters Bind Access Description
OnStaminaChanged float OldStamina, float NewStamina, float Delta Public Fired on any stamina change
OnStaminaDrained E_StaminaActionType ActionType, float Amount Public Fired when stamina is consumed
OnStaminaRestored float Amount, GameplayTagContainer Tags Public Fired when stamina is gained
OnStaminaFullyRestored none Public Fired when stamina reaches MaxStamina
OnExhaustionStateChanged E_ExhaustionState OldState, E_ExhaustionState NewState Public Fired on any exhaustion tier change
OnExhausted none Public Fired when entering Exhausted state
OnActionCooldownStarted E_StaminaActionType ActionType, float Cooldown Public Fired when a per-action cooldown begins
OnActionCooldownEnded E_StaminaActionType ActionType Public Fired when a per-action cooldown expires

6. Overridden Events / Custom Events

Event: BeginPlay

  • Description: Initialises stamina, starts regen if enabled, binds to movement state changes.
  • Flow:
    1. CurrentStamina = MaxStamina
    2. Start regen timer with initial delay = 0
    3. Find BPC_MovementStateSystem on owner, bind to its OnMovementStateChanged dispatcher
    4. Initialise ExhaustionState = Normal

Event: OnComponentDestroyed

  • Description: Clean up all timers.
  • Flow:
    1. Clear RegenTimerHandle, DrainTimerHandle
    2. Clear all ActionCooldownTimers

7. Blueprint Graph Logic Flow

flowchart TD
    A[DrainStamina called] --> B{CanAffordAction?}
    B -->|No| C[Return false]
    B -->|Yes| D[Apply drain amount]
    D --> E[Update CurrentStamina]
    E --> F{ExhaustedThreshold crossed?}
    F -->|Yes| G[Set Exhausted state]
    F -->|No| H{LowThreshold crossed?}
    H -->|Yes| I[Set Low state]
    H -->|No| J[Keep Normal state]
    G --> K[Fire OnExhausted]
    K --> L[Stop continuous drains]
    I --> M[Fire OnExhaustionStateChanged]
    J --> M
    L --> M
    M --> N[Start regen delay]
    N --> O[Fire OnStaminaChanged]
    O --> P[Return true]
    D --> Q{Continuous action?}
    Q -->|Yes| R[Start DrainTimer loop]
    Q -->|No| S[Start action cooldown]
    R --> O
    S --> O

8. Communication Matrix

Who Talks How What Is Sent
BPC_StaminaSystem Dispatcher OnStaminaChanged -> WBP_HUD (stamina bar update)
BPC_StaminaSystem Dispatcher OnExhausted -> BPC_PlayerController (player feedback), BPC_AdaptiveEnvironment
BPC_StaminaSystem Dispatcher OnExhaustionStateChanged -> ABP_GASP (breathing animation)
External (PC_PlayerController) Direct Calls DrainStamina(Sprint) / StartContinuousDrain on input
BPC_StaminaSystem Dispatcher OnStaminaFullyRestored -> WBP_HUD (hide bar)
BPC_StaminaSystem Listener Binds to BPC_MovementStateSystem.OnMovementStateChanged for regen blocking

9. Validation / Testing Checklist

  • DrainStamina deducts correct amount and returns false when stamina is insufficient
  • Continuous drain stops when stamina reaches 0
  • Regen does not start until RegenDelay has passed
  • Exhausted state correctly uses ExhaustedRegenRate and ExhaustedRegenDelay
  • Exhaustion state transitions are one-way downward until full rest
  • Per-action cooldowns prevent spamming dodge/jump
  • BlockRegen pauses all regen for its duration
  • RegenBlockedWhileMoving pauses regen at high speed, resumes when walking
  • Edge case: MaxStamina change with bMaintainRatio=true preserves percentage
  • Edge case: Multiple simultaneous continuous drains stack correctly
  • Edge case: DrainStamina called during active cooldown returns false without state change
  • All timers cleaned up on component destroy

10. Reuse Notes

  • Can be placed on AI characters with simplified config (e.g. only Sprint drain, no Exhaustion).
  • For enemy stamina, consider removing the exhaustion mechanic and using only drain/restore.
  • The drain rate map supports runtime modification for buffs/debuffs (e.g. Adrenaline reduces sprint cost).
  • UI widgets should bind to OnStaminaChanged for smooth bar animation, not tick polling.
  • For multiplayer: Server authorises all DrainStamina calls; client predicts and corrects on repnotify.

11. Multiplayer Networking (Expanded)

Server RPCs

RPC Direction Description
Server_DrainStamina Client→Server Client requests stamina drain for action. Server validates MinStamina, applies.
Server_StartContinuousDrain Client→Server Client starts sprinting. Server begins drain timer.
Server_StopContinuousDrain Client→Server Client stops sprinting. Server stops drain, begins regen.
Server_RestoreStamina Client→Server Client uses stamina item. Server validates item, applies restore.

Authority Gates

Function DrainStamina(ActionType)
  If HasAuthority:
    → Check cooldown, MinStamina
    → Apply drain, update exhaustion, fire dispatchers
  Else:
    → Client predicts stamina bar decrease for responsiveness
    → Server_ RPC called; server corrects via OnRep if wrong

Function SetMaxStamina(NewMax, bMaintainRatio)
  If NOT HasAuthority → Return
  → Apply change, fire dispatchers, auto-replicates

Client Prediction

  • Stamina bar: Client predicts decrease on sprint/jump. Server corrects via OnRep_CurrentStamina.
  • Exhaustion: ExhaustionState replicated. Client plays breathing audio locally.
  • Cooldowns: Server-authoritative. Client shows cooldown timer after server confirms action.
  • Exhaustion state can drive conditional audio: heavy breathing, heart-beat, fatigue voice lines.

Blueprint Spec: Stamina System. Conforms to TEMPLATE.md v1.0 — part of the UE5 Modular Game Framework.