aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMelanie Thielker2009-04-12 15:18:04 +0000
committerMelanie Thielker2009-04-12 15:18:04 +0000
commitcc86df4a3f61230c5487cadf8e93fc1e87a88574 (patch)
treecbd8ac36909d4ac6915162d7fe567bd89442ff29
parentActually do what I promised in the previous commit :/ (diff)
downloadopensim-SC-cc86df4a3f61230c5487cadf8e93fc1e87a88574.zip
opensim-SC-cc86df4a3f61230c5487cadf8e93fc1e87a88574.tar.gz
opensim-SC-cc86df4a3f61230c5487cadf8e93fc1e87a88574.tar.bz2
opensim-SC-cc86df4a3f61230c5487cadf8e93fc1e87a88574.tar.xz
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
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs15
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs438
2 files changed, 197 insertions, 256 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 54c420d..49b8bda 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -233,12 +233,6 @@ namespace OpenSim.Region.Framework.Scenes
233 get { return m_defaultScriptEngine; } 233 get { return m_defaultScriptEngine; }
234 } 234 }
235 235
236 // Local reference to the objects in the scene (which are held in the scenegraph)
237 // public Dictionary<UUID, SceneObjectGroup> Objects
238 // {
239 // get { return m_sceneGraph.SceneObjects; }
240 // }
241
242 // Reference to all of the agents in the scene (root and child) 236 // Reference to all of the agents in the scene (root and child)
243 protected Dictionary<UUID, ScenePresence> m_scenePresences 237 protected Dictionary<UUID, ScenePresence> m_scenePresences
244 { 238 {
@@ -246,12 +240,6 @@ namespace OpenSim.Region.Framework.Scenes
246 set { m_sceneGraph.ScenePresences = value; } 240 set { m_sceneGraph.ScenePresences = value; }
247 } 241 }
248 242
249 // protected Dictionary<UUID, SceneObjectGroup> m_sceneObjects
250 // {
251 // get { return m_sceneGraph.SceneObjects; }
252 // set { m_sceneGraph.SceneObjects = value; }
253 // }
254
255 public EntityManager Entities 243 public EntityManager Entities
256 { 244 {
257 get { return m_sceneGraph.Entities; } 245 get { return m_sceneGraph.Entities; }
@@ -3492,7 +3480,6 @@ namespace OpenSim.Region.Framework.Scenes
3492 protected internal void jointMoved(PhysicsJoint joint) 3480 protected internal void jointMoved(PhysicsJoint joint)
3493 { 3481 {
3494 // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked 3482 // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked
3495 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
3496 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); 3483 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
3497 if (jointProxyObject == null) 3484 if (jointProxyObject == null)
3498 { 3485 {
@@ -3555,7 +3542,6 @@ namespace OpenSim.Region.Framework.Scenes
3555 protected internal void jointDeactivated(PhysicsJoint joint) 3542 protected internal void jointDeactivated(PhysicsJoint joint)
3556 { 3543 {
3557 //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene); 3544 //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene);
3558 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
3559 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); 3545 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
3560 if (jointProxyObject == null) 3546 if (jointProxyObject == null)
3561 { 3547 {
@@ -3580,7 +3566,6 @@ namespace OpenSim.Region.Framework.Scenes
3580 // from within the OdePhysicsScene. 3566 // from within the OdePhysicsScene.
3581 public void jointErrorMessage(PhysicsJoint joint, string message) 3567 public void jointErrorMessage(PhysicsJoint joint, string message)
3582 { 3568 {
3583 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
3584 if (joint != null) 3569 if (joint != null)
3585 { 3570 {
3586 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages) 3571 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index e6328dc..4c3d00e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes
77 77
78 protected RegionInfo m_regInfo; 78 protected RegionInfo m_regInfo;
79 protected Scene m_parentScene; 79 protected Scene m_parentScene;
80 protected List<EntityBase> m_updateList = new List<EntityBase>(); 80 protected Dictionary<UUID, EntityBase> m_updateList = new Dictionary<UUID, EntityBase>();
81 protected int m_numRootAgents = 0; 81 protected int m_numRootAgents = 0;
82 protected int m_numPrim = 0; 82 protected int m_numPrim = 0;
83 protected int m_numChildAgents = 0; 83 protected int m_numChildAgents = 0;
@@ -90,6 +90,10 @@ namespace OpenSim.Region.Framework.Scenes
90 90
91 protected internal PhysicsScene _PhyScene; 91 protected internal PhysicsScene _PhyScene;
92 92
93 protected internal Dictionary<uint, SceneObjectGroup> SceneObjectGroupsByLocalID = new Dictionary<uint, SceneObjectGroup>();
94 protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
95 private readonly Object m_dictionary_lock = new Object();
96
93 #endregion 97 #endregion
94 98
95 protected internal SceneGraph(Scene parent, RegionInfo regInfo) 99 protected internal SceneGraph(Scene parent, RegionInfo regInfo)
@@ -126,6 +130,11 @@ namespace OpenSim.Region.Framework.Scenes
126 { 130 {
127 ScenePresences.Clear(); 131 ScenePresences.Clear();
128 } 132 }
133 lock (m_dictionary_lock)
134 {
135 SceneObjectGroupsByFullID.Clear();
136 SceneObjectGroupsByLocalID.Clear();
137 }
129 138
130 Entities.Clear(); 139 Entities.Clear();
131 } 140 }
@@ -300,6 +309,17 @@ namespace OpenSim.Region.Framework.Scenes
300 309
301 if (OnObjectCreate != null) 310 if (OnObjectCreate != null)
302 OnObjectCreate(sceneObject); 311 OnObjectCreate(sceneObject);
312
313 lock (m_dictionary_lock)
314 {
315 SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
316 SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject;
317 foreach (SceneObjectPart part in sceneObject.Children.Values)
318 {
319 SceneObjectGroupsByFullID[part.UUID] = sceneObject;
320 SceneObjectGroupsByLocalID[part.LocalId] = sceneObject;
321 }
322 }
303 323
304 return true; 324 return true;
305 } 325 }
@@ -329,6 +349,11 @@ namespace OpenSim.Region.Framework.Scenes
329 if (OnObjectRemove != null) 349 if (OnObjectRemove != null)
330 OnObjectRemove(Entities[uuid]); 350 OnObjectRemove(Entities[uuid]);
331 351
352 lock (m_dictionary_lock)
353 {
354 SceneObjectGroupsByFullID.Remove(uuid);
355 SceneObjectGroupsByLocalID.Remove(((SceneObjectGroup)Entities[uuid]).LocalId);
356 }
332 Entities.Remove(uuid); 357 Entities.Remove(uuid);
333 //SceneObjectGroup part; 358 //SceneObjectGroup part;
334 //((part.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) 359 //((part.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
@@ -349,10 +374,7 @@ namespace OpenSim.Region.Framework.Scenes
349 { 374 {
350 lock (m_updateList) 375 lock (m_updateList)
351 { 376 {
352 if (!m_updateList.Contains(obj)) 377 m_updateList[obj.UUID] = obj;
353 {
354 m_updateList.Add(obj);
355 }
356 } 378 }
357 } 379 }
358 380
@@ -361,25 +383,27 @@ namespace OpenSim.Region.Framework.Scenes
361 /// </summary> 383 /// </summary>
362 protected internal void ProcessUpdates() 384 protected internal void ProcessUpdates()
363 { 385 {
386 Dictionary<UUID, EntityBase> updates;
387 // Some updates add more updates to the updateList.
388 // Get the current list of updates and clear the list before iterating
364 lock (m_updateList) 389 lock (m_updateList)
365 { 390 {
366 for (int i = 0; i < m_updateList.Count; i++) 391 updates = new Dictionary<UUID, EntityBase>(m_updateList);
392 m_updateList.Clear();
393 }
394 // Go through all timers
395 foreach (KeyValuePair<UUID, EntityBase> kvp in updates)
396 {
397 // Don't abort the whole update if one entity happens to give us an exception.
398 try
367 { 399 {
368 EntityBase entity = m_updateList[i]; 400 kvp.Value.Update();
369 401 }
370 // Don't abort the whole update if one entity happens to give us an exception. 402 catch (Exception e)
371 try 403 {
372 { 404 m_log.ErrorFormat(
373 m_updateList[i].Update(); 405 "[INNER SCENE]: Failed to update {0}, {1} - {2}", kvp.Value.Name, kvp.Value.UUID, e);
374 }
375 catch (Exception e)
376 {
377 m_log.ErrorFormat(
378 "[INNER SCENE]: Failed to update {0}, {1} - {2}", entity.Name, entity.UUID, e);
379 }
380 } 406 }
381
382 m_updateList.Clear();
383 } 407 }
384 } 408 }
385 409
@@ -405,38 +429,20 @@ namespace OpenSim.Region.Framework.Scenes
405 429
406 public void DropObject(uint objectLocalID, IClientAPI remoteClient) 430 public void DropObject(uint objectLocalID, IClientAPI remoteClient)
407 { 431 {
408 List<EntityBase> EntityList = GetEntities(); 432 SceneObjectGroup group = GetGroupByPrim(objectLocalID);
409 433 if (group != null)
410 foreach (EntityBase obj in EntityList)
411 { 434 {
412 if (obj is SceneObjectGroup) 435 m_parentScene.DetachSingleAttachmentToGround(group.UUID, remoteClient);
413 {
414 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
415 {
416 SceneObjectGroup group = (SceneObjectGroup)obj;
417
418 m_parentScene.DetachSingleAttachmentToGround(group.UUID,remoteClient);
419 }
420 }
421 } 436 }
422 } 437 }
423 438
424 protected internal void DetachObject(uint objectLocalID, IClientAPI remoteClient) 439 protected internal void DetachObject(uint objectLocalID, IClientAPI remoteClient)
425 { 440 {
426 List<EntityBase> EntityList = GetEntities(); 441 SceneObjectGroup group = GetGroupByPrim(objectLocalID);
427 442 if( group != null )
428 foreach (EntityBase obj in EntityList)
429 { 443 {
430 if (obj is SceneObjectGroup) 444 //group.DetachToGround();
431 { 445 m_parentScene.DetachSingleAttachmentToInv(group.GetFromAssetID(),remoteClient);
432 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
433 {
434 SceneObjectGroup group = (SceneObjectGroup)obj;
435
436 //group.DetachToGround();
437 m_parentScene.DetachSingleAttachmentToInv(group.GetFromAssetID(),remoteClient);
438 }
439 }
440 } 446 }
441 } 447 }
442 448
@@ -453,20 +459,11 @@ namespace OpenSim.Region.Framework.Scenes
453 protected internal void HandleObjectGroupUpdate( 459 protected internal void HandleObjectGroupUpdate(
454 IClientAPI remoteClient, UUID GroupID, uint objectLocalID, UUID Garbage) 460 IClientAPI remoteClient, UUID GroupID, uint objectLocalID, UUID Garbage)
455 { 461 {
456 List<EntityBase> EntityList = GetEntities(); 462 SceneObjectGroup group = GetGroupByPrim(objectLocalID);
457 463 if( group != null )
458 foreach (EntityBase obj in EntityList)
459 { 464 {
460 if (obj is SceneObjectGroup) 465 if (group.OwnerID == remoteClient.AgentId)
461 { 466 group.SetGroup(GroupID, remoteClient);
462 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
463 {
464 SceneObjectGroup group = (SceneObjectGroup)obj;
465
466 if (group.OwnerID == remoteClient.AgentId)
467 group.SetGroup(GroupID, remoteClient);
468 }
469 }
470 } 467 }
471 } 468 }
472 469
@@ -527,19 +524,26 @@ namespace OpenSim.Region.Framework.Scenes
527 if (itemID == UUID.Zero) // If this happened, someone made a mistake.... 524 if (itemID == UUID.Zero) // If this happened, someone made a mistake....
528 return; 525 return;
529 526
530 List<EntityBase> EntityList = GetEntities(); 527 // We can NOT use the dictionries here, as we are looking
528 // for an entity by the fromAssetID, which is NOT the prim UUID
529 //
530 List<EntityBase> detachEntities = GetEntities();
531 SceneObjectGroup group;
531 532
532 foreach (EntityBase obj in EntityList) 533 foreach (EntityBase entity in detachEntities)
533 { 534 {
534 if (obj is SceneObjectGroup) 535 if (entity is SceneObjectGroup)
535 { 536 {
536 if (((SceneObjectGroup)obj).GetFromAssetID() == itemID) 537 group = (SceneObjectGroup)entity;
538 if (group.GetFromAssetID() == itemID)
537 { 539 {
538 SceneObjectGroup group = (SceneObjectGroup)obj;
539 group.DetachToInventoryPrep(); 540 group.DetachToInventoryPrep();
540 m_log.Debug("[DETACH]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 541 m_log.Debug("[DETACH]: Saving attachpoint: " +
541 m_parentScene.updateKnownAsset(remoteClient, group, group.GetFromAssetID(), group.OwnerID); 542 ((uint)group.GetAttachmentPoint()).ToString());
543 m_parentScene.updateKnownAsset(remoteClient, group,
544 group.GetFromAssetID(), group.OwnerID);
542 m_parentScene.DeleteSceneObject(group, false); 545 m_parentScene.DeleteSceneObject(group, false);
546 return;
543 } 547 }
544 } 548 }
545 } 549 }
@@ -548,73 +552,61 @@ namespace OpenSim.Region.Framework.Scenes
548 protected internal void AttachObject( 552 protected internal void AttachObject(
549 IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent) 553 IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent)
550 { 554 {
551 List<EntityBase> EntityList = GetEntities(); 555 SceneObjectGroup group = GetGroupByPrim(objectLocalID);
552 foreach (EntityBase obj in EntityList) 556 if( group != null )
553 { 557 {
554 if (obj is SceneObjectGroup) 558 if (m_parentScene.Permissions.CanTakeObject(group.UUID, remoteClient.AgentId))
555 { 559 {
556 if (((SceneObjectGroup)obj).LocalId == objectLocalID) 560 // If the attachment point isn't the same as the one previously used
561 // set it's offset position = 0 so that it appears on the attachment point
562 // and not in a weird location somewhere unknown.
563 if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
557 { 564 {
558 SceneObjectGroup group = (SceneObjectGroup)obj; 565 attachPos = Vector3.Zero;
559 if (m_parentScene.Permissions.CanTakeObject(obj.UUID, remoteClient.AgentId)) 566 }
560 {
561 // If the attachment point isn't the same as the one previously used
562 // set it's offset position = 0 so that it appears on the attachment point
563 // and not in a weird location somewhere unknown.
564 if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
565 {
566
567 attachPos = Vector3.Zero;
568 }
569
570 // AttachmentPt 0 means the client chose to 'wear' the attachment.
571 if (AttachmentPt == 0)
572 {
573
574 // Check object for stored attachment point
575 AttachmentPt = (uint)group.GetAttachmentPoint();
576
577 567
578 } 568 // AttachmentPt 0 means the client chose to 'wear' the attachment.
569 if (AttachmentPt == 0)
570 {
571 // Check object for stored attachment point
572 AttachmentPt = (uint)group.GetAttachmentPoint();
573 }
579 574
580 // if we still didn't find a suitable attachment point....... 575 // if we still didn't find a suitable attachment point.......
581 if (AttachmentPt == 0) 576 if (AttachmentPt == 0)
582 { 577 {
583 // Stick it on left hand with Zero Offset from the attachment point. 578 // Stick it on left hand with Zero Offset from the attachment point.
584 AttachmentPt = (uint)AttachmentPoint.LeftHand; 579 AttachmentPt = (uint)AttachmentPoint.LeftHand;
585 attachPos = Vector3.Zero; 580 attachPos = Vector3.Zero;
586 } 581 }
587 582
588 group.SetAttachmentPoint(Convert.ToByte(AttachmentPt)); 583 group.SetAttachmentPoint(Convert.ToByte(AttachmentPt));
589 group.AbsolutePosition = attachPos; 584 group.AbsolutePosition = attachPos;
590 585
591 // Saves and gets assetID 586 // Saves and gets assetID
592 UUID itemId; 587 UUID itemId;
593 588
594 if (group.GetFromAssetID() == UUID.Zero) 589 if (group.GetFromAssetID() == UUID.Zero)
595 { 590 {
596 m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId); 591 m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId);
597 } 592 }
598 else 593 else
599 { 594 {
600 itemId = group.GetFromAssetID(); 595 itemId = group.GetFromAssetID();
601 } 596 }
602
603 m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group);
604 597
605 group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent); 598 m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group);
606 // In case it is later dropped again, don't let
607 // it get cleaned up
608 //
609 group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
610 group.HasGroupChanged = false;
611 }
612 else
613 {
614 remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false);
615 }
616 599
617 } 600 group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent);
601 // In case it is later dropped again, don't let
602 // it get cleaned up
603 //
604 group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
605 group.HasGroupChanged = false;
606 }
607 else
608 {
609 remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false);
618 } 610 }
619 } 611 }
620 } 612 }
@@ -864,6 +856,15 @@ namespace OpenSim.Region.Framework.Scenes
864 return Entities[localID] as SceneObjectGroup; 856 return Entities[localID] as SceneObjectGroup;
865 857
866 //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID); 858 //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID);
859 SceneObjectGroup sog;
860 lock (SceneObjectGroupsByLocalID)
861 {
862 if (SceneObjectGroupsByLocalID.TryGetValue(localID, out sog))
863 {
864 return sog;
865 }
866 }
867
867 List<EntityBase> EntityList = GetEntities(); 868 List<EntityBase> EntityList = GetEntities();
868 foreach (EntityBase ent in EntityList) 869 foreach (EntityBase ent in EntityList)
869 { 870 {
@@ -871,7 +872,14 @@ namespace OpenSim.Region.Framework.Scenes
871 if (ent is SceneObjectGroup) 872 if (ent is SceneObjectGroup)
872 { 873 {
873 if (((SceneObjectGroup)ent).HasChildPrim(localID)) 874 if (((SceneObjectGroup)ent).HasChildPrim(localID))
874 return (SceneObjectGroup)ent; 875 {
876 sog = (SceneObjectGroup)ent;
877 lock (SceneObjectGroupsByLocalID)
878 {
879 SceneObjectGroupsByLocalID[localID] = sog;
880 }
881 return sog;
882 }
875 } 883 }
876 } 884 }
877 return null; 885 return null;
@@ -884,6 +892,15 @@ namespace OpenSim.Region.Framework.Scenes
884 /// <returns>null if no scene object group containing that prim is found</returns> 892 /// <returns>null if no scene object group containing that prim is found</returns>
885 private SceneObjectGroup GetGroupByPrim(UUID fullID) 893 private SceneObjectGroup GetGroupByPrim(UUID fullID)
886 { 894 {
895 SceneObjectGroup sog;
896 lock (SceneObjectGroupsByFullID)
897 {
898 if (SceneObjectGroupsByFullID.TryGetValue(fullID, out sog))
899 {
900 return sog;
901 }
902 }
903
887 List<EntityBase> EntityList = GetEntities(); 904 List<EntityBase> EntityList = GetEntities();
888 905
889 foreach (EntityBase ent in EntityList) 906 foreach (EntityBase ent in EntityList)
@@ -891,7 +908,14 @@ namespace OpenSim.Region.Framework.Scenes
891 if (ent is SceneObjectGroup) 908 if (ent is SceneObjectGroup)
892 { 909 {
893 if (((SceneObjectGroup)ent).HasChildPrim(fullID)) 910 if (((SceneObjectGroup)ent).HasChildPrim(fullID))
894 return (SceneObjectGroup)ent; 911 {
912 sog = (SceneObjectGroup)ent;
913 lock (SceneObjectGroupsByFullID)
914 {
915 SceneObjectGroupsByFullID[fullID] = sog;
916 }
917 return sog;
918 }
895 } 919 }
896 } 920 }
897 return null; 921 return null;
@@ -930,11 +954,9 @@ namespace OpenSim.Region.Framework.Scenes
930 protected internal SceneObjectPart GetSceneObjectPart(uint localID) 954 protected internal SceneObjectPart GetSceneObjectPart(uint localID)
931 { 955 {
932 SceneObjectGroup group = GetGroupByPrim(localID); 956 SceneObjectGroup group = GetGroupByPrim(localID);
933 957 if (group == null)
934 if (group != null)
935 return group.GetChildPart(localID);
936 else
937 return null; 958 return null;
959 return group.GetChildPart(localID);
938 } 960 }
939 961
940 /// <summary> 962 /// <summary>
@@ -972,11 +994,9 @@ namespace OpenSim.Region.Framework.Scenes
972 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID) 994 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
973 { 995 {
974 SceneObjectGroup group = GetGroupByPrim(fullID); 996 SceneObjectGroup group = GetGroupByPrim(fullID);
975 997 if (group == null)
976 if (group != null)
977 return group.GetChildPart(fullID);
978 else
979 return null; 998 return null;
999 return group.GetChildPart(fullID);
980 } 1000 }
981 1001
982 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) 1002 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
@@ -1503,43 +1523,25 @@ namespace OpenSim.Region.Framework.Scenes
1503 /// <param name="client"></param> 1523 /// <param name="client"></param>
1504 /// <param name="parentPrim"></param> 1524 /// <param name="parentPrim"></param>
1505 /// <param name="childPrims"></param> 1525 /// <param name="childPrims"></param>
1506 protected internal void LinkObjects(IClientAPI client, uint parentPrim, List<uint> childPrims) 1526 protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
1507 { 1527 {
1508 List<EntityBase> EntityList = GetEntities(); 1528 SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId);
1509
1510 SceneObjectGroup parenPrim = null;
1511 foreach (EntityBase ent in EntityList)
1512 {
1513 if (ent is SceneObjectGroup)
1514 {
1515 if (((SceneObjectGroup)ent).LocalId == parentPrim)
1516 {
1517 parenPrim = (SceneObjectGroup)ent;
1518 break;
1519 }
1520 }
1521 }
1522 1529
1523 List<SceneObjectGroup> children = new List<SceneObjectGroup>(); 1530 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1524 if (parenPrim != null) 1531 if (parentGroup != null)
1525 { 1532 {
1526 // We do this in reverse to get the link order of the prims correct 1533 // We do this in reverse to get the link order of the prims correct
1527 for (int i = childPrims.Count - 1; i >= 0; i--) 1534 for (int i = childPrimIds.Count - 1; i >= 0; i--)
1528 { 1535 {
1529 foreach (EntityBase ent in EntityList) 1536 SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]);
1537 if( child != null )
1530 { 1538 {
1531 if (ent is SceneObjectGroup) 1539 // Make sure no child prim is set for sale
1532 { 1540 // So that, on delink, no prims are unwittingly
1533 if (((SceneObjectGroup)ent).LocalId == childPrims[i]) 1541 // left for sale and sold off
1534 { 1542 child.RootPart.ObjectSaleType = 0;
1535 // Make sure no child prim is set for sale 1543 child.RootPart.SalePrice = 10;
1536 // So that, on delink, no prims are unwittingly 1544 childGroups.Add(child);
1537 // left for sale and sold off
1538 ((SceneObjectGroup)ent).RootPart.ObjectSaleType = 0;
1539 ((SceneObjectGroup)ent).RootPart.SalePrice = 10;
1540 children.Add((SceneObjectGroup)ent);
1541 }
1542 }
1543 } 1545 }
1544 } 1546 }
1545 } 1547 }
@@ -1548,29 +1550,29 @@ namespace OpenSim.Region.Framework.Scenes
1548 return; // parent is null so not in this region 1550 return; // parent is null so not in this region
1549 } 1551 }
1550 1552
1551 foreach (SceneObjectGroup sceneObj in children) 1553 foreach (SceneObjectGroup child in childGroups)
1552 { 1554 {
1553 parenPrim.LinkToGroup(sceneObj); 1555 parentGroup.LinkToGroup(child);
1554 1556
1555 // this is here so physics gets updated! 1557 // this is here so physics gets updated!
1556 // Don't remove! Bad juju! Stay away! or fix physics! 1558 // Don't remove! Bad juju! Stay away! or fix physics!
1557 sceneObj.AbsolutePosition = sceneObj.AbsolutePosition; 1559 child.AbsolutePosition = child.AbsolutePosition;
1558 } 1560 }
1559 1561
1560 // We need to explicitly resend the newly link prim's object properties since no other actions 1562 // We need to explicitly resend the newly link prim's object properties since no other actions
1561 // occur on link to invoke this elsewhere (such as object selection) 1563 // occur on link to invoke this elsewhere (such as object selection)
1562 parenPrim.RootPart.AddFlag(PrimFlags.CreateSelected); 1564 parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected);
1563 parenPrim.TriggerScriptChangedEvent(Changed.LINK); 1565 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1564 1566
1565 if (client != null) 1567 if (client != null)
1566 { 1568 {
1567 parenPrim.GetProperties(client); 1569 parentGroup.GetProperties(client);
1568 } 1570 }
1569 else 1571 else
1570 { 1572 {
1571 foreach (ScenePresence p in GetScenePresences()) 1573 foreach (ScenePresence p in GetScenePresences())
1572 { 1574 {
1573 parenPrim.GetProperties(p.ControllingClient); 1575 parentGroup.GetProperties(p.ControllingClient);
1574 } 1576 }
1575 } 1577 }
1576 } 1578 }
@@ -1586,58 +1588,34 @@ namespace OpenSim.Region.Framework.Scenes
1586 1588
1587 protected internal void DelinkObjects(List<uint> primIds, bool sendEvents) 1589 protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
1588 { 1590 {
1589 SceneObjectGroup parenPrim = null; 1591 SceneObjectGroup parentPrim = null;
1590
1591 // Need a list of the SceneObjectGroup local ids
1592 // XXX I'm anticipating that building this dictionary once is more efficient than
1593 // repeated scanning of the Entity.Values for a large number of primIds. However, it might
1594 // be more efficient yet to keep this dictionary permanently on hand.
1595
1596 Dictionary<uint, SceneObjectGroup> sceneObjects = new Dictionary<uint, SceneObjectGroup>();
1597
1598 List<EntityBase> EntityList = GetEntities();
1599 foreach (EntityBase ent in EntityList)
1600 {
1601 if (ent is SceneObjectGroup)
1602 {
1603 SceneObjectGroup obj = (SceneObjectGroup)ent;
1604 // Nasty one. Can't unlink anything in the sim
1605 // If a duplicate local ID sneaks in
1606 // So, check it here!
1607 //
1608 if (!sceneObjects.ContainsKey(obj.LocalId))
1609 sceneObjects.Add(obj.LocalId, obj);
1610
1611 }
1612 }
1613
1614 // Find the root prim among the prim ids we've been given 1592 // Find the root prim among the prim ids we've been given
1615 for (int i = 0; i < primIds.Count; i++) 1593 for (int i = 0; i < primIds.Count; i++)
1616 { 1594 {
1617 1595 // Get the group for this prim and check that it is the parent
1618 if (sceneObjects.ContainsKey(primIds[i])) 1596 parentPrim = GetGroupByPrim(primIds[i]);
1597 if (parentPrim != null && parentPrim.LocalId == primIds[i])
1619 { 1598 {
1620 parenPrim = sceneObjects[primIds[i]];
1621 primIds.RemoveAt(i); 1599 primIds.RemoveAt(i);
1622 break; 1600 break;
1623 } 1601 }
1624 } 1602 }
1625 1603
1626 if (parenPrim != null) 1604 if (parentPrim != null)
1627 { 1605 {
1628 foreach (uint childPrimId in primIds) 1606 foreach (uint childPrimId in primIds)
1629 { 1607 {
1630 parenPrim.DelinkFromGroup(childPrimId, sendEvents); 1608 parentPrim.DelinkFromGroup(childPrimId, sendEvents);
1631 } 1609 }
1632 1610
1633 if (parenPrim.Children.Count == 1) 1611 if (parentPrim.Children.Count == 1)
1634 { 1612 {
1635 // The link set has been completely torn down 1613 // The link set has been completely torn down
1636 // This is the case if you select a link set and delink 1614 // This is the case if you select a link set and delink
1637 // 1615 //
1638 parenPrim.RootPart.LinkNum = 0; 1616 parentPrim.RootPart.LinkNum = 0;
1639 if (sendEvents) 1617 if (sendEvents)
1640 parenPrim.TriggerScriptChangedEvent(Changed.LINK); 1618 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
1641 } 1619 }
1642 else 1620 else
1643 { 1621 {
@@ -1645,7 +1623,7 @@ namespace OpenSim.Region.Framework.Scenes
1645 // when a subset of a link set's prims are selected 1623 // when a subset of a link set's prims are selected
1646 // and the root prim is part of that selection 1624 // and the root prim is part of that selection
1647 // 1625 //
1648 List<SceneObjectPart> parts = new List<SceneObjectPart>(parenPrim.Children.Values); 1626 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
1649 1627
1650 List<uint> unlink_ids = new List<uint>(); 1628 List<uint> unlink_ids = new List<uint>();
1651 foreach (SceneObjectPart unlink_part in parts) 1629 foreach (SceneObjectPart unlink_part in parts)
@@ -1662,9 +1640,9 @@ namespace OpenSim.Region.Framework.Scenes
1662 DelinkObjects(unlink_ids, false); 1640 DelinkObjects(unlink_ids, false);
1663 1641
1664 // Send event to root prim, then we're done with it 1642 // Send event to root prim, then we're done with it
1665 parenPrim.TriggerScriptChangedEvent(Changed.LINK); 1643 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
1666 1644
1667 unlink_ids.Remove(parenPrim.RootPart.LocalId); 1645 unlink_ids.Remove(parentPrim.RootPart.LocalId);
1668 1646
1669 foreach (uint localId in unlink_ids) 1647 foreach (uint localId in unlink_ids)
1670 { 1648 {
@@ -1683,7 +1661,7 @@ namespace OpenSim.Region.Framework.Scenes
1683 // The selected prims were all child prims. Edit linked parts 1661 // The selected prims were all child prims. Edit linked parts
1684 // without the root prim selected will get us here 1662 // without the root prim selected will get us here
1685 // 1663 //
1686 List<SceneObjectGroup> parents = new List<SceneObjectGroup>(); 1664 List<SceneObjectGroup> parentGroups = new List<SceneObjectGroup>();
1687 1665
1688 // If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow 1666 // If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow
1689 // We know that this is not the root prim now essentially, so we don't have to worry about remapping 1667 // 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
1691 bool delinkedSomething = false; 1669 bool delinkedSomething = false;
1692 for (int i = 0; i < primIds.Count; i++) 1670 for (int i = 0; i < primIds.Count; i++)
1693 { 1671 {
1694 foreach (SceneObjectGroup grp in sceneObjects.Values) 1672 SceneObjectGroup parent = GetGroupByPrim(primIds[i]);
1695 { 1673 parent.DelinkFromGroup(primIds[i]);
1696 SceneObjectPart gPart = grp.GetChildPart(primIds[i]); 1674 delinkedSomething = true;
1697 if (gPart != null) 1675 if (!parentGroups.Contains(parent))
1698 { 1676 parentGroups.Add(parent);
1699 grp.DelinkFromGroup(primIds[i]);
1700 delinkedSomething = true;
1701 if (!parents.Contains(grp))
1702 parents.Add(grp);
1703 }
1704
1705 }
1706 } 1677 }
1707 if (!delinkedSomething) 1678 if (!delinkedSomething)
1708 { 1679 {
@@ -1712,7 +1683,7 @@ namespace OpenSim.Region.Framework.Scenes
1712 } 1683 }
1713 else 1684 else
1714 { 1685 {
1715 foreach (SceneObjectGroup g in parents) 1686 foreach (SceneObjectGroup g in parentGroups)
1716 { 1687 {
1717 g.TriggerScriptChangedEvent(Changed.LINK); 1688 g.TriggerScriptChangedEvent(Changed.LINK);
1718 } 1689 }
@@ -1790,30 +1761,15 @@ namespace OpenSim.Region.Framework.Scenes
1790 /// <param name="originalPrim"></param> 1761 /// <param name="originalPrim"></param>
1791 /// <param name="offset"></param> 1762 /// <param name="offset"></param>
1792 /// <param name="flags"></param> 1763 /// <param name="flags"></param>
1793 protected internal SceneObjectGroup DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) 1764 protected internal SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1794 { 1765 {
1795 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID); 1766 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1796 1767 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1797 List<EntityBase> EntityList = GetEntities(); 1768 if (original != null)
1798
1799 SceneObjectGroup originPrim = null;
1800 foreach (EntityBase ent in EntityList)
1801 {
1802 if (ent is SceneObjectGroup)
1803 {
1804 if (((SceneObjectGroup)ent).LocalId == originalPrim)
1805 {
1806 originPrim = (SceneObjectGroup)ent;
1807 break;
1808 }
1809 }
1810 }
1811
1812 if (originPrim != null)
1813 { 1769 {
1814 if (m_parentScene.Permissions.CanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition)) 1770 if (m_parentScene.Permissions.CanDuplicateObject(original.Children.Count, original.UUID, AgentID, original.AbsolutePosition))
1815 { 1771 {
1816 SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID, true); 1772 SceneObjectGroup copy = original.Copy(AgentID, GroupID, true);
1817 copy.AbsolutePosition = copy.AbsolutePosition + offset; 1773 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1818 1774
1819 Entities.Add(copy); 1775 Entities.Add(copy);
@@ -1840,7 +1796,7 @@ namespace OpenSim.Region.Framework.Scenes
1840 copy.AbsolutePosition = copy.AbsolutePosition; 1796 copy.AbsolutePosition = copy.AbsolutePosition;
1841 1797
1842 if (OnObjectDuplicate != null) 1798 if (OnObjectDuplicate != null)
1843 OnObjectDuplicate(originPrim, copy); 1799 OnObjectDuplicate(original, copy);
1844 1800
1845 return copy; 1801 return copy;
1846 } 1802 }