Resource Recovery¶
Summary: The
UResourceRecoveryComponentmanages passive regeneration of Health, Stamina, and Resonance using infinite-duration GameplayEffects. This document explains the recovery architecture, configuration, and integration with combat systems.
Why GE-Based Recovery?¶
Using GameplayEffects for recovery provides: - GAS Integration: Recovery interacts naturally with buffs, debuffs, and tags - Attribute-Driven: Recovery rates are attributes that can be modified by equipment - Tag Blocking: Combat states can block recovery via gameplay tags - Consistent Timing: GE periodic ticks ensure predictable regeneration
Architecture¶
+---------------------------+
| UResourceRecoveryComponent| On Character pawn
+---------------------------+
|
| Applies infinite-duration GEs
v
+---------------------------+ +---------------------------+
| HealthRecoveryEffect | | StaminaRecoveryEffect |
| (Periodic: 0.5s) | | (Periodic: 0.5s) |
+---------------------------+ +---------------------------+
| |
v v
+---------------------------+ +---------------------------+
| Modifies Health by: | | Modifies Stamina by: |
| HealthRecoveryRate * 0.5 | | StaminaRecoveryRate * 0.5 |
+---------------------------+ +---------------------------+
+---------------------------+
| ResonanceRecoveryEffect |
| (Periodic: 0.5s) |
+---------------------------+
|
v
+---------------------------+
| Modifies Resonance by: |
| ResonanceRecoveryRate*0.5 |
+---------------------------+
Recovery Formula¶
Recovery Per Tick = RecoveryRate * Period
Example:
+---------------------+--------+
| Recovery Rate | 10/sec |
| Effect Period | 0.5s |
+---------------------+--------+
| Recovery Per Tick | 5 |
| Recovery Per Second | 10 |
+---------------------+--------+
The 0.5s period provides responsive recovery while minimizing network traffic and effect evaluations.
Component API¶
Control Methods¶
| Method | Action |
|---|---|
InitializeRecovery() |
Called on BeginPlay, starts all recovery |
StartHealthRecovery() |
Applies health GE if not already active |
StartStaminaRecovery() |
Applies stamina GE if not already active |
StartResonanceRecovery() |
Applies resonance GE if not already active |
StartAllRecovery() |
Convenience method for all three |
StopHealthRecovery() |
Removes health recovery GE |
StopStaminaRecovery() |
Removes stamina recovery GE |
StopResonanceRecovery() |
Removes resonance recovery GE |
StopAllRecovery() |
Removes all recovery effects |
Duplicate Prevention¶
Each Start*Recovery() method checks for the corresponding tag before applying:
Stats.Effects.Resource.HealthRecovery
Stats.Effects.Resource.StaminaRecovery
Stats.Effects.Resource.ResonanceRecovery
If the tag is already present, the effect is not reapplied.
GameplayEffect Configuration¶
Structure¶
+----------------------------------+
| Recovery Effect Properties |
+----------------------------------+
| Duration Policy: Infinite |
| Period: 0.5 seconds |
| Execute Periodic Effect on Apply |
+----------------------------------+
+----------------------------------+
| Modifier |
+----------------------------------+
| Attribute: Health (or Stamina) |
| Modifier Op: Additive |
| Magnitude Type: Attribute Based |
| Backing Attribute: *RecoveryRate |
| Coefficient: 0.5 (= period) |
+----------------------------------+
+----------------------------------+
| Granted Tags |
+----------------------------------+
| Stats.Effects.Resource.*Recovery |
+----------------------------------+
Recovery Rate Attributes¶
Definitions¶
| Attribute | Category | Default Purpose |
|---|---|---|
| HealthRecoveryRate | Recovery Rates | HP regenerated per second |
| StaminaRecoveryRate | Recovery Rates | Stamina regenerated per second |
| ResonanceRecoveryRate | Recovery Rates | Mana regenerated per second |
Modification Sources¶
| Source | How It Works |
|---|---|
| Equipment | Items with +X HealthRecoveryRate modifier |
| Buffs | Temporary GEs that boost recovery attributes |
| Character Class | Base values set via class default GE |
| Level Scaling | Secondary attribute calculation GE |
| Auras | Persistent effects from passive skills |
Combat Integration¶
Blocking During Stagger¶
Poise Broken
|
v
+---------------------------+
| UPoiseSystemComponent |
| HandleBrokenState() |
+---------------------------+
|
| Applies PoiseRecoveryBlockEffect
v
+---------------------------+
| Grants Tag: |
| Stats.Effects.Recovery |
| .Blocked |
+---------------------------+
|
| Recovery effects have this as blocked tag
v
+---------------------------+
| Recovery ticks skipped |
| while tag is present |
+---------------------------+
Ability Integration¶
Abilities can control recovery for gameplay purposes:
| Scenario | Implementation |
|---|---|
| Charge attack | Stop stamina recovery during charge, resume on end |
| Sprint | Continuous stamina drain, no recovery while active |
| Meditation skill | Boost recovery rates via temporary GE |
Ability Cost & Cooldown (Shared SetByCaller GEs)¶
Recovery restores resources; abilities spend them. Spending is now standardized on shared, SetByCaller-driven GameplayEffects rather than direct attribute writes — the project-wide convention every new ability follows.
One Shared Cost GE Per Resource¶
| Resource | Cost GE | How it deducts |
|---|---|---|
| Resonance | Ge_ResonanceCost_Dynamic |
SetByCaller magnitude (negative), multiplied by ResonanceCostMultiplier |
| Stamina | Ge_StaminaCost_Dynamic |
SetByCaller magnitude (negative), multiplied by StaminaCostMultiplier |
An ability sets the cost as a SetByCaller magnitude on an outgoing spec of the shared GE and applies it to self. A dual-cost ability (e.g. a body-originated AOE skill) applies both — it checks each pool up front, then deducts each via its shared GE.
Shared Cooldown GE¶
Cooldowns use a single GE_Cooldown_Shared for every ability:
- Duration is passed via the
SetByCaller_Cooldownmagnitude, so the same GE serves any duration. - The per-ability cooldown tag is added to the spec's
DynamicGrantedTags, so blocking is per-ability even though the GE is shared. The ability reports that tag throughGetCooldownTags().
The Direct-Set Fallbacks Were Retired¶
Earlier abilities had a direct-set fallback (ConsumeStamina / ConsumeResonance) that wrote the resource attribute directly. Those paths were removed: on a LocalPredicted ability the direct write was a client-reachable write to a replicated attribute, and a silent no-op when misconfigured. The GE path is now mandatory — a missing cost effect class fails activation loudly, and the ability validator errors on a null cost effect class at authoring time. New abilities must use the shared cost/cooldown GEs.
Lifecycle¶
Initialization¶
1. BeginPlay()
2. Find ASC via IAbilitySystemInterface on owner
3. Cache ASC reference
4. InitializeRecovery() -> StartAllRecovery()
Effect Handles¶
The component maintains FActiveGameplayEffectHandle for each recovery type:
HealthRecoveryHandle -> Active health GE instance
StaminaRecoveryHandle -> Active stamina GE instance
ResonanceRecoveryHandle -> Active resonance GE instance
These handles enable: - Checking if recovery is active - Removing specific recovery effects - Preventing duplicate applications
Source Reference¶
| Component | Location |
|---|---|
| UResourceRecoveryComponent | Source/ProjectEternal/Public/AbilitySystem/Components/ResourceRecoveryComponent.h |
| Recovery Rate Attributes | Source/ProjectEternal/Public/AbilitySystem/EternalAttributeSet.h |
| Recovery GameplayEffects | Content/AbilitySystem/Effects/Recovery/ |
Related Systems¶
- GAS Overview - Recovery rate attributes
- Poise System - Recovery blocking during stagger
- Character Framework - Component ownership
Refactoring Considerations¶
| Issue | Current State | Recommendation |
|---|---|---|
| No state queries | Cannot check if recovery is active | Add IsHealthRecoveryActive() etc. |
| No multiplier support | Cannot boost recovery temporarily | Add multiplier effect stacking |
| Immediate recovery | No delay after taking damage | Add configurable delay timer |
| No events | UI cannot react to recovery state | Add OnRecoveryStateChanged delegates |
Recent Changes¶
| Date | Change | Impact |
|---|---|---|
| 2026-07-07 | Shared SetByCaller cost/cooldown convention | One shared cost GE per resource (Ge_ResonanceCost_Dynamic / Ge_StaminaCost_Dynamic) deducting via SetByCaller; dual-cost abilities apply both; GE_Cooldown_Shared with SetByCaller_Cooldown duration + per-ability tag in DynamicGrantedTags; direct-set ConsumeStamina/ConsumeResonance fallbacks retired — missing cost GE now fails loudly and the validator errors on a null cost class |
| 2024-Q4 | Tag-based duplicate prevention | Prevents stacking recovery effects |
| 2024-Q4 | Poise system integration | Recovery blocked during stagger/break |
| 2024-Q3 | Resonance recovery added | Full mana regeneration support |
| 2024-Q3 | Component moved to Character | Recovery tied to pawn lifecycle |