Skip to content

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

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 actors
  • StatusContext — attribution for who/what applied a status
  • TimedStatusEffect — base class for timed behaviours
  • StatusRegistry — open–closed builder for status instances
  • DefaultStatusMathService — pluggable potency/duration math
  • StatusProviderAggregator — provider cache for performance
  • StatusUtility — pure helper math + convenience apply seam
  • StatusFx — optional global FX seam
  • StatusUseEvents — 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:

  • OnTick
  • OnApplyFX
  • OnRefreshFX
  • OnRemoveFX

Never call FX hooks directly — the controller drives them.


Math & Providers

  • DefaultStatusMathService computes final potency & duration
  • StatusProviderAggregator caches IStatusPotency / IStatusResistance
  • Falls back to StatusUtility if no service is present

All math is deterministic and side‑effect free.


Events

Designer (UnityEvents)

  • _onStatusApplied
  • _onStatusRefreshed
  • _onStatusRemoved
  • _onStatusExpired

Coder (C# events)

  • StatusApplied
  • StatusRefreshed
  • StatusRemoved
  • StatusExpired

Context-aware

  • OnStatusAppliedCtx
  • OnStatusRefreshedCtx
  • OnStatusRemovedCtx
  • OnStatusExpiredCtx

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 — use Refresh() to extend
  • Replace stacking + UI may flicker; StatusBuffBar coalesces changes
  • StatusFx is optional; safe to leave unassigned
  • Always return fresh instances from BuildEffect()
  • Only effects implementing IAdjustableMagnitude respond to recompute

Extending

  • Subclass TimedStatusEffect for new timed effects
  • Implement IStatusEffect for instant/passive logic
  • Write a custom IStatusMathService for specialised math
  • Add StatusProviderAggregator for performance
  • Wire visuals via StatusFx
  • Register effects in StatusRegistry (OCP-friendly)

See Also