Skip to content

Pickups System — System Guarantees Matrix

This page defines the runtime guarantees provided by the RevFramework Pickups system.

What a guarantee means

A guarantee means the system always behaves this way when used through its supported APIs and runtime components.

If something is not listed here, it should not be relied upon as a system invariant.


Purpose

The guarantees matrix answers the question:

“What behaviour can gameplay code safely depend on?”

This is different from:

Document Purpose
Overview What the system does
Mental Model How the system is structured
Public API What developers can call
Guarantees Matrix What behaviour is guaranteed

Core Pickup Guarantees

Area Guarantee Notes
Consumption A pickup can only be consumed once per physics step Prevents duplicate triggers from multi-collider actors
Effect execution A successful pickup produces a single effect execution chain Decorators wrap the effect into one deterministic chain
Destroy behaviour A pickup either destroys or re-arms, never both Controlled by destroyOnUse or respawn configuration
Trigger routing Trigger events are routed through IPickupTriggerReceiver when using relay components Relays normalize physics callbacks
Actor resolution Actor GameObject passed to the pickup is resolved consistently from the trigger source Rigidbody root is preferred when present

Effect Guarantees

Area Guarantee Notes
Application routing When using built-in runtime components, effects are applied via PickupEffectRunner Ensures correct dispatch between standard and context-aware paths
Context routing Context-aware effects receive ItemUseContext when provided Runner selects the correct entrypoint automatically
Null target safety Effects that do not implement IEffectAllowsNullDamageable will not run without an IDamageable Enforced by PickupEffect
Context optionality ItemUseContext values may be null or unset Effects must tolerate missing data
Composite effects Composite effects execute child effects in declared order Each child enforces its own gating and cooldown rules

Decorator Guarantees

Area Guarantee Notes
Order Decorators execute in deterministic priority order Lower priority wraps first
Wrapping Decorators form a single nested execution chain around the core effect Built by PickupEffectFactory
Cancellation A decorator may cancel execution of the wrapped effect chain Cancelling skips the wrapped effect and any inner decorators
Chain stability Decorator structure is fixed after factory construction Runtime does not mutate the chain

Authority Guarantees

Every system that mutates state exposes the same kind of authority seam, and the differences that do exist — absent default, scope, discovery, what happens when your implementation throws — are tabulated in the cross-system authority reference. They are real differences: seven interfaces across six systems, one of them assigned rather than discovered, and four systems with no seam at all. Nothing in Pickups linked to the comparison before, so it was there and unreachable.

Area Guarantee Notes
Authority check The shipped trigger pickupsTriggerPickup and UnifiedPickup2D — do not execute effects when authority explicitly denies the action Checked through PickupAuthority on every accepted enter
Interactable pickups InteractablePickupBase checks, since 1.3.0. Every subclass is covered without writing a gate Resolved in TryPickup before DoPickup runs, so a denied actor never reaches your delivery code. Before 1.3.0 the base enforced nothing and only InventoryPickupInteractable checked
Optional authority If no authority implementation is resolved, pickups proceed normally Authority is optional
Other IPickupTriggerReceivers Not gated. LootPickupPayload rides the same trigger plumbing and never resolves IPickupAuthority, so a scene-wide denying binder does not stop a loot pickup Deliberate: Loot's gate is the delivery boundary, where the receiving Inventory or Currency authority answers. See the cross-system authority reference
How a denial is reported Two shapes, neither of them a result type. TriggerPickup and UnifiedPickup2D return silently; every InteractablePickupBase subclass reports an ordinary failed attempt — PickupFailed, onPickupFailed and the fail feedback Indistinguishable from no item, no service or a full bag. Pickups has no result type by design; branch inside your authority, not on the outcome
Effect cooldown after a refusal ✔ Not started. PickupEffect consults the reporting seam first and opens the per-owner window only for a delivery that happened Before 1.3.0 a refused attempt burned the cooldown, and the actor's retry was refused by a window opened for nothing
Resolver consistency Authority resolution follows a consistent lookup path (context → scene → global fallback) Ensures predictable behaviour
Per-pickup-hierarchy authority A binder above a pickup — on its prefab or on a parent it sits under — gates those pickups only The hierarchy step is checked first and is never cached per scene, so two pickups under different parents each resolve their own
Scope of the answer Resolution starts at the pickup, never at the actor. The actor is only the argument to HasAuthority A binder placed on a player does not scope the answer to that player: a world pickup does not walk through the player, so the binder is found by the scene-root step and asked about every actor. Express per-actor rules inside your implementation, from the actor it is handed

Interactables are gated by the base, since 1.3.0

This row read as an unconditional guarantee before 1.2.0, when it was not one; 1.2.0 corrected it to say the base enforced nothing and scheduled the check for this release. The check now lives in TryPickup, which resolves PickupAuthority and refuses before calling DoPickup.

If you do not use pickup authority, nothing changes. Resolve returns null when no implementation is in reach and the pickup proceeds, which is the optional-authority rule the rest of the system already follows.

Migrating from 1.2.0. A subclass that already resolved and tested authority inside DoPickup can drop that check — leaving it is harmless, it resolves twice for the same answer. A subclass deliberately left ungated in a project that has an IPickupAuthority is now gated by it: that is the one behaviour change. If a particular pickup must ignore the scene's authority, scope the authority rather than the pickup — a binder on the pickup's own prefab or parent answers for that hierarchy only.


Feedback Guarantees

Area Guarantee Notes
Success feedback Success feedback executes after a successful pickup Triggered by runtime components
Failure feedback Failure feedback executes when pickup conditions fail Effect is not applied in this case
Feedback isolation Feedback components do not affect effect execution logic Purely presentation/UX

Runtime Component Guarantees

Area Guarantee Notes
Interaction modes Interactable pickups support Auto, Press, and Hold modes Defined by PickupMode
Prompt behaviour Prompt UI is shown only when interaction requires input Hidden for Auto mode
Facing checks Facing requirements are optional and configurable Controlled by dot threshold; -1 (the default) disables the check entirely
Which plane facing is measured in facingPlaneXZ for top-down, XY for side-on, Auto (the default) to keep the pre-1.3.0 guess Auto picks the second axis per call from that pickup's geometry, so a raised pickup can be refused while the actor looks straight at it. Name the plane your game uses
Where the facing provider is looked for On the actor, then its children — the same walk IInputService gets Before 1.3.0 the root only, so a provider on a rig or sprite child was never found and the transform answered instead
Respawn behaviour Respawn restores visibility and interaction state without duplicating objects Same instance reused
Duplicate prevention Trigger-based pickups guard against multi-collider double-consume within the same physics step Internal latch mechanism

Integration Guarantees

Area Guarantee Notes
System independence Pickups does not require other gameplay systems to function Fully standalone
Integration model External systems integrate through effects or decorators No hard dependencies
Determinism Integration behaviour runs within the same effect chain Preserves execution order

Explicit Non-Guarantees

The system intentionally does not guarantee

  • Inventory behaviour
  • Health rules or clamping policies
  • Status effect stacking logic
  • Save/load persistence
  • Multiplayer replication policy
  • Input system implementation
  • UI behaviour outside pickup components
  • External system availability

These responsibilities belong to other systems or the host project.


Summary

The Pickups system guarantees

  • deterministic effect-chain execution
  • safe and consistent trigger routing
  • deterministic decorator wrapping
  • optional authority gating
  • isolated feedback behaviour
  • predictable interaction flows

Everything else is intentionally delegated to integrations or higher-level gameplay systems.