en-clothing handles appearance and clothes. A new survivor goes through a character creator covering model, heritage, 20 face features, overlays, hair and eyes, and starts out wearing a few starter items. After that the face is fixed, except at barbers, where you can pay cash to change hair, facial hair, brows, makeup, blush, lipstick and chest hair.
Clothing isn't a free outfit menu. Every garment is an inventory item that you find, trade or loot, then wear. Wearing an item moves it out of your inventory into an equipment slot. Clothes add up to warmth for the temperature system, and some give radiation protection, like a gas mask. A worn bag gives you its own storage grid in en-inventory.
At a glance
| Depends on | oxmysql, en-core, en-ui, en-inventory |
| Start after | All of the above |
| Database tables | encore_appearance, encore_worn |
| Config files | config/shared.lua; clothing items live in en-inventory/data/items.lua |
| Key binds | en_clothing_equipment (O), en_clothing_barber (E, at a barber) |
| Radial menu | en-clothing:equipment under survivor |
| In-game builder | Content kind barber in en-admin |
How it works
Creator and barbers
The full creator can only be used once, while a character has no appearance saved. After that, only an admin running /appearance reopens it. Barbers can change hair and the overlays listed in Config.barberOverlays, but never the model. Appearance data larger than 12,000 characters of JSON is rejected.
Equipment slots
| Slot | Label | GTA part |
|---|---|---|
hat | Head | prop 0 |
mask | Face | component 1 |
glasses | Eyes | prop 1 |
top | Jacket | component 11 |
undershirt | Shirt | component 8 |
vest | Vest | component 9 |
gloves | Hands | component 3 |
legs | Legs | component 4 |
shoes | Feet | component 6 |
bag | Back | component 5 |
An empty slot shows the Config.bare drawable for that model.
Wearing and removing
Every item with a clothing block is registered as usable, and using it means wearing it. If the slot is already taken, the old item has to fit back into your inventory first. If space runs out mid-swap, the old item is put back on. en-inventory's equipment column calls the CanEquip, Equip and Unequip exports.
Warmth and radiation
Worn items add up to two player state bags:
warmthis capped atConfig.warmthCap. en-weathersync uses it to reduce the pull of cold and rain chill.radProtectionis capped at 0.95. en-core's survival system uses it for radiation.
Configuration
| Key | Default | What it does |
|---|---|---|
Config.keys.equipment | 'O' | Equipment panel (opens the en-inventory page when en-inventory is started) |
Config.models | male = 'mp_m_freemode_01', female = 'mp_f_freemode_01' | Character models |
Config.slots | 10 slots | { id, label, icon, component = n } or { id, label, icon, prop = n } |
Config.bare | per model | What each component shows when empty: [component] = { drawable, texture } |
Config.starter | { 'tshirt', 'jeans', 'sneakers' } for both models | Clothes a new character wears after the creator |
Config.warmthCap | 1.0 | Maximum total warmth |
Config.creator | parents = 46, features (20 labels), overlays (11: id, label, palette) | Creator options |
Config.barbers | 3 barbers | { id?, label, coords = vec3, radius, price, blip? }; id defaults to config:<index> |
Config.barberOverlays | { [1] = true, [2] = true, [4] = true, [5] = true, [8] = true, [10] = true } | Overlay ids a barber may change |
Adding a clothing item
Clothing items are defined in en-inventory's data/items.lua with a clothing block:
| Field | What it does |
|---|---|
slot | A slot id from the table above |
male, female | { drawable, texture } for base-game clothes, or { collection = 'pack_name', drawable = localIndex, texture, fallback = { drawable, texture } } for addon packs. An item with no entry for the character's model doesn't fit |
arms | { male = n, female = n }, for tops: the arms drawable (component 3) that fits |
warmth | 0–1, summed across worn items |
radProtection | 0–1, summed across worn items |
A bag also needs a container = { width, height, maxWeight } block on the item. en-inventory uses it for the worn bag's storage.
-- en-inventory/data/items.lua
parka = {
label = 'Arctic Parka', description = 'Fur-lined hood. Nothing gets through.',
category = 'clothing', size = { 3, 3 }, weight = 1.8, usable = true, consume = 0,
clothing = { slot = 'top', male = { 58, 1 }, female = { 73, 1 }, arms = { male = 14, female = 14 }, warmth = 0.6 },
},
hazmat_hood = {
label = 'Hazmat Hood', description = 'Sealed and filtered.',
category = 'clothing', size = { 2, 2 }, weight = 0.7, usable = true, consume = 0,
clothing = { slot = 'mask', male = { 46, 0 }, female = { 46, 0 }, warmth = 0.05, radProtection = 0.6 },
},
field_pack = {
label = 'Field Pack', description = 'Wear it to carry what\'s inside.',
category = 'equipment', size = { 3, 3 }, weight = 1.2, usable = true, consume = 0,
clothing = { slot = 'bag', male = { 45, 0 }, female = { 45, 0 } },
container = { width = 6, height = 5, maxWeight = 20.0 },
},The drawable numbers above are only examples. Use /clothingdev in game to find the right ones. See Add an item for the rest of the item fields.
Existing clothing includes tshirt (warmth 0.05), hoodie (0.2), winter_jacket (0.45), jeans, cargo_pants, sneakers, boots, beanie, bandana, gas_mask (radProtection 0.35) and work_gloves. Bags include backpack (6x4, 15 kg), duffel_bag (8x4, 25 kg) and military_rucksack (8x6, 32 kg), plus satchel, daypack, scav_pack, scav_pack_heavy, hiking_rucksack, wasteland_rucksack, tactical_pack and assault_pack from the bundled clothing pack.
Addon pack drawables only stream when the server has an Element Club Argentum (or higher) key. Without one, the item's fallback drawable is used.
Exports
Server
| Export | Arguments | Returns |
|---|---|---|
GetWorn | source | { [slot] = itemName } |
GetWornEntries | source | { [slot] = { item, metadata } } |
GetAppearance | source | Appearance table or nil |
GetCharacterLook | citizenid | { appearance (or false), worn = { [slot] = item } }; works for offline characters |
Wear | source, itemName, metadata? | ok, err. Takes the item from the player's inventory and wears it; the previous item goes back to the inventory |
Remove | source, slot | ok, err. Takes the item off into the inventory |
CanEquip | source, itemName | ok, err, slot, with no side effects |
Equip | source, itemName, metadata | ok, previous ({ item, metadata }) or false, err. The caller has already removed the item from wherever it was |
Unequip | source, slot | { item, metadata } or nil. The caller decides where it goes |
SetWornMetadata | source, slot, fields | boolean. Merges fields into the worn item's metadata |
IsLoaded | source | boolean |
GetSlots | none | { id, label, icon }[] in display order |
BuilderList, BuilderGet, BuilderValidate, BuilderSchema, BuilderTemplate | kind, ... | For 'barber': fields label, coords, radius (0.5–25), price (cash per visit), blip |
Client
| Export | Arguments | Returns |
|---|---|---|
ApplyLook | ped, look | Applies { appearance, worn } to any ped, such as a character select preview |
Commands
| Command | Restricted | What it does |
|---|---|---|
/appearance [target] | group.admin | Lets the player redo their look in the full creator |
/clothingdev | Client command | Developer tool for finding drawables (see below) |
/clothingdev usage:
/clothingdevlists drawable ranges per slot./clothingdev packslists clothing packs./clothingdev <slot> <drawable> [texture]previews a base-game drawable./clothingdev <slot> <pack> <drawable> [texture]previews a pack drawable and prints the{ collection, drawable, texture }snippet to paste into an item.
Events
Emitted, server-local:
| Event | Payload |
|---|---|
en-clothing:server:loaded | source |
en-clothing:server:worn | source, slot, itemName |
en-clothing:server:removed | source, slot, itemName |
en-clothing:server:appearanceSaved | source, isFirstTime |
Client events: en-clothing:client:dress ({ appearance, worn }) and en-clothing:client:openCreator.
State bags
| Key | Scope | Meaning |
|---|---|---|
warmth | Player | 0 to warmthCap |
radProtection | Player | 0 to 0.95 |
Database
| Table | Columns |
|---|---|
encore_appearance | citizenid (primary key), appearance (LONGTEXT JSON: model, heritage, features, overlays, hair, eyes), updated_at |
encore_worn | Primary key (citizenid, slot), item, metadata (JSON) |
Examples
Hand out a hazmat outfit and put it straight on:
-- server
if encore.inventory.addItem(source, 'gas_mask', 1) then
local ok, err = exports['en-clothing']:Wear(source, 'gas_mask')
if not ok then print('Could not wear gas mask: ' .. tostring(err)) end
endOnly let players into a radiation zone with a mask on:
-- server
local worn = exports['en-clothing']:GetWorn(source)
if worn.mask ~= 'gas_mask' then
return false, 'You need a gas mask to go in there.'
endPreview a character's look on a ped in your own selector:
-- server: fetch the look for an offline character
local look = exports['en-clothing']:GetCharacterLook(citizenid)
-- client: apply it to a preview ped
exports['en-clothing']:ApplyLook(previewPed, look)