/// <summary> /// Synchronously delete the given object from the scene. /// </summary> /// <param name="group">Object Id</param> /// <param name="silent">Suppress broadcasting changes to other clients.</param> /// <param name="removeScripts">If true, then scripts are removed. If false, then they are only stopped.</para> public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts) { // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); if (removeScripts) group.RemoveScriptInstances(true); else group.StopScriptInstances(); List<ScenePresence> avatars = group.GetSittingAvatars(); foreach (ScenePresence av in avatars) { if(av.ParentUUID == UUID.Zero) av.StandUp(); } SceneObjectPart[] partList = group.Parts; foreach (SceneObjectPart part in partList) { if (part.KeyframeMotion != null) { part.KeyframeMotion.Delete(); part.KeyframeMotion = null; } if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) { PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? } else if (part.PhysActor != null) { part.RemoveFromPhysics(); } } if (UnlinkSceneObject(group, false)) { EventManager.TriggerObjectBeingRemovedFromScene(group); EventManager.TriggerParcelPrimCountTainted(); } group.DeleteGroupFromScene(silent); // use this to mean also full delete if (removeScripts) group.Clear(); partList = null; // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); }
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 this didn't come from inventory, it also shouldn't go there // on detach. It's likely a temp attachment. if (so.FromItemID == UUID.Zero) { // Retirn value is ignored PrepareScriptInstanceForSave(so, true); lock (sp.AttachmentsSyncLock) { bool changed = sp.Appearance.DetachAttachment(so.FromItemID); if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); sp.RemoveAttachment(so); } m_scene.DeleteSceneObject(so, false, false); so.RemoveScriptInstances(true); so.Clear(); 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 SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val) { Scene sogScene = sog.m_scene; IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface<IEntityTransferModule>(); Vector3 newpos = Vector3.Zero; OpenSim.Services.Interfaces.GridRegion destination = null; if (sog.RootPart.DIE_AT_EDGE) { try { sogScene.DeleteSceneObject(sog, false); } catch (Exception) { m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border."); } return sog; } if (sog.RootPart.RETURN_AT_EDGE) { // We remove the object here try { List<uint> localIDs = new List<uint>(); localIDs.Add(sog.RootPart.LocalId); sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition, "Returned at region cross"); sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero); } catch (Exception) { m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border."); } return sog; } if (sog.m_rootPart.KeyframeMotion != null) sog.m_rootPart.KeyframeMotion.StartCrossingCheck(); if (entityTransfer == null) return sog; destination = entityTransfer.GetObjectDestination(sog, val, out newpos); if (destination == null) return sog; if (sog.m_sittingAvatars.Count == 0) { entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, true); return sog; } string reason = String.Empty; EntityTransferContext ctx = new EntityTransferContext(); foreach (ScenePresence av in sog.m_sittingAvatars) { // We need to cross these agents. First, let's find // out if any of them can't cross for some reason. // We have to deny the crossing entirely if any // of them are banned. Alternatively, we could // unsit banned agents.... // We set the avatar position as being the object // position to get the region to send to if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, ctx, out reason)) { return sog; } m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); } // We unparent the SP quietly so that it won't // be made to stand up List<avtocrossInfo> avsToCross = new List<avtocrossInfo>(); foreach (ScenePresence av in sog.m_sittingAvatars) { byte cflags = 1; avtocrossInfo avinfo = new avtocrossInfo(); SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID); if (parentPart != null) { av.ParentUUID = parentPart.UUID; if(parentPart.SitTargetAvatar == av.UUID) cflags = 7; // low 3 bits set else cflags = 3; } // 1 is crossing // 2 is sitting // 4 is sitting at sittarget av.crossingFlags = cflags; avinfo.av = av; avinfo.ParentID = av.ParentID; avsToCross.Add(avinfo); av.PrevSitOffset = av.OffsetPosition; av.ParentID = 0; } if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, false)) { foreach (avtocrossInfo avinfo in avsToCross) { ScenePresence av = avinfo.av; if (!av.IsInTransit) // just in case... { m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val); av.IsInTransit = true; // CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync; // d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d); entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, av.Flying, ctx); if (av.IsChildAgent) { // avatar crossed do some extra cleanup if (av.ParentUUID != UUID.Zero) { av.ClearControls(); av.ParentPart = null; } } else { // avatar cross failed we need do dedicated standUp // part of it was done at CrossAgentToNewRegionAsync // so for now just remove the sog controls // this may need extra care av.UnRegisterSeatControls(sog.UUID); } av.ParentUUID = UUID.Zero; // In any case av.IsInTransit = false; av.crossingFlags = 0; m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname); } else m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar already in transit {0} to {1}", av.Name, val); } avsToCross.Clear(); sog.RemoveScriptInstances(true); sog.Clear(); return sog; } else // cross failed, put avas back ?? { foreach (avtocrossInfo avinfo in avsToCross) { ScenePresence av = avinfo.av; av.ParentUUID = UUID.Zero; av.ParentID = avinfo.ParentID; av.crossingFlags = 0; } } avsToCross.Clear(); return sog; }
private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState) { // Don't save attachments for HG visitors, it // messes up their inventory. When a HG visitor logs // out on a foreign grid, their attachments will be // reloaded in the state they were in when they left // the home grid. This is best anyway as the visited // grid may use an incompatible script engine. bool saveChanged = sp.PresenceType != PresenceType.Npc && (m_scene.UserManagementModule == null || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); // Remove the object from the scene so no more updates // are sent. Doing this before the below changes will ensure // updates can't cause "HUD artefacts" m_scene.DeleteSceneObject(so, false, false); // Prepare sog for storage so.AttachedAvatar = UUID.Zero; so.RootPart.SetParentLocalId(0); so.IsAttachment = false; if (saveChanged) { // We cannot use AbsolutePosition here because that would // attempt to cross the prim as it is detached so.ForEachPart(x => { x.GroupPosition = so.RootPart.AttachedPos; }); UpdateKnownItem(sp, so, scriptedState); } // Now, remove the scripts so.RemoveScriptInstances(true); so.Clear(); }