Skip to content

00 — Loot Quickstart

Goal: See both halves of Loot in one scene: a table rolling exactly the odds you authored, and the awards it produced trying — and in this scene failing — to reach somebody.


What This Scene Demonstrates

Loot splits into two verbs, and the scene gives each its own panel:

Roll answers what did you win. Grant answers where did it go.

LootRollPanel calls LootRoller directly. No service, no owner, no Play Mode — that is not a demo shortcut, it is the design, and it is why drop rates can be checked as arithmetic.

LootDeliveryPanel is where a LootService, an owner and real state come in. It reports which adapters are bound and then names which of the three delivery outcomes each award actually reached, read back from the service's own events rather than assumed from the call.


What Is In The Scene

Object What it is
Main Camera, Directional Light, Plane Ordinary scene furniture
Characters ▸ Player (Visual Only) The loot recipient. A capsule; nothing is attached to it
Loot Service A LootService with all three adapter slots empty, Default Container Backpack, Spawn Pickups off
Sample Loot Receiver A SampleLootReceiver — the smallest possible delivery adapter, a list for items and a dictionary for currency. Not bound to anything; binding it is the exercise
LootRollPanel Bound to Chest_Weighted, fixed seed 12345, 5000 samples
LootDeliveryPanel Bound to the Loot Service, to Purse_IndependentChance, and to Player (Visual Only) as owner. Container left blank

No inventory adapter, no currency adapter and no pickup spawner are bound, and that is deliberate. It is also what makes the delivery half honest: a scene wired to succeed would teach you what success looks like and nothing about the failure every project meets first. The receiver that could be bound sits in the scene one drag away, because making that drag is the lesson — see Making It Deliver Something below.

Each panel is on its own GameObject. Two panels sharing one object draw into the same screen rect and open stacked and unreadable.


What To Look For

Rolling, without entering Play Mode:

  • Roll Once — one pull of the chest. Often nothing, because the Nothing entry carries the largest weight
  • Sample — thousands of pulls, measured. Compare the observed rates against the authored weights: 60 / 30 / 12 / 8 is relative, not a percentage, and only the sample states behaviour
  • Fixed seed — the same seed replays the same roll exactly, which is what makes a surprising result investigable

Delivery, in Play Mode:

  • Bound adapters — the panel lists what is actually bound, not what the inspector shows. In this scene: nothing
  • Roll And Grant — the purse always rolls gold, so there is always something to deliver. With no currency adapter, the award reaches nowhere and the panel says so: "Rolled, but nothing could be delivered — check the bound adapters above."
  • Roll Only, then Grant Last — this is the case worth watching. Grant returns false, and the panel distinguishes why: the roll exists and the owner is assigned, so the message names the unbound adapters rather than sending you to check the two things that are already correct. It also notes that Grant never spawns, so there was no fallback to the world

The three outcomes the panel is naming are the system's whole delivery contract: Granted for what reached the owner, Spawned for what was dropped into the world instead, and Undelivered for what reached neither.


Sample Scope

This scene covers:

  • Both roll models — weighted and independent chance
  • Relative weights, seeds and reproducibility
  • Sampling a table to measure its real rates
  • The roll/grant split, and Grant applying a result rolled earlier
  • Which adapters are bound, and what an unbound one costs
  • Delivery outcomes reported from the service's events
  • A successful delivery — once you bind the SampleLootReceiver yourself (see below)

This scene does not cover:

  • Pickup spawning, LootPickupPayload, or collect-time granting
  • ILootModifier — no modifier is demonstrated anywhere in Loot's samples
  • LootDropOnDeath and the Health integration
  • Persistence — Loot has no save participant, and an uncollected drop does not survive a load

Making It Deliver Something

The fastest way is already in the scene. Select Loot Service and drag Sample Loot Receiver into Inventory Adapter and Currency Adapter, then press Play and roll again. The awards that were refused by name now land — Granted instead of Undelivered, read back from the same events by the same panel. That receiver is the whole adapter seam in about twenty lines (SampleLootReceiver.cs, beside this sample): a list, a dictionary, and the one contract that matters — a refused add leaves the container untouched. It starts refusing once its capacity fills, so the Undelivered path stays demonstrable after the bind.

Delivering into the real systems is the same wiring with real services, and is your own wiring rather than part of the sample:

  1. Add the service the awards should land in — a SceneInventoryService for items, a SceneCurrencyService for currency
  2. Add the matching adapter from Add Component ▸ RevFramework ▸ Integrations ▸ Loot ▸ … and assign it to the Loot Service. The shipped adapters are components, not API — you wire them, you do not construct them
  3. Point LootDeliveryPanel at a table whose ids resolve in your project

Step 3 is the one that catches people. The example tables use placeholder ids — sample-potion, sample-blade, gold, gems — which resolve to nothing in a fresh project, and nothing before delivery notices that. The roller awards any id that is not blank, and the debugger counts raw id strings without consulting a database, so a placeholder or a typo looks perfectly healthy in a sample of any size. It fails at the adapter, and surfaces as Undelivered.

Which adapters you can add depends on what you own. LootCurrencyAdapter compiles only where Currency is installed, and the Inventory, Pickups & Crafting SKU does not include it — so in that SKU the currency-only purse table this panel is bound to can never deliver, whatever you wire. That is not a fault in the sample; it is the adapter model being visible.


Failure Behaviour

Failures here are teaching signals, not bugs to fix:

  • Play Mode required — granting mutates real state, so the grant buttons are disabled outside Play Mode. Rolling is not gated
  • Assign an owner — with no owner there is nobody to deliver to, and the grant buttons stay disabled
  • Nothing could be delivered — the ordinary case in this scene. An unbound adapter is not an error; the awards it would have handled are reported through Undelivered rather than dropped in silence
  • Nothing to grant — pressing Grant Last before any roll. Distinct from the case above, and the panel says which one it is

Behind The Scenes

Both panels are hostile consumers: public surface only, no reflection, no internals, and nothing attached to an object they do not own.

LootRollPanel uses LootRoller.Roll and its buffer overload, plus a local IRandomProvider.

LootDeliveryPanel uses LootService.Roll, RollAndGrant, Grant, TryGetInventoryAdapter, TryGetCurrencyAdapter, SpawnPickups and DefaultContainer, and subscribes to Granted, Spawned and Undelivered for the duration of a call — because RollAndGrant returns what the table produced whether or not any of it could be delivered, so its return value cannot answer where the awards went.


Key Takeaway

Rolling is a decision. Granting is a consequence, and it can fail on its own.

A table that rolls perfectly and delivers nothing is the most common confusion in this system, and it is almost always an unbound adapter or an id that does not resolve. This scene shows you both, from the outside, through the same API your game will use.


Panels: LootRollPanel, LootDeliveryPanel Scene Path: Assets/RevFramework/Samples/Systems/Loot/Scenes/00_Loot_Quickstart/