RevFramework — Status Effects • Core¶
Core runtime of the Status Effects system.
This folder owns all runtime behaviour: lifecycle, stacking, authority, math, timing, events, and optional FX seams.
If you want to understand how statuses actually work, this is the folder that matters.
Table of Contents¶
- Overview
- Mental Model
- Quick Start
- Composition Cheatsheet
- Core Components
- Events
- Authority Interaction
- Gotchas
- Extending
Overview¶
The Core folder contains the central runtime types for Status Effects.
This is where:
- Status instances are applied, ticked, refreshed, stacked, dispelled, and removed
- Authority is enforced (when enabled)
- Potency and duration math is resolved
- Context is attached and preserved
- Events and FX hooks are raised
Everything here executes at runtime and may mutate state.
Primary Types¶
StatusEffectController— the runtime manager; attach to actorsStatusContext— attribution for who/what applied a statusTimedStatusEffect— base class for timed behavioursStatusRegistry— open–closed builder for status instancesDefaultStatusMathService— pluggable potency/duration mathStatusProviderAggregator— provider cache for performanceStatusUtility— pure helper math + convenience apply seamStatusFx— optional global FX seamStatusUseEvents— global telemetry for item-applied statuses
Mental Model¶
StatusEffectController is the single source of truth.
- Effects never tick themselves
- Effects never decide stacking
- Effects never decide authority
- Effects never decide immunity or dispels
Effects describe behaviour.
The controller owns rules.
If something feels “missing”, it usually belongs here — not in effects or abstractions.
Quick Start¶
// Build and apply directly
ctrl.ApplyStatus(
new PoisonStatus(5f, 10f),
StatusContext.FromAbility("firebolt")
);
// Preferred: centralised refresh / stacking
ctrl.ApplyOrRefresh(
() => new PoisonStatus(5f, 10f),
StatusContext.FromItemUse(itemDef, slotIndex)
);
// Remove / cleanse / dispel
ctrl.RemoveStatus(StatusRegistry.Id.Poison);
ctrl.CleanseByTag(StatusTag.Debuff | StatusTag.DOT);
ctrl.Dispel(DispelType.Magic, minTier: 1);
Composition Cheatsheet¶
| Layer | Component | Responsibility |
|---|---|---|
| Controller | StatusEffectController |
Owns lifecycle, stacking, authority, immunity, events |
| Math Service | DefaultStatusMathService |
Computes final potency & duration |
| Aggregator | StatusProviderAggregator |
Caches potency/resistance providers |
| Context | StatusContext |
Instigator, source, slot, note |
| Utility | StatusUtility |
Pure math helpers + simple apply |
| Registry | StatusRegistry |
Central builder (open–closed) |
| FX Seam | StatusFx |
Optional global visual hooks |
| Global Events | StatusUseEvents |
Item-use telemetry |
| Timed Base | TimedStatusEffect |
Duration, ticking, FX hooks |
Core Components¶
StatusEffectController¶
Implements IStatusEffectController and coordinates all runtime behaviour.
Key responsibilities:
- Apply / Refresh / Stack / Remove
- Enforce authority (when enabled)
- Apply immunity and resistance rules
- Drive ticking and expiry
- Recompute potency and duration
- Raise all events
Public surface (abridged):
void ApplyStatus(IStatusEffect effect, StatusContext ctx);
void ApplyOrRefresh(Func<IStatusEffect> build, StatusContext ctx);
void RemoveStatus(StatusId id);
void ClearAll();
int Dispel(DispelType type, int minTier = 0);
int CleanseByTag(StatusTag mask);
IReadOnlyList<IStatusEffect> Active { get; }
bool HasStatus(StatusId id);
void SetStackCap(StatusId id, int max);
void SetPerSourceStacks(StatusId id, bool enabled);
void RecomputePotencyForAll();
void SetTimeMode(StatusTimeMode mode, MonoBehaviour custom = null);
Important:
Never mutate effect state directly. Always go through the controller.
StatusContext¶
Immutable attribution data carried with each applied status.
Used for:
- Analytics / logging
- UI messaging
- Item & ability attribution
Contexts are preserved across refresh and stacking.
StatusRegistry¶
Open–closed factory for constructing status instances.
- Eliminates switch statements
- Supports stub builds for refresh logic
- Safe to extend at runtime or boot
Always return new instances — never reuse.
TimedStatusEffect¶
Base class for timed behaviour.
Owns:
- Duration / remaining time
- Tick progression
- FX hook lifecycle
Override:
OnTickOnApplyFXOnRefreshFXOnRemoveFX
Never call FX hooks directly — the controller drives them.
Math & Providers¶
DefaultStatusMathServicecomputes final potency & durationStatusProviderAggregatorcachesIStatusPotency/IStatusResistance- Falls back to
StatusUtilityif no service is present
All math is deterministic and side‑effect free.
Events¶
Designer (UnityEvents)¶
_onStatusApplied_onStatusRefreshed_onStatusRemoved_onStatusExpired
Coder (C# events)¶
StatusAppliedStatusRefreshedStatusRemovedStatusExpired
Context-aware¶
OnStatusAppliedCtxOnStatusRefreshedCtxOnStatusRemovedCtxOnStatusExpiredCtx
Global¶
StatusUseEvents.StatusAppliedFromItemUse
Authority Interaction¶
When requireAuthority = true:
- The controller resolves a scene-level
IStatusAuthority - If authority is denied or missing:
- No ticking
- No mutation
- No expiry
This is intentional and prevents desync.
Authority is opt-in and fully netcode-agnostic.
Gotchas¶
requireAuthority = true+ no binder = frozen effects (by design)TimedStatusEffect.Apply()resets time — useRefresh()to extend- Replace stacking + UI may flicker;
StatusBuffBarcoalesces changes StatusFxis optional; safe to leave unassigned- Always return fresh instances from
BuildEffect() - Only effects implementing
IAdjustableMagnituderespond to recompute
Extending¶
- Subclass
TimedStatusEffectfor new timed effects - Implement
IStatusEffectfor instant/passive logic - Write a custom
IStatusMathServicefor specialised math - Add
StatusProviderAggregatorfor performance - Wire visuals via
StatusFx - Register effects in
StatusRegistry(OCP-friendly)