Clothing stores, barbers, tattoo parlors and a plastic surgeon for FiveM, or a full character creator.
nCore Development · intelnpc.com · Resource: ncore_character · Version: see fxmanifest.lua
What it is#
By default it sits next to illenium-appearance or qb-clothing, so you get new stores without throwing out the appearance script your server already runs. The player walks to a counter, picks a new look, pays, and the look is saved through that script, so character select and your other scripts keep reading it like before.
If you'd rather replace the old script, set Config.Takeover = true. Then it's a full character creator with its own saved looks, and it answers the exports and events your other scripts call on the usual appearance resources.
It's free, and the whole code is open.
Features#
Two modes#
- Beside mode (default) -
Config.Takeover = false. The stores run next toillenium-appearanceorqb-clothing. The player pays here, the look is put on and saved through that resource's own save. Needs oxmysql, because the server reads the saved row back. - Takeover mode -
Config.Takeover = true. Its own creator, its own saved looks, and stand-in answers for the old appearance resource. Needs nothing else. Outfit saves from other scripts skip the counter distance and the price, see Known limits. - Items-only clothing store - With ncore_inventory selling clothes as items, the clothing store also works in Beside mode when no supported appearance resource runs. Bought pieces become inventory items, nothing is saved through an appearance script. It serves MP (freemode) characters only and tells a GTA character so.
- Unsupported hosts are named -
fivem-appearanceandesx_skinare recognized but can't be saved through. When one of them runs, the console prints a red box that says why and what to do. With no appearance resource running at all, the same box comes after 15 seconds. It also notices when the host starts or stops later. - Conflict guard - In Takeover mode, if illenium-appearance, fivem-appearance, qb-clothing or esx_skin is running, a red console box names both
ensurelines and the resource stops itself. Off withConfig.Conflicts.enabled = false.
Store counters#
- Shipped locations - 7 barbers, 6 tattoo parlors and 14 clothing stores. The plastic surgeon ships off with no locations (there's no surgeon interior in the game).
- Map blips - One per counter: barber sprite 71, tattoo 75, clothing 73. Set
blip = falseon a store to hide them. - Marker and E prompt - A marker shows over each counter within 12 m. On foot inside the counter area (3.0 m radius, 2.5 m high) you get a prompt, E opens the store. No prompt in a vehicle or with a menu open.
- Interaction key -
Config.Interact.control, 51 (E) by default. The prompt shows the right key for controls 23, 38, 46, 47 and 51, any other control still works but the prompt says E.Config.Interact.marker = falseremoves the markers. - Server-side distance - The server measures the distance itself before it opens a store and again before it charges. This needs OneSync, without it every counter answers "too far".
- Clerks - A clerk NPC stands at each clothing, barber and tattoo counter when you come within 30 m (
Config.Clerks.distance). Clerks are frozen, can't be hurt and ignore events. Per-spot model override with{ vector4(...), model = '...' }. All off withConfig.Clerks.enabled = false, one kind off withConfig.Stores.<kind>.clerk = false. - Clerk reach for scripts - A store also opens within
clerkRadius(3.0 m) of its clerk spot when another script asks for it through an export. ncore_inventory's Binco clerk uses this: G at a Binco clerk opens the clothing store as a fitting room. - Refusals are shown - A store that won't open says why, as a hint for 4 seconds and in the game feed. With ncore_inventory running the hint sits in its key-hint stack, otherwise in GTA's help box (
Config.Hints.style). - Surgeon setup - Set
Config.Stores.surgeon.enabled = trueand add locations./apphereprints ready lines to paste.
Clothing store#
- Card browser - One category per body part: hat, mask, glasses, ears, top, undershirt, arms, pants, shoes, chain, watch, bracelet and decals. Bag and vest show up too when clothes are not inventory items. The worn piece is highlighted and changed categories get a dot.
- Camera per category - Picking a category frames the head, torso, legs, feet or hands.
- Pieces and variants - Left and Right arrows (or the buttons) step through pieces, Up and Down change the texture variant, the dots under the selected card do the same.
- Only what fits - Pieces the game won't put on this body are hidden and the arrows skip them. A piece you wear that isn't sold stays as a dimmed card.
- Cart - "Your picks" lists every changed area: buy, take off, not sold here, bag or restyle. Click an entry to jump to its category, the cross puts back what you wore there. It shows the total, and the button reads Buy (clothes as items) or Save.
- Card pictures - By default each player's game loads clothing pictures from a public render set on cdn.jsdelivr.net (
Config.Thumbs.remote). Not every piece has one, those cards show their number. Set it tofalsefor numbered cards only. - Your own pictures -
/appthumbsrenders a picture per piece on a hidden capture ped, add-on clothing included, and your pictures always win over the public set. NeedsConfig.Debug = trueand screenshot-basic. Uploads are token-checked, capped at 4 MB and format-checked. - Add-on clothing - Declare streamed collections in
Config.Clothing.addonCollections, for example['my_pack'] = { drawables = 120 }. Those pieces pass the server check and can be sold. - Clothing index -
/appindexreads every clothing collection from an admin's game and writesdata/generated/apparel.luainto this resource and into ncore_inventory. Restart both afterwards. When the index is behind the game, the store logs it once with a hint to run it.
Barber#
- What it changes - Hair style, texture, color and highlight, facial hair, eyebrows, makeup, blush, lipstick and chest hair.
- Barber colors - Only the hair colors the game marks as barber colors are offered.
- Hair list - 79 male and 84 female styles, filtered by what the player's game really has.
- Own part only - The server only takes the barber's part of the look. Opens on the face camera.
Tattoo parlor#
- 1,837 tattoos - 967 male and 870 female, in 6 zones: torso, head, left arm, right arm, left leg, right leg.
- Browsing - Search by name, click to add or remove, each zone shows how many you picked there.
- Limit - "N of 60 chosen". Change it with
Config.Creator.tattoosMax, the server enforces it too. - Other tattoos stay - Tattoos are put back without wiping scars or decorations other resources added.
- Not beside qb-clothing - qb-clothing can't save tattoos, so the parlor is refused there.
Plastic surgeon#
- What it changes - Heritage, the 20 face features, eye color and skin details: blemishes, aging, complexion, sun damage, moles and body blemishes.
- Off by default - No locations, no blip, price 1500 when you turn it on.
Character creator (Takeover mode)#
- Body - Male, female or a GTA character.
- Heritage - Mother and father with the game's own portraits (numbered buttons if a portrait isn't found, or with
Config.Creator.portraits = false), resemblance and skin tone. - Face and details - 20 face-feature sliders, 13 overlays with opacity and color, hair, eye color and tattoos.
- Opening it -
/appearance(Config.Creator.command) for players without a saved look. Players who already have one need an admin. - Forced creation -
Config.Creator.forceOnFirstLogin = trueopens it after loading for a player with no look, and they can't cancel. Off by default, then the player gets a one-time hint to type/appearance. - Private bucket - The player is in a routing bucket of their own while creating (
Config.Creator.bucketed), the old one comes back afterwards. - Starting hair and tattoos -
Config.Creator.defaults.mand.f, for exampletattoos = { { col = 'mp2023_02_overlays', name = 'MP_2023_02_Tat_004_M' } }.
GTA characters#
- 269 to pick from - 215 civilians and 54 gang members, with search, All/Men/Women/Gangs filters and a picture per character from docs.fivem.net (
Config.Peds.images,falseshows the name). - Outfit tab - Same cards and arrows over the character's own clothes, plus a dice for a random outfit.
- Allow list - The server refuses any model not on the list.
Config.Peds.gangs = falsedrops the gang members,allowanddenyadd or remove names from 791 more human peds that ship in the data (cops, soldiers, story characters). Animals can't be added. - Where it works - Barber, surgeon and tattoo refuse a GTA character. The clothing store works for them, except beside qb-clothing and in the items-only store.
Every menu#
- Live preview - Every slider, color and pick shows on the character right away.
- Cancel - The Cancel button or Escape puts back the look from when the menu opened. Escape is blocked while creation is forced.
- Camera - Face, body and feet buttons, eased moves (
Config.Creator.cameraEaseMs), presets inConfig.Creator.presets. If another script's camera is running, the camera buttons are off. - Turning - Two buttons turn the character 15 degrees at a time. The mouse wheel scrolls the cards.
- Menu lock - While a menu is open
LocalPlayer.state.invBusyis set, so ncore_inventory won't open on top of it, and a menu won't open while something else holds it.
Paying#
- Flat price per counter -
Config.Pricing: create 0, barber 150, surgeon 1500, tattoo 250, clothing 200. Use whole numbers. - Account - Charged from
Config.Pricing.account(cash). On ox_core it has to be'bank', on ND_Core cash or bank. - Checked first - The balance is read before anything is taken. A player who can't pay is refused.
- Nothing changed, nothing paid - A visit that changes nothing is free.
- Refunds - If the save fails, the money goes back. If a refund itself fails, the console logs an error so staff can pay it back by hand.
- Standalone - No money system, so only free visits work.
Beside mode saving#
- Read from the host - With illenium-appearance the current look is read through its own export before the store opens. With qb-clothing it's read from the ped.
- Saved through the host - The paid look is put on and saved with the host's own save event, then checked on the client part by part.
- Server check - For up to 5 seconds the server reads the host's saved row (
playerskinson QBCore and QBox,users.skinon ESX) and compares face, overlays, hair color and texture, eyes and tattoos. Hair style and clothes are only checked on the client. - Undo - If the row doesn't hold the paid look or the save times out, the player gets the money back and the old look is put back and saved again.
- Only what the host keeps - Beside qb-clothing there is no tattoo parlor and no chest hair, and the surgeon's skin details are cut to aging and moles. Beside illenium-appearance one body-blemish option is hidden and values are rounded to its steps. A visit that changes nothing the host can keep is refused before any charge.
- illenium tattoo data - Tattoos illenium-appearance already saved keep their opacity, name and label. Tattoos the shipped index doesn't know stay on the character but don't show in the parlor.
Takeover mode saving#
- Storage - oxmysql table
ncore_character(created at start,sql/install.sqlis included) or the server's KVP store without oxmysql.Config.Database.preferpicks'auto','mysql'or'kvp'. - Write check - Every save is checked after the write: the full text on KVP, the length on MySQL. A row that can't be read counts as an error, not as "no look".
- Loading the look - The saved look goes on when the character loads (
esx:playerLoaded,QBCore:Client:OnPlayerLoaded,ox:playerLoaded,ND:characterLoaded), on spawnmanager'splayerSpawnedand when the resource starts. If the server is still starting it asks again, 5 times, 2 seconds apart. - Respawn - With the same model, everything except the clothes is put back.
- Model change - The player model only changes when it differs, and only after the player has fully loaded (30 s wait). If that wait runs out, the look goes on at the next load.
- Checked on the ped - After a look is applied every part is read back, and anything the game refused is named once in F8.
- Character select mirror - Every save is also written into
playerskinsin illenium-appearance format (QBox) or intousers.skin(ESX), so character select previews keep working. Switches:Config.Database.mirrorPlayerskins,mirrorUsersSkin. Needs MySQL. QBCore's qb-multicharacter reads another format, so turnmirrorPlayerskinsoff on QBCore. - Old global numbers - Looks imported with global clothing numbers are turned into collection pieces on the client and saved again for free. The server takes this save without a distance check.
- Outfit with the look - When clothes are not inventory items the worn clothes are saved with the look. The server takes the clothes the client sends, with no distance check and no price.
Config.Outfit.saveLook = falseturns off the outfit save from other scripts.
Stand-in for the old appearance resource (Takeover mode)#
Only while the original resource is not running.
- QBox / illenium-appearance - Client exports
setPedAppearance,setPlayerAppearance,getPedAppearance. - QBCore / qb-clothing - Client events
qb-clothes:client:CreateFirstCharacter,qb-clothing:client:openMenu,qb-clothing:client:loadOutfit,qb-clothing:client:loadPlayerClothing, exportsIsCreatingCharacterandreloadSkin, server eventsqb-clothes:loadPlayerSkinandqb-clothing:saveSkin(saves clothes only). - ESX / esx_skin -
esx_skin:openSaveableMenuopens the creator, plusresetFirstSpawn,playerRegistered,getLastSkin,setLastSkin, theesx_skin:getPlayerSkincallback andesx_skin:save(clothes only). A script that asks for the ESX clothing or barber menu (esx_skin:openMenu,openRestrictedMenu,openSaveableRestrictedMenu) is told the menu was canceled, the counters do that job. - ESX / skinchanger - Exports
GetSkin,LoadSkin,LoadClothes,Change,GetMaxValsandGetDataand the matchingskinchanger:events.GetMaxValsandGetDataanswer empty tables.
Moving from another appearance script#
appmigrate- Server console only, needs oxmysql.appmigrate appearance dry, thenrun(qbfor qb-clothing skins,esxforusers.skin). A dry run is required first, players who already have a look are skipped, rows that can't be read are counted, dropped tattoos are reported, and each source imports once.runneeds Takeover mode. Table names inConfig.Migrate.
ncore_inventory#
All of this needs ncore_inventory 1.0.25 or newer, it's optional.
- Clothes as items - Bought pieces become inventory items and are worn right away. Each one carries a share of the price for selling back. Taking a piece off puts it in the inventory for free.
- Full inventory - If nothing could be handed over, the purchase is refunded. If only some pieces fit, the rest is refunded.
- Gloves - With the inventory's gloves slot on, the arms row sells gloves.
- Bags - With the inventory's bag item set up there's a Bag category. A bought bag is a real wearable bag with storage at the bag item's own price.
- Sell clothes - With the inventory's
clothing_buybackcounter, the clothing store shows a Sell clothes button that opens it. - Binco fitting room - G at a Binco clerk opens the clothing store.
- Admin panel - Admins open the clothing, barber, surgeon, tattoo or creator menu for a player from the inventory's admin panel.
- Demo characters - While a player plays an ncore_inventory demo character, every counter except the items-only clothing store is closed, so the demo look is never saved.
- Hints - Counter prompts and refusals show in the inventory's key-hint stack.
Admin and server#
appcreator [id]- Opens the creator on a player's screen even if they have a look. If it can't open right then (another menu is open), they have 30 seconds to open it with/appearance. Console or thencore_character.adminace. Takeover mode only.AdminOpenexport - Opens any menu for a player away from a counter, the distance check is skipped for 10 seconds. Logged in the console.- Server checks - Open, save, close and the other player requests are rate-limited per player, and the server checks every value in a look against the game data before it saves. A look with a value the game data doesn't allow is refused and named in the console.
- Framework - ESX, QBCore, QBox, ND_Core, ox_core or standalone, detected at start or pinned in
Config.Framework('esx','qb','qbox','nd','oxcore','standalone'). - Languages - English and Hungarian. Add one with
locales/<code>.lua, missing keys fall back to English. - Debug -
Config.Debugis off by default, the server warns at every start while it's on. - Config backfill - Any setting missing from
config.luagets its default.
Tools for you#
/appwhy- Stand at the counter and type it. It prints in F8 and the server console why a store does or doesn't open: counters, nearest clothing spot and clerk with distances, menu state, appearance resource, last E press, last request and answer, last refusal and the server's own verdict./apphere- Prints your position and heading asvector3(...)andvector4(...)lines for store and clerk spots./appdiag- Debug only. Prints the model and setup, then writes and reads back every clothing slot and says if it was taken, taken then lost, or refused.
For developers#
| Export or event | Side | What it does |
|---|---|---|
OpenClothing(), OpenBarber(), OpenSurgeon(), OpenTattoo() |
client | Asks the server to open that store. true once sent, false, reason when refused first. The server still checks counter or clerk reach. |
OpenCreator() |
client | Asks for the creator. Refused in Beside mode. |
IsOpen() |
client | The open menu (create, clothing, barber, surgeon, tattoo) or nil. |
GetLook() |
client | A copy of the last look the server sent. Nil in Beside mode. |
ApplyPieces(pieces) |
client | Puts checked sections over the stored look without saving. Refused in Beside mode. |
SaveLook() |
client | Saves the worn clothes into the saved look. Takeover mode, clothes not inventory items. |
IsShopkeeperPed(ped) |
client | True for this resource's clerks. |
AdminOpen(target, context, by) |
server | See above. Returns ok, reason. |
OwnsLooks() |
server | True in Takeover mode. |
GetSavedPieces(src) |
server | A copy of the saved look, nil in Beside mode. |
DemoAware() |
server | Always true, read by ncore_inventory's demo. |
ncore_character:applied (context) |
client event | After a full look with model goes on: load, create, cancel (creator and clothing store) and compat:setPlayerAppearance / compat:loadSkin. Not after barber, surgeon or tattoo saves. |
ncore_character:modelChanged (model) |
client event | After this resource swapped the player model. |
Known limits#
- OneSync is required for every counter.
Config.Locale = 'auto'takes the first of thelr:locale,locale,ox:localeandesx:localeconvars that names a shipped language (en-UScounts asen), and English when none does. The server reads it and sends the result to the players. Or setConfig.Locale = 'hu'directly.- In Takeover mode the server accepts an outfit save or a convert save from the client without the store distance check or a price. The
SaveLookexport and the qb-clothing and esx_skin save stand-ins depend on that. An outfit save changes only the clothes. A convert save only runs on a look imported with old global numbers and changes the hair style and the clothes. A modded client can use the outfit save to put on any valid clothes for free, anywhere. SetConfig.Outfit.saveLook = falseif your players shouldn't change clothes that way. - An appearance table read with the
getPedAppearancestand-in and edited is put on as it was read. Scripts that edit and set it back (uniform scripts) need illenium-appearance itself. - Beside mode's server check knows
playerskinsandusers.skin. On ND_Core and ox_core use Takeover mode. - To turn a store off use
enabled = false, notConfig.Stores.<kind> = false.
Requirements#
- OneSync on.
- Beside mode (default):
illenium-appearanceorqb-clothing, and oxmysql. - Takeover mode: nothing. oxmysql is optional, without it looks go to KVP.
- Paid visits: ESX, QBCore, QBox, ND_Core or ox_core. Standalone runs free visits only.
- Optional: ncore_inventory 1.0.25+ (clothes as items, bags, Binco fitting room, admin panel, key hints), screenshot-basic (only for
/appthumbs).
Keys and commands#
| What | Who | Default |
|---|---|---|
| Open a store at its counter | player | E (Config.Interact.control) |
| Previous / next piece | player, clothing store | Left / Right arrow |
| Next / previous variant | player, clothing store | Up / Down arrow |
| Cancel and put the old look back | player, any menu | Escape |
| Open the creator | player without a look, Takeover | /appearance |
| Why a store won't open | any player | /appwhy |
| Print position for config | any player | /apphere |
| Open the creator for a player | console or ncore_character.admin |
appcreator [id] |
| Import old looks | console | appmigrate <appearance\|qb\|esx> <dry\|run> |
| Rebuild the clothing index | ncore_character.admin |
/appindex |
| Render clothing pictures | debug on, Config.Thumbs.ace if set |
/appthumbs [m\|f\|both] [c11,a0,...], /appthumbs stop |
| Slot diagnostics | debug on | /appdiag |
With /appthumbs the body is optional, /appthumbs c11,a0 renders both. Category keys: c1 mask, c3 arms, c4 pants, c6 shoes, c7 chain, c8 undershirt, c10 decals, c11 top, a0 hat, a1 glasses, a2 ears, a6 watch, a7 bracelet. While debug is on and Config.Thumbs.ace is false, any player can run it, so set an ace or turn debug off before you go live.
Where to configure#
| File | What's in it |
|---|---|
config.lua |
Every setting: mode, framework, language, stores, blips, clerks, prices, creator, cameras, GTA characters, pictures, database, mirror, migration, conflict guard, add-on clothing, debug. |
locales/*.lua |
English and Hungarian text, counter prompts included. |
data/generated/*.lua |
Game data: clothing index (rebuilt by /appindex), hair, tattoos, GTA characters. |
sql/install.sql |
The ncore_character table for Takeover mode. |
web/thumbs/m, web/thumbs/f |
Your own clothing pictures from /appthumbs. |
tools/gen_appearance_data.lua |
The generator I build data/generated with. It needs a game data index that isn't in this package, you don't need it to run the script. |
Other settings in config.lua#
The ones the sections above don't name.
| Setting | What it does |
|---|---|
Config.Stores.<kind> |
Per store: radius and height of the counter area, clerkRadius, blip = { sprite, colour, scale } or false, and clerk.model, clerk.scenario (what the clerk plays) and clerk.at (the clerk spots). |
Config.Pricing.currency |
The money sign in the menus, '$'. |
Config.Creator.cameras |
The camera preset each menu opens on: creator and tattoo body, barber and surgeon face. |
Config.Creator.bucketBase |
The private creator bucket is this number plus the player's server id (8000). |
Config.Creator.adminAce |
The admin ace, ncore_character.admin. A player with it can also open the creator with /appearance while they have a look. |
Config.Heads |
The ranges the server accepts: heritage heads 0 to 45, 32 eye colors, 64 hair and makeup colors, and the style count of each of the 13 overlays. The menus offer the smaller of this and what the game has. F8 tells you when the game has another head count. |
Config.Peds.enabled |
false turns GTA characters off. The creator shows no GTA character button and the server refuses those models. |
Config.Database.table |
The Takeover table name (ncore_character). Letters, digits and underscores only. |
Config.Thumbs |
For /appthumbs: command, encoding ('webp' or 'png'), quality (0.6), endpoint (where screenshot-basic uploads, empty uses the address the game is connected to, set it when that address doesn't reach the server), height (the capture ped stands 40 m above you) and settleMs (150 ms wait before each picture). |
Common questions#
A store doesn't open#
Stand at the counter and type /appwhy. It prints in F8 and on the server console the nearest counter and clerk with their distances, the last refusal and the server's own verdict. If every counter says you're too far, OneSync is off. Send that output with a support request.
Your server runs fivem-appearance or esx_skin#
Beside mode can't save through either of them, the console says so in a red box. Use Takeover mode and remove the old resource. appmigrate appearance reads every skin with a headBlend field (illenium-appearance's format) from both playerskins and users.skin, and appmigrate esx reads skinchanger skins from users.skin. The dry run tells you how many it found.
Uniforms and job outfits#
In Takeover mode, outfits other scripts put on through qb-clothing:client:loadOutfit or skinchanger's LoadClothes change the clothes on the character without saving them. With clothes as inventory items they're not put on, hand the uniform out as items instead. A script that reads the look with illenium-appearance's getPedAppearance, edits it and sets it back needs illenium-appearance itself, so run Beside mode next to it.
Saved outfits#
There is no wardrobe of named outfits. In Takeover mode the clothes a player wears are saved with their look when clothes are not inventory items, and the SaveLook export saves what they wear now. With ncore_inventory selling clothes as items, every piece is an item in the inventory.
Pictures for add-on clothing#
/appthumbs renders a picture of every piece the game has in the store categories on a hidden ped, streamed add-on clothing included, and a second run skips the pictures already saved. Turn Config.Debug on, start screenshot-basic, set Config.Thumbs.ace if other players are online, and turn debug off again when it's done. To sell those pieces, declare their collection in Config.Clothing.addonCollections, run /appindex and restart.
Where the looks are stored#
Beside mode saves through the host script's own table, playerskins on QBCore and QBox or users.skin on ESX. Takeover mode uses the ncore_character table, one row per character, or the server's KVP store without oxmysql. On QBox and ESX with MySQL each save is also mirrored for character select, see Character select mirror above.
Updating#
Download the new version from intelnpc.com, keep your config.lua and the web/thumbs folder if you rendered pictures, and copy every other file over the old ones. Settings missing from an older config get their default. CHANGELOG.md says when a version needs anything else.
Docs#
- INSTALLATION.md - setup step by step.
- CHANGELOG.md - what changed in each version.
Support#
Support is on intelnpc.com and I reply within 72 hours. It covers installing, configuring and bugs in the script as shipped. Send your framework, which mode you run, the console error and what /appwhy printed.
nCore Character is made by nCore Development. It is not approved, sponsored or endorsed by Rockstar Games.
