private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); sp.RemoveAttachment(so); UpdateDetachedObject(sp, so); }
// What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID) { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); if (itemID == UUID.Zero) // If this happened, someone made a mistake.... { return; } // We can NOT use the dictionries here, as we are looking // for an entity by the fromAssetID, which is NOT the prim UUID EntityBase[] detachEntities = m_scene.GetEntities(); SceneObjectGroup group; lock (sp.AttachmentsSyncLock) { foreach (EntityBase entity in detachEntities) { if (entity is SceneObjectGroup) { group = (SceneObjectGroup)entity; if (group.GetFromItemID() == itemID) { m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); sp.RemoveAttachment(group); // Prepare sog for storage group.AttachedAvatar = UUID.Zero; group.RootPart.SetParentLocalId(0); group.IsAttachment = false; group.AbsolutePosition = group.RootPart.AttachedPos; UpdateKnownItem(sp, group, true); m_scene.DeleteSceneObject(group, false); return; } } } } }
protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append) { if (m_invAccessModule == null) return null; SceneObjectGroup objatt; if (itemID != UUID.Zero) objatt = m_invAccessModule.RezObject(sp.ControllingClient, itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); else objatt = m_invAccessModule.RezObject(sp.ControllingClient, null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); if (objatt == null) { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", itemID, sp.Name, attachmentPt); return null; } else if (itemID == UUID.Zero) { // We need to have a FromItemID for multiple attachments on a single attach point to appear. This is // true on Singularity 1.8.5 and quite possibly other viewers as well. As NPCs don't have an inventory // we will satisfy this requirement by inserting a random UUID. objatt.FromItemID = UUID.Random(); } if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Rezzed single object {0} with {1} prims for attachment to {2} on point {3} in {4}", objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; bool tainted = false; if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) tainted = true; // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal // course of events. If not, then it's probably not worth trying to recover the situation // since this is more likely to trigger further exceptions and confuse later debugging. If // exceptions can be thrown in expected error conditions (not NREs) then make this consistent // since other normal error conditions will simply return false instead. // This will throw if the attachment fails try { AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append); } catch (Exception e) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); // Make sure the object doesn't stick around and bail sp.RemoveAttachment(objatt); m_scene.DeleteSceneObject(objatt, false); return null; } if (tainted) objatt.HasGroupChanged = true; if (ThrottlePer100PrimsRezzed > 0) { int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed); if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}", throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); Thread.Sleep(throttleMs); } return objatt; }
public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) { if (so.AttachedAvatar != sp.UUID) { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}", so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName); return; } if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}", so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name); // Scripts MUST be snapshotted before the object is // removed from the scene because doing otherwise will // clobber the run flag // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from // scripts performing attachment operations at the same time. Getting object states stops the scripts. string scriptedState = PrepareScriptInstanceForSave(so, true); lock (sp.AttachmentsSyncLock) { // Save avatar attachment information // m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); bool changed = sp.Appearance.DetachAttachment(so.FromItemID); if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); sp.RemoveAttachment(so); UpdateDetachedObject(sp, so, scriptedState); } }
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId, Vector3 absolutePos, Quaternion absoluteRot) { if (!Enabled) return; if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", sp.UUID, soLocalId); SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); if (so == null) return; if (so.AttachedAvatar != sp.UUID) return; UUID inventoryID = so.FromItemID; // As per Linden spec, drop is disabled for temp attachs if (inventoryID == UUID.Zero) return; if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", so.Name, so.LocalId, inventoryID); lock (sp.AttachmentsSyncLock) { if (!m_scene.Permissions.CanRezObject( so.PrimCount, sp.UUID, sp.AbsolutePosition)) return; bool changed = false; if (inventoryID != UUID.Zero) changed = sp.Appearance.DetachAttachment(inventoryID); if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); sp.RemoveAttachment(so); so.FromItemID = UUID.Zero; SceneObjectPart rootPart = so.RootPart; so.AbsolutePosition = absolutePos; if (absoluteRot != Quaternion.Identity) { so.UpdateGroupRotationR(absoluteRot); } so.AttachedAvatar = UUID.Zero; rootPart.SetParentLocalId(0); so.ClearPartAttachmentData(); rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive); so.HasGroupChanged = true; so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint; rootPart.Rezzed = DateTime.Now; rootPart.RemFlag(PrimFlags.TemporaryOnRez); so.AttachToBackup(); m_scene.EventManager.TriggerParcelPrimCountTainted(); rootPart.ScheduleFullUpdate(); rootPart.ClearUndoState(); List<UUID> uuids = new List<UUID>(); uuids.Add(inventoryID); m_scene.InventoryService.DeleteItems(sp.UUID, uuids); sp.ControllingClient.SendRemoveInventoryItem(inventoryID); } m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); }
private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface <IInventoryAccessModule>(); if (invAccess != null) { lock (sp.AttachmentsSyncLock) { SceneObjectGroup objatt; if (itemID != UUID.Zero) { objatt = invAccess.RezObject(sp.ControllingClient, itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); } else { objatt = invAccess.RezObject(sp.ControllingClient, null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); } // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", // objatt.Name, remoteClient.Name, AttachmentPt); if (objatt != null) { // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; bool tainted = false; if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) { tainted = true; } // This will throw if the attachment fails try { AttachObject(sp, objatt, attachmentPt, false); } catch (Exception e) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); // Make sure the object doesn't stick around and bail sp.RemoveAttachment(objatt); m_scene.DeleteSceneObject(objatt, false); return(null); } if (tainted) { objatt.HasGroupChanged = true; } // Fire after attach, so we don't get messy perms dialogs // 4 == AttachedRez objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); objatt.ResumeScripts(); // Do this last so that event listeners have access to all the effects of the attachment m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); return(objatt); } else { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", itemID, sp.Name, attachmentPt); } } } return(null); }
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) { if (!Enabled) { return; } // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", // sp.UUID, soLocalId); SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); if (so == null) { return; } if (so.AttachedAvatar != sp.UUID) { return; } UUID inventoryID = so.GetFromItemID(); // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", // so.Name, so.LocalId, inventoryID); lock (sp.AttachmentsSyncLock) { if (!m_scene.Permissions.CanRezObject( so.PrimCount, sp.UUID, sp.AbsolutePosition)) { return; } bool changed = sp.Appearance.DetachAttachment(inventoryID); if (changed && m_scene.AvatarFactory != null) { m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); } sp.RemoveAttachment(so); SceneObjectPart rootPart = so.RootPart; rootPart.FromItemID = UUID.Zero; so.AbsolutePosition = sp.AbsolutePosition; so.AttachedAvatar = UUID.Zero; rootPart.SetParentLocalId(0); so.ClearPartAttachmentData(); rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive); so.HasGroupChanged = true; rootPart.Rezzed = DateTime.Now; rootPart.RemFlag(PrimFlags.TemporaryOnRez); so.AttachToBackup(); m_scene.EventManager.TriggerParcelPrimCountTainted(); rootPart.ScheduleFullUpdate(); rootPart.ClearUndoState(); List <UUID> uuids = new List <UUID>(); uuids.Add(inventoryID); m_scene.InventoryService.DeleteItems(sp.UUID, uuids); sp.ControllingClient.SendRemoveInventoryItem(inventoryID); } m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); }
private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) { if (m_invAccessModule == null) return null; lock (sp.AttachmentsSyncLock) { SceneObjectGroup objatt; if (itemID != UUID.Zero) objatt = m_invAccessModule.RezObject(sp.ControllingClient, itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); else objatt = m_invAccessModule.RezObject(sp.ControllingClient, null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); if (objatt != null) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", // objatt.Name, sp.Name, attachmentPt, m_scene.Name); // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; bool tainted = false; if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) tainted = true; // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal // course of events. If not, then it's probably not worth trying to recover the situation // since this is more likely to trigger further exceptions and confuse later debugging. If // exceptions can be thrown in expected error conditions (not NREs) then make this consistent // since other normal error conditions will simply return false instead. // This will throw if the attachment fails try { AttachObjectInternal(sp, objatt, attachmentPt, false, false); } catch (Exception e) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); // Make sure the object doesn't stick around and bail sp.RemoveAttachment(objatt); m_scene.DeleteSceneObject(objatt, false); return null; } if (tainted) objatt.HasGroupChanged = true; // Fire after attach, so we don't get messy perms dialogs // 4 == AttachedRez objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); objatt.ResumeScripts(); // Do this last so that event listeners have access to all the effects of the attachment m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); return objatt; } else { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", itemID, sp.Name, attachmentPt); } } return null; }
private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); if (invAccess != null) { lock (sp.AttachmentsSyncLock) { SceneObjectGroup objatt; if (itemID != UUID.Zero) objatt = invAccess.RezObject(sp.ControllingClient, itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); else objatt = invAccess.RezObject(sp.ControllingClient, null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", // objatt.Name, remoteClient.Name, AttachmentPt); if (objatt != null) { // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; bool tainted = false; if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) tainted = true; // This will throw if the attachment fails try { AttachObject(sp, objatt, attachmentPt, false); } catch (Exception e) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); // Make sure the object doesn't stick around and bail sp.RemoveAttachment(objatt); m_scene.DeleteSceneObject(objatt, false); return null; } if (tainted) objatt.HasGroupChanged = true; // Fire after attach, so we don't get messy perms dialogs // 4 == AttachedRez objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); objatt.ResumeScripts(); // Do this last so that event listeners have access to all the effects of the attachment m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); return objatt; } else { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", itemID, sp.Name, attachmentPt); } } } return null; }
// What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID) { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); if (itemID == UUID.Zero) // If this happened, someone made a mistake.... return; // We can NOT use the dictionries here, as we are looking // for an entity by the fromAssetID, which is NOT the prim UUID EntityBase[] detachEntities = m_scene.GetEntities(); SceneObjectGroup group; lock (sp.AttachmentsSyncLock) { foreach (EntityBase entity in detachEntities) { if (entity is SceneObjectGroup) { group = (SceneObjectGroup)entity; if (group.GetFromItemID() == itemID) { m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); sp.RemoveAttachment(group); // Prepare sog for storage group.AttachedAvatar = UUID.Zero; group.RootPart.SetParentLocalId(0); group.IsAttachment = false; group.AbsolutePosition = group.RootPart.AttachedPos; UpdateKnownItem(sp, group); m_scene.DeleteSceneObject(group, false); return; } } } } }
protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append) { if (m_invAccessModule == null) return null; SceneObjectGroup objatt; if (itemID != UUID.Zero) objatt = m_invAccessModule.RezObject(sp.ControllingClient, itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); else objatt = m_invAccessModule.RezObject(sp.ControllingClient, null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); if (objatt == null) { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", itemID, sp.Name, attachmentPt); return null; } if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", objatt.Name, sp.Name, attachmentPt, m_scene.Name); // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; bool tainted = false; if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) tainted = true; // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal // course of events. If not, then it's probably not worth trying to recover the situation // since this is more likely to trigger further exceptions and confuse later debugging. If // exceptions can be thrown in expected error conditions (not NREs) then make this consistent // since other normal error conditions will simply return false instead. // This will throw if the attachment fails try { AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append); } catch (Exception e) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); // Make sure the object doesn't stick around and bail sp.RemoveAttachment(objatt); m_scene.DeleteSceneObject(objatt, false); return null; } if (tainted) objatt.HasGroupChanged = true; return objatt; }
private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) { if (m_invAccessModule == null) { return(null); } lock (sp.AttachmentsSyncLock) { SceneObjectGroup objatt; if (itemID != UUID.Zero) { objatt = m_invAccessModule.RezObject(sp.ControllingClient, itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); } else { objatt = m_invAccessModule.RezObject(sp.ControllingClient, null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); } if (objatt != null) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", // objatt.Name, sp.Name, attachmentPt, m_scene.Name); // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; bool tainted = false; if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) { tainted = true; } // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal // course of events. If not, then it's probably not worth trying to recover the situation // since this is more likely to trigger further exceptions and confuse later debugging. If // exceptions can be thrown in expected error conditions (not NREs) then make this consistent // since other normal error conditions will simply return false instead. // This will throw if the attachment fails try { AttachObjectInternal(sp, objatt, attachmentPt, false, false); } catch (Exception e) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); // Make sure the object doesn't stick around and bail sp.RemoveAttachment(objatt); m_scene.DeleteSceneObject(objatt, false); return(null); } if (tainted) { objatt.HasGroupChanged = true; } // Fire after attach, so we don't get messy perms dialogs // 4 == AttachedRez objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); objatt.ResumeScripts(); // Do this last so that event listeners have access to all the effects of the attachment m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); return(objatt); } else { m_log.WarnFormat( "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", itemID, sp.Name, attachmentPt); } } return(null); }
private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); sp.RemoveAttachment(so); m_scene.DeleteSceneObject(so, false); // Prepare sog for storage so.AttachedAvatar = UUID.Zero; so.RootPart.SetParentLocalId(0); so.IsAttachment = false; so.AbsolutePosition = so.RootPart.AttachedPos; UpdateKnownItem(sp, so, true); }
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) { if (!Enabled) return; // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", // sp.UUID, soLocalId); SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); if (so == null) return; if (so.AttachedAvatar != sp.UUID) return; UUID inventoryID = so.GetFromItemID(); // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", // so.Name, so.LocalId, inventoryID); lock (sp.AttachmentsSyncLock) { if (!m_scene.Permissions.CanRezObject( so.PrimCount, sp.UUID, sp.AbsolutePosition)) return; bool changed = sp.Appearance.DetachAttachment(inventoryID); if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); sp.RemoveAttachment(so); SceneObjectPart rootPart = so.RootPart; rootPart.FromItemID = UUID.Zero; so.AbsolutePosition = sp.AbsolutePosition; so.AttachedAvatar = UUID.Zero; rootPart.SetParentLocalId(0); so.ClearPartAttachmentData(); rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive,false); so.HasGroupChanged = true; rootPart.Rezzed = DateTime.Now; rootPart.RemFlag(PrimFlags.TemporaryOnRez); so.AttachToBackup(); m_scene.EventManager.TriggerParcelPrimCountTainted(); rootPart.ScheduleFullUpdate(); rootPart.ClearUndoState(); List<UUID> uuids = new List<UUID>(); uuids.Add(inventoryID); m_scene.InventoryService.DeleteItems(sp.UUID, uuids); sp.ControllingClient.SendRemoveInventoryItem(inventoryID); } m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); }