Skip to content

Loot — FAQ

My table drops nothing

The table rolls, but nothing appears in the inventory

Check in this order, because they are ordered by how often they are the answer:

  1. Is an Inventory Adapter assigned on the LootService? No adapter means item awards are not delivered. Nothing errors — that is the supported configuration for a project without Inventory.
  2. Are the item GUIDs right? Nothing validates them — and sampling cannot tell you. The roller awards any id that is not blank, and the debugger tallies the id strings it produced without ever consulting an ItemDatabase, so a typo'd id appears in the sample at exactly its authored rate and looks healthy. Resolution happens later, at delivery: LootInventoryAdapter asks the database for the GUID, gets nothing back, and the award falls through to the spawner or into Undelivered. The check that works is to grant the table in Play Mode and watch where the awards go — an entry that appears in every roll and never in the container is telling you its id does not resolve. The LootDeliveryPanel in the sample scene reports exactly that.
  3. Is the quantity what you meant? A row added in the inspector starts at zero, and the roller treats anything below one as one — so a forgotten quantity drops a single item rather than nothing. An entry that should sometimes award nothing is a Nothing row or a chance, never a quantity.
  4. Is the container right? Item awards go to DefaultContainer ("Backpack") unless you pass one — and a name that does not exist on the owner is created, not rejected. SceneInventoryService creates a container on demand (twelve slots, unless a size policy says otherwise), so a mistyped container name delivers successfully, raises Granted, and puts the items somewhere nothing in your game is looking. That is the more dangerous shape of this bug, because every report says it worked. If items are "missing", compare the name you passed with the name your UI reads.

It says it delivered, but the player has nothing

Check which event you are listening to. Rolled fires with the whole roll, before anything is granted — driving UI from it announces things the player may never receive.

Granted carries only what actually landed. That is the one to drive a "you received" toast from.

If Granted fired and the player still has nothing, check the container name. An unknown name is created rather than refused, so the award really did land — in a container nothing in your game is reading. Compare the name you passed with the name your UI opens, remembering that both are canonicalised, so the difference will not be casing.

Everything drops except one entry

Separate the two cases, because they have different causes and only one of them is findable by sampling.

Missing from the sample is a fault in the table, never a bad id: an Item or Currency entry with a blank id (the console warns, and it consumes a pick and awards nothing), a zero weight, a zero chance, or a Table entry with no nested table assigned. Ids are not checked at roll time, so a wrong-but-typed id cannot make an entry disappear from a sample.

Present in the sample but never arriving is the bad id. Grant it and watch the delivery events.

Odds

My weights are not producing the percentages I expect

Weights are relative within one table, not percentages. 1 against 3 is identical to 25 against 75.

If the numbers still look wrong, check whether the table nests. A nested table does not share the parent's weight pool — the nested entry competes at the parent's level, then the nested table rolls its own weights independently. End-to-end odds across nesting are not the product of the printed numbers in any way you can compute by hand, which is why the debugger samples.

How do I make "nothing" a possible outcome?

Add an entry of kind Nothing and give it weight, in a weighted table. Or use an IndependentChance table, where every entry is its own coin flip and all of them can decline.

Do not express it with a zero quantity — the roller treats a quantity below one as one, so that row keeps dropping a single item and reads as a broken table.

How do I add luck, magic find, or a pity counter?

You cannot, today, without editing LootRoller. ILootModifier runs against the result, so it can double a currency award or swap an item, but it cannot make a rare entry more likely.

This is deliberate — a table whose printed weights do not describe its behaviour is very hard to reason about — and it is also the most likely reason a project outgrows this system. Decide whether you need odds-shaping before you design around it.

Are drops reproducible?

UseDeterministicRng(seed) repeats a sequence within a build. It does not survive changes to the table: adding an entry, reordering rows or changing a quantity range changes what that seed produces.

Never store a loot seed as a save-compatible record of "which sword the player got".

Delivery

The player's bag was full — where did the item go?

If a Pickup Spawner is bound, at their feet: spawning is a fallback, not only a mode, so a refused award is dropped into the world even with Spawn Pickups off. That is what most games do with a full bag, and it is recoverable by the player.

If no spawner is bound, the award is reported through Undelivered. Subscribe to it if that matters — mail it, queue it, or just tell the player their bag is full. Nothing is retried automatically, because where an undeliverable award should go is a design decision.

Undelivered does not always mean the award is gone. The exception is the shipped pickup flow: a collector with a full bag walking over a loot pickup fires Undelivered and Grant returns false, but the pickup is not consumed — it stays in the world still carrying its award and can be collected again once there is room. Check whether the caller still holds the award before mailing or re-granting what this event reports.

Grant returned false but I definitely rolled something

Grant returns true only when at least one award actually reached the owner — not when there was merely something to deliver. A false with a non-empty result means nothing landed: no adapter, a full container, or an id that did not resolve.

A collected pickup spawned another pickup

That should be impossible: Grant never spawns, whatever SpawnPickups is set to, precisely so a pickup granting on collect cannot produce another.

If you are seeing it, you are probably calling RollAndGrant on collect rather than Grant. The pickup should apply the award it is already carrying, not roll a new one.

My spawned pickup does nothing when collected

LootPickupPayload must be on the prefab, not added to the instance after Instantiate. TriggerRelay3D resolves its receiver during Awake, which has already run by the time Instantiate returns — a payload added afterwards is never found.

My boss dropped its loot twice

LootDropOnDeath guards against this, because Health can raise Died more than once across a revive cycle.

The guard clears itself on Revived, so an enemy that dies, drops, is revived and dies again drops the second time with no work from you. ResetDropGuard() is there for pools that reuse an object without disabling it or reviving it — that path re-arms nothing on its own, and without the call the object would be permanently unable to drop.

Setup and structure

Which package is Loot in?

The Inventory, Pickups & Crafting SKU, and Complete. A drop table's output has to land in a container, so it belongs to the purchase that provides one.

Do I need Inventory and Currency both?

No. Each adapter is optional and independent. Awards of a kind you cannot deliver are simply not delivered, and the roll is unchanged.

Can I roll without a LootService at all?

Yes — LootRoller.Roll(table, rng) is static and dependency-free. You get a LootResult and deliver it yourself. The service exists to run modifiers and adapters, not because rolling needs it.

Where is the sample?

Samples/Systems/Loot/Scenes/00_Loot_Quickstart, with two teaching panels: LootRollPanel for odds and LootDeliveryPanel for where awards land. Open the scene and press Play.

How do I check a table is doing what I think?

Window ▸ RevFramework ▸ Loot ▸ Debugger. It rolls thousands of times against a fixed seed and shows what actually dropped against what you authored.

Do this before shipping any table. Weights describe intent; only sampling describes behaviour.