diff options
author | Melanie Thielker | 2009-04-12 15:18:04 +0000 |
---|---|---|
committer | Melanie Thielker | 2009-04-12 15:18:04 +0000 |
commit | cc86df4a3f61230c5487cadf8e93fc1e87a88574 (patch) | |
tree | cbd8ac36909d4ac6915162d7fe567bd89442ff29 /OpenSim/Region/Framework/Scenes | |
parent | Actually do what I promised in the previous commit :/ (diff) | |
download | opensim-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
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 15 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 438 |
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 | } |