Skip to content
Work in progress. These docs describe Spawnite at launch, and some parts are still being built.

Loot

Loot puts a stack of an item on an entity in the world. The character who walks within its radius takes it into her bag, and whatever her bag cannot take stays on the ground. The character here is an entity that carries the ControlledTrait trait, whether or not a player controls it now: every character <CharacterSpawn> spawns, and any other entity control linked to a player, a kart she has left among them. A view reads her own character with useCharacter().

Its props are in LootProps.

Loot draws the model its item’s definition names in model. Where the definition names none, it draws a small glowing gem in the definition’s color, white unless the definition says otherwise, so an item needs no model to be seen. Headless it draws nothing. Minecraft draws a lying item as its own icon, and Roblox draws a dropped Tool’s handle; Unity, Unreal and Godot draw what the game gives them.

Each step, Loot adds its stack to the bag of the nearest character within radius, as addItem does: into the stacks it can merge with first, then empty slots. Its count drops by what the bag took, and the entity is destroyed when none is left. A character with a full bag, or with no bag, takes nothing, and the loot stays where it is.

Loot and Pickup share the same reach check. Pickup stays for coins, which go into the wallet.

Loot comes back by default: each load lays the scene as it is written, so every loot lies again, whole. Give a loot an id and it stays taken instead: the save keeps what is left of it under loot, by id, and a reload lays only that, or nothing once it is all taken.

import { Entity, Loot } from "@spawnite/engine";
export function MeadowLoot() {
return (
<>
{/* TakenEvent once, gone for good. */}
<Entity position={[3, 0, -2.5]}>
<Loot id="meadow-potions" item="potion" count={3} />
</Entity>
{/* Back at every load. */}
<Entity position={[8, 0, 1]}>
<Loot item="herb" />
</Entity>
</>
);
}

The id names this loot in the save, so it has to be unique in the game, and it has to stay the same between versions of the game, or a player’s taken loot lies again. Two loot mounted at once with one id throw in development, naming the id. The save keeps what is left of each where the game’s save includes loot, as Saving progress says, so a game writes no code for it. The counts live on the world, so a save written from any scene keeps the loot taken in the others. A game with rooms keeps none: its loot is the room’s. The place_loot tool takes an id too.

No engine keeps this for you. Unity, Unreal, PlayCanvas and Roblox rebuild a level as authored, and the game saves the ids of taken objects itself; Godot saves only the nodes in its “Persist” group. Zelda: Breath of the Wild marks each object with its own revival policy, and Skyrim refills a whole area after days away. Loot takes the per-object choice, and makes the id the switch, since a stable name is what the save needs anyway.

dropItem(world, { holder, slot, count }) takes count copies out of bag slot slot and spawns an entity with Loot 1.5 metres in front of the holder, carrying the stack’s data and the item’s model. That is past a loot’s default radius of 1 metre, so she does not take it back on the next step. It returns the new entity, or nothing when the slot is empty or holds fewer than count.

An item’s definition names the model it is drawn as in the world with model, a name registered with registerModel. A dropped copy is drawn as that model, or as the gem in the item’s color where it names none, as a Loot in the scene is. In a room, Replicas draws it from the stream. Playing alone, the engine draws it itself, as it draws every entity that gameplay spawns with a model, such as a weapon’s projectile: Roblox, Unity, Unreal and Godot draw a spawned object whether or not a network is up.

Server. Loot has a consequence: it changes the character’s bag.

In the AI tree, a loot entity is its item’s display name and count, Potion ×3, with the action “take it”.

Minecraft drops an item as its own entity carrying the stack, merges nearby stacks, and waits two seconds before anyone can pick it up. Unreal’s Lyra spawns a collectable actor that holds item definitions or instances. Roblox moves the Tool itself into the workspace, and a touch collects it. Loot takes Minecraft’s item entity and leaves out its pickup delay, its despawn timer and the merging of stacks on the ground.

import { Entity, Loot, registerItem } from "@spawnite/engine";
registerItem("potion", {
displayName: "Potion",
color: "crimson",
maxStack: 10,
});
export function PotionPile() {
return (
<Entity position={[4, 0, -2]}>
<Loot item="potion" count={3} />
</Entity>
);
}