<?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%2FCode_Map%2FAttachmentsModule</id>
	<title>OpenSimulator Internals/Code Map/AttachmentsModule - 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%2FCode_Map%2FAttachmentsModule"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/AttachmentsModule&amp;action=history"/>
	<updated>2026-08-04T15:28:07Z</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/Code_Map/AttachmentsModule&amp;diff=92&amp;oldid=prev</id>
		<title>Jwbshaw: first</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/AttachmentsModule&amp;diff=92&amp;oldid=prev"/>
		<updated>2026-07-07T13:19:05Z</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/Code Map/AttachmentsModule =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs&lt;br /&gt;
&lt;br /&gt;
INonSharedRegionModule. Handles all attachment operations: rezzing attachments on login, attaching/detaching objects, saving attachment state to inventory, and transferring attachments between regions. One instance per region.&lt;br /&gt;
&lt;br /&gt;
Registered as IAttachmentsModule. Can be disabled via [Attachments] Enabled=false.&lt;br /&gt;
&lt;br /&gt;
Requires IInventoryAccessModule -- disables itself if unavailable.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
 [Attachments] section&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Enabled || true || Enable/disable the module&lt;br /&gt;
|-&lt;br /&gt;
| WearReplacesAll || true || When attaching to a point, remove all existing attachments at that point&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Event Wiring ==&lt;br /&gt;
&lt;br /&gt;
SubscribeToClientEvents() hooks per client:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Event !! Handler&lt;br /&gt;
|-&lt;br /&gt;
| OnRezSingleAttachmentFromInv || Client_OnRezSingleAttachmentFromInv()&lt;br /&gt;
|-&lt;br /&gt;
| OnRezMultipleAttachmentsFromInv || Client_OnRezMultipleAttachmentsFromInv()&lt;br /&gt;
|-&lt;br /&gt;
| OnObjectAttach || Client_OnObjectAttach()&lt;br /&gt;
|-&lt;br /&gt;
| OnObjectDetach || Client_OnObjectDetach()&lt;br /&gt;
|-&lt;br /&gt;
| OnDetachAttachmentIntoInv || Client_OnDetachAttachmentIntoInv()&lt;br /&gt;
|-&lt;br /&gt;
| OnObjectDrop || Client_OnObjectDrop()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Scene events:&lt;br /&gt;
* OnStartScript / OnStopScript -- sets HasGroupChanged on attachment SOGs when scripts start/stop.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== RezAttachments() ==&lt;br /&gt;
&lt;br /&gt;
Called from ScenePresence.CompleteMovement() on real login (IsRealLogin true). Not called for teleports or crossings -- those carry attachments in AgentData.&lt;br /&gt;
&lt;br /&gt;
# Returns immediately if sp.GetAttachmentsCount() &amp;gt; 0 (viewer already rezzed them).&lt;br /&gt;
# Fetches all attachment item UUIDs in a single batch: InventoryService.GetMultipleItems().&lt;br /&gt;
# For each attachment in sp.Appearance.GetAttachments():&lt;br /&gt;
#* Validates item exists and owner matches sp.UUID. If not: removes from appearance.&lt;br /&gt;
#* Calls RezSingleAttachmentFromInventoryInternal().&lt;br /&gt;
# For NPCs: uses AssetID directly, skips inventory item checks.&lt;br /&gt;
&lt;br /&gt;
; DB reads:&lt;br /&gt;
* inventoryitems -- SELECT batch by item UUID array&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== RezSingleAttachmentFromInventoryInternal() ==&lt;br /&gt;
&lt;br /&gt;
Core rez path for a single attachment.&lt;br /&gt;
&lt;br /&gt;
# Calls IInventoryAccessModule.RezObject() -- fetches asset, deserialises SOG, adds to scene.&lt;br /&gt;
# Calls AttachObjectInternal() -- attaches SOG to avatar.&lt;br /&gt;
# If doc (saved script state) provided: LoadScriptState() before attach.&lt;br /&gt;
# If attach fails: removes SOG from scene and returns null.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== AttachObjectInternal() ==&lt;br /&gt;
&lt;br /&gt;
Attaches a SOG already in the scene to an avatar.&lt;br /&gt;
&lt;br /&gt;
# Rejects if any avatars are sitting on the object.&lt;br /&gt;
# Resolves attachment point: uses explicit point, or stored LastAttachPoint, or left hand as fallback.&lt;br /&gt;
# Rejects if &amp;gt; Constants.MaxAgentAttachments already attached.&lt;br /&gt;
# If not appending (WearReplacesAll): collects existing SOGs at same attach point for removal.&lt;br /&gt;
# Calls DetachSingleAttachmentToInv() for each displaced attachment.&lt;br /&gt;
# Calls UpdateUserInventoryWithAttachment() -- updates inventory item to reflect new attach point.&lt;br /&gt;
# Calls AttachToAgent() -- physically attaches SOG to avatar in scene.&lt;br /&gt;
# If resumeScripts: CreateScriptInstances() + ResumeScripts().&lt;br /&gt;
# Fires EventManager.TriggerOnAttach().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== AttachToAgent() ==&lt;br /&gt;
&lt;br /&gt;
Low-level scene attachment.&lt;br /&gt;
&lt;br /&gt;
# Calls m_scene.DeleteFromStorage() -- removes object from region storage.&lt;br /&gt;
# Removes physics actors from all parts.&lt;br /&gt;
# Sets so.AttachedAvatar, so.AttachmentPoint, so.IsAttachment = true.&lt;br /&gt;
# Calls sp.AddAttachment(so).&lt;br /&gt;
# For HUD attachments (HasPrivateAttachmentPoint): sends kill packets to all other clients.&lt;br /&gt;
# Schedules full update for the SOG.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DetachSingleAttachmentToInv() ==&lt;br /&gt;
&lt;br /&gt;
Detach and save to inventory.&lt;br /&gt;
&lt;br /&gt;
# Calls PrepareScriptInstanceForSave() -- fires detach event, waits 30ms, snapshots script state. Must be done OUTSIDE AttachmentsSyncLock to avoid deadlock.&lt;br /&gt;
# Under AttachmentsSyncLock:&lt;br /&gt;
#* Calls sp.Appearance.DetachAttachment() -- updates appearance wearables.&lt;br /&gt;
#* Calls AvatarFactory.QueueAppearanceSave().&lt;br /&gt;
#* Calls sp.RemoveAttachment().&lt;br /&gt;
#* Calls UpdateDetachedObject().&lt;br /&gt;
&lt;br /&gt;
UpdateDetachedObject():&lt;br /&gt;
* Calls m_scene.DeleteSceneObject() -- removes from scene.&lt;br /&gt;
* Clears attachment fields (AttachedAvatar, ParentLocalId, IsAttachment).&lt;br /&gt;
* For local grid users (not HG visitors): calls UpdateKnownItem() -- serialises SOG to XML, updates asset and inventory item.&lt;br /&gt;
* Calls so.RemoveScriptInstances() + so.Dispose().&lt;br /&gt;
&lt;br /&gt;
UpdateKnownItem():&lt;br /&gt;
* Serialises SOG to XML via SceneObjectSerializer.ToOriginalXmlFormat() including script state.&lt;br /&gt;
* Recalculates permissions from current prim permissions.&lt;br /&gt;
* Creates new asset via m_scene.CreateAsset().&lt;br /&gt;
* Calls IInventoryAccessModule.UpdateInventoryItemAsset().&lt;br /&gt;
* Sends SendInventoryItemCreateUpdate() to client.&lt;br /&gt;
&lt;br /&gt;
; DB writes (on detach):&lt;br /&gt;
* assets -- INSERT: new serialised object asset&lt;br /&gt;
* inventoryitems -- UPDATE: new assetID, permissions&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DetachSingleAttachmentToGround() ==&lt;br /&gt;
&lt;br /&gt;
Drops attachment to world at position 2.5m in front of avatar.&lt;br /&gt;
&lt;br /&gt;
# Removes from inventory (DeleteItems).&lt;br /&gt;
# Clears attachment fields, sets AbsolutePosition.&lt;br /&gt;
# Calls so.ApplyPhysics(), so.AttachToBackup().&lt;br /&gt;
# Sends SendRemoveInventoryItem() to client.&lt;br /&gt;
# Fires TriggerOnAttach(localId, UUID.Zero) -- signals scripts.&lt;br /&gt;
# Removes script permissions (take controls, camera).&lt;br /&gt;
# Resumes scripts, schedules updates.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- DELETE: removes item from user inventory&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== CopyAttachments() (for region transfer) ==&lt;br /&gt;
&lt;br /&gt;
CopyAttachments(IScenePresence, AgentData) -- called by ScenePresence.CopyTo() on departure:&lt;br /&gt;
* Clones each attachment SOG for transfer.&lt;br /&gt;
* Snapshots script state via GetStateSnapshot().&lt;br /&gt;
* Stores clones and states in ad.AttachmentObjects / ad.AttachmentObjectStates.&lt;br /&gt;
&lt;br /&gt;
CopyAttachments(AgentData, IScenePresence) -- called by ScenePresence.CopyFrom() on arrival:&lt;br /&gt;
* Calls DeleteAttachmentsFromScene() to clear any existing attachments.&lt;br /&gt;
* Calls m_scene.IncomingAttechments() [sic -- typo in source] to add transferred SOGs.&lt;br /&gt;
* Note: typo IncomingAttechments() in Scene.cs line 2976 and AttachmentsModule.cs (Mantis pending).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DeRezAttachments() ==&lt;br /&gt;
&lt;br /&gt;
Called on avatar departure (not crossing -- crossing uses CopyAttachments).&lt;br /&gt;
&lt;br /&gt;
* For each attachment: PrepareScriptInstanceForSave() then UpdateDetachedObject().&lt;br /&gt;
* For NPCs: UpdateDetachedObject() with empty script state.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Known Issues ==&lt;br /&gt;
&lt;br /&gt;
* IncomingAttechments() typo in Scene.cs line 2976 and AttachmentsModule.cs (Mantis pending).&lt;br /&gt;
* Comment in source notes that RegionCombiner module accesses SubscribeToClientEvents() and UnsubscribeFromClientEvents() directly, breaking module encapsulation. Marked as needing a fix.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AvatarFactoryModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Change Outfit]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>