Skip to content

RevFramework – Pickups • Core

Folder: Runtime/Systems/Pickups/Core

The Core folder contains the foundation of the entire pickup-effect pipeline.
These files define how effects are created, decorated, validated, cooldown-gated, and executed at runtime.

✔ Base class for all pickup effects
✔ Global cooldown system
✔ Null-damageable support
✔ Context-aware effect API
✔ Factory-driven decorator pipeline
✔ No reflection in the hot path
✔ Fully deterministic and multiplayer-safe (ownership rules live in Authority)


🎯 Purpose (accurate)

This folder provides:

  • PickupEffect — base class with cooldown gating, decorator traversal, and null-damageable checks
  • IEffectAllowsNullDamageable — marker enabling execution without an IDamageable
  • PickupEffectStaticCooldowns — global (ownerID, effectID) → expiryTime map
  • PickupEffectFactory — constructs a full decorated effect chain from a definition
  • IPickupEffectWithContext + ItemUseContext — richer API for item / inventory-driven effects
  • Decorator registration via IPickupDecoratorRegistry
  • PickupEffectRunner — unified dispatcher (context-aware and classic paths)

This folder deliberately does not handle:

  • triggers or colliders
  • authority or ownership
  • world pickups or interactables
  • inventory usage logic
  • UI or feedback
  • networking or replication

Those responsibilities live in other folders.


🧩 Key Types (truth-aligned)

PickupEffect

The abstract base for all pickup effects — including decorators.

Capabilities:

  • Built-in cooldown gating
  • Enforces null-damageable policy by walking the decorator chain
  • Applies cooldowns per owner, resolved as:
  • The Component backing IDamageable (if present)
  • Fallback to the context GameObject
  • Skips cooldown enforcement if no valid owner exists
  • Calls OnApply only after all policy checks succeed

Runtime entry point:

public void ApplyTo(IDamageable target, GameObject context)

Implement effect logic in:

protected abstract void OnApply(IDamageable target, GameObject context);

Decorator chains are traversed correctly at runtime to determine policy and execution order.


IEffectAllowsNullDamageable

A simple marker interface.

If any effect or decorator in the chain implements this interface,
the effect may execute without an IDamageable.

Utility access:

effect.AllowsNullDamageable();

Internally this walks the decorator chain via PickupEffect logic.


PickupEffectStaticCooldowns

Global, per-session cooldown storage.

Important (post-refactor):
This class is pure runtime — there is no editor-only pruning or editor dependency.

Behaviour:

  • Keys are (ownerInstanceID, effectInstanceID)
  • Expired entries are removed lazily during lookup
  • Cooldowns are never persisted (session-only)
  • Zero allocations on the hot path

Public API:

bool IsOnCooldown(Object owner, int key);
void StartCooldown(Object owner, int key, float duration);
void ClearFor(Object owner);
void ClearAll();

PickupEffectFactory

Builds a fully decorated PickupEffect from a ScriptableObject definition.

Construction process:

  1. Create the core effect via def.CreateCoreEffect()
  2. Sort decorators ascending by priority
  3. For each decorator:
  4. Resolve a creator from IPickupDecoratorRegistry
  5. Instantiate the decorator ScriptableObject
  6. Wrap the previous effect
  7. Return the outermost decorated effect

Key guarantees:

  • Default registry includes Sound, VFX, PersistentVFX, Conditional, and DebugLog creators
  • Registry is pluggable via:
  • SetRegistry(...)
  • RegisterCreator(...)
  • UnregisterCreator(...)
  • No reflection is used during construction

ItemUseContext + IPickupEffectWithContext

Used when effects originate from inventory or item usage, rather than world pickups.

ItemUseContext fields:

  • itemDef — originating item definition (optional)
  • owner — GameObject owning the inventory (optional)
  • slotIndex — slot index or -1 when not applicable

If an effect implements:

IPickupEffectWithContext

then the runner routes execution to:

ApplyTo(IDamageable damageable, GameObject target, ItemUseContext ctx);

Otherwise, it falls back to the classic PickupEffect.ApplyTo path.

This routing logic lives in PickupEffectRunner, not in PickupEffect itself.


DecoratorType

Enum mapping definition entries to concrete decorator creators:

  • VFX
  • Sound
  • DebugLog
  • Conditional
  • PersistentVFX

Creators live in Decorators/Creators.


PickupEffectRunner

Single, unified API for executing pickup effects.

Responsibilities:

  • Detects whether the effect implements IPickupEffectWithContext
  • Routes to the context-aware overload when available
  • Otherwise invokes PickupEffect.ApplyTo
  • Provides a convenience overload for world pickups:
PickupEffectRunner.Apply(effect, dmg, target);

🔁 Runtime Flow (exact to code)

  1. A pickup effect definition is selected
  2. PickupEffectFactory.BuildEffect(def) constructs the decorated effect instance
  3. Caller invokes PickupEffectRunner.Apply(...)
  4. Runner selects:
  5. context-aware path (IPickupEffectWithContext), or
  6. classic ApplyTo path
  7. PickupEffect.ApplyTo performs:
  8. decorator-chain walk to compute null-damageable policy
  9. enforcement of that policy
  10. IHealthReadonly.IsDead check when applicable
  11. cooldown owner resolution
  12. cooldown check and early-out if active
  13. cooldown registration when applicable
  14. invocation of OnApply
  15. Decorators execute in order:
  16. BeforeApply → wrapped effect → AfterApply

This sequence exactly mirrors the runtime implementation.


🧱 Extending Core (supported paths)

Goal Action
Add a new effect type Subclass PickupEffect and override OnApply
Allow execution without IDamageable Implement IEffectAllowsNullDamageable
Add item-use context logic Implement IPickupEffectWithContext
Add a new decorator Subclass PickupEffectDecorator + implement IPickupDecoratorCreator
Replace decorator registry PickupEffectFactory.SetRegistry(...)
Register additional decorators PickupEffectFactory.RegisterCreator(...)

📘 See Also

  • Definitions — effect authoring ScriptableObjects
  • Decorators — wrappers providing pre/post behaviour
  • Effects — built-in effect implementations
  • Runtime — triggers, interactables, authority, world pickups