Thank you, dslake, for a patch that converts many of the linear searches

in SceneGraph to fast dictionary lookups.
Includes a regression fix for attachments by myself.
Fixes Mantis #3312
0.6.5-rc1
Melanie Thielker 2009-04-12 15:18:04 +00:00
parent 87ce5ea0eb
commit cc86df4a3f
2 changed files with 204 additions and 263 deletions

View File

@ -233,12 +233,6 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_defaultScriptEngine; } get { return m_defaultScriptEngine; }
} }
// Local reference to the objects in the scene (which are held in the scenegraph)
// public Dictionary<UUID, SceneObjectGroup> Objects
// {
// get { return m_sceneGraph.SceneObjects; }
// }
// Reference to all of the agents in the scene (root and child) // Reference to all of the agents in the scene (root and child)
protected Dictionary<UUID, ScenePresence> m_scenePresences protected Dictionary<UUID, ScenePresence> m_scenePresences
{ {
@ -246,12 +240,6 @@ namespace OpenSim.Region.Framework.Scenes
set { m_sceneGraph.ScenePresences = value; } set { m_sceneGraph.ScenePresences = value; }
} }
// protected Dictionary<UUID, SceneObjectGroup> m_sceneObjects
// {
// get { return m_sceneGraph.SceneObjects; }
// set { m_sceneGraph.SceneObjects = value; }
// }
public EntityManager Entities public EntityManager Entities
{ {
get { return m_sceneGraph.Entities; } get { return m_sceneGraph.Entities; }
@ -3492,7 +3480,6 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void jointMoved(PhysicsJoint joint) protected internal void jointMoved(PhysicsJoint joint)
{ {
// m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked
// FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
if (jointProxyObject == null) if (jointProxyObject == null)
{ {
@ -3555,7 +3542,6 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void jointDeactivated(PhysicsJoint joint) protected internal void jointDeactivated(PhysicsJoint joint)
{ {
//m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene); //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene);
// FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
if (jointProxyObject == null) if (jointProxyObject == null)
{ {
@ -3580,7 +3566,6 @@ namespace OpenSim.Region.Framework.Scenes
// from within the OdePhysicsScene. // from within the OdePhysicsScene.
public void jointErrorMessage(PhysicsJoint joint, string message) public void jointErrorMessage(PhysicsJoint joint, string message)
{ {
// FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
if (joint != null) if (joint != null)
{ {
if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages) if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)

View File

@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes
protected RegionInfo m_regInfo; protected RegionInfo m_regInfo;
protected Scene m_parentScene; protected Scene m_parentScene;
protected List<EntityBase> m_updateList = new List<EntityBase>(); protected Dictionary<UUID, EntityBase> m_updateList = new Dictionary<UUID, EntityBase>();
protected int m_numRootAgents = 0; protected int m_numRootAgents = 0;
protected int m_numPrim = 0; protected int m_numPrim = 0;
protected int m_numChildAgents = 0; protected int m_numChildAgents = 0;
@ -90,6 +90,10 @@ namespace OpenSim.Region.Framework.Scenes
protected internal PhysicsScene _PhyScene; protected internal PhysicsScene _PhyScene;
protected internal Dictionary<uint, SceneObjectGroup> SceneObjectGroupsByLocalID = new Dictionary<uint, SceneObjectGroup>();
protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
private readonly Object m_dictionary_lock = new Object();
#endregion #endregion
protected internal SceneGraph(Scene parent, RegionInfo regInfo) protected internal SceneGraph(Scene parent, RegionInfo regInfo)
@ -126,6 +130,11 @@ namespace OpenSim.Region.Framework.Scenes
{ {
ScenePresences.Clear(); ScenePresences.Clear();
} }
lock (m_dictionary_lock)
{
SceneObjectGroupsByFullID.Clear();
SceneObjectGroupsByLocalID.Clear();
}
Entities.Clear(); Entities.Clear();
} }
@ -301,6 +310,17 @@ namespace OpenSim.Region.Framework.Scenes
if (OnObjectCreate != null) if (OnObjectCreate != null)
OnObjectCreate(sceneObject); OnObjectCreate(sceneObject);
lock (m_dictionary_lock)
{
SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject;
foreach (SceneObjectPart part in sceneObject.Children.Values)
{
SceneObjectGroupsByFullID[part.UUID] = sceneObject;
SceneObjectGroupsByLocalID[part.LocalId] = sceneObject;
}
}
return true; return true;
} }
} }
@ -329,6 +349,11 @@ namespace OpenSim.Region.Framework.Scenes
if (OnObjectRemove != null) if (OnObjectRemove != null)
OnObjectRemove(Entities[uuid]); OnObjectRemove(Entities[uuid]);
lock (m_dictionary_lock)
{
SceneObjectGroupsByFullID.Remove(uuid);
SceneObjectGroupsByLocalID.Remove(((SceneObjectGroup)Entities[uuid]).LocalId);
}
Entities.Remove(uuid); Entities.Remove(uuid);
//SceneObjectGroup part; //SceneObjectGroup part;
//((part.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) //((part.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
@ -349,10 +374,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
lock (m_updateList) lock (m_updateList)
{ {
if (!m_updateList.Contains(obj)) m_updateList[obj.UUID] = obj;
{
m_updateList.Add(obj);
}
} }
} }
@ -361,26 +383,28 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
protected internal void ProcessUpdates() protected internal void ProcessUpdates()
{ {
Dictionary<UUID, EntityBase> updates;
// Some updates add more updates to the updateList.
// Get the current list of updates and clear the list before iterating
lock (m_updateList) lock (m_updateList)
{ {
for (int i = 0; i < m_updateList.Count; i++) updates = new Dictionary<UUID, EntityBase>(m_updateList);
{
EntityBase entity = m_updateList[i];
// Don't abort the whole update if one entity happens to give us an exception.
try
{
m_updateList[i].Update();
}
catch (Exception e)
{
m_log.ErrorFormat(
"[INNER SCENE]: Failed to update {0}, {1} - {2}", entity.Name, entity.UUID, e);
}
}
m_updateList.Clear(); m_updateList.Clear();
} }
// Go through all timers
foreach (KeyValuePair<UUID, EntityBase> kvp in updates)
{
// Don't abort the whole update if one entity happens to give us an exception.
try
{
kvp.Value.Update();
}
catch (Exception e)
{
m_log.ErrorFormat(
"[INNER SCENE]: Failed to update {0}, {1} - {2}", kvp.Value.Name, kvp.Value.UUID, e);
}
}
} }
protected internal void AddPhysicalPrim(int number) protected internal void AddPhysicalPrim(int number)
@ -405,38 +429,20 @@ namespace OpenSim.Region.Framework.Scenes
public void DropObject(uint objectLocalID, IClientAPI remoteClient) public void DropObject(uint objectLocalID, IClientAPI remoteClient)
{ {
List<EntityBase> EntityList = GetEntities(); SceneObjectGroup group = GetGroupByPrim(objectLocalID);
if (group != null)
foreach (EntityBase obj in EntityList)
{ {
if (obj is SceneObjectGroup) m_parentScene.DetachSingleAttachmentToGround(group.UUID, remoteClient);
{
if (((SceneObjectGroup)obj).LocalId == objectLocalID)
{
SceneObjectGroup group = (SceneObjectGroup)obj;
m_parentScene.DetachSingleAttachmentToGround(group.UUID,remoteClient);
}
}
} }
} }
protected internal void DetachObject(uint objectLocalID, IClientAPI remoteClient) protected internal void DetachObject(uint objectLocalID, IClientAPI remoteClient)
{ {
List<EntityBase> EntityList = GetEntities(); SceneObjectGroup group = GetGroupByPrim(objectLocalID);
if( group != null )
foreach (EntityBase obj in EntityList)
{ {
if (obj is SceneObjectGroup) //group.DetachToGround();
{ m_parentScene.DetachSingleAttachmentToInv(group.GetFromAssetID(),remoteClient);
if (((SceneObjectGroup)obj).LocalId == objectLocalID)
{
SceneObjectGroup group = (SceneObjectGroup)obj;
//group.DetachToGround();
m_parentScene.DetachSingleAttachmentToInv(group.GetFromAssetID(),remoteClient);
}
}
} }
} }
@ -453,20 +459,11 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void HandleObjectGroupUpdate( protected internal void HandleObjectGroupUpdate(
IClientAPI remoteClient, UUID GroupID, uint objectLocalID, UUID Garbage) IClientAPI remoteClient, UUID GroupID, uint objectLocalID, UUID Garbage)
{ {
List<EntityBase> EntityList = GetEntities(); SceneObjectGroup group = GetGroupByPrim(objectLocalID);
if( group != null )
foreach (EntityBase obj in EntityList)
{ {
if (obj is SceneObjectGroup) if (group.OwnerID == remoteClient.AgentId)
{ group.SetGroup(GroupID, remoteClient);
if (((SceneObjectGroup)obj).LocalId == objectLocalID)
{
SceneObjectGroup group = (SceneObjectGroup)obj;
if (group.OwnerID == remoteClient.AgentId)
group.SetGroup(GroupID, remoteClient);
}
}
} }
} }
@ -527,19 +524,26 @@ namespace OpenSim.Region.Framework.Scenes
if (itemID == UUID.Zero) // If this happened, someone made a mistake.... if (itemID == UUID.Zero) // If this happened, someone made a mistake....
return; return;
List<EntityBase> EntityList = GetEntities(); // We can NOT use the dictionries here, as we are looking
// for an entity by the fromAssetID, which is NOT the prim UUID
//
List<EntityBase> detachEntities = GetEntities();
SceneObjectGroup group;
foreach (EntityBase obj in EntityList) foreach (EntityBase entity in detachEntities)
{ {
if (obj is SceneObjectGroup) if (entity is SceneObjectGroup)
{ {
if (((SceneObjectGroup)obj).GetFromAssetID() == itemID) group = (SceneObjectGroup)entity;
if (group.GetFromAssetID() == itemID)
{ {
SceneObjectGroup group = (SceneObjectGroup)obj;
group.DetachToInventoryPrep(); group.DetachToInventoryPrep();
m_log.Debug("[DETACH]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); m_log.Debug("[DETACH]: Saving attachpoint: " +
m_parentScene.updateKnownAsset(remoteClient, group, group.GetFromAssetID(), group.OwnerID); ((uint)group.GetAttachmentPoint()).ToString());
m_parentScene.updateKnownAsset(remoteClient, group,
group.GetFromAssetID(), group.OwnerID);
m_parentScene.DeleteSceneObject(group, false); m_parentScene.DeleteSceneObject(group, false);
return;
} }
} }
} }
@ -548,73 +552,61 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void AttachObject( protected internal void AttachObject(
IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent) IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent)
{ {
List<EntityBase> EntityList = GetEntities(); SceneObjectGroup group = GetGroupByPrim(objectLocalID);
foreach (EntityBase obj in EntityList) if( group != null )
{ {
if (obj is SceneObjectGroup) if (m_parentScene.Permissions.CanTakeObject(group.UUID, remoteClient.AgentId))
{ {
if (((SceneObjectGroup)obj).LocalId == objectLocalID) // 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 != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
{ {
SceneObjectGroup group = (SceneObjectGroup)obj; attachPos = Vector3.Zero;
if (m_parentScene.Permissions.CanTakeObject(obj.UUID, remoteClient.AgentId))
{
// 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 != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
{
attachPos = Vector3.Zero;
}
// AttachmentPt 0 means the client chose to 'wear' the attachment.
if (AttachmentPt == 0)
{
// Check object for stored attachment point
AttachmentPt = (uint)group.GetAttachmentPoint();
}
// 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;
}
group.SetAttachmentPoint(Convert.ToByte(AttachmentPt));
group.AbsolutePosition = attachPos;
// Saves and gets assetID
UUID itemId;
if (group.GetFromAssetID() == UUID.Zero)
{
m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId);
}
else
{
itemId = group.GetFromAssetID();
}
m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group);
group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent);
// In case it is later dropped again, don't let
// it get cleaned up
//
group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
group.HasGroupChanged = false;
}
else
{
remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false);
}
} }
// AttachmentPt 0 means the client chose to 'wear' the attachment.
if (AttachmentPt == 0)
{
// Check object for stored attachment point
AttachmentPt = (uint)group.GetAttachmentPoint();
}
// 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;
}
group.SetAttachmentPoint(Convert.ToByte(AttachmentPt));
group.AbsolutePosition = attachPos;
// Saves and gets assetID
UUID itemId;
if (group.GetFromAssetID() == UUID.Zero)
{
m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId);
}
else
{
itemId = group.GetFromAssetID();
}
m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group);
group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent);
// In case it is later dropped again, don't let
// it get cleaned up
//
group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
group.HasGroupChanged = false;
}
else
{
remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false);
} }
} }
} }
@ -864,6 +856,15 @@ namespace OpenSim.Region.Framework.Scenes
return Entities[localID] as SceneObjectGroup; return Entities[localID] as SceneObjectGroup;
//m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID); //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID);
SceneObjectGroup sog;
lock (SceneObjectGroupsByLocalID)
{
if (SceneObjectGroupsByLocalID.TryGetValue(localID, out sog))
{
return sog;
}
}
List<EntityBase> EntityList = GetEntities(); List<EntityBase> EntityList = GetEntities();
foreach (EntityBase ent in EntityList) foreach (EntityBase ent in EntityList)
{ {
@ -871,7 +872,14 @@ namespace OpenSim.Region.Framework.Scenes
if (ent is SceneObjectGroup) if (ent is SceneObjectGroup)
{ {
if (((SceneObjectGroup)ent).HasChildPrim(localID)) if (((SceneObjectGroup)ent).HasChildPrim(localID))
return (SceneObjectGroup)ent; {
sog = (SceneObjectGroup)ent;
lock (SceneObjectGroupsByLocalID)
{
SceneObjectGroupsByLocalID[localID] = sog;
}
return sog;
}
} }
} }
return null; return null;
@ -884,6 +892,15 @@ namespace OpenSim.Region.Framework.Scenes
/// <returns>null if no scene object group containing that prim is found</returns> /// <returns>null if no scene object group containing that prim is found</returns>
private SceneObjectGroup GetGroupByPrim(UUID fullID) private SceneObjectGroup GetGroupByPrim(UUID fullID)
{ {
SceneObjectGroup sog;
lock (SceneObjectGroupsByFullID)
{
if (SceneObjectGroupsByFullID.TryGetValue(fullID, out sog))
{
return sog;
}
}
List<EntityBase> EntityList = GetEntities(); List<EntityBase> EntityList = GetEntities();
foreach (EntityBase ent in EntityList) foreach (EntityBase ent in EntityList)
@ -891,7 +908,14 @@ namespace OpenSim.Region.Framework.Scenes
if (ent is SceneObjectGroup) if (ent is SceneObjectGroup)
{ {
if (((SceneObjectGroup)ent).HasChildPrim(fullID)) if (((SceneObjectGroup)ent).HasChildPrim(fullID))
return (SceneObjectGroup)ent; {
sog = (SceneObjectGroup)ent;
lock (SceneObjectGroupsByFullID)
{
SceneObjectGroupsByFullID[fullID] = sog;
}
return sog;
}
} }
} }
return null; return null;
@ -930,11 +954,9 @@ namespace OpenSim.Region.Framework.Scenes
protected internal SceneObjectPart GetSceneObjectPart(uint localID) protected internal SceneObjectPart GetSceneObjectPart(uint localID)
{ {
SceneObjectGroup group = GetGroupByPrim(localID); SceneObjectGroup group = GetGroupByPrim(localID);
if (group == null)
if (group != null)
return group.GetChildPart(localID);
else
return null; return null;
return group.GetChildPart(localID);
} }
/// <summary> /// <summary>
@ -972,11 +994,9 @@ namespace OpenSim.Region.Framework.Scenes
protected internal SceneObjectPart GetSceneObjectPart(UUID fullID) protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
{ {
SceneObjectGroup group = GetGroupByPrim(fullID); SceneObjectGroup group = GetGroupByPrim(fullID);
if (group == null)
if (group != null)
return group.GetChildPart(fullID);
else
return null; return null;
return group.GetChildPart(fullID);
} }
protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
@ -1503,43 +1523,25 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="parentPrim"></param> /// <param name="parentPrim"></param>
/// <param name="childPrims"></param> /// <param name="childPrims"></param>
protected internal void LinkObjects(IClientAPI client, uint parentPrim, List<uint> childPrims) protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
{ {
List<EntityBase> EntityList = GetEntities(); SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId);
SceneObjectGroup parenPrim = null; List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
foreach (EntityBase ent in EntityList) if (parentGroup != null)
{
if (ent is SceneObjectGroup)
{
if (((SceneObjectGroup)ent).LocalId == parentPrim)
{
parenPrim = (SceneObjectGroup)ent;
break;
}
}
}
List<SceneObjectGroup> children = new List<SceneObjectGroup>();
if (parenPrim != null)
{ {
// We do this in reverse to get the link order of the prims correct // We do this in reverse to get the link order of the prims correct
for (int i = childPrims.Count - 1; i >= 0; i--) for (int i = childPrimIds.Count - 1; i >= 0; i--)
{ {
foreach (EntityBase ent in EntityList) SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]);
if( child != null )
{ {
if (ent is SceneObjectGroup) // Make sure no child prim is set for sale
{ // So that, on delink, no prims are unwittingly
if (((SceneObjectGroup)ent).LocalId == childPrims[i]) // left for sale and sold off
{ child.RootPart.ObjectSaleType = 0;
// Make sure no child prim is set for sale child.RootPart.SalePrice = 10;
// So that, on delink, no prims are unwittingly childGroups.Add(child);
// left for sale and sold off
((SceneObjectGroup)ent).RootPart.ObjectSaleType = 0;
((SceneObjectGroup)ent).RootPart.SalePrice = 10;
children.Add((SceneObjectGroup)ent);
}
}
} }
} }
} }
@ -1548,29 +1550,29 @@ namespace OpenSim.Region.Framework.Scenes
return; // parent is null so not in this region return; // parent is null so not in this region
} }
foreach (SceneObjectGroup sceneObj in children) foreach (SceneObjectGroup child in childGroups)
{ {
parenPrim.LinkToGroup(sceneObj); parentGroup.LinkToGroup(child);
// this is here so physics gets updated! // this is here so physics gets updated!
// Don't remove! Bad juju! Stay away! or fix physics! // Don't remove! Bad juju! Stay away! or fix physics!
sceneObj.AbsolutePosition = sceneObj.AbsolutePosition; child.AbsolutePosition = child.AbsolutePosition;
} }
// We need to explicitly resend the newly link prim's object properties since no other actions // We need to explicitly resend the newly link prim's object properties since no other actions
// occur on link to invoke this elsewhere (such as object selection) // occur on link to invoke this elsewhere (such as object selection)
parenPrim.RootPart.AddFlag(PrimFlags.CreateSelected); parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected);
parenPrim.TriggerScriptChangedEvent(Changed.LINK); parentGroup.TriggerScriptChangedEvent(Changed.LINK);
if (client != null) if (client != null)
{ {
parenPrim.GetProperties(client); parentGroup.GetProperties(client);
} }
else else
{ {
foreach (ScenePresence p in GetScenePresences()) foreach (ScenePresence p in GetScenePresences())
{ {
parenPrim.GetProperties(p.ControllingClient); parentGroup.GetProperties(p.ControllingClient);
} }
} }
} }
@ -1586,58 +1588,34 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void DelinkObjects(List<uint> primIds, bool sendEvents) protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
{ {
SceneObjectGroup parenPrim = null; SceneObjectGroup parentPrim = 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<uint, SceneObjectGroup> sceneObjects = new Dictionary<uint, SceneObjectGroup>();
List<EntityBase> EntityList = GetEntities();
foreach (EntityBase ent in EntityList)
{
if (ent is SceneObjectGroup)
{
SceneObjectGroup obj = (SceneObjectGroup)ent;
// Nasty one. Can't unlink anything in the sim
// If a duplicate local ID sneaks in
// So, check it here!
//
if (!sceneObjects.ContainsKey(obj.LocalId))
sceneObjects.Add(obj.LocalId, obj);
}
}
// Find the root prim among the prim ids we've been given // Find the root prim among the prim ids we've been given
for (int i = 0; i < primIds.Count; i++) for (int i = 0; i < primIds.Count; i++)
{ {
// Get the group for this prim and check that it is the parent
if (sceneObjects.ContainsKey(primIds[i])) parentPrim = GetGroupByPrim(primIds[i]);
if (parentPrim != null && parentPrim.LocalId == primIds[i])
{ {
parenPrim = sceneObjects[primIds[i]];
primIds.RemoveAt(i); primIds.RemoveAt(i);
break; break;
} }
} }
if (parenPrim != null) if (parentPrim != null)
{ {
foreach (uint childPrimId in primIds) foreach (uint childPrimId in primIds)
{ {
parenPrim.DelinkFromGroup(childPrimId, sendEvents); parentPrim.DelinkFromGroup(childPrimId, sendEvents);
} }
if (parenPrim.Children.Count == 1) if (parentPrim.Children.Count == 1)
{ {
// The link set has been completely torn down // The link set has been completely torn down
// This is the case if you select a link set and delink // This is the case if you select a link set and delink
// //
parenPrim.RootPart.LinkNum = 0; parentPrim.RootPart.LinkNum = 0;
if (sendEvents) if (sendEvents)
parenPrim.TriggerScriptChangedEvent(Changed.LINK); parentPrim.TriggerScriptChangedEvent(Changed.LINK);
} }
else else
{ {
@ -1645,7 +1623,7 @@ namespace OpenSim.Region.Framework.Scenes
// when a subset of a link set's prims are selected // when a subset of a link set's prims are selected
// and the root prim is part of that selection // and the root prim is part of that selection
// //
List<SceneObjectPart> parts = new List<SceneObjectPart>(parenPrim.Children.Values); List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
List<uint> unlink_ids = new List<uint>(); List<uint> unlink_ids = new List<uint>();
foreach (SceneObjectPart unlink_part in parts) foreach (SceneObjectPart unlink_part in parts)
@ -1662,9 +1640,9 @@ namespace OpenSim.Region.Framework.Scenes
DelinkObjects(unlink_ids, false); DelinkObjects(unlink_ids, false);
// Send event to root prim, then we're done with it // Send event to root prim, then we're done with it
parenPrim.TriggerScriptChangedEvent(Changed.LINK); parentPrim.TriggerScriptChangedEvent(Changed.LINK);
unlink_ids.Remove(parenPrim.RootPart.LocalId); unlink_ids.Remove(parentPrim.RootPart.LocalId);
foreach (uint localId in unlink_ids) foreach (uint localId in unlink_ids)
{ {
@ -1683,7 +1661,7 @@ namespace OpenSim.Region.Framework.Scenes
// The selected prims were all child prims. Edit linked parts // The selected prims were all child prims. Edit linked parts
// without the root prim selected will get us here // without the root prim selected will get us here
// //
List<SceneObjectGroup> parents = new List<SceneObjectGroup>(); List<SceneObjectGroup> parentGroups = new List<SceneObjectGroup>();
// If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow // If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow
// We know that this is not the root prim now essentially, so we don't have to worry about remapping // We know that this is not the root prim now essentially, so we don't have to worry about remapping
@ -1691,18 +1669,11 @@ namespace OpenSim.Region.Framework.Scenes
bool delinkedSomething = false; bool delinkedSomething = false;
for (int i = 0; i < primIds.Count; i++) for (int i = 0; i < primIds.Count; i++)
{ {
foreach (SceneObjectGroup grp in sceneObjects.Values) SceneObjectGroup parent = GetGroupByPrim(primIds[i]);
{ parent.DelinkFromGroup(primIds[i]);
SceneObjectPart gPart = grp.GetChildPart(primIds[i]); delinkedSomething = true;
if (gPart != null) if (!parentGroups.Contains(parent))
{ parentGroups.Add(parent);
grp.DelinkFromGroup(primIds[i]);
delinkedSomething = true;
if (!parents.Contains(grp))
parents.Add(grp);
}
}
} }
if (!delinkedSomething) if (!delinkedSomething)
{ {
@ -1712,7 +1683,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
foreach (SceneObjectGroup g in parents) foreach (SceneObjectGroup g in parentGroups)
{ {
g.TriggerScriptChangedEvent(Changed.LINK); g.TriggerScriptChangedEvent(Changed.LINK);
} }
@ -1790,30 +1761,15 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="originalPrim"></param> /// <param name="originalPrim"></param>
/// <param name="offset"></param> /// <param name="offset"></param>
/// <param name="flags"></param> /// <param name="flags"></param>
protected internal SceneObjectGroup DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) protected internal SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
{ {
//m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID); //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
SceneObjectGroup original = GetGroupByPrim(originalPrimID);
List<EntityBase> EntityList = GetEntities(); if (original != null)
SceneObjectGroup originPrim = null;
foreach (EntityBase ent in EntityList)
{ {
if (ent is SceneObjectGroup) if (m_parentScene.Permissions.CanDuplicateObject(original.Children.Count, original.UUID, AgentID, original.AbsolutePosition))
{ {
if (((SceneObjectGroup)ent).LocalId == originalPrim) SceneObjectGroup copy = original.Copy(AgentID, GroupID, true);
{
originPrim = (SceneObjectGroup)ent;
break;
}
}
}
if (originPrim != null)
{
if (m_parentScene.Permissions.CanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition))
{
SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID, true);
copy.AbsolutePosition = copy.AbsolutePosition + offset; copy.AbsolutePosition = copy.AbsolutePosition + offset;
Entities.Add(copy); Entities.Add(copy);
@ -1840,7 +1796,7 @@ namespace OpenSim.Region.Framework.Scenes
copy.AbsolutePosition = copy.AbsolutePosition; copy.AbsolutePosition = copy.AbsolutePosition;
if (OnObjectDuplicate != null) if (OnObjectDuplicate != null)
OnObjectDuplicate(originPrim, copy); OnObjectDuplicate(original, copy);
return copy; return copy;
} }