Registration — registerPack / unregisterPack
Stability: Stable.
The entry point for every cosmetic pack. A pack resource builds a plain-data
pack descriptor and registers it with the SDK. customization
mirrors the registry to render the "Appearance" page and apply skins — it is a
consumer, so a pack depends on both sdk (this contract) and customization
(the runtime).
Registration runs as a shared script: the descriptor lands in the SDK's client
registry (where the cosmetic is rendered and applied) and its server registry
(the equip-gating authority — ownership is checked server-side before an equip is
granted). Preferences stay client KVP; no database. This is the cosmetic sibling of
registerMode — the same registry pattern, a different domain.
exports.sdk:registerPack(def)
Registers a pack. Call it from a script listed in your pack's shared_scripts once
the SDK has started — the shipped templates use the SDK helper, which registers now
AND re-announces on a live restart sdk:
Sdk.autoRegister(function() exports.sdk:registerPack(PACK) end)| Parameter | Type | Required | Notes |
|---|---|---|---|
def | table | yes | The pack descriptor. Must have a unique def.id. |
Validation
The descriptor is validated before it is accepted (Sdk.validatePack). A
plain-data pack otherwise fails silently — a skin card that does nothing, a missing
tab. Validation turns those into a clear console diagnostic.
-
Errors refuse the pack. If anything is structurally wrong, the pack is not registered and every problem is printed:
[sdk] pack neon REFUSED -- 1 error(s): [sdk] - `skins` must be a non-empty array of items -
Warnings are logged but allowed (e.g. an unknown
apiVersion, a missinglabel, an unknownrarity). -
What's checked:
id, theapiVersionpin, thekind/status/accessenums, a non-emptyskinsarray where each item has anid(and, advised, alabel/rarity) — plus, forkind='outfit', the clothing payload (base/collection/pieces— see the outfit validation rules). Asset existence is NOT checked here — a skin's model (IsModelInCdimage) and an outfit's mounted collection are verified client-side at apply time (incustomization), because a streamed asset may not be indexed/mounted yet at registration.
Behaviour
-
The SDK tags the descriptor with the calling resource (
def.resource = GetInvokingResource()), so it can drop the pack if that resource stops. -
Missing fields are filled with defaults at registration time:
Field Default applied kind'skin'status'owned'access'player'skins{} -
Registering an
idthat already exists overwrites the previous descriptor. -
On success the SDK announces
sdk:packRegistered(id)(socustomizationmirrors it) and prints:[sdk] pack registered: <id> (<name>) from <resource>
exports.sdk:unregisterPack(id)
Removes a pack by id. After this, customization drops it from the catalogue (it
listens for sdk:packUnregistered).
exports.sdk:unregisterPack('neon')| Parameter | Type | Required | Notes |
|---|---|---|---|
id | string | yes | The id of a registered pack. Unknown ids are a no-op. |
Automatic cleanup
You usually don't need unregisterPack. When a pack's owning resource stops, the
SDK automatically unregisters every pack tagged with that resource and fires
sdk:packUnregistered, so customization drops its skins from the catalogue.
Versioning
The cosmetic contract has its own version, exports.sdk:packApiVersion(),
independent of the mode contract (exports.sdk:modeApiVersion()). Pin
apiVersion = N in your pack so a future SDK can flag a breaking change.
See also
- Pack descriptor — every field you can put in
def. - registerMode — the gameplay sibling, same registry pattern.
- Cosmetics SDK overview