From eb41ec00c94170305fd764d5e0ad5bee04018551 Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Tue, 13 Nov 2007 19:57:11 +0000 Subject: first pass on unlinking of objects. From Jay Clarke (IBM) --- OpenSim/Region/ClientStack/ClientView.API.cs | 1 + .../ClientStack/ClientView.ProcessPackets.cs | 24 ++++- OpenSim/Region/Environment/Scenes/InnerScene.cs | 50 ++++++++++ OpenSim/Region/Environment/Scenes/Scene.cs | 3 +- .../Region/Environment/Scenes/SceneObjectGroup.cs | 105 +++++++++++++++++++-- OpenSim/Region/Environment/Scenes/ScenePresence.cs | 21 ++++- .../Region/Examples/SimpleApp/MyNpcCharacter.cs | 1 + 7 files changed, 191 insertions(+), 14 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/ClientView.API.cs b/OpenSim/Region/ClientStack/ClientView.API.cs index b18a844..b24b207 100644 --- a/OpenSim/Region/ClientStack/ClientView.API.cs +++ b/OpenSim/Region/ClientStack/ClientView.API.cs @@ -58,6 +58,7 @@ namespace OpenSim.Region.ClientStack public event StartAnim OnStartAnim; public event Action OnRequestAvatarsData; public event LinkObjects OnLinkObjects; + public event DelinkObjects OnDelinkObjects; public event UpdateVector OnGrabObject; public event ObjectSelect OnDeGrabObject; public event ObjectDuplicate OnObjectDuplicate; diff --git a/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs b/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs index f941d6c..82ad1c8 100644 --- a/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs +++ b/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs @@ -223,7 +223,7 @@ namespace OpenSim.Region.ClientStack #region Objects/m_sceneObjects case PacketType.ObjectLink: - // OpenSim.Framework.Console.MainLog.Instance.Verbose( Pack.ToString()); + //OpenSim.Framework.Console.MainLog.Instance.Verbose( Pack.ToString()); ObjectLinkPacket link = (ObjectLinkPacket) Pack; uint parentprimid = 0; List childrenprims = new List(); @@ -241,6 +241,26 @@ namespace OpenSim.Region.ClientStack OnLinkObjects(parentprimid, childrenprims); } break; + case PacketType.ObjectDelink: + //OpenSim.Framework.Console.MainLog.Instance.Verbose( Pack.ToString()); + ObjectDelinkPacket delink = (ObjectDelinkPacket) Pack; + + // It appears the prim at index 0 is not always the root prim (for + // instance, when one prim of a link set has been edited independently + // of the others). Therefore, we'll pass all the ids onto the delink + // method for it to decide which is the root. + List prims = new List(); + for (int i = 0; i < delink.ObjectData.Length; i++) + { + prims.Add(delink.ObjectData[i].ObjectLocalID); + } + + if (OnDelinkObjects != null) + { + OnDelinkObjects(prims); + } + + break; case PacketType.ObjectAdd: if (OnAddPrim != null) { @@ -775,4 +795,4 @@ namespace OpenSim.Region.ClientStack OutPacket(logReply); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/InnerScene.cs b/OpenSim/Region/Environment/Scenes/InnerScene.cs index 90478c6..c8e9b73 100644 --- a/OpenSim/Region/Environment/Scenes/InnerScene.cs +++ b/OpenSim/Region/Environment/Scenes/InnerScene.cs @@ -536,6 +536,56 @@ namespace OpenSim.Region.Environment.Scenes parenPrim.LinkToGroup(sceneObj); } } + + /// + /// Delink a linkset + /// + /// + public void DelinkObjects(List primIds) + { + //OpenSim.Framework.Console.MainLog.Instance.Verbose("DelinkObjects()"); + + SceneObjectGroup parenPrim = null; + + // Need a list of the SceneObjectGroup local ids + // XXX I'm anticipating that building this dictionary once is more efficient than + // repeated scanning of the Entity.Values for a large number of primIds. However, it might + // be more efficient yet to keep this dictionary permanently on hand. + Dictionary sceneObjects = new Dictionary(); + foreach (EntityBase ent in Entities.Values) + { + if (ent is SceneObjectGroup) + { + SceneObjectGroup obj = (SceneObjectGroup)ent; + sceneObjects.Add(obj.LocalId, obj); + } + } + + // Find the root prim among the prim ids we've been given + for (int i = 0; i < primIds.Count; i++) + { + if (sceneObjects.ContainsKey(primIds[i])) + { + parenPrim = sceneObjects[primIds[i]]; + primIds.RemoveAt(i); + break; + } + } + + if (parenPrim != null) + { + foreach (uint childPrimId in primIds) + { + parenPrim.DelinkFromGroup(childPrimId); + } + } + else + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( + "DelinkObjects(): Could not find a root prim out of {0} as given to a delink request!", + primIds); + } + } /// /// diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 2d58b0e..bf56fe8 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -705,6 +705,7 @@ namespace OpenSim.Region.Environment.Scenes client.OnObjectDescription += m_innerScene.PrimDescription; client.OnObjectName += m_innerScene.PrimName; client.OnLinkObjects += m_innerScene.LinkObjects; + client.OnDelinkObjects += m_innerScene.DelinkObjects; client.OnObjectDuplicate += m_innerScene.DuplicateObject; client.OnUpdatePrimFlags += m_innerScene.UpdatePrimFlags; @@ -1273,4 +1274,4 @@ namespace OpenSim.Region.Environment.Scenes #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index e2415b9..a9f0bb3 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -222,6 +222,27 @@ namespace OpenSim.Region.Environment.Scenes public SceneObjectGroup() { } + + /// + /// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart. + /// The original SceneObjectPart will be used rather than a copy, preserving + /// its existing localID and UUID. + /// + public SceneObjectGroup(Scene scene, ulong regionHandle, SceneObjectPart part) + { + m_scene = scene; + m_regionHandle = regionHandle; + + part.SetParent(this); + part.ParentID = 0; + + m_parts.Add(part.UUID, part); + SetPartAsRoot(part); + + AttachToBackup(); + + ScheduleGroupForFullUpdate(); + } /// /// @@ -594,10 +615,10 @@ namespace OpenSim.Region.Environment.Scenes #region SceneGroupPart Methods /// - /// + /// Get a child part with a given UUID /// /// - /// + /// null if a child part with the primID was not found public SceneObjectPart GetChildPart(LLUUID primID) { SceneObjectPart childPart = null; @@ -609,10 +630,10 @@ namespace OpenSim.Region.Environment.Scenes } /// - /// + /// Get a child part with a given local ID /// /// - /// + /// null if a child part with the local ID was not found public SceneObjectPart GetChildPart(uint localID) { foreach (SceneObjectPart part in m_parts.Values) @@ -717,13 +738,85 @@ namespace OpenSim.Region.Environment.Scenes objectGroup.DeleteParts(); ScheduleGroupForFullUpdate(); } + + /// + /// Delink the given prim from this group. The delinked prim is established as + /// an independent SceneObjectGroup. + /// + /// + public void DelinkFromGroup(uint partID) + { + SceneObjectPart linkPart = GetChildPart(partID); + + if (null != linkPart) + { + // Remove the part from this object + m_parts.Remove(linkPart.UUID); + + // We need to reset the child part's position + // ready for life as a separate object after being a part of another object + Quaternion parentRot + = new Quaternion( + m_rootPart.RotationOffset.W, + m_rootPart.RotationOffset.X, + m_rootPart.RotationOffset.Y, + m_rootPart.RotationOffset.Z); + + Vector3 axPos + = new Vector3( + linkPart.OffsetPosition.X, + linkPart.OffsetPosition.Y, + linkPart.OffsetPosition.Z); + + axPos = parentRot * axPos; + linkPart.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z); + linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; + linkPart.OffsetPosition = new LLVector3(0, 0, 0); + + Quaternion oldRot + = new Quaternion( + linkPart.RotationOffset.W, + linkPart.RotationOffset.X, + linkPart.RotationOffset.Y, + linkPart.RotationOffset.Z); + Quaternion newRot = parentRot * oldRot; + linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); + + // Add physics information back to delinked part if appropriate + // XXX This is messy and should be refactorable with the similar section in + // SceneObjectPart.UpdatePrimFlags() + if (m_rootPart.PhysActor != null) + { + linkPart.PhysActor = m_scene.PhysScene.AddPrimShape( + linkPart.Name, + linkPart.Shape, + new PhysicsVector(linkPart.AbsolutePosition.X, linkPart.AbsolutePosition.Y, + linkPart.AbsolutePosition.Z), + new PhysicsVector(linkPart.Scale.X, linkPart.Scale.Y, linkPart.Scale.Z), + new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X, + linkPart.RotationOffset.Y, linkPart.RotationOffset.Z), + m_rootPart.PhysActor.IsPhysical); + } + + SceneObjectGroup objectGroup = new SceneObjectGroup(m_scene, m_regionHandle, linkPart); + + m_scene.AddEntity(objectGroup); + + ScheduleGroupForFullUpdate(); + } + else + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( + "DelinkFromGroup(): Child prim local id {0} not found in object with root prim id {1}", + partID, LocalId); + } + } private void DetachFromBackup(SceneObjectGroup objectGroup) { m_scene.EventManager.OnBackup -= objectGroup.ProcessBackup; } - private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation) { part.SetParent(this); @@ -1431,4 +1524,4 @@ namespace OpenSim.Region.Environment.Scenes Text = text; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs index 20ec72e..c9c24fe 100644 --- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs @@ -328,17 +328,28 @@ namespace OpenSim.Region.Environment.Scenes if (m_updateTimes.ContainsKey(part.UUID)) { ScenePartUpdate update = m_updateTimes[part.UUID]; - if (update.LastFullUpdateTime < part.TimeStampFull) + + // Two updates can occur with the same timestamp (especially + // since our timestamp resolution is to the nearest second). The first + // could have been sent in the last update - we still need to send the + // second here. + if (update.LastFullUpdateTime <= part.TimeStampFull) { //need to do a full update part.SendFullUpdate(ControllingClient); - update.LastFullUpdateTime = (uint) Util.UnixTimeSinceEpoch(); + + // We'll update to the part's timestamp rather than the current to + // avoid the race condition whereby the next tick occurs while we are + // doing this update. If this happened, then subsequent updates which occurred + // on the same tick or the next tick of the last update would be ignored. + update.LastFullUpdateTime = part.TimeStampFull; + updateCount++; } - else if (update.LastTerseUpdateTime < part.TimeStampTerse) + else if (update.LastTerseUpdateTime <= part.TimeStampTerse) { part.SendTerseUpdate(ControllingClient); - update.LastTerseUpdateTime = (uint) Util.UnixTimeSinceEpoch(); + update.LastTerseUpdateTime = part.TimeStampTerse; updateCount++; } } @@ -348,7 +359,7 @@ namespace OpenSim.Region.Environment.Scenes part.SendFullUpdate(ControllingClient); ScenePartUpdate update = new ScenePartUpdate(); update.FullID = part.UUID; - update.LastFullUpdateTime = (uint) Util.UnixTimeSinceEpoch(); + update.LastFullUpdateTime = part.TimeStampFull; m_updateTimes.Add(part.UUID, update); updateCount++; } diff --git a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs index 0232b2d..86bb532 100644 --- a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs @@ -57,6 +57,7 @@ namespace SimpleApp public event SetAppearance OnSetAppearance; public event StartAnim OnStartAnim; public event LinkObjects OnLinkObjects; + public event DelinkObjects OnDelinkObjects; public event RequestMapBlocks OnRequestMapBlocks; public event TeleportLocationRequest OnTeleportLocationRequest; public event DisconnectUser OnDisconnectUser; -- cgit v1.1