Files
MetaCrate/docs/appearance.md
Chili Palmer a9927fcfcb
Some checks failed
Native code generation / deterministic (push) Failing after 2m19s
Imaging and meshing gate / native (push) Failing after 1m26s
Native Rust workspace compile / compile (push) Failing after 2m11s
Implement appearance and current outfit services (#65)
2026-08-10 08:58:29 +00:00

62 lines
3.6 KiB
Markdown

# Appearance, wearables, and the Current Outfit Folder
`AppearanceManager` owns the client-visible wearable and attachment snapshots.
Wearables retain their inventory item, asset, asset type, and wearable slot. A
clothing slot accepts at most 60 ordered layers; body parts are single-value
slots and replace an existing value of the same type. Sending the outfit emits
the native `AgentIsNowWearing` packet from a snapshot, then publishes the
appearance event after the send. Wearable reply and appearance subscribers are
also snapshotted before invocation, so no state or subscriber lock is held
during a callback.
Attachment calls preserve the inventory owner, name, description, permission
masks, flags, and requested attachment point in
`RezSingleAttachmentFromInv`. Add versus replace is encoded in the attachment
point field, and replace removes only objects at the selected non-default
point. `DetachAttachmentIntoInv` is keyed by inventory item ID. Queries expose
the same state by item, item ID, and attachment point.
## Current Outfit Folder ownership
`CurrentOutfitFolder` discovers the `CurrentOutfit` system folder from the
inventory store unless an explicit folder has been supplied. Its contents are
links: link UUIDs identify COF entries and link asset UUIDs identify the worn
inventory objects. Resolution first consults committed local link targets and
then the inventory store. This keeps successful mutations immediately
queryable while an asynchronous inventory reply is still being reconciled.
Clothing link descriptions encode the wearable type followed by a two-digit
layer number. Add chooses the first free layer, preserves existing layers, and
rejects a 61st layer. Replace removes the selected wearable type before
allocating its new layers. Body-part and attachment descriptions remain empty,
matching the reference link format. Folder ancestry and recursive outfit
discovery are cycle-safe and bounded to 256 nodes.
Mutations pass through a one-permit asynchronous operation gate. Waiting for
the gate is cancellation-aware, but the gate is not an inventory/state lock;
network awaits never retain a synchronous lock. Cancellation is checked while
planning and before committing. Once a commit begins, it completes or runs its
compensation before reporting the result, preventing a cancellation race from
leaving a half-written outfit.
Outfit changes create replacement links before removing old links. If removal
fails, new links are removed and old link descriptions are recreated. Attach
creates its COF link before executing the rez request; replacement removes the
displaced links only after the new attachment succeeds. A later failure
detaches the new item and restores displaced attachments. Detach similarly
restores the attachment if its COF link cannot be removed. The local shadow is
changed only after those network steps succeed.
`ICurrentOutfitPolicy` remains a pure decision/reporting boundary. Composite
policies use a stable subscriber snapshot, consult every policy for attach and
detach decisions, and invoke reports in registration order. Policy locks are
released before callbacks and committed changes are reported exactly once.
Focused compatibility coverage lives in `current_outfit_folder_semantics`,
`current_outfit_policy_semantics`, the COF link-description cases, and the
issue-relevant appearance cases. Native recording fakes additionally prove
create/remove compensation, create-before-attach ordering, replacement state,
layer preservation, and cancellation before backend interaction. Texture
baking, visual-parameter synthesis, and texture upload are a separate
appearance pipeline and are not owned by this service slice.