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