Adding an Item¶
No C# required. This is the guide ADR-0004 exists to make possible: adding an item is an authoring task, not a programming one.
What you'll have at the end: a new, working item — using the original's "Delicious Cake" as the worked example — spawnable in-game, editable without touching code, and updating live while the server runs.
1. Before you start¶
You need: the S&box editor open on this project, and a model to use (this project ships no art — see Architecture/01_PROJECT_LAYOUT.md §3 for where content assets belong and why none are checked in).
If you're recreating a legacy item, its original values are in
Legacy/03_INVENTORY_AND_ITEMS.md — item ids stay
snake_case matching the original specifically so that document is usable as a content
specification (Standards/01_NAMING.md §10).
2. Create the asset¶
In the S&box editor's asset browser:
- Navigate to
Assets/Items/Food/(or the category folder that fits — see Architecture/01_PROJECT_LAYOUT.md §3). - Right-click → Create → Item. This is the
.itemGameResourcetype registered by Architecture/09_ITEM_FRAMEWORK.md. - Name the file
cake.item—snake_case, matching the item's id.
3. Fill in the inspector¶
| Field | Value | Why |
|---|---|---|
| Name | Delicious Cake |
Display name, singular |
| Plural Name | Delicious Cakes |
Used when reporting quantities |
| Size | 2 |
Space consumed — pick something reasonable; the legacy value isn't recorded for this item |
| Cost | 2500 |
Legacy: items/food/cake.lua — see Legacy/03_INVENTORY_AND_ITEMS.md |
| Is Stackable | unchecked | One cake is one cake |
| Category | Food |
Gates manufacturing rights per Legacy/05_TEAMS_JOBS_FACTIONS.md §5 |
4. Give it behaviour¶
Behaviour is composition, not code — see Architecture/09_ITEM_FRAMEWORK.md §2. In the Behaviours list:
- Click Add → select Edible.
- Set its Need Id to
hunger. - Set its Restore Amount to
50— the original'sITEM.Hunger = 50.
That's the entire behaviour. No onUse callback, no code path to write — the Edible
behaviour component already knows how to restore a need; you're only supplying the numbers.
A second example: a weapon (Equippable)¶
Weapons use a different behaviour, Equippable — worked here using glock_18.item
(Assets/Items/Weapons/) since its fields aren't self-explanatory the way Edible's are.
In the Behaviours list:
- Click Add → select Equippable.
- Set Slot to
SmallorLarge— which holster slot this occupies. UseNonefor somethingEquippableabout, but not actually a weapon (rare; mostEquippableitems are one or the other). - Set Required Ammo Item Id to the
AssetIdof the ammo item this weapon consumes —ammo_pistolforglock_18. Leave it empty for a weapon that needs no ammo (a melee weapon likeknife). - Set Equip Duration — how long equipping takes, as a duration (e.g.
1s). Legacy'sitems/base/weapon.luaequip delay; see Legacy/03_INVENTORY_AND_ITEMS.md §3.5. - (Milestone 12, optional) Set Base Jam Chance — this weapon's per-shot jam
probability with nothing attached,
0–1(e.g.0.05for a 5% chance). Leave it at0for a weapon that should never jam (most melee weapons; any weapon you haven't deliberately tuned). - (Milestone 12, optional) Set Unjam Duration — how long clearing a jam takes, as a
duration. Only matters if Base Jam Chance is above
0. - (Milestone 12, optional) Add entries to Attachment Slots — which
AttachmentSlotKinds this weapon accepts (Sight,Muzzle,Magazine). Leave it empty for a weapon that accepts no attachments.
What this doesn't do yet: Equippable's equip-branch OnComplete is a documented no-op —
actually giving/selecting the weapon and enforcing the holster-slot limit both need a service
that doesn't exist yet. See
Architecture/09_ITEM_FRAMEWORK.md's Equippable
listing. Authoring the item is still worth doing — the data is real and ready the moment that
service lands. BaseJamChance/AttemptFire are real and unit-tested today (see
09_ITEM_FRAMEWORK.md §2.2);
only the "roll a jam when this weapon fires" hook is pending, because this project has no
weapon-firing/combat system yet. Clearing an existing jam works today: using a jammed weapon
(the same /use-style flow as equipping) runs the "clear_jam" interaction instead of "equip".
A third example: an attachment (WeaponAttachment)¶
Attachments are ordinary items, added exactly like any other — worked here using a new
acog_scope.item under Assets/Items/Weapons/, an attachment for glock_18's Sight
slot.
- Follow §2–3 above: Create → Item, name it
acog_scope.item, fill in Name, Plural Name, Size, Cost, Is Stackable (unchecked— one scope is one scope), Category (Weapons, matching the weapon it goes with). - In the Behaviours list, click Add → select WeaponAttachment.
- Set Slot Kind to
Sight— must match one of the entries in the target weapon's own Attachment Slots (step 7 above) for the attach to be accepted. - Set Jam Chance Modifier — added to the host weapon's Base Jam Chance while
attached. Negative for an attachment that makes jamming less likely (a quality
magazine), positive for one that makes it more likely (a poorly-fitted suppressor);
0for one with no mechanical effect at all (a purely cosmetic skin). - On
glock_18.item, addSightto Attachment Slots so it can actually accept this.
That is the entire behaviour — no code path to write, same as Edible/Equippable. In-game,
attaching and detaching are separate actions from "use": drag the attachment onto the weapon
(or the equivalent UI action, once the inventory panel exposes one) to call
RequestAttachItem; the reverse calls RequestDetachItem. Both operate only on items already
in your own inventory — see
09_ITEM_FRAMEWORK.md §2.2
for why this is a dedicated RPC rather than routed through the same "use" hook Edible/
Equippable answer (attaching is a two-item action; using is a one-item action).
What this doesn't do yet: no inventory-panel UI action calls RequestAttachItem/
RequestDetachItem yet — Milestone 6/11's inventory panel is display-only
(11_UI_ARCHITECTURE.md §3). The RPCs
themselves, and the data, are real today; wiring a drag-to-attach UI gesture is a natural
follow-up, not invented here.
5. Save and spawn it¶
Save the asset. If a server is already running, S&box hot-reloads
GameResource assets automatically —
Architecture/09_ITEM_FRAMEWORK.md §5 — so
you don't need to restart to see the new item registered.
Spawn one with /give <yourItemId> (admin-only — see
04_SERVER_ADMIN_GUIDE.md for becoming an admin on your own
server), or through the editor's asset browser drag-to-scene during development.
6. Edit it live¶
With the item spawned and a server running, change Cost in the inspector and save again.
The change applies without a restart — this is the direct improvement over the original,
where sh_config.lua and item files required editing source and reloading the whole
gamemode.
7. Verify it worked¶
- The item appears in the asset browser under its category.
- It loads with no error in the console — an inheritance or model error would fail loudly, naming this asset specifically (Architecture/09_ITEM_FRAMEWORK.md §4).
- Using it in-game restores hunger by the configured amount.
- Editing a property and re-saving while the server runs updates the live item without a restart.
8. Inheritance (optional)¶
If several items share most of their fields — a family of drinks, say — create a base item
(base_drink.item) with the shared values, then set each child's Parent Id field
(ItemDefinition.ParentId — Code/Items/ItemDefinition.cs) to base_drink. A child field you
explicitly set, including to false or 0, is never silently overwritten by the parent's
value — this is the fix for D-04, where the original's
array-inheritance path silently did nothing. Setting Parent Id to something that doesn't
exist is a load failure naming the asset, not a silent empty item.
A real worked chain exists under Assets/Items/Food/ — base_food.item plus baguette,
banana, hot_dog, beer, cola, and whiskey inheriting from it (beer/cola/whiskey
each override Category, proving the previous paragraph's explicit-override claim against
real content, not just this guide's text). See Assets/Items/README.md for the full list
across all four categories built for Milestone 5, and that file's format-uncertainty note
before trusting the raw JSON shape.
9. What needs a programmer¶
If the item needs to do something no existing behaviour supports — not "restore a need" or
"hold an inventory", but something genuinely new — that's the one case this guide can't cover.
See Architecture/09_ITEM_FRAMEWORK.md §2
for what a new ItemBehaviour looks like, and consider whether the new behaviour is
parameterisable enough that the next strange item won't need one too.