<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://osimdev.org/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenSimulator_Internals%2FWalkthroughs%2FAvatar_Change_Outfit</id>
	<title>OpenSimulator Internals/Walkthroughs/Avatar Change Outfit - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://osimdev.org/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenSimulator_Internals%2FWalkthroughs%2FAvatar_Change_Outfit"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Change_Outfit&amp;action=history"/>
	<updated>2026-08-04T15:37:11Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Change_Outfit&amp;diff=83&amp;oldid=prev</id>
		<title>Jwbshaw: first</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Change_Outfit&amp;diff=83&amp;oldid=prev"/>
		<updated>2026-07-07T13:04:31Z</updated>

		<summary type="html">&lt;p&gt;first&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Change Outfit =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar changes outfit -- replacing wearables and rebaking appearance textures.&lt;br /&gt;
&lt;br /&gt;
This covers the standard viewer-initiated outfit change. The sequence differs slightly between V1-style viewers (AvatarIsWearing only) and V2/3 viewers (AvatarIsWearing followed by AgentSetAppearance with baked textures).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Viewer Sends AvatarIsWearing ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs -- Client_OnAvatarNowWearing()&lt;br /&gt;
&lt;br /&gt;
# Avatar selects new outfit or drags wearable items onto avatar in viewer.&lt;br /&gt;
# Viewer sends AvatarIsWearing packet listing new wearable ItemIDs by WearableType slot.&lt;br /&gt;
# AvatarFactoryModule.Client_OnAvatarNowWearing() fires.&lt;br /&gt;
# Makes a copy of current AvatarAppearance (without textures).&lt;br /&gt;
# Updates Wearables array on the copy: sets ItemID for each type, AssetID = UUID.Zero initially.&lt;br /&gt;
# Calls avatAppearance.GetAssetsFrom(sp.Appearance) -- fills in known AssetIDs from current appearance where ItemID matches.&lt;br /&gt;
# Under m_setAppearanceLock: writes sp.Appearance.Wearables only. Does NOT overwrite baked textures or visual params.&lt;br /&gt;
# Calls QueueAppearanceSave() -- schedules async save after m_savetime (default 5s).&lt;br /&gt;
&lt;br /&gt;
Note: No appearance send at this step. The viewer will bake and send new textures next.&lt;br /&gt;
&lt;br /&gt;
; No DB writes yet (save is queued, not executed).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Viewer Bakes New Textures Locally ==&lt;br /&gt;
&lt;br /&gt;
This step happens entirely on the viewer side. No server involvement.&lt;br /&gt;
&lt;br /&gt;
* Viewer composites the new wearable assets (clothing layers, skin, etc.) into baked texture images for each BakeType (Head, UpperBody, LowerBody, Eyes, Skirt, Hair, and PBR variants).&lt;br /&gt;
* Viewer uploads baked texture assets to the region&amp;#039;s asset upload cap.&lt;br /&gt;
* Assets arrive at AssetService and are stored (temporary=true, local=true initially).&lt;br /&gt;
&lt;br /&gt;
; DB writes (via AssetService):&lt;br /&gt;
* assets -- INSERT: each new baked texture asset (temporary, local)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Viewer Sends AgentSetAppearance ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs -- Client_OnSetAppearance() → SetAppearance()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends AgentSetAppearance packet containing:&lt;br /&gt;
#* New TextureEntry -- baked texture UUIDs for each face index.&lt;br /&gt;
#* New VisualParams -- slider values (height, body shape, etc.).&lt;br /&gt;
#* WearableCacheItems -- CacheId/TextureID pairs for each bake index.&lt;br /&gt;
#* AvatarSize vector.&lt;br /&gt;
# AvatarFactoryModule.SetAppearance() called under m_setAppearanceLock.&lt;br /&gt;
# Calls sp.Appearance.SetVisualParams() -- updates slider bytes, recalculates avatar height if changed.&lt;br /&gt;
# Calls sp.Appearance.SetTextureEntries() -- updates baked texture UUIDs in appearance.&lt;br /&gt;
# Calls UpdateBakedTextureCache():&lt;br /&gt;
#* Checks local IAssetCache for each baked texture asset.&lt;br /&gt;
#* Updates WearableCacheItems with confirmed TextureID and CacheId.&lt;br /&gt;
#* If any textures missing from cache: sends SendRebakeAvatarTextures() -- viewer must re-upload. Throttled to one request per texture per 30 seconds.&lt;br /&gt;
#* If full set valid and changed: stores to IBakedTextureModule (bake server cache).&lt;br /&gt;
# Calls QueueAppearanceSave() (appearance changed).&lt;br /&gt;
# Calls QueueAppearanceSend().&lt;br /&gt;
&lt;br /&gt;
; No immediate DB writes -- both saves are queued.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. Appearance Sent to Other Clients (Deferred) ==&lt;br /&gt;
&lt;br /&gt;
 AvatarFactoryModule.HandleAppearanceUpdateTimer() → SendAppearance()&lt;br /&gt;
&lt;br /&gt;
After m_sendtime (default 2s), timer drains m_sendqueue:&lt;br /&gt;
&lt;br /&gt;
# Calls sp.SendAppearanceToAllOtherAgents():&lt;br /&gt;
#* Iterates all root ScenePresences.&lt;br /&gt;
#* Calls ControllingClient.SendAppearance() for each -- sends AvatarAppearance packet with new VisualParams and baked texture bytes.&lt;br /&gt;
#* Respects parcel visibility (ParcelHideThisAvatar).&lt;br /&gt;
# Calls Animator.SendAnimPack() -- sends current animation state.&lt;br /&gt;
&lt;br /&gt;
Other clients now render the avatar with the new appearance.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Appearance Saved to AvatarService (Deferred) ==&lt;br /&gt;
&lt;br /&gt;
 AvatarFactoryModule.HandleAppearanceUpdateTimer() → SaveAppearance()&lt;br /&gt;
&lt;br /&gt;
After m_savetime (default 5s), timer drains m_savequeue. Runs on thread pool.&lt;br /&gt;
&lt;br /&gt;
# Calls SetAppearanceAssets():&lt;br /&gt;
#* For each wearable slot: calls InventoryService.GetItem(userID, itemID) -- resolves ItemID to AssetID.&lt;br /&gt;
#* If item not found: removes wearable from appearance, logs warning.&lt;br /&gt;
#* Ignores Ruth default wearables.&lt;br /&gt;
# Calls m_scene.AvatarService.SetAppearance(agentID, sp.Appearance):&lt;br /&gt;
#* Connector: HTTP PUT to ROBUST AvatarService.&lt;br /&gt;
#* ROBUST writes avatarappearance table (wearable list, texture entry, visual params) and avatarattachments table.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- SELECT: resolve each wearable ItemID to AssetID&lt;br /&gt;
* avatarappearance -- UPDATE: new wearable list, texture entry, visual params&lt;br /&gt;
* avatarattachments -- UPDATE: current attachment list&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. Attachments Changed (if outfit includes attachment changes) ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs&lt;br /&gt;
&lt;br /&gt;
If the outfit change includes adding or removing attachments, the viewer sends separate RezSingleAttachmentFromInv / DetachAttachmentIntoInv packets independently of the appearance packets above.&lt;br /&gt;
&lt;br /&gt;
Adding an attachment:&lt;br /&gt;
# Client_OnRezSingleAttachmentFromInv() fires.&lt;br /&gt;
# RezSingleAttachmentFromInventory() checks not already worn.&lt;br /&gt;
# RezSingleAttachmentFromInventoryInternal() calls IInventoryAccessModule.RezObject() -- fetches asset, deserialises SOG, adds to scene.&lt;br /&gt;
# AttachObjectInternal() attaches to avatar, displaces any existing attachment at same point (if WearReplacesAll=true).&lt;br /&gt;
# UpdateUserInventoryWithAttachment() updates inventory item to reflect attachment point.&lt;br /&gt;
# ShowAttachInUserInventory() calls sp.Appearance.SetAttachment() and QueueAppearanceSave().&lt;br /&gt;
# Scripts created and started (CreateScriptInstances, ResumeScripts).&lt;br /&gt;
# TriggerOnAttach() fires.&lt;br /&gt;
&lt;br /&gt;
Removing an attachment:&lt;br /&gt;
# Client_OnDetachAttachmentIntoInv() fires.&lt;br /&gt;
# DetachSingleAttachmentToInv() called -- see [[OpenSimulator Internals/Code Map/AttachmentsModule]].&lt;br /&gt;
# Script state snapshotted, object removed from scene, asset and inventory item updated.&lt;br /&gt;
&lt;br /&gt;
; DB writes (per attachment change):&lt;br /&gt;
* assets -- INSERT: updated attachment object asset (serialised XML)&lt;br /&gt;
* inventoryitems -- UPDATE: new assetID, attach point&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Summary: DB Tables Touched ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Operation !! Step&lt;br /&gt;
|-&lt;br /&gt;
| assets || INSERT || Viewer uploads baked textures (step 2)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || SELECT || SetAppearanceAssets() resolves wearable AssetIDs (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| avatarappearance || UPDATE || AvatarService.SetAppearance() (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| avatarattachments || UPDATE || AvatarService.SetAppearance() (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| assets || INSERT || Attachment object re-saved (step 6, if attachments changed)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || UPDATE || Attachment inventory item updated (step 6, if attachments changed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Timing Notes ==&lt;br /&gt;
&lt;br /&gt;
* Appearance send is deferred 2s (m_sendtime) -- prevents flooding if multiple rapid changes.&lt;br /&gt;
* Appearance save is deferred 5s (m_savetime) -- ensures all wearable asset uploads complete before inventory lookup.&lt;br /&gt;
* Both delays are configurable in [Appearance] section of OpenSim.ini.&lt;br /&gt;
* The AvatarIsWearing and AgentSetAppearance packets often arrive nearly simultaneously. m_setAppearanceLock ensures AvatarIsWearing does not overwrite SetAppearance texture changes.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AvatarFactoryModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/AvatarService]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Logs Out]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>