> For the complete documentation index, see [llms.txt](https://atiysus-organization.gitbook.io/aty-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://atiysus-organization.gitbook.io/aty-scripts/inventory/features/items-and-metadata.md).

# Items & Metadata

## Items & Metadata

Items are defined once, in `data/items.lua`, and read by both sides. The NUI never invents item data and never trusts what the client sends.

#### Definition fields

```lua
weapon_pistol = {
    label       = 'Pistol',
    weight      = 1100,            -- ALWAYS grams
    stack       = false,           -- one per slot
    category    = 'weapon',
    rarity      = 'rare',
    description = 'Standard semi-automatic pistol.',
    durability  = true,
}
```

| Field         | Meaning                                                                                                                                                                                                   |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`       | Display name                                                                                                                                                                                              |
| `weight`      | Grams. The server computes in grams everywhere                                                                                                                                                            |
| `stack`       | `false` never merges · absent uses `Config.UI.maxStack` · `N` caps at exactly N. `false` is for items that must be told apart — a weapon, a container, anything with `durability` — not a way to say rare |
| `category`    | `weapon` `ammo` `consumable` `medical` `tool` `clothing` `valuable` `document` `container` `misc`                                                                                                         |
| `rarity`      | `common` `uncommon` `rare` `epic` `legendary` — visual only                                                                                                                                               |
| `description` | One line in the detail column                                                                                                                                                                             |
| `image`       | Override; defaults to `images/<name>.webp`, then `.png` (see Images)                                                                                                                                      |
| `usable`      | Override for whether "Use" appears                                                                                                                                                                        |
| `durability`  | Created at 100 and wears down                                                                                                                                                                             |
| `effect`      | What using it does — see Consumables                                                                                                                                                                      |
| `cooldown`    | ms before this item can be used again                                                                                                                                                                     |
| `useTime`     | ms one use takes. The portion is spent when it **finishes**                                                                                                                                               |
| `portions`    | How many uses one unit is worth. Read only while `Config.Portions.enabled` is on (off by default, as ox\_inventory)                                                                                       |
| `cancel`      | `true` = the action bar can be cancelled with the cancel key; absent = it cannot (ox `client.cancel`)                                                                                                     |
| `disable`     | `{ move, sprint, car, combat }` the player cannot do while using it; combat is off during every use unless set `false` (ox `client.disable`)                                                              |
| `close`       | `false` = using it leaves the inventory open; absent = it closes (ox `close`)                                                                                                                             |

#### Serial numbers

Any item that cannot stack gets a **ULID** when it is created — a sortable, unique id that stays with that specific unit for its whole life.

```
invtrace <uid>
```

prints where it was born, every hand it passed through, and where it is now.

{% hint style="info" %}
Stackable items do not get serials, and should not. Six identical bandages are six of a thing, not six things — giving them individual identity would triple the ledger for no answerable question.
{% endhint %}

#### Metadata

Beyond durability and serials, a unit can carry arbitrary metadata: a weapon's registered owner and attachments, a note's text, a licence's issue date.

```lua
exports.aty_inventory:SetMetadata(inv, slot, {
    registered = 'John Miller',
    components = { 'suppressor', 'flashlight' },
})
```

Metadata travels with the unit through every move, and differing metadata is what keeps two otherwise-identical items in separate slots.

#### Where definitions can come from

| Source                    | When                                                 |
| ------------------------- | ---------------------------------------------------- |
| `data/items.lua`          | The resource's own list — the file a developer edits |
| The framework             | QBCore / ESX shared items, read through the bridge   |
| Admin panel → Definitions | Live field edits, stored in `aty_overrides`          |

A panel edit is an override on a single **field**, not a second catalogue. Nothing there ever writes to `data/items.lua`, and the panel shows the file value beside the live one — the moment two records disagree without showing it, nobody can say which one the server is running.

Framework items work as they are. `invmigrate items write` writes them to `data/items.generated.lua`; list that file in `fxmanifest.lua`'s `shared_scripts` after `data/items.lua` and this resource owns them, no longer depending on the framework being up. Items already in `data/items.lua` are skipped — the file here wins.

An adopted item is one-per-slot only when its own catalogue says so — qb's `unique`, ox's `stack = false`. qb's `rare` is about value, not storage, and is not read as uniqueness. Items already stored under an older rule are brought up to date with `invrestack confirm`, which repairs loaded bags as well as stored ones.

#### Images

Drop a WebP or PNG named after the item into `ui/images/`. The interface tries, in order:

1. the definition's `image`
2. `images/<name>.webp`, then `images/<name>.png`
3. each entry of `Config.UI.imageFallback` — another resource's art, `%s` standing for the item name
4. a placeholder

```lua
Config.UI.imageFallback = {
    'nui://qb-inventory/html/images/%s.png',
    'nui://ox_inventory/web/images/%s.png',
}
```

Adopting a framework's catalogue adopts hundreds of names and none of their art; the inventory they came from usually still holds the pictures. Point the list at wherever that folder lives on your server. A file in `ui/images/` always wins, because it is tried first.

`scripts/collect-item-images.py` copies matching pictures from the rest of the server into `ui/images/`.

```
invdoctor
```

reports how many items have no picture and writes the full list to `data/missing-images.txt`.
