esx_clotheshop
esx_clotheshop adds 14 clothing stores to ESX Legacy. Configure prices, per-piece charging and saved outfits, and learn the server callback and its checks.
esx_clotheshop places clothing stores around the map where players change their outfit through the esx_skin menu and pay with cash. After paying, players can optionally save the outfit to their wardrobe (the property datastore used by esx_property).
Overview
| Fact | Value |
|---|---|
| Resource | esx_clotheshop |
| Side | Client + server |
| Dependencies | esx_lib, es_extended, esx_skin (plus oxmysql) |
| Optional | esx_datastore with a property datastore for saved outfits |
| Database | None of its own |
In-game flow
- Walk into a store marker and press E.
- Change clothing in the restricted skin menu (t-shirt, torso, decals, arms, pants, shoes, bags, chain, helmet, glasses, watches).
- Confirm the purchase. The server charges cash and saves the new skin through
esx_skin. - If a
propertydatastore exists, choose whether to save the outfit and type a name.
If the player cancels, leaves the marker or cannot pay, the previous skin is restored.
Installation
There is no SQL file. Make sure the dependencies start first:
ensure esx_skin
ensure esx_datastore
ensure esx_clotheshopTo enable saved outfits, create the per-player datastore once:
INSERT INTO `datastore` (`name`, `label`, `shared`) VALUES ('property', 'Property', 0);Configuration
| Key | Default | Description |
|---|---|---|
Config.Locale | GetConvar('esx:locale', 'en') | Locale used for texts. |
Config.Price | 250 | Price of a purchase (or of each changed piece). |
Config.ChargePerPiece | false | Charge Config.Price per changed item in Config.SkinProps instead of a flat price. |
Config.ShopDistance | 3.0 | Max distance in meters from a shop that the server accepts for a purchase. |
Config.PurchaseSessionDuration | 60000 | Time in ms after paying during which the outfit can be saved. |
Config.MaxOutfits | 20 | Max outfits in the dressing list. New saves are ignored when full. |
Config.MaxOutfitLabelLength | 40 | Outfit names are trimmed to this length. Control characters are removed. |
Config.DrawDistance | 10.0 | Marker draw distance. |
Config.MarkerSize | { x = 1.5, y = 1.5, z = 1.0 } | Marker size. x is also the interaction radius. |
Config.MarkerColor | { r = 102, g = 102, b = 204 } | Marker color (alpha is fixed at 100). |
Config.MarkerType | 1 | Marker type. |
Config.Shops | 14 vector3 positions | Store locations. Each also gets a blip (sprite 73, color 47). |
Config.SkinProps | { 'tshirt', 'torso', 'decals', 'arms', 'pants', 'shoes', 'bags', 'chain', 'helmet', 'glasses', 'watches' } | Items compared for per-piece pricing (<name>_1 and <name>_2). |
-- Charge 150 per changed piece, minimum 150
Config.Price = 150
Config.ChargePerPiece = trueServer callbacks and events
esx_clotheshop:buyClothes (callback)
Triggered by the client with (newSkin, oldSkin). Returns bought, failure where failure is 'not_enough_money' or 'save_failed'.
Server-side safeguards:
- The player must be within
Config.ShopDistanceof a shop. newSkinis validated withexports.esx_skin:ValidateSkin.- The price is calculated against the skin stored on the server (
exports.esx_skin:GetSkin), not theoldSkinsent by the client. - The money operation is wrapped in
beginAccountOperation/endAccountOperationand refunded ifesx_skin:SaveSkinfails. - Only one purchase per identifier can run at a time.
esx_clotheshop:checkPropertyDataStore (callback)
Returns true when the player has a property datastore. The client uses it to decide whether to show the save prompt.
esx_clotheshop:saveOutfit (net event)
TriggerServerEvent('esx_clotheshop:saveOutfit', label, skin)Client-triggerable
This event can be fired by any client. It is safe by design: it only works within Config.PurchaseSessionDuration after a successful purchase, ignores the skin argument and stores the skin that was actually paid for, sanitizes the label and respects Config.MaxOutfits.
Saved outfits are appended to dressing in the player's property datastore as { label = string, skin = table }.
Integration tips
esx_propertyreads the samedressinglist, so outfits bought here show up in property wardrobes.- To read outfits from your own resource on the server:
TriggerEvent('esx_datastore:getDataStore', 'property', xPlayer.getIdentifier(), function(store)
local outfits = store and store.get('dressing') or {}
for i, outfit in ipairs(outfits) do
print(i, outfit.label)
end
end)- Payment uses the cash account (
xPlayer.removeMoney). Editserver/main.luaif you want bank payments.
Common issues
- Purchase always fails with a "save failed" message: the server distance check uses
Config.ShopDistance(3.0). If you moved a shop marker, update theConfig.Shopsentry, not just the visual marker. - Outfit not saved: the
propertydatastore is missing, the 60 second window expired, or the player already hasConfig.MaxOutfitsoutfits. - Skin resets after buying:
esx_skinfailed to save the skin. Check the server console; the purchase is refunded in that case.
Related
Frequently asked questions
Independent documentation
Last updated on
esx_boat
esx_boat adds a boat shop, a boat license and six boat garages to ESX Legacy. Covers setup, every config key, callbacks, the getGarages export and pitfalls.
esx_cruisecontrol
esx_cruisecontrol adds cruise control and a seatbelt with ejection to ESX Legacy. Covers keybinds, config keys, the isSeatbeltOn export and HUD integration.