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/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 ++++-
4 files changed, 167 insertions(+), 12 deletions(-)
(limited to 'OpenSim/Region/Environment/Scenes')
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++;
}
--
cgit v1.1