/// <summary> /// Attach this scene object to the given avatar. /// </summary> /// <remarks> /// This isn't publicly available since attachments should always perform the corresponding inventory /// operation (to show the attach in user inventory and update the asset with positional information). /// </remarks> /// <param name="sp"></param> /// <param name="so"></param> /// <param name="attachmentpoint"></param> /// <param name="attachOffset"></param> /// <param name="silent"></param> private void AttachToAgent( IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) { if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); so.DetachFromBackup(); // Remove from database and parcel prim count m_scene.DeleteFromStorage(so.UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); so.AttachedAvatar = sp.UUID; if (so.RootPart.PhysActor != null) so.RootPart.RemoveFromPhysics(); so.AbsolutePosition = attachOffset; so.RootPart.AttachedPos = attachOffset; so.IsAttachment = true; so.RootPart.SetParentLocalId(sp.LocalId); so.AttachmentPoint = attachmentpoint; sp.AddAttachment(so); if (!silent) { if (so.HasPrivateAttachmentPoint) { if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", so.Name, sp.Name, so.AttachmentPoint); // As this scene object can now only be seen by the attaching avatar, tell everybody else in the // scene that it's no longer in their awareness. m_scene.ForEachClient( client => { if (client.AgentId != so.AttachedAvatar) client.SendKillObject(new List<uint>() { so.LocalId }); }); } // Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update // will succeed, as that will not update if an attachment is selected. so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(); } // In case it is later dropped again, don't let // it get cleaned up so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); }
/// <summary> /// Unlink the given object from the scene. Unlike delete, this just removes the record of the object - the /// object itself is not destroyed. /// </summary> /// <param name="so">The scene object.</param> /// <param name="softDelete">If true, only deletes from scene, but keeps the object in the database.</param> /// <returns>true if the object was in the scene, false if it was not</returns> public bool UnlinkSceneObject(SceneObjectGroup so, bool softDelete) { if (m_sceneGraph.DeleteSceneObject(so.UUID, softDelete)) { if (!softDelete) { // Force a database update so that the scene object group ID is accurate. It's possible that the // group has recently been delinked from another group but that this change has not been persisted // to the DB. // This is an expensive thing to do so only do it if absolutely necessary. if (so.HasGroupChangedDueToDelink) ForceSceneObjectBackup(so); so.DetachFromBackup(); SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID); } // We need to keep track of this state in case this group is still queued for further backup. so.IsDeleted = true; return true; } return false; }
/// <summary> /// Attach this scene object to the given avatar. /// </summary> /// <remarks> /// This isn't publicly available since attachments should always perform the corresponding inventory /// operation (to show the attach in user inventory and update the asset with positional information). /// </remarks> /// <param name="sp"></param> /// <param name="so"></param> /// <param name="attachmentpoint"></param> /// <param name="attachOffset"></param> /// <param name="silent"></param> private void AttachToAgent( IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", // so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); so.DetachFromBackup(); // Remove from database and parcel prim count m_scene.DeleteFromStorage(so.UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); so.AttachedAvatar = sp.UUID; if (so.RootPart.PhysActor != null) so.RootPart.RemoveFromPhysics(); so.AbsolutePosition = attachOffset; so.RootPart.AttachedPos = attachOffset; so.IsAttachment = true; so.RootPart.SetParentLocalId(sp.LocalId); so.AttachmentPoint = attachmentpoint; sp.AddAttachment(so); if (!silent) { // Killing it here will cause the client to deselect it // It then reappears on the avatar, deselected // through the full update below // if (so.IsSelected) { m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId }); } else if (so.HasPrivateAttachmentPoint) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", // so.Name, sp.Name, so.AttachmentPoint); // As this scene object can now only be seen by the attaching avatar, tell everybody else in the // scene that it's no longer in their awareness. m_scene.ForEachClient( client => { if (client.AgentId != so.AttachedAvatar) client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId }); }); } so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(); } // In case it is later dropped again, don't let // it get cleaned up so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); }
/// <summary> /// Attach this scene object to the given avatar. /// </summary> /// /// This isn't publicly available since attachments should always perform the corresponding inventory /// operation (to show the attach in user inventory and update the asset with positional information). /// /// <param name="sp"></param> /// <param name="so"></param> /// <param name="attachmentpoint"></param> /// <param name="AttachOffset"></param> /// <param name="silent"></param> protected void AttachToAgent(ScenePresence avatar, SceneObjectGroup so, int attachmentpoint, Vector3 AttachOffset, bool silent) { // don't attach attachments to child agents if (avatar.IsChildAgent) return; // m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1}", Name, avatar.Name); so.DetachFromBackup(); // Remove from database and parcel prim count m_scene.DeleteFromStorage(so.UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); so.RootPart.AttachedAvatar = avatar.UUID; //Anakin Lohner bug #3839 SceneObjectPart[] parts = so.Parts; for (int i = 0; i < parts.Length; i++) parts[i].AttachedAvatar = avatar.UUID; if (so.RootPart.PhysActor != null) { m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor); so.RootPart.PhysActor = null; } so.AbsolutePosition = AttachOffset; so.RootPart.AttachedPos = AttachOffset; so.RootPart.IsAttachment = true; so.RootPart.SetParentLocalId(avatar.LocalId); so.SetAttachmentPoint(Convert.ToByte(attachmentpoint)); avatar.AddAttachment(so); if (!silent) { // Killing it here will cause the client to deselect it // It then reappears on the avatar, deselected // through the full update below // if (so.IsSelected) { m_scene.SendKillObject(so.RootPart.LocalId); } so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(PrimUpdateFlags.FullUpdate); } // In case it is later dropped again, don't let // it get cleaned up so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); so.HasGroupChanged = false; }
/// <summary> /// Unlink the given object from the scene. Unlike delete, this just removes the record of the object - the /// object itself is not destroyed. /// </summary> /// <param name="so">The scene object.</param> /// <param name="softDelete">If true, only deletes from scene, but keeps the object in the database.</param> /// <returns>true if the object was in the scene, false if it was not</returns> public bool UnlinkSceneObject(SceneObjectGroup so, bool softDelete) { if (m_sceneGraph.DeleteSceneObject(so.UUID, softDelete)) { if (!softDelete) { // If the group contains prims whose SceneGroupID is incorrect then force a // database update, because RemoveObject() works by searching on the SceneGroupID. // This is an expensive thing to do so only do it if absolutely necessary. if (so.GroupContainsForeignPrims) ForceSceneObjectBackup(so); so.DetachFromBackup(); SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID); } // We need to keep track of this state in case this group is still queued for further backup. so.IsDeleted = true; return true; } return false; }
/// <summary> /// Internal method which actually does all the work for attaching an object. /// </summary> /// <returns>The object attached.</returns> /// <param name='sp'></param> /// <param name='group'>The object to attach.</param> /// <param name='attachmentPt'></param> /// <param name='silent'></param> /// <param name='addToInventory'>If true then add object to user inventory.</param> /// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param> private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool resumeScripts, bool append) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", // group.Name, group.LocalId, sp.Name, attachmentPt, silent); if (sp.GetAttachments().Contains(group)) { // m_log.WarnFormat( // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", // group.Name, group.LocalId, sp.Name, AttachmentPt); return false; } if (group.GetSittingAvatarsCount() != 0) { if (DebugLevel > 0) m_log.WarnFormat( "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); return false; } Vector3 attachPos = group.AbsolutePosition; // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should // be removed when that functionality is implemented in opensim attachmentPt &= 0x7f; // If the attachment point isn't the same as the one previously used // set it's offset position = 0 so that it appears on the attachment point // and not in a weird location somewhere unknown. if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint) { attachPos = Vector3.Zero; } // if the attachment point is the same as previous, make sure we get the saved // position info. if (attachmentPt != 0 && attachmentPt == group.RootPart.Shape.LastAttachPoint) { attachPos = group.RootPart.AttachedPos; } // AttachmentPt 0 means the client chose to 'wear' the attachment. if (attachmentPt == (uint)AttachmentPoint.Default) { // Check object for stored attachment point attachmentPt = group.AttachmentPoint; } // if we didn't find an attach point, look for where it was last attached if (attachmentPt == 0) { attachmentPt = (uint)group.RootPart.Shape.LastAttachPoint; attachPos = group.RootPart.AttachedPos; group.HasGroupChanged = true; } // if we still didn't find a suitable attachment point....... if (attachmentPt == 0) { // Stick it on left hand with Zero Offset from the attachment point. attachmentPt = (uint)AttachmentPoint.LeftHand; attachPos = Vector3.Zero; } List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); if (attachments.Contains(group)) { if (DebugLevel > 0) m_log.WarnFormat( "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", group.Name, group.LocalId, sp.Name, attachmentPt); return false; } // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones while (attachments.Count >= 5) { if (attachments[0].FromItemID != UUID.Zero) DetachSingleAttachmentToInv(sp, attachments[0]); attachments.RemoveAt(0); } // If we're not appending, remove the rest as well if (attachments.Count != 0 && !append) { foreach (SceneObjectGroup g in attachments) { if (g.FromItemID != UUID.Zero) DetachSingleAttachmentToInv(sp, g); } } group.DetachFromBackup(); lock (sp.AttachmentsSyncLock) { group.AttachmentPoint = attachmentPt; group.AbsolutePosition = attachPos; if (addToInventory && sp.PresenceType != PresenceType.Npc) UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append); AttachToAgent(sp, group, attachmentPt, attachPos, silent); if (resumeScripts) { // Fire after attach, so we don't get messy perms dialogs // 4 == AttachedRez group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); group.ResumeScripts(); } // Do this last so that event listeners have access to all the effects of the attachment m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); } return true; }
private SceneObjectGroup MakeDefaultPrim(string name) { PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere (); shape.Scale = new Vector3 (0.5f, 0.5f, 0.5f); SceneObjectGroup prim = new SceneObjectGroup (m_owner, new Vector3 (128f, 128f, 25f), shape); prim.Name = name; prim.DetachFromBackup (); m_scene.AddNewSceneObject (prim, false); return prim; }
/// <summary> /// Attach this scene object to the given avatar. /// </summary> /// <remarks> /// This isn't publicly available since attachments should always perform the corresponding inventory /// operation (to show the attach in user inventory and update the asset with positional information). /// </remarks> /// <param name="sp"></param> /// <param name="so"></param> /// <param name="attachmentpoint"></param> /// <param name="attachOffset"></param> /// <param name="silent"></param> private void AttachToAgent( IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); so.DetachFromBackup(); // Remove from database and parcel prim count m_scene.DeleteFromStorage(so.UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); so.AttachedAvatar = sp.UUID; if (so.RootPart.PhysActor != null) so.RootPart.RemoveFromPhysics(); so.AbsolutePosition = attachOffset; so.RootPart.AttachedPos = attachOffset; so.IsAttachment = true; so.RootPart.SetParentLocalId(sp.LocalId); so.AttachmentPoint = attachmentpoint; sp.AddAttachment(so); if (!silent) { // Killing it here will cause the client to deselect it // It then reappears on the avatar, deselected // through the full update below // if (so.IsSelected) { m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId }); } so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(); } // In case it is later dropped again, don't let // it get cleaned up so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); }
public bool AttachObject( IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool append) { if (!Enabled) return false; group.DetachFromBackup(); bool success = AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append); if (!success) group.AttachToBackup(); return success; }