Server
Last updated on
The appearance contract on the server — read and store faces and clothing, open the fitting room.
local appearance = OPX.Api.Get('appearance')From server code inside opx_infinity. identifier is a player table, a server id or a citizen id.
GetAppearance
The stored face. Online: reads memory. Offline (citizen id string): reads the database, so it yields.
appearance.GetAppearance(identifier)Parameters
- identifier:
table | number | string
Returns
Result— the snapshot, or nil
SaveAppearance
Validates and stores a face, then tells the client (faceSaved). Yields: call from a thread. The character must be loaded.
appearance.SaveAppearance(identifier, snapshot)Parameters
- identifier:
table | number | string - snapshot:
table
Returns
Result— the canonical snapshot; errorserror.notLoggedIn,appearance.invalid(detail= validation code),appearance.tooLarge
CreateThread(function()
local saved = appearance.SaveAppearance(source, snapshot)
if not saved.ok then print(saved.error, saved.detail) end
end)GetClothing
The stored clothing record. Offline reads yield.
appearance.GetClothing(identifier)Parameters
- identifier:
table | number | string
Returns
Result— the record,falsewhen nothing is stored,nilwhen the stored row could not be read; errorclothing.unreadable
SaveClothing
Stores a clothing record. Yields. The character must be loaded. Does not check a fitting-room grant.
appearance.SaveClothing(identifier, clothing)Parameters
- identifier:
table | number | string - clothing:
table— a clothing record
Returns
Result— errorserror.notLoggedIn,clothing.invalid(detail= code),error.unavailable(clothing_unavailable: stored record unreadable this session),clothing.tooLarge
OpenWardrobe
Asks the player's client to open the fitting room and grants a clothing save. The caller checks permission. With charge, the room is priced: the server bills the save, not the client (see AllowClothingSave).
appearance.OpenWardrobe(playerId, options)Parameters
- playerId:
number - options?:
tableowner?:string— only loggedcharge?:function(source, slots)— see below. Without it the room is free.
Returns
boolean—true: the ask went out (not that a room opened)string?—'invalid_player'onfalse
AllowClothingSave
Lets the player's client save clothing. A save with no grant is refused clothing.noFittingRoom. What options holds picks the kind of grant:
appearance.AllowClothingSave(playerId, owner, options)Parameters
- playerId:
number - owner:
string— only logged - options?:
table- nothing: open grant. Any save for 10 minutes, free (the join's room, staff, a clothing store).
charge: priced grant.function(source, slots)is called with the slots the server finds changed (the save against the stored record, outfit overrides included), before anything is written. Answertrue[, nil, undo]to let it through (undorefunds if the write then fails) orfalse, codeto refuse the save; the client puts the stored look back.wear = { Slot = 'Items.Record' | false }: look grant. One free save of exactly that look on top of what is stored, for a door that dresses without a room (a bought uniform, a saved outfit). At most 8 are held per player.bill: withwear, the look's price.function(source)answers likechargeand runs only on the save that keeps the look (a Cancel costs nothing). The slots it covers are not billed again by a priced room. If any bill on a save is refused, the save is refused and every charge of that save is refunded through itsundo; the grant stays usable.
- A priced or open grant lasts 10 minutes; while the room is open the client renews it every 2 minutes (
opx:net:appearance:roomAlive), up to 30 minutes after the grant.
Returns
booleanstring?—'invalid_player','invalid_slot','invalid_item'onfalse
appearance.OpenWardrobe(playerId, { owner = 'mytailor', charge = function(source, slots)
local paid = character.RemoveMoney(source, 'EDDIES', 50 * #slots, 'tailor')
if not paid then return false, 'clothing.unpaid' end
return true, nil, function() character.AddMoney(source, 'EDDIES', 50 * #slots, 'refund') end
end })A look already paid for inside the room (a uniform bought from a shop) is not billed again by the room's save.
PricedRoom
The owner of the priced room (a charge grant) the player holds right now, or nil. A read of the unexpired grant, not of the screen. Shops use it to accept a share code only inside their own room (shops:<key>).
appearance.PricedRoom(playerId)Parameters
- playerId:
integer
Returns
string?— the owner the room was opened under
if appearance.PricedRoom(source) ~= 'shops:' .. shopKey then return refuse('shops.redeemInRoom') endThe clothing record
{
schemaVersion = 1,
equipment = { Head = 'Items.…' or false, Face, InnerChest, OuterChest, Legs, Feet,
Outfit, UnderwearTop, UnderwearBottom },
wardrobe = { active = 0..6 or nil, outfits = { ['0'] = { Head = 'Items.…', … }, … } },
}- Every item matches
^Items%.[%w_%.%-]+$and is at most 160 bytes. - Outfits are indexed
0to6and may override the seven visible slots only (not underwear).