Loot — Overview¶
Drop tables for items and currency, with the odds authored as assets rather than written into code.
The problem it solves¶
Every game that drops things ends up with the same three problems: where the odds live, who is allowed to change them, and what happens when the thing you won cannot be delivered.
Odds written in code mean a designer files a ticket to change a drop rate. Odds written in data mean nothing validates them. And the third problem is the one that bites late — a chest rolls a sword, the player's bag is full, and the sword quietly ceases to exist while the UI says "you received a sword".
Loot answers all three. Tables are assets, so odds are a designer's to edit. Rolling is a pure function, so the odds are testable without a scene. And every award ends up in exactly one of three places — delivered, spawned into the world, or named in an event — with no fourth option where it vanishes.
The shape¶
LootTable asset — what can drop, and how likely
↓
LootRoller pure — turns a table + RNG into a LootResult. Grants nothing.
↓
LootResult value — what was won
↓
LootService MonoBehaviour — runs modifiers, then delivers through adapters
↓
adapters define-gated — Inventory, Currency, Pickups
The shortest version¶
using RevGaming.RevFramework.Loot.Core;
using RevGaming.RevFramework.Loot.UnityIntegration;
// Roll only — produces a result, grants nothing.
LootResult won = lootService.Roll(chestTable, player);
// Roll and deliver in one call.
LootResult dropped = lootService.RollAndGrant(chestTable, player);
// Deliver something rolled earlier — this is how pickups work.
bool delivered = lootService.Grant(won, player);
Rolling is pure, and everything else follows from it¶
LootRoller.Roll(table, rng) is static. It takes a table and an IRandomProvider, returns a LootResult, and touches nothing else — no scene, no owner, no other system.
That single decision buys three things:
- Drop rates are unit-testable with no Play Mode. A table is data and a roll is a function, so asserting "this table yields 2–3 entries by weight" needs no GameObject.
- The assembly compiles with Inventory deleted. Granting lives in define-gated integration assemblies, so
RevFramework.Lootdepends on neither Inventory nor Currency. - The teaching panel demonstrates rolling with nothing else installed. You can see odds working before you own a container to put anything in.
Items travel as GUID strings, the same as Crafting.Core.ItemRef, for the same reason: a string costs nothing to hold and does not drag the Inventory assembly into the roller.
Two ways to author odds¶
Weighted picks a fixed number of entries, each chosen by relative weight. The classic drop table: exactly one of these five things, three times over. Always yields something.
Independent chance tests every entry separately against its own probability. Use it when each drop is its own coin flip rather than a competition. May yield nothing at all.
Weights carry no absolute meaning — 1 and 3 behave identically to 25 and 75. To express "sometimes nothing drops" in a weighted table, add an entry of kind Nothing and give it weight.
The one thing that will catch you¶
A quantity of 0 awards one, not nothing. A row added in the inspector starts at zero, and the roller corrects anything below one to one — so an entry you added and never filled in does something visible instead of silently never appearing. The catch runs the other way: you cannot express "drops nothing" with a quantity, and a row you zeroed expecting it to stop will keep dropping one item.
Express "sometimes nothing" with a Nothing entry or a chance, never with a zero quantity.
What you need installed¶
The table and the rolling work on their own. Where the awards go depends on what else you have:
| You have | You get |
|---|---|
| Inventory | Item awards land in a container |
| Currency | Currency awards are credited to a wallet |
| Pickups | Awards can spawn into the world instead of being granted directly |
| Health | LootDropOnDeath rolls a table when something dies |
An absent adapter is not an error. Awards it would have handled are simply not delivered and the roll itself is unchanged, which is what lets a project install Loot without Currency and still use it.
Where an award goes when delivery fails¶
Every award ends in exactly one of three places, and this is the guarantee worth knowing:
- Delivered to the owner, through the adapter.
- Spawned into the world where a spawner is bound — including when direct delivery was refused. Spawning is a fallback, not only a mode: an award the inventory will not take is dropped at the owner's feet, which is what most games do with a full bag and is recoverable by the player.
- Named in
Undeliveredwhen neither worked. At that point the award exists nowhere and the player has lost it, which is precisely why it is an event rather than a log line.
Granted carries what actually landed, not what was rolled. Drive a "you received" toast from it and it can never announce something the player does not have.
Checking your odds¶
Window ▸ RevFramework ▸ Loot ▸ Debugger rolls a table thousands of times with a fixed seed and shows what actually dropped against what you authored.
Weights describe intent; only sampling describes behaviour. Nesting, quantity ranges and independent-chance entries all make the printed weights an incomplete picture of the outcome.
Where to go next¶
- Mental Model — the three ideas the rest follows from
- Public API — the supported surface
- Integration Surfaces — adapters and modifiers
- System Boundaries — what it deliberately does not do
- FAQ — "my table drops nothing" and its friends