Clothing as Items
One Inventory turns clothing into real items. They equip, unequip, drop, trade, give and sell like anything else, and the matching item auto-creates whenever the worn clothing changes. Every appearance / clothing script works with the inventory; some need a small one-time edit.
Appearance script support
Every appearance / clothing script works with the inventory. Most need no setup at all; a few need one small edit (see Required edits). The matching item auto-creates whenever the worn clothing changes, whatever script you run.
exports.one_inventory:SetClothingPollingEnabled(false) -- pause
exports.one_inventory:SetClothingPollingEnabled(true) -- resume
Required edits
Most appearance scripts need no changes. The ones below need one small, one-time edit.
We read the current outfit from qb-clothing, so it needs one export. Paste this at the bottom of qb-clothing/client.lua (some forks use qb-clothing/client/main.lua):
exports('GetSkinData', function() return skinData end)
How it works
Two modes
One DB row per piece, with a fixed drawable / texture. Good for unique pieces. Given by name:
exports.one_inventory:AddItem(src, 'onestudios_jacket', 1)
Static pieces use their own definition name and carry no metadata.
One item per component (clothing_hat ... 14 seeded), with the drawable / texture / image in the item metadata, so one item covers unlimited variants:
exports.one_inventory:AddItem(src, 'clothing_shirt', 1, { drawable = 42, texture = 3 })
When a script sets a new outfit
When an appearance change comes from a script (a clothing store, a wardrobe, the character creator), the affected slot is reconciled. What happens to that slot's item depends on what was already in it:
| Slot state | Result |
|---|---|
| Wearing a dynamic item | Its ids morph in place, no clutter, unless Keep Replaced Clothing is enabled in the config (then the replaced piece returns to the inventory and a new one is minted). |
| Wearing a static piece | It always swaps back, and a new dynamic item is created. |
| Empty | A new dynamic item is created. |
Config (admin panel)
Taking clothing images
Dynamic clothing icons are generated in-game with an admin green-screen capture. The capture assets ship disabled by default, because, while they're loaded, a green-screen box is streamed into the world. Only enable them to generate icons, and do it on a dev / staging server or during downtime.
Enable the capture stream
Two switches must BOTH be on (screenshot-basic must also be started before one_inventory):
- Rename
one_inventory/stream_disabledtostream(FiveM only auto-loads a folder named exactlystream). - Uncomment
this_is_a_map 'yes'inone_inventory/fxmanifest.lua(this places the green-screen box in the world). restart one_inventory(or restart the server).
Take the pictures
Open the admin panel, go to Clothing -> Take pictures, then pick a component (or all), a drawable (or all), the gender, and optionally override the camera. X / Escape cancels.
Find the icons
Captured icons are written to:
one_inventory/web/images/clothing/<component>/<model>-<drawable>.webp
Restart the resource (or let the file watcher pick them up) to see new icons in-game.
Disable the capture stream
Back to normal play, reverse both switches:
- Rename
streamback tostream_disabled. - Comment out
this_is_a_map 'yes'inone_inventory/fxmanifest.luaagain. restart one_inventory.
Already-captured icons are served independently of this stream, so disabling it does not affect icons you've already made.
Adding a new appearance script (devs)
Drop client/integrations/clothing/<resource>.lua, plus a server file only if the script has a real save event.
Guard and name
if GetResourceState('<resource>') == 'missing' then return end
Clothing = Clothing or {}
Clothing.Name = '<resource>'
Provide Clothing.ApplyEquipped
function Clothing.ApplyEquipped(equippedMap)
-- equippedMap = { [component] = { drawable, texture } }, equipped slots only; absent = bare
-- Read the script's full skin, overlay our 14, apply clothing-only, return true.
-- return false to fall back to native apply.
end
Pick the outbound helper that matches the script's skin format:
qb.lua.ClothingOverlayAppearance(appearance, equippedMap, slotMap). See illenium.lua / fivem.lua.ClothingOverlayFlatSkin(skin, equippedMap, flatMap). See esxskin.lua.Inbound auto-create
Pick the path that matches the script:
Set Clothing.ConcileByEvent = true in the client file so the polling thread skips this script and the save event drives sync instead. If the script persists and re-applies our look on login, also mark our own saves (with MarkInternalClothingSave()) before triggering its save, so it restores exactly what we equipped:
-- client file
Clothing.ConcileByEvent = true
-- when we apply clothing, persist it through the script
MarkInternalClothingSave()
-- then trigger the script's save
Add server/integrations/clothing/<resource>.lua that hooks the save event, skips the saves we triggered, and reconciles the rest:
-- server file
RegisterNetEvent('<resource>:onSave', function(src, skin)
if ConsumeInternalClothingSave(src) then return end
ReconcileClothingSkin(src, <toPieces>(skin, MAP, GetClothingSex(src)))
end)
Do nothing. The polling thread reads the ped after the script paints it and reconciles automatically (format-agnostic), keeping the inventory in sync.
SyncClothingFromPed() is still available as a manual one-shot if ever needed.
See also
The client-side clothing exports (GetEquippedClothing, EquipClothing, UnequipClothing) drive equip / unequip from your own scripts.
