diff options
Merge branch 'master' into careminster-presence-refactor
Integrate the next large patch.
Don't use this version, it has a ghost avatar issue. Next push
will fix it.
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 1460 |
1 files changed, 561 insertions, 899 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 142f5d8..3bc7834 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -131,89 +131,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
131 | } | 131 | } |
132 | } | 132 | } |
133 | 133 | ||
134 | public void lockPartsForRead(bool locked) | ||
135 | { | ||
136 | if (locked) | ||
137 | { | ||
138 | if (m_partsLock.RecursiveReadCount > 0) | ||
139 | { | ||
140 | m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); | ||
141 | try | ||
142 | { | ||
143 | StackTrace stackTrace = new StackTrace(); // get call stack | ||
144 | StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) | ||
145 | |||
146 | // write call stack method names | ||
147 | foreach (StackFrame stackFrame in stackFrames) | ||
148 | { | ||
149 | m_log.Error("[SceneObjectGroup.m_parts] "+(stackFrame.GetMethod().Name)); // write method name | ||
150 | } | ||
151 | |||
152 | m_partsLock.ExitReadLock(); | ||
153 | } | ||
154 | catch { } // Ignore errors, to allow resync | ||
155 | } | ||
156 | if (m_partsLock.RecursiveWriteCount > 0) | ||
157 | { | ||
158 | m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested (write lock exists on this thread). This should not happen and means something needs to be fixed."); | ||
159 | try | ||
160 | { | ||
161 | m_partsLock.ExitWriteLock(); | ||
162 | } | ||
163 | catch { } | ||
164 | |||
165 | } | ||
166 | |||
167 | while (!m_partsLock.TryEnterReadLock(60000)) | ||
168 | { | ||
169 | m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire READ lock of m_parts in SceneObjectGroup. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); | ||
170 | if (m_partsLock.IsWriteLockHeld) | ||
171 | { | ||
172 | m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | if (m_partsLock.RecursiveReadCount > 0) | ||
179 | { | ||
180 | m_partsLock.ExitReadLock(); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | public void lockPartsForWrite(bool locked) | ||
185 | { | ||
186 | if (locked) | ||
187 | { | ||
188 | if (m_partsLock.RecursiveReadCount > 0) | ||
189 | { | ||
190 | m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); | ||
191 | m_partsLock.ExitReadLock(); | ||
192 | } | ||
193 | if (m_partsLock.RecursiveWriteCount > 0) | ||
194 | { | ||
195 | m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed."); | ||
196 | m_partsLock.ExitWriteLock(); | ||
197 | } | ||
198 | |||
199 | while (!m_partsLock.TryEnterWriteLock(60000)) | ||
200 | { | ||
201 | m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); | ||
202 | if (m_partsLock.IsWriteLockHeld) | ||
203 | { | ||
204 | m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | if (m_partsLock.RecursiveWriteCount > 0) | ||
211 | { | ||
212 | m_partsLock.ExitWriteLock(); | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | public bool HasGroupChanged | 134 | public bool HasGroupChanged |
218 | { | 135 | { |
219 | set | 136 | set |
@@ -305,17 +222,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
305 | } | 222 | } |
306 | } | 223 | } |
307 | 224 | ||
308 | public float scriptScore = 0f; | 225 | public float scriptScore; |
309 | 226 | ||
310 | private Vector3 lastPhysGroupPos; | 227 | private Vector3 lastPhysGroupPos; |
311 | private Quaternion lastPhysGroupRot; | 228 | private Quaternion lastPhysGroupRot; |
312 | 229 | ||
313 | private bool m_isBackedUp = false; | 230 | private bool m_isBackedUp; |
314 | 231 | ||
315 | /// <summary> | 232 | protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); |
316 | /// The constituent parts of this group | ||
317 | /// </summary> | ||
318 | protected Dictionary<UUID, SceneObjectPart> m_parts = new Dictionary<UUID, SceneObjectPart>(); | ||
319 | 233 | ||
320 | protected ulong m_regionHandle; | 234 | protected ulong m_regionHandle; |
321 | protected SceneObjectPart m_rootPart; | 235 | protected SceneObjectPart m_rootPart; |
@@ -324,13 +238,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
324 | private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); | 238 | private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); |
325 | private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); | 239 | private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); |
326 | 240 | ||
327 | private bool m_scriptListens_atTarget = false; | 241 | private bool m_scriptListens_atTarget; |
328 | private bool m_scriptListens_notAtTarget = false; | 242 | private bool m_scriptListens_notAtTarget; |
243 | private bool m_scriptListens_atRotTarget; | ||
244 | private bool m_scriptListens_notAtRotTarget; | ||
329 | 245 | ||
330 | private bool m_scriptListens_atRotTarget = false; | ||
331 | private bool m_scriptListens_notAtRotTarget = false; | ||
332 | public bool m_dupeInProgress = false; | 246 | public bool m_dupeInProgress = false; |
333 | internal Dictionary<UUID, string> m_savedScriptState = null; | 247 | internal Dictionary<UUID, string> m_savedScriptState; |
334 | 248 | ||
335 | #region Properties | 249 | #region Properties |
336 | 250 | ||
@@ -341,7 +255,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
341 | { | 255 | { |
342 | get { | 256 | get { |
343 | if (RootPart == null) | 257 | if (RootPart == null) |
344 | return ""; | 258 | return String.Empty; |
345 | return RootPart.Name; | 259 | return RootPart.Name; |
346 | } | 260 | } |
347 | set { RootPart.Name = value; } | 261 | set { RootPart.Name = value; } |
@@ -361,7 +275,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
361 | /// </summary> | 275 | /// </summary> |
362 | public int PrimCount | 276 | public int PrimCount |
363 | { | 277 | { |
364 | get { lock (m_parts) { return m_parts.Count; } } | 278 | get { return m_parts.Count; } |
365 | } | 279 | } |
366 | 280 | ||
367 | protected Quaternion m_rotation = Quaternion.Identity; | 281 | protected Quaternion m_rotation = Quaternion.Identity; |
@@ -370,17 +284,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
370 | { | 284 | { |
371 | get { return m_rotation; } | 285 | get { return m_rotation; } |
372 | set { | 286 | set { |
373 | lockPartsForRead(true); | 287 | foreach(SceneObjectPart p in m_parts.GetArray()) |
374 | try | ||
375 | { | 288 | { |
376 | foreach(SceneObjectPart p in m_parts.Values) | 289 | p.StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
377 | { | ||
378 | p.StoreUndoState(UndoType.STATE_GROUP_ROTATION); | ||
379 | } | ||
380 | } | ||
381 | finally | ||
382 | { | ||
383 | lockPartsForRead(false); | ||
384 | } | 290 | } |
385 | m_rotation = value; | 291 | m_rotation = value; |
386 | } | 292 | } |
@@ -397,16 +303,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
397 | set { m_rootPart.GroupID = value; } | 303 | set { m_rootPart.GroupID = value; } |
398 | } | 304 | } |
399 | 305 | ||
400 | /// <value> | 306 | public SceneObjectPart[] Parts |
401 | /// The parts of this scene object group. You must lock this property before using it. | 307 | { |
402 | /// If you're doing anything other than reading values, please take a copy of the values rather than locking | 308 | get { return m_parts.GetArray(); } |
403 | /// the dictionary for the entirety of the operation. This increases liveness and reduces the danger of deadlock | 309 | } |
404 | /// If you want to know the number of children, consider using the PrimCount property instead | 310 | |
405 | /// </value> | 311 | public bool ContainsPart(UUID partID) |
406 | public Dictionary<UUID, SceneObjectPart> Children | ||
407 | { | 312 | { |
408 | get { return m_parts; } | 313 | return m_parts.ContainsKey(partID); |
409 | set { m_parts = value; } | ||
410 | } | 314 | } |
411 | 315 | ||
412 | /// <value> | 316 | /// <value> |
@@ -423,16 +327,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
423 | set | 327 | set |
424 | { | 328 | { |
425 | m_regionHandle = value; | 329 | m_regionHandle = value; |
426 | lockPartsForRead(true); | 330 | SceneObjectPart[] parts = m_parts.GetArray(); |
427 | { | 331 | for (int i = 0; i < parts.Length; i++) |
428 | foreach (SceneObjectPart part in m_parts.Values) | 332 | parts[i].RegionHandle = value; |
429 | { | ||
430 | |||
431 | part.RegionHandle = m_regionHandle; | ||
432 | |||
433 | } | ||
434 | } | ||
435 | lockPartsForRead(false); | ||
436 | } | 333 | } |
437 | } | 334 | } |
438 | 335 | ||
@@ -467,8 +364,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
467 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | 364 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); |
468 | } | 365 | } |
469 | 366 | ||
470 | lockPartsForRead(true); | 367 | foreach (SceneObjectPart part in m_parts.GetArray()) |
471 | foreach (SceneObjectPart part in m_parts.Values) | ||
472 | { | 368 | { |
473 | part.IgnoreUndoUpdate = true; | 369 | part.IgnoreUndoUpdate = true; |
474 | } | 370 | } |
@@ -479,12 +375,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
479 | RootPart.ScriptSetPhysicsStatus(false); | 375 | RootPart.ScriptSetPhysicsStatus(false); |
480 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), | 376 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), |
481 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); | 377 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); |
482 | lockPartsForRead(false); | ||
483 | return; | 378 | return; |
484 | } | 379 | } |
485 | } | 380 | } |
486 | List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values); | 381 | SceneObjectPart[] parts = m_parts.GetArray(); |
487 | lockPartsForRead(false); | ||
488 | foreach (SceneObjectPart part in parts) | 382 | foreach (SceneObjectPart part in parts) |
489 | { | 383 | { |
490 | part.IgnoreUndoUpdate = false; | 384 | part.IgnoreUndoUpdate = false; |
@@ -499,10 +393,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
499 | { | 393 | { |
500 | foreach (ScenePresence av in m_linkedAvatars) | 394 | foreach (ScenePresence av in m_linkedAvatars) |
501 | { | 395 | { |
502 | Vector3 offset = m_parts[av.LinkedPrim].GetWorldPosition() - av.ParentPosition; | 396 | SceneObjectPart p; |
503 | av.AbsolutePosition += offset; | 397 | if (m_parts.TryGetValue(av.LinkedPrim, out p)) |
504 | av.ParentPosition = m_parts[av.LinkedPrim].GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition | 398 | { |
505 | av.SendFullUpdateToAllClients(); | 399 | Vector3 offset = p.GetWorldPosition() - av.ParentPosition; |
400 | av.AbsolutePosition += offset; | ||
401 | av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition | ||
402 | av.SendFullUpdateToAllClients(); | ||
403 | } | ||
506 | } | 404 | } |
507 | } | 405 | } |
508 | 406 | ||
@@ -526,14 +424,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
526 | { | 424 | { |
527 | get { return m_rootPart.UUID; } | 425 | get { return m_rootPart.UUID; } |
528 | set | 426 | set |
529 | { | 427 | { |
530 | m_rootPart.UUID = value; | 428 | m_rootPart.UUID = value; |
531 | 429 | m_parts.AddOrReplace(value, m_rootPart); | |
532 | lock (m_parts) | ||
533 | { | ||
534 | m_parts.Remove(m_rootPart.UUID); | ||
535 | m_parts.Add(m_rootPart.UUID, m_rootPart); | ||
536 | } | ||
537 | } | 430 | } |
538 | } | 431 | } |
539 | 432 | ||
@@ -595,12 +488,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
595 | { | 488 | { |
596 | m_rootPart.PhysActor.Selected = value; | 489 | m_rootPart.PhysActor.Selected = value; |
597 | // Pass it on to the children. | 490 | // Pass it on to the children. |
598 | foreach (SceneObjectPart child in Children.Values) | 491 | SceneObjectPart[] parts = m_parts.GetArray(); |
492 | for (int i = 0; i < parts.Length; i++) | ||
599 | { | 493 | { |
494 | SceneObjectPart child = parts[i]; | ||
600 | if (child.PhysActor != null) | 495 | if (child.PhysActor != null) |
601 | { | ||
602 | child.PhysActor.Selected = value; | 496 | child.PhysActor.Selected = value; |
603 | } | ||
604 | } | 497 | } |
605 | } | 498 | } |
606 | } | 499 | } |
@@ -704,16 +597,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
704 | 597 | ||
705 | public void SetFromItemID(UUID AssetId) | 598 | public void SetFromItemID(UUID AssetId) |
706 | { | 599 | { |
707 | lockPartsForRead(true); | 600 | SceneObjectPart[] parts = m_parts.GetArray(); |
708 | { | 601 | for (int i = 0; i < parts.Length; i++) |
709 | foreach (SceneObjectPart part in m_parts.Values) | 602 | parts[i].FromItemID = AssetId; |
710 | { | ||
711 | |||
712 | part.FromItemID = AssetId; | ||
713 | |||
714 | } | ||
715 | } | ||
716 | lockPartsForRead(false); | ||
717 | } | 603 | } |
718 | 604 | ||
719 | public UUID GetFromItemID() | 605 | public UUID GetFromItemID() |
@@ -755,23 +641,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
755 | if (m_rootPart.LocalId == 0) | 641 | if (m_rootPart.LocalId == 0) |
756 | m_rootPart.LocalId = m_scene.AllocateLocalId(); | 642 | m_rootPart.LocalId = m_scene.AllocateLocalId(); |
757 | 643 | ||
758 | lock (m_parts) | 644 | SceneObjectPart[] parts = m_parts.GetArray(); |
645 | for (int i = 0; i < parts.Length; i++) | ||
759 | { | 646 | { |
760 | foreach (SceneObjectPart part in m_parts.Values) | 647 | SceneObjectPart part = parts[i]; |
761 | { | 648 | if (Object.ReferenceEquals(part, m_rootPart)) |
762 | if (Object.ReferenceEquals(part, m_rootPart)) | 649 | continue; |
763 | { | 650 | |
764 | continue; | 651 | if (part.LocalId == 0) |
765 | } | 652 | part.LocalId = m_scene.AllocateLocalId(); |
766 | 653 | ||
767 | if (part.LocalId == 0) | 654 | part.ParentID = m_rootPart.LocalId; |
768 | { | 655 | //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); |
769 | part.LocalId = m_scene.AllocateLocalId(); | ||
770 | } | ||
771 | |||
772 | part.ParentID = m_rootPart.LocalId; | ||
773 | //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); | ||
774 | } | ||
775 | } | 656 | } |
776 | 657 | ||
777 | ApplyPhysics(m_scene.m_physicalPrim); | 658 | ApplyPhysics(m_scene.m_physicalPrim); |
@@ -787,24 +668,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
787 | Vector3 maxScale = Vector3.Zero; | 668 | Vector3 maxScale = Vector3.Zero; |
788 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); | 669 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); |
789 | 670 | ||
790 | lockPartsForRead(true); | 671 | SceneObjectPart[] parts = m_parts.GetArray(); |
672 | for (int i = 0; i < parts.Length; i++) | ||
791 | { | 673 | { |
792 | foreach (SceneObjectPart part in m_parts.Values) | 674 | SceneObjectPart part = parts[i]; |
793 | { | 675 | Vector3 partscale = part.Scale; |
794 | Vector3 partscale = part.Scale; | 676 | Vector3 partoffset = part.OffsetPosition; |
795 | Vector3 partoffset = part.OffsetPosition; | ||
796 | 677 | ||
797 | minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; | 678 | minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; |
798 | minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; | 679 | minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; |
799 | minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; | 680 | minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; |
800 | 681 | ||
801 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; | 682 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; |
802 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; | 683 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; |
803 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; | 684 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; |
804 | |||
805 | } | ||
806 | } | 685 | } |
807 | lockPartsForRead(false); | ||
808 | 686 | ||
809 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; | 687 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; |
810 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; | 688 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; |
@@ -821,42 +699,40 @@ namespace OpenSim.Region.Framework.Scenes | |||
821 | 699 | ||
822 | EntityIntersection result = new EntityIntersection(); | 700 | EntityIntersection result = new EntityIntersection(); |
823 | 701 | ||
824 | lockPartsForRead(true); | 702 | SceneObjectPart[] parts = m_parts.GetArray(); |
703 | for (int i = 0; i < parts.Length; i++) | ||
825 | { | 704 | { |
826 | foreach (SceneObjectPart part in m_parts.Values) | 705 | SceneObjectPart part = parts[i]; |
827 | { | 706 | |
828 | 707 | // Temporary commented to stop compiler warning | |
829 | // Temporary commented to stop compiler warning | 708 | //Vector3 partPosition = |
830 | //Vector3 partPosition = | 709 | // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); |
831 | // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); | 710 | Quaternion parentrotation = GroupRotation; |
832 | Quaternion parentrotation = GroupRotation; | ||
833 | 711 | ||
834 | // Telling the prim to raytrace. | 712 | // Telling the prim to raytrace. |
835 | //EntityIntersection inter = part.TestIntersection(hRay, parentrotation); | 713 | //EntityIntersection inter = part.TestIntersection(hRay, parentrotation); |
836 | 714 | ||
837 | EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation,frontFacesOnly, faceCenters); | 715 | EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); |
838 | 716 | ||
839 | // This may need to be updated to the maximum draw distance possible.. | 717 | // This may need to be updated to the maximum draw distance possible.. |
840 | // We might (and probably will) be checking for prim creation from other sims | 718 | // We might (and probably will) be checking for prim creation from other sims |
841 | // when the camera crosses the border. | 719 | // when the camera crosses the border. |
842 | float idist = Constants.RegionSize; | 720 | float idist = Constants.RegionSize; |
843 | 721 | ||
844 | if (inter.HitTF) | 722 | if (inter.HitTF) |
723 | { | ||
724 | // We need to find the closest prim to return to the testcaller along the ray | ||
725 | if (inter.distance < idist) | ||
845 | { | 726 | { |
846 | // We need to find the closest prim to return to the testcaller along the ray | 727 | result.HitTF = true; |
847 | if (inter.distance < idist) | 728 | result.ipoint = inter.ipoint; |
848 | { | 729 | result.obj = part; |
849 | result.HitTF = true; | 730 | result.normal = inter.normal; |
850 | result.ipoint = inter.ipoint; | 731 | result.distance = inter.distance; |
851 | result.obj = part; | ||
852 | result.normal = inter.normal; | ||
853 | result.distance = inter.distance; | ||
854 | } | ||
855 | } | 732 | } |
856 | 733 | ||
857 | } | 734 | } |
858 | } | 735 | } |
859 | lockPartsForRead(false); | ||
860 | return result; | 736 | return result; |
861 | } | 737 | } |
862 | 738 | ||
@@ -875,243 +751,239 @@ namespace OpenSim.Region.Framework.Scenes | |||
875 | minY = 256f; | 751 | minY = 256f; |
876 | minZ = 8192f; | 752 | minZ = 8192f; |
877 | 753 | ||
878 | lockPartsForRead(true); | 754 | SceneObjectPart[] parts = m_parts.GetArray(); |
755 | foreach (SceneObjectPart part in parts) | ||
879 | { | 756 | { |
880 | foreach (SceneObjectPart part in m_parts.Values) | 757 | Vector3 worldPos = part.GetWorldPosition(); |
758 | Vector3 offset = worldPos - AbsolutePosition; | ||
759 | Quaternion worldRot; | ||
760 | if (part.ParentID == 0) | ||
881 | { | 761 | { |
882 | 762 | worldRot = part.RotationOffset; | |
883 | Vector3 worldPos = part.GetWorldPosition(); | 763 | } |
884 | Vector3 offset = worldPos - AbsolutePosition; | 764 | else |
885 | Quaternion worldRot; | 765 | { |
886 | if (part.ParentID == 0) | 766 | worldRot = part.GetWorldRotation(); |
887 | { | 767 | } |
888 | worldRot = part.RotationOffset; | ||
889 | } | ||
890 | else | ||
891 | { | ||
892 | worldRot = part.GetWorldRotation(); | ||
893 | } | ||
894 | 768 | ||
895 | Vector3 frontTopLeft; | 769 | Vector3 frontTopLeft; |
896 | Vector3 frontTopRight; | 770 | Vector3 frontTopRight; |
897 | Vector3 frontBottomLeft; | 771 | Vector3 frontBottomLeft; |
898 | Vector3 frontBottomRight; | 772 | Vector3 frontBottomRight; |
899 | 773 | ||
900 | Vector3 backTopLeft; | 774 | Vector3 backTopLeft; |
901 | Vector3 backTopRight; | 775 | Vector3 backTopRight; |
902 | Vector3 backBottomLeft; | 776 | Vector3 backBottomLeft; |
903 | Vector3 backBottomRight; | 777 | Vector3 backBottomRight; |
904 | 778 | ||
905 | // Vector3[] corners = new Vector3[8]; | 779 | // Vector3[] corners = new Vector3[8]; |
906 | 780 | ||
907 | Vector3 orig = Vector3.Zero; | 781 | Vector3 orig = Vector3.Zero; |
908 | 782 | ||
909 | frontTopLeft.X = orig.X - (part.Scale.X / 2); | 783 | frontTopLeft.X = orig.X - (part.Scale.X / 2); |
910 | frontTopLeft.Y = orig.Y - (part.Scale.Y / 2); | 784 | frontTopLeft.Y = orig.Y - (part.Scale.Y / 2); |
911 | frontTopLeft.Z = orig.Z + (part.Scale.Z / 2); | 785 | frontTopLeft.Z = orig.Z + (part.Scale.Z / 2); |
912 | 786 | ||
913 | frontTopRight.X = orig.X - (part.Scale.X / 2); | 787 | frontTopRight.X = orig.X - (part.Scale.X / 2); |
914 | frontTopRight.Y = orig.Y + (part.Scale.Y / 2); | 788 | frontTopRight.Y = orig.Y + (part.Scale.Y / 2); |
915 | frontTopRight.Z = orig.Z + (part.Scale.Z / 2); | 789 | frontTopRight.Z = orig.Z + (part.Scale.Z / 2); |
916 | 790 | ||
917 | frontBottomLeft.X = orig.X - (part.Scale.X / 2); | 791 | frontBottomLeft.X = orig.X - (part.Scale.X / 2); |
918 | frontBottomLeft.Y = orig.Y - (part.Scale.Y / 2); | 792 | frontBottomLeft.Y = orig.Y - (part.Scale.Y / 2); |
919 | frontBottomLeft.Z = orig.Z - (part.Scale.Z / 2); | 793 | frontBottomLeft.Z = orig.Z - (part.Scale.Z / 2); |
920 | 794 | ||
921 | frontBottomRight.X = orig.X - (part.Scale.X / 2); | 795 | frontBottomRight.X = orig.X - (part.Scale.X / 2); |
922 | frontBottomRight.Y = orig.Y + (part.Scale.Y / 2); | 796 | frontBottomRight.Y = orig.Y + (part.Scale.Y / 2); |
923 | frontBottomRight.Z = orig.Z - (part.Scale.Z / 2); | 797 | frontBottomRight.Z = orig.Z - (part.Scale.Z / 2); |
924 | 798 | ||
925 | backTopLeft.X = orig.X + (part.Scale.X / 2); | 799 | backTopLeft.X = orig.X + (part.Scale.X / 2); |
926 | backTopLeft.Y = orig.Y - (part.Scale.Y / 2); | 800 | backTopLeft.Y = orig.Y - (part.Scale.Y / 2); |
927 | backTopLeft.Z = orig.Z + (part.Scale.Z / 2); | 801 | backTopLeft.Z = orig.Z + (part.Scale.Z / 2); |
928 | 802 | ||
929 | backTopRight.X = orig.X + (part.Scale.X / 2); | 803 | backTopRight.X = orig.X + (part.Scale.X / 2); |
930 | backTopRight.Y = orig.Y + (part.Scale.Y / 2); | 804 | backTopRight.Y = orig.Y + (part.Scale.Y / 2); |
931 | backTopRight.Z = orig.Z + (part.Scale.Z / 2); | 805 | backTopRight.Z = orig.Z + (part.Scale.Z / 2); |
932 | 806 | ||
933 | backBottomLeft.X = orig.X + (part.Scale.X / 2); | 807 | backBottomLeft.X = orig.X + (part.Scale.X / 2); |
934 | backBottomLeft.Y = orig.Y - (part.Scale.Y / 2); | 808 | backBottomLeft.Y = orig.Y - (part.Scale.Y / 2); |
935 | backBottomLeft.Z = orig.Z - (part.Scale.Z / 2); | 809 | backBottomLeft.Z = orig.Z - (part.Scale.Z / 2); |
936 | 810 | ||
937 | backBottomRight.X = orig.X + (part.Scale.X / 2); | 811 | backBottomRight.X = orig.X + (part.Scale.X / 2); |
938 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); | 812 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); |
939 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); | 813 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); |
940 | 814 | ||
941 | 815 | ||
942 | 816 | ||
943 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | 817 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); |
944 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | 818 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); |
945 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | 819 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); |
946 | //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); | 820 | //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); |
947 | //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); | 821 | //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); |
948 | //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); | 822 | //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); |
949 | //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | 823 | //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); |
950 | //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); | 824 | //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); |
951 | |||
952 | //for (int i = 0; i < 8; i++) | ||
953 | //{ | ||
954 | // corners[i] = corners[i] * worldRot; | ||
955 | // corners[i] += offset; | ||
956 | |||
957 | // if (corners[i].X > maxX) | ||
958 | // maxX = corners[i].X; | ||
959 | // if (corners[i].X < minX) | ||
960 | // minX = corners[i].X; | ||
961 | |||
962 | // if (corners[i].Y > maxY) | ||
963 | // maxY = corners[i].Y; | ||
964 | // if (corners[i].Y < minY) | ||
965 | // minY = corners[i].Y; | ||
966 | |||
967 | // if (corners[i].Z > maxZ) | ||
968 | // maxZ = corners[i].Y; | ||
969 | // if (corners[i].Z < minZ) | ||
970 | // minZ = corners[i].Z; | ||
971 | //} | ||
972 | |||
973 | frontTopLeft = frontTopLeft * worldRot; | ||
974 | frontTopRight = frontTopRight * worldRot; | ||
975 | frontBottomLeft = frontBottomLeft * worldRot; | ||
976 | frontBottomRight = frontBottomRight * worldRot; | ||
977 | |||
978 | backBottomLeft = backBottomLeft * worldRot; | ||
979 | backBottomRight = backBottomRight * worldRot; | ||
980 | backTopLeft = backTopLeft * worldRot; | ||
981 | backTopRight = backTopRight * worldRot; | ||
982 | |||
983 | |||
984 | frontTopLeft += offset; | ||
985 | frontTopRight += offset; | ||
986 | frontBottomLeft += offset; | ||
987 | frontBottomRight += offset; | ||
988 | |||
989 | backBottomLeft += offset; | ||
990 | backBottomRight += offset; | ||
991 | backTopLeft += offset; | ||
992 | backTopRight += offset; | ||
993 | |||
994 | //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | ||
995 | //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | ||
996 | //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | ||
997 | //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); | ||
998 | //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); | ||
999 | //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); | ||
1000 | //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | ||
1001 | //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); | ||
1002 | |||
1003 | if (frontTopRight.X > maxX) | ||
1004 | maxX = frontTopRight.X; | ||
1005 | if (frontTopLeft.X > maxX) | ||
1006 | maxX = frontTopLeft.X; | ||
1007 | if (frontBottomRight.X > maxX) | ||
1008 | maxX = frontBottomRight.X; | ||
1009 | if (frontBottomLeft.X > maxX) | ||
1010 | maxX = frontBottomLeft.X; | ||
1011 | |||
1012 | if (backTopRight.X > maxX) | ||
1013 | maxX = backTopRight.X; | ||
1014 | if (backTopLeft.X > maxX) | ||
1015 | maxX = backTopLeft.X; | ||
1016 | if (backBottomRight.X > maxX) | ||
1017 | maxX = backBottomRight.X; | ||
1018 | if (backBottomLeft.X > maxX) | ||
1019 | maxX = backBottomLeft.X; | ||
1020 | |||
1021 | if (frontTopRight.X < minX) | ||
1022 | minX = frontTopRight.X; | ||
1023 | if (frontTopLeft.X < minX) | ||
1024 | minX = frontTopLeft.X; | ||
1025 | if (frontBottomRight.X < minX) | ||
1026 | minX = frontBottomRight.X; | ||
1027 | if (frontBottomLeft.X < minX) | ||
1028 | minX = frontBottomLeft.X; | ||
1029 | |||
1030 | if (backTopRight.X < minX) | ||
1031 | minX = backTopRight.X; | ||
1032 | if (backTopLeft.X < minX) | ||
1033 | minX = backTopLeft.X; | ||
1034 | if (backBottomRight.X < minX) | ||
1035 | minX = backBottomRight.X; | ||
1036 | if (backBottomLeft.X < minX) | ||
1037 | minX = backBottomLeft.X; | ||
1038 | 825 | ||
1039 | // | 826 | //for (int i = 0; i < 8; i++) |
1040 | if (frontTopRight.Y > maxY) | 827 | //{ |
1041 | maxY = frontTopRight.Y; | 828 | // corners[i] = corners[i] * worldRot; |
1042 | if (frontTopLeft.Y > maxY) | 829 | // corners[i] += offset; |
1043 | maxY = frontTopLeft.Y; | 830 | |
1044 | if (frontBottomRight.Y > maxY) | 831 | // if (corners[i].X > maxX) |
1045 | maxY = frontBottomRight.Y; | 832 | // maxX = corners[i].X; |
1046 | if (frontBottomLeft.Y > maxY) | 833 | // if (corners[i].X < minX) |
1047 | maxY = frontBottomLeft.Y; | 834 | // minX = corners[i].X; |
1048 | 835 | ||
1049 | if (backTopRight.Y > maxY) | 836 | // if (corners[i].Y > maxY) |
1050 | maxY = backTopRight.Y; | 837 | // maxY = corners[i].Y; |
1051 | if (backTopLeft.Y > maxY) | 838 | // if (corners[i].Y < minY) |
1052 | maxY = backTopLeft.Y; | 839 | // minY = corners[i].Y; |
1053 | if (backBottomRight.Y > maxY) | 840 | |
1054 | maxY = backBottomRight.Y; | 841 | // if (corners[i].Z > maxZ) |
1055 | if (backBottomLeft.Y > maxY) | 842 | // maxZ = corners[i].Y; |
1056 | maxY = backBottomLeft.Y; | 843 | // if (corners[i].Z < minZ) |
1057 | 844 | // minZ = corners[i].Z; | |
1058 | if (frontTopRight.Y < minY) | 845 | //} |
1059 | minY = frontTopRight.Y; | ||
1060 | if (frontTopLeft.Y < minY) | ||
1061 | minY = frontTopLeft.Y; | ||
1062 | if (frontBottomRight.Y < minY) | ||
1063 | minY = frontBottomRight.Y; | ||
1064 | if (frontBottomLeft.Y < minY) | ||
1065 | minY = frontBottomLeft.Y; | ||
1066 | |||
1067 | if (backTopRight.Y < minY) | ||
1068 | minY = backTopRight.Y; | ||
1069 | if (backTopLeft.Y < minY) | ||
1070 | minY = backTopLeft.Y; | ||
1071 | if (backBottomRight.Y < minY) | ||
1072 | minY = backBottomRight.Y; | ||
1073 | if (backBottomLeft.Y < minY) | ||
1074 | minY = backBottomLeft.Y; | ||
1075 | 846 | ||
1076 | // | 847 | frontTopLeft = frontTopLeft * worldRot; |
1077 | if (frontTopRight.Z > maxZ) | 848 | frontTopRight = frontTopRight * worldRot; |
1078 | maxZ = frontTopRight.Z; | 849 | frontBottomLeft = frontBottomLeft * worldRot; |
1079 | if (frontTopLeft.Z > maxZ) | 850 | frontBottomRight = frontBottomRight * worldRot; |
1080 | maxZ = frontTopLeft.Z; | 851 | |
1081 | if (frontBottomRight.Z > maxZ) | 852 | backBottomLeft = backBottomLeft * worldRot; |
1082 | maxZ = frontBottomRight.Z; | 853 | backBottomRight = backBottomRight * worldRot; |
1083 | if (frontBottomLeft.Z > maxZ) | 854 | backTopLeft = backTopLeft * worldRot; |
1084 | maxZ = frontBottomLeft.Z; | 855 | backTopRight = backTopRight * worldRot; |
1085 | 856 | ||
1086 | if (backTopRight.Z > maxZ) | 857 | |
1087 | maxZ = backTopRight.Z; | 858 | frontTopLeft += offset; |
1088 | if (backTopLeft.Z > maxZ) | 859 | frontTopRight += offset; |
1089 | maxZ = backTopLeft.Z; | 860 | frontBottomLeft += offset; |
1090 | if (backBottomRight.Z > maxZ) | 861 | frontBottomRight += offset; |
1091 | maxZ = backBottomRight.Z; | 862 | |
1092 | if (backBottomLeft.Z > maxZ) | 863 | backBottomLeft += offset; |
1093 | maxZ = backBottomLeft.Z; | 864 | backBottomRight += offset; |
1094 | 865 | backTopLeft += offset; | |
1095 | if (frontTopRight.Z < minZ) | 866 | backTopRight += offset; |
1096 | minZ = frontTopRight.Z; | 867 | |
1097 | if (frontTopLeft.Z < minZ) | 868 | //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); |
1098 | minZ = frontTopLeft.Z; | 869 | //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); |
1099 | if (frontBottomRight.Z < minZ) | 870 | //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); |
1100 | minZ = frontBottomRight.Z; | 871 | //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); |
1101 | if (frontBottomLeft.Z < minZ) | 872 | //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); |
1102 | minZ = frontBottomLeft.Z; | 873 | //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); |
1103 | 874 | //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | |
1104 | if (backTopRight.Z < minZ) | 875 | //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); |
1105 | minZ = backTopRight.Z; | 876 | |
1106 | if (backTopLeft.Z < minZ) | 877 | if (frontTopRight.X > maxX) |
1107 | minZ = backTopLeft.Z; | 878 | maxX = frontTopRight.X; |
1108 | if (backBottomRight.Z < minZ) | 879 | if (frontTopLeft.X > maxX) |
1109 | minZ = backBottomRight.Z; | 880 | maxX = frontTopLeft.X; |
1110 | if (backBottomLeft.Z < minZ) | 881 | if (frontBottomRight.X > maxX) |
1111 | minZ = backBottomLeft.Z; | 882 | maxX = frontBottomRight.X; |
1112 | } | 883 | if (frontBottomLeft.X > maxX) |
884 | maxX = frontBottomLeft.X; | ||
885 | |||
886 | if (backTopRight.X > maxX) | ||
887 | maxX = backTopRight.X; | ||
888 | if (backTopLeft.X > maxX) | ||
889 | maxX = backTopLeft.X; | ||
890 | if (backBottomRight.X > maxX) | ||
891 | maxX = backBottomRight.X; | ||
892 | if (backBottomLeft.X > maxX) | ||
893 | maxX = backBottomLeft.X; | ||
894 | |||
895 | if (frontTopRight.X < minX) | ||
896 | minX = frontTopRight.X; | ||
897 | if (frontTopLeft.X < minX) | ||
898 | minX = frontTopLeft.X; | ||
899 | if (frontBottomRight.X < minX) | ||
900 | minX = frontBottomRight.X; | ||
901 | if (frontBottomLeft.X < minX) | ||
902 | minX = frontBottomLeft.X; | ||
903 | |||
904 | if (backTopRight.X < minX) | ||
905 | minX = backTopRight.X; | ||
906 | if (backTopLeft.X < minX) | ||
907 | minX = backTopLeft.X; | ||
908 | if (backBottomRight.X < minX) | ||
909 | minX = backBottomRight.X; | ||
910 | if (backBottomLeft.X < minX) | ||
911 | minX = backBottomLeft.X; | ||
912 | |||
913 | // | ||
914 | if (frontTopRight.Y > maxY) | ||
915 | maxY = frontTopRight.Y; | ||
916 | if (frontTopLeft.Y > maxY) | ||
917 | maxY = frontTopLeft.Y; | ||
918 | if (frontBottomRight.Y > maxY) | ||
919 | maxY = frontBottomRight.Y; | ||
920 | if (frontBottomLeft.Y > maxY) | ||
921 | maxY = frontBottomLeft.Y; | ||
922 | |||
923 | if (backTopRight.Y > maxY) | ||
924 | maxY = backTopRight.Y; | ||
925 | if (backTopLeft.Y > maxY) | ||
926 | maxY = backTopLeft.Y; | ||
927 | if (backBottomRight.Y > maxY) | ||
928 | maxY = backBottomRight.Y; | ||
929 | if (backBottomLeft.Y > maxY) | ||
930 | maxY = backBottomLeft.Y; | ||
931 | |||
932 | if (frontTopRight.Y < minY) | ||
933 | minY = frontTopRight.Y; | ||
934 | if (frontTopLeft.Y < minY) | ||
935 | minY = frontTopLeft.Y; | ||
936 | if (frontBottomRight.Y < minY) | ||
937 | minY = frontBottomRight.Y; | ||
938 | if (frontBottomLeft.Y < minY) | ||
939 | minY = frontBottomLeft.Y; | ||
940 | |||
941 | if (backTopRight.Y < minY) | ||
942 | minY = backTopRight.Y; | ||
943 | if (backTopLeft.Y < minY) | ||
944 | minY = backTopLeft.Y; | ||
945 | if (backBottomRight.Y < minY) | ||
946 | minY = backBottomRight.Y; | ||
947 | if (backBottomLeft.Y < minY) | ||
948 | minY = backBottomLeft.Y; | ||
949 | |||
950 | // | ||
951 | if (frontTopRight.Z > maxZ) | ||
952 | maxZ = frontTopRight.Z; | ||
953 | if (frontTopLeft.Z > maxZ) | ||
954 | maxZ = frontTopLeft.Z; | ||
955 | if (frontBottomRight.Z > maxZ) | ||
956 | maxZ = frontBottomRight.Z; | ||
957 | if (frontBottomLeft.Z > maxZ) | ||
958 | maxZ = frontBottomLeft.Z; | ||
959 | |||
960 | if (backTopRight.Z > maxZ) | ||
961 | maxZ = backTopRight.Z; | ||
962 | if (backTopLeft.Z > maxZ) | ||
963 | maxZ = backTopLeft.Z; | ||
964 | if (backBottomRight.Z > maxZ) | ||
965 | maxZ = backBottomRight.Z; | ||
966 | if (backBottomLeft.Z > maxZ) | ||
967 | maxZ = backBottomLeft.Z; | ||
968 | |||
969 | if (frontTopRight.Z < minZ) | ||
970 | minZ = frontTopRight.Z; | ||
971 | if (frontTopLeft.Z < minZ) | ||
972 | minZ = frontTopLeft.Z; | ||
973 | if (frontBottomRight.Z < minZ) | ||
974 | minZ = frontBottomRight.Z; | ||
975 | if (frontBottomLeft.Z < minZ) | ||
976 | minZ = frontBottomLeft.Z; | ||
977 | |||
978 | if (backTopRight.Z < minZ) | ||
979 | minZ = backTopRight.Z; | ||
980 | if (backTopLeft.Z < minZ) | ||
981 | minZ = backTopLeft.Z; | ||
982 | if (backBottomRight.Z < minZ) | ||
983 | minZ = backBottomRight.Z; | ||
984 | if (backBottomLeft.Z < minZ) | ||
985 | minZ = backBottomLeft.Z; | ||
1113 | } | 986 | } |
1114 | lockPartsForRead(false); | ||
1115 | } | 987 | } |
1116 | 988 | ||
1117 | public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) | 989 | public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) |
@@ -1155,21 +1027,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1155 | XmlDocument doc = new XmlDocument(); | 1027 | XmlDocument doc = new XmlDocument(); |
1156 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); | 1028 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); |
1157 | 1029 | ||
1158 | // Capture script state while holding the lock | 1030 | SceneObjectPart[] parts = m_parts.GetArray(); |
1159 | lockPartsForRead(true); | 1031 | for (int i = 0; i < parts.Length; i++) |
1160 | { | 1032 | { |
1161 | foreach (SceneObjectPart part in m_parts.Values) | 1033 | Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); |
1162 | { | 1034 | foreach (KeyValuePair<UUID, string> kvp in pstates) |
1163 | 1035 | states.Add(kvp.Key, kvp.Value); | |
1164 | Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(oldIDs); | ||
1165 | foreach (UUID itemid in pstates.Keys) | ||
1166 | { | ||
1167 | states.Add(itemid, pstates[itemid]); | ||
1168 | } | ||
1169 | |||
1170 | } | ||
1171 | } | 1036 | } |
1172 | lockPartsForRead(false); | ||
1173 | 1037 | ||
1174 | if (states.Count > 0) | 1038 | if (states.Count > 0) |
1175 | { | 1039 | { |
@@ -1255,7 +1119,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1255 | //Anakin Lohner bug #3839 | 1119 | //Anakin Lohner bug #3839 |
1256 | lock (m_parts) | 1120 | lock (m_parts) |
1257 | { | 1121 | { |
1258 | foreach (SceneObjectPart p in m_parts.Values) | 1122 | foreach (SceneObjectPart p in m_parts.GetArray()) |
1259 | { | 1123 | { |
1260 | p.AttachedAvatar = agentID; | 1124 | p.AttachedAvatar = agentID; |
1261 | } | 1125 | } |
@@ -1326,15 +1190,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1326 | 1190 | ||
1327 | AbsolutePosition = detachedpos; | 1191 | AbsolutePosition = detachedpos; |
1328 | m_rootPart.AttachedAvatar = UUID.Zero; | 1192 | m_rootPart.AttachedAvatar = UUID.Zero; |
1329 | 1193 | ||
1330 | //Anakin Lohner bug #3839 | 1194 | SceneObjectPart[] parts = m_parts.GetArray(); |
1331 | lock (m_parts) | 1195 | for (int i = 0; i < parts.Length; i++) |
1332 | { | 1196 | parts[i].AttachedAvatar = UUID.Zero; |
1333 | foreach (SceneObjectPart p in m_parts.Values) | ||
1334 | { | ||
1335 | p.AttachedAvatar = UUID.Zero; | ||
1336 | } | ||
1337 | } | ||
1338 | 1197 | ||
1339 | m_rootPart.SetParentLocalId(0); | 1198 | m_rootPart.SetParentLocalId(0); |
1340 | SetAttachmentPoint((byte)0); | 1199 | SetAttachmentPoint((byte)0); |
@@ -1359,15 +1218,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1359 | } | 1218 | } |
1360 | 1219 | ||
1361 | m_rootPart.AttachedAvatar = UUID.Zero; | 1220 | m_rootPart.AttachedAvatar = UUID.Zero; |
1362 | 1221 | ||
1363 | //Anakin Lohner bug #3839 | 1222 | SceneObjectPart[] parts = m_parts.GetArray(); |
1364 | lock (m_parts) | 1223 | for (int i = 0; i < parts.Length; i++) |
1365 | { | 1224 | parts[i].AttachedAvatar = UUID.Zero; |
1366 | foreach (SceneObjectPart p in m_parts.Values) | ||
1367 | { | ||
1368 | p.AttachedAvatar = UUID.Zero; | ||
1369 | } | ||
1370 | } | ||
1371 | 1225 | ||
1372 | m_rootPart.SetParentLocalId(0); | 1226 | m_rootPart.SetParentLocalId(0); |
1373 | //m_rootPart.SetAttachmentPoint((byte)0); | 1227 | //m_rootPart.SetAttachmentPoint((byte)0); |
@@ -1390,16 +1244,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1390 | 1244 | ||
1391 | public override void UpdateMovement() | 1245 | public override void UpdateMovement() |
1392 | { | 1246 | { |
1393 | lockPartsForRead(true); | 1247 | SceneObjectPart[] parts = m_parts.GetArray(); |
1394 | { | 1248 | for (int i = 0; i < parts.Length; i++) |
1395 | foreach (SceneObjectPart part in m_parts.Values) | 1249 | parts[i].UpdateMovement(); |
1396 | { | ||
1397 | |||
1398 | part.UpdateMovement(); | ||
1399 | |||
1400 | } | ||
1401 | } | ||
1402 | lockPartsForRead(false); | ||
1403 | } | 1250 | } |
1404 | 1251 | ||
1405 | public ushort GetTimeDilation() | 1252 | public ushort GetTimeDilation() |
@@ -1432,8 +1279,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1432 | part.ParentID = 0; | 1279 | part.ParentID = 0; |
1433 | part.LinkNum = 0; | 1280 | part.LinkNum = 0; |
1434 | 1281 | ||
1435 | lock (m_parts) | 1282 | m_parts.Add(m_rootPart.UUID, m_rootPart); |
1436 | m_parts.Add(m_rootPart.UUID, m_rootPart); | ||
1437 | } | 1283 | } |
1438 | 1284 | ||
1439 | /// <summary> | 1285 | /// <summary> |
@@ -1442,17 +1288,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1442 | /// <param name="part"></param> | 1288 | /// <param name="part"></param> |
1443 | public void AddPart(SceneObjectPart part) | 1289 | public void AddPart(SceneObjectPart part) |
1444 | { | 1290 | { |
1445 | lockPartsForWrite(true); | 1291 | part.SetParent(this); |
1446 | { | 1292 | m_parts.Add(part.UUID, part); |
1447 | part.SetParent(this); | ||
1448 | m_parts.Add(part.UUID, part); | ||
1449 | 1293 | ||
1450 | part.LinkNum = m_parts.Count; | 1294 | part.LinkNum = m_parts.Count; |
1451 | 1295 | ||
1452 | if (part.LinkNum == 2 && RootPart != null) | 1296 | if (part.LinkNum == 2 && RootPart != null) |
1453 | RootPart.LinkNum = 1; | 1297 | RootPart.LinkNum = 1; |
1454 | } | ||
1455 | lockPartsForWrite(false); | ||
1456 | } | 1298 | } |
1457 | 1299 | ||
1458 | /// <summary> | 1300 | /// <summary> |
@@ -1460,33 +1302,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1460 | /// </summary> | 1302 | /// </summary> |
1461 | private void UpdateParentIDs() | 1303 | private void UpdateParentIDs() |
1462 | { | 1304 | { |
1463 | lockPartsForRead(true); | 1305 | SceneObjectPart[] parts = m_parts.GetArray(); |
1306 | for (int i = 0; i < parts.Length; i++) | ||
1464 | { | 1307 | { |
1465 | foreach (SceneObjectPart part in m_parts.Values) | 1308 | SceneObjectPart part = parts[i]; |
1466 | { | 1309 | if (part.UUID != m_rootPart.UUID) |
1467 | 1310 | part.ParentID = m_rootPart.LocalId; | |
1468 | if (part.UUID != m_rootPart.UUID) | ||
1469 | { | ||
1470 | part.ParentID = m_rootPart.LocalId; | ||
1471 | } | ||
1472 | |||
1473 | } | ||
1474 | } | 1311 | } |
1475 | lockPartsForRead(false); | ||
1476 | } | 1312 | } |
1477 | 1313 | ||
1478 | public void RegenerateFullIDs() | 1314 | public void RegenerateFullIDs() |
1479 | { | 1315 | { |
1480 | lockPartsForRead(true); | 1316 | SceneObjectPart[] parts = m_parts.GetArray(); |
1481 | { | 1317 | for (int i = 0; i < parts.Length; i++) |
1482 | foreach (SceneObjectPart part in m_parts.Values) | 1318 | parts[i].UUID = UUID.Random(); |
1483 | { | ||
1484 | |||
1485 | part.UUID = UUID.Random(); | ||
1486 | |||
1487 | } | ||
1488 | } | ||
1489 | lockPartsForRead(false); | ||
1490 | } | 1319 | } |
1491 | 1320 | ||
1492 | // helper provided for parts. | 1321 | // helper provided for parts. |
@@ -1519,7 +1348,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1519 | 1348 | ||
1520 | // teravus: AbsolutePosition is NOT a normal property! | 1349 | // teravus: AbsolutePosition is NOT a normal property! |
1521 | // the code in the getter of AbsolutePosition is significantly different then the code in the setter! | 1350 | // the code in the getter of AbsolutePosition is significantly different then the code in the setter! |
1522 | 1351 | // jhurliman: Then why is it a property instead of two methods? | |
1523 | } | 1352 | } |
1524 | 1353 | ||
1525 | public UUID GetPartsFullID(uint localID) | 1354 | public UUID GetPartsFullID(uint localID) |
@@ -1572,18 +1401,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1572 | 1401 | ||
1573 | DetachFromBackup(); | 1402 | DetachFromBackup(); |
1574 | 1403 | ||
1575 | lockPartsForRead(true); | 1404 | SceneObjectPart[] parts = m_parts.GetArray(); |
1576 | List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values); | 1405 | for (int i = 0; i < parts.Length; i++) |
1577 | lockPartsForRead(false); | ||
1578 | |||
1579 | foreach (SceneObjectPart part in parts) | ||
1580 | { | 1406 | { |
1581 | Scene.ForEachScenePresence(delegate (ScenePresence avatar) | 1407 | SceneObjectPart part = parts[i]; |
1408 | |||
1409 | Scene.ForEachScenePresence(delegate(ScenePresence avatar) | ||
1582 | { | 1410 | { |
1583 | if (avatar.ParentID == LocalId) | 1411 | if (avatar.ParentID == LocalId) |
1584 | { | ||
1585 | avatar.StandUp(); | 1412 | avatar.StandUp(); |
1586 | } | ||
1587 | 1413 | ||
1588 | if (!silent) | 1414 | if (!silent) |
1589 | { | 1415 | { |
@@ -1619,20 +1445,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1619 | 1445 | ||
1620 | scriptEvents aggregateScriptEvents = 0; | 1446 | scriptEvents aggregateScriptEvents = 0; |
1621 | 1447 | ||
1622 | lockPartsForRead(true); | 1448 | SceneObjectPart[] parts = m_parts.GetArray(); |
1449 | for (int i = 0; i < parts.Length; i++) | ||
1623 | { | 1450 | { |
1624 | foreach (SceneObjectPart part in m_parts.Values) | 1451 | SceneObjectPart part = parts[i]; |
1625 | { | 1452 | if (part == null) |
1626 | 1453 | continue; | |
1627 | if (part == null) | 1454 | if (part != RootPart) |
1628 | continue; | 1455 | part.Flags = objectflagupdate; |
1629 | if (part != RootPart) | 1456 | aggregateScriptEvents |= part.AggregateScriptEvents; |
1630 | part.Flags = objectflagupdate; | ||
1631 | aggregateScriptEvents |= part.AggregateScriptEvents; | ||
1632 | |||
1633 | } | ||
1634 | } | 1457 | } |
1635 | lockPartsForRead(false); | ||
1636 | 1458 | ||
1637 | m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); | 1459 | m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); |
1638 | m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); | 1460 | m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); |
@@ -1674,30 +1496,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
1674 | /// <param name="m_physicalPrim"></param> | 1496 | /// <param name="m_physicalPrim"></param> |
1675 | public void ApplyPhysics(bool m_physicalPrim) | 1497 | public void ApplyPhysics(bool m_physicalPrim) |
1676 | { | 1498 | { |
1677 | lockPartsForRead(true); | 1499 | // Apply physics to the root prim |
1500 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1678 | 1501 | ||
1679 | if (m_parts.Count > 1) | 1502 | // Apply physics to child prims |
1503 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
1504 | if (parts.Length > 1) | ||
1680 | { | 1505 | { |
1681 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | 1506 | for (int i = 0; i < parts.Length; i++) |
1682 | lockPartsForRead(false); | ||
1683 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1684 | foreach (SceneObjectPart part in values) | ||
1685 | { | 1507 | { |
1686 | 1508 | SceneObjectPart part = parts[i]; | |
1687 | if (part.LocalId != m_rootPart.LocalId) | 1509 | if (part.LocalId != m_rootPart.LocalId) |
1688 | { | ||
1689 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); | 1510 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); |
1690 | } | ||
1691 | |||
1692 | } | 1511 | } |
1512 | |||
1693 | // Hack to get the physics scene geometries in the right spot | 1513 | // Hack to get the physics scene geometries in the right spot |
1694 | ResetChildPrimPhysicsPositions(); | 1514 | ResetChildPrimPhysicsPositions(); |
1695 | } | 1515 | } |
1696 | else | ||
1697 | { | ||
1698 | lockPartsForRead(false); | ||
1699 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1700 | } | ||
1701 | } | 1516 | } |
1702 | 1517 | ||
1703 | public void SetOwnerId(UUID userId) | 1518 | public void SetOwnerId(UUID userId) |
@@ -1712,15 +1527,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1712 | 1527 | ||
1713 | public void ForEachPart(Action<SceneObjectPart> whatToDo) | 1528 | public void ForEachPart(Action<SceneObjectPart> whatToDo) |
1714 | { | 1529 | { |
1715 | lockPartsForRead(true); | 1530 | SceneObjectPart[] parts = m_parts.GetArray(); |
1716 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | 1531 | for (int i = 0; i < parts.Length; i++) |
1717 | lockPartsForRead(false); | 1532 | whatToDo(parts[i]); |
1718 | foreach (SceneObjectPart part in values) | ||
1719 | { | ||
1720 | |||
1721 | whatToDo(part); | ||
1722 | |||
1723 | } | ||
1724 | } | 1533 | } |
1725 | 1534 | ||
1726 | #region Events | 1535 | #region Events |
@@ -1790,7 +1599,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1790 | // Possible ghost prim | 1599 | // Possible ghost prim |
1791 | if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition) | 1600 | if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition) |
1792 | { | 1601 | { |
1793 | foreach (SceneObjectPart part in Children.Values) | 1602 | foreach (SceneObjectPart part in m_parts.GetArray()) |
1794 | { | 1603 | { |
1795 | // Re-set physics actor positions and | 1604 | // Re-set physics actor positions and |
1796 | // orientations | 1605 | // orientations |
@@ -1842,17 +1651,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1842 | RootPart.SendFullUpdate( | 1651 | RootPart.SendFullUpdate( |
1843 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); | 1652 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); |
1844 | 1653 | ||
1845 | lockPartsForRead(true); | 1654 | SceneObjectPart[] parts = m_parts.GetArray(); |
1655 | for (int i = 0; i < parts.Length; i++) | ||
1846 | { | 1656 | { |
1847 | foreach (SceneObjectPart part in m_parts.Values) | 1657 | SceneObjectPart part = parts[i]; |
1848 | { | 1658 | if (part != RootPart) |
1849 | 1659 | part.SendFullUpdate(remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); | |
1850 | if (part != RootPart) | ||
1851 | part.SendFullUpdate( | ||
1852 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); | ||
1853 | } | ||
1854 | } | 1660 | } |
1855 | lockPartsForRead(false); | ||
1856 | } | 1661 | } |
1857 | 1662 | ||
1858 | #region Copying | 1663 | #region Copying |
@@ -1870,7 +1675,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1870 | m_dupeInProgress = true; | 1675 | m_dupeInProgress = true; |
1871 | dupe = (SceneObjectGroup)MemberwiseClone(); | 1676 | dupe = (SceneObjectGroup)MemberwiseClone(); |
1872 | dupe.m_isBackedUp = false; | 1677 | dupe.m_isBackedUp = false; |
1873 | dupe.m_parts = new Dictionary<UUID, SceneObjectPart>(); | 1678 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); |
1874 | 1679 | ||
1875 | // Warning, The following code related to previousAttachmentStatus is needed so that clones of | 1680 | // Warning, The following code related to previousAttachmentStatus is needed so that clones of |
1876 | // attachments do not bordercross while they're being duplicated. This is hacktastic! | 1681 | // attachments do not bordercross while they're being duplicated. This is hacktastic! |
@@ -1916,13 +1721,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1916 | dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true); | 1721 | dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true); |
1917 | } | 1722 | } |
1918 | 1723 | ||
1919 | lockPartsForRead(true); | 1724 | List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); |
1920 | |||
1921 | List<SceneObjectPart> partList; | ||
1922 | |||
1923 | partList = new List<SceneObjectPart>(m_parts.Values); | ||
1924 | |||
1925 | lockPartsForRead(false); | ||
1926 | 1725 | ||
1927 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) | 1726 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) |
1928 | { | 1727 | { |
@@ -2261,14 +2060,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2261 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); | 2060 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); |
2262 | newPart.SetParent(this); | 2061 | newPart.SetParent(this); |
2263 | 2062 | ||
2264 | lockPartsForWrite(true); | 2063 | AddPart(newPart); |
2265 | { | ||
2266 | m_parts.Add(newPart.UUID, newPart); | ||
2267 | } | ||
2268 | lockPartsForWrite(false); | ||
2269 | 2064 | ||
2270 | SetPartAsNonRoot(newPart); | 2065 | SetPartAsNonRoot(newPart); |
2271 | |||
2272 | return newPart; | 2066 | return newPart; |
2273 | } | 2067 | } |
2274 | 2068 | ||
@@ -2280,9 +2074,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2280 | /// </summary> | 2074 | /// </summary> |
2281 | public void ResetIDs() | 2075 | public void ResetIDs() |
2282 | { | 2076 | { |
2283 | lock (m_parts) | 2077 | lock (m_parts.SyncRoot) |
2284 | { | 2078 | { |
2285 | List<SceneObjectPart> partsList = new List<SceneObjectPart>(m_parts.Values); | 2079 | List<SceneObjectPart> partsList = new List<SceneObjectPart>(m_parts.GetArray()); |
2286 | m_parts.Clear(); | 2080 | m_parts.Clear(); |
2287 | foreach (SceneObjectPart part in partsList) | 2081 | foreach (SceneObjectPart part in partsList) |
2288 | { | 2082 | { |
@@ -2298,7 +2092,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2298 | /// <param name="part"></param> | 2092 | /// <param name="part"></param> |
2299 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) | 2093 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) |
2300 | { | 2094 | { |
2301 | |||
2302 | remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, | 2095 | remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, |
2303 | RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, | 2096 | RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, |
2304 | RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | 2097 | RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, |
@@ -2329,8 +2122,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2329 | //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) | 2122 | //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) |
2330 | // return; | 2123 | // return; |
2331 | 2124 | ||
2332 | lockPartsForRead(true); | ||
2333 | |||
2334 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 2125 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); |
2335 | 2126 | ||
2336 | if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) | 2127 | if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) |
@@ -2345,16 +2136,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2345 | lastPhysGroupRot = GroupRotation; | 2136 | lastPhysGroupRot = GroupRotation; |
2346 | } | 2137 | } |
2347 | 2138 | ||
2348 | List<SceneObjectPart> partList = null; | 2139 | SceneObjectPart[] parts = m_parts.GetArray(); |
2349 | partList = new List<SceneObjectPart>(m_parts.Values); | 2140 | for (int i = 0; i < parts.Length; i++) |
2350 | |||
2351 | foreach (SceneObjectPart part in partList) | ||
2352 | { | 2141 | { |
2142 | SceneObjectPart part = parts[i]; | ||
2353 | if (!IsSelected) | 2143 | if (!IsSelected) |
2354 | part.UpdateLookAt(); | 2144 | part.UpdateLookAt(); |
2355 | part.SendScheduledUpdates(); | 2145 | part.SendScheduledUpdates(); |
2356 | } | 2146 | } |
2357 | lockPartsForRead(false); | ||
2358 | } | 2147 | } |
2359 | 2148 | ||
2360 | public void ScheduleFullUpdateToAvatar(ScenePresence presence) | 2149 | public void ScheduleFullUpdateToAvatar(ScenePresence presence) |
@@ -2363,29 +2152,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
2363 | 2152 | ||
2364 | RootPart.AddFullUpdateToAvatar(presence); | 2153 | RootPart.AddFullUpdateToAvatar(presence); |
2365 | 2154 | ||
2366 | lockPartsForRead(true); | 2155 | SceneObjectPart[] parts = m_parts.GetArray(); |
2156 | for (int i = 0; i < parts.Length; i++) | ||
2367 | { | 2157 | { |
2368 | foreach (SceneObjectPart part in m_parts.Values) | 2158 | SceneObjectPart part = parts[i]; |
2369 | { | 2159 | if (part != RootPart) |
2370 | 2160 | part.AddFullUpdateToAvatar(presence); | |
2371 | if (part != RootPart) | ||
2372 | part.AddFullUpdateToAvatar(presence); | ||
2373 | |||
2374 | } | ||
2375 | } | 2161 | } |
2376 | lockPartsForRead(false); | ||
2377 | } | 2162 | } |
2378 | 2163 | ||
2379 | public void ScheduleTerseUpdateToAvatar(ScenePresence presence) | 2164 | public void ScheduleTerseUpdateToAvatar(ScenePresence presence) |
2380 | { | 2165 | { |
2381 | lockPartsForRead(true); | 2166 | // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); |
2382 | |||
2383 | foreach (SceneObjectPart part in m_parts.Values) | ||
2384 | { | ||
2385 | part.AddTerseUpdateToAvatar(presence); | ||
2386 | } | ||
2387 | 2167 | ||
2388 | lockPartsForRead(false); | 2168 | SceneObjectPart[] parts = m_parts.GetArray(); |
2169 | for (int i = 0; i < parts.Length; i++) | ||
2170 | parts[i].AddTerseUpdateToAvatar(presence); | ||
2389 | } | 2171 | } |
2390 | 2172 | ||
2391 | /// <summary> | 2173 | /// <summary> |
@@ -2399,17 +2181,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2399 | checkAtTargets(); | 2181 | checkAtTargets(); |
2400 | RootPart.ScheduleFullUpdate(); | 2182 | RootPart.ScheduleFullUpdate(); |
2401 | 2183 | ||
2402 | lockPartsForRead(true); | 2184 | SceneObjectPart[] parts = m_parts.GetArray(); |
2185 | for (int i = 0; i < parts.Length; i++) | ||
2403 | { | 2186 | { |
2404 | foreach (SceneObjectPart part in m_parts.Values) | 2187 | SceneObjectPart part = parts[i]; |
2405 | { | 2188 | if (part != RootPart) |
2406 | 2189 | part.ScheduleFullUpdate(); | |
2407 | if (part != RootPart) | ||
2408 | part.ScheduleFullUpdate(); | ||
2409 | |||
2410 | } | ||
2411 | } | 2190 | } |
2412 | lockPartsForRead(false); | ||
2413 | } | 2191 | } |
2414 | 2192 | ||
2415 | /// <summary> | 2193 | /// <summary> |
@@ -2417,13 +2195,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2417 | /// </summary> | 2195 | /// </summary> |
2418 | public void ScheduleGroupForTerseUpdate() | 2196 | public void ScheduleGroupForTerseUpdate() |
2419 | { | 2197 | { |
2420 | lockPartsForRead(true); | 2198 | // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); |
2421 | foreach (SceneObjectPart part in m_parts.Values) | ||
2422 | { | ||
2423 | part.ScheduleTerseUpdate(); | ||
2424 | } | ||
2425 | 2199 | ||
2426 | lockPartsForRead(false); | 2200 | SceneObjectPart[] parts = m_parts.GetArray(); |
2201 | for (int i = 0; i < parts.Length; i++) | ||
2202 | parts[i].ScheduleTerseUpdate(); | ||
2427 | } | 2203 | } |
2428 | 2204 | ||
2429 | /// <summary> | 2205 | /// <summary> |
@@ -2438,17 +2214,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2438 | 2214 | ||
2439 | RootPart.SendFullUpdateToAllClients(); | 2215 | RootPart.SendFullUpdateToAllClients(); |
2440 | 2216 | ||
2441 | lockPartsForRead(true); | 2217 | SceneObjectPart[] parts = m_parts.GetArray(); |
2218 | for (int i = 0; i < parts.Length; i++) | ||
2442 | { | 2219 | { |
2443 | foreach (SceneObjectPart part in m_parts.Values) | 2220 | SceneObjectPart part = parts[i]; |
2444 | { | 2221 | if (part != RootPart) |
2445 | 2222 | part.SendFullUpdateToAllClients(); | |
2446 | if (part != RootPart) | ||
2447 | part.SendFullUpdateToAllClients(); | ||
2448 | |||
2449 | } | ||
2450 | } | 2223 | } |
2451 | lockPartsForRead(false); | ||
2452 | } | 2224 | } |
2453 | 2225 | ||
2454 | /// <summary> | 2226 | /// <summary> |
@@ -2481,14 +2253,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2481 | if (IsDeleted) | 2253 | if (IsDeleted) |
2482 | return; | 2254 | return; |
2483 | 2255 | ||
2484 | lockPartsForRead(true); | 2256 | SceneObjectPart[] parts = m_parts.GetArray(); |
2485 | { | 2257 | for (int i = 0; i < parts.Length; i++) |
2486 | foreach (SceneObjectPart part in m_parts.Values) | 2258 | parts[i].SendTerseUpdateToAllClients(); |
2487 | { | ||
2488 | part.SendTerseUpdateToAllClients(); | ||
2489 | } | ||
2490 | } | ||
2491 | lockPartsForRead(false); | ||
2492 | } | 2259 | } |
2493 | 2260 | ||
2494 | #endregion | 2261 | #endregion |
@@ -2502,18 +2269,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2502 | /// <returns>null if no child part with that linknum or child part</returns> | 2269 | /// <returns>null if no child part with that linknum or child part</returns> |
2503 | public SceneObjectPart GetLinkNumPart(int linknum) | 2270 | public SceneObjectPart GetLinkNumPart(int linknum) |
2504 | { | 2271 | { |
2505 | lockPartsForRead(true); | 2272 | SceneObjectPart[] parts = m_parts.GetArray(); |
2273 | for (int i = 0; i < parts.Length; i++) | ||
2506 | { | 2274 | { |
2507 | foreach (SceneObjectPart part in m_parts.Values) | 2275 | if (parts[i].LinkNum == linknum) |
2508 | { | 2276 | return parts[i]; |
2509 | if (part.LinkNum == linknum) | ||
2510 | { | ||
2511 | lockPartsForRead(false); | ||
2512 | return part; | ||
2513 | } | ||
2514 | } | ||
2515 | } | 2277 | } |
2516 | lockPartsForRead(false); | ||
2517 | 2278 | ||
2518 | return null; | 2279 | return null; |
2519 | } | 2280 | } |
@@ -2526,8 +2287,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2526 | public SceneObjectPart GetChildPart(UUID primID) | 2287 | public SceneObjectPart GetChildPart(UUID primID) |
2527 | { | 2288 | { |
2528 | SceneObjectPart childPart; | 2289 | SceneObjectPart childPart; |
2529 | lock (m_parts) | 2290 | m_parts.TryGetValue(primID, out childPart); |
2530 | m_parts.TryGetValue(primID, out childPart); | ||
2531 | return childPart; | 2291 | return childPart; |
2532 | } | 2292 | } |
2533 | 2293 | ||
@@ -2538,20 +2298,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2538 | /// <returns>null if a child part with the local ID was not found</returns> | 2298 | /// <returns>null if a child part with the local ID was not found</returns> |
2539 | public SceneObjectPart GetChildPart(uint localID) | 2299 | public SceneObjectPart GetChildPart(uint localID) |
2540 | { | 2300 | { |
2541 | //m_log.DebugFormat("Entered looking for {0}", localID); | 2301 | SceneObjectPart[] parts = m_parts.GetArray(); |
2542 | lockPartsForRead(true); | 2302 | for (int i = 0; i < parts.Length; i++) |
2543 | { | 2303 | { |
2544 | foreach (SceneObjectPart part in m_parts.Values) | 2304 | if (parts[i].LocalId == localID) |
2545 | { | 2305 | return parts[i]; |
2546 | //m_log.DebugFormat("Found {0}", part.LocalId); | ||
2547 | if (part.LocalId == localID) | ||
2548 | { | ||
2549 | lockPartsForRead(false); | ||
2550 | return part; | ||
2551 | } | ||
2552 | } | ||
2553 | } | 2306 | } |
2554 | lockPartsForRead(false); | ||
2555 | 2307 | ||
2556 | return null; | 2308 | return null; |
2557 | } | 2309 | } |
@@ -2564,13 +2316,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2564 | /// <returns></returns> | 2316 | /// <returns></returns> |
2565 | public bool HasChildPrim(UUID primID) | 2317 | public bool HasChildPrim(UUID primID) |
2566 | { | 2318 | { |
2567 | lock (m_parts) | 2319 | return m_parts.ContainsKey(primID); |
2568 | { | ||
2569 | if (m_parts.ContainsKey(primID)) | ||
2570 | return true; | ||
2571 | } | ||
2572 | |||
2573 | return false; | ||
2574 | } | 2320 | } |
2575 | 2321 | ||
2576 | /// <summary> | 2322 | /// <summary> |
@@ -2581,20 +2327,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2581 | /// <returns></returns> | 2327 | /// <returns></returns> |
2582 | public bool HasChildPrim(uint localID) | 2328 | public bool HasChildPrim(uint localID) |
2583 | { | 2329 | { |
2584 | //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); | 2330 | SceneObjectPart[] parts = m_parts.GetArray(); |
2585 | lockPartsForRead(true); | 2331 | for (int i = 0; i < parts.Length; i++) |
2586 | { | 2332 | { |
2587 | foreach (SceneObjectPart part in m_parts.Values) | 2333 | if (parts[i].LocalId == localID) |
2588 | { | 2334 | return true; |
2589 | //m_log.DebugFormat("Found {0}", part.LocalId); | ||
2590 | if (part.LocalId == localID) | ||
2591 | { | ||
2592 | lockPartsForRead(false); | ||
2593 | return true; | ||
2594 | } | ||
2595 | } | ||
2596 | } | 2335 | } |
2597 | lockPartsForRead(false); | ||
2598 | 2336 | ||
2599 | return false; | 2337 | return false; |
2600 | } | 2338 | } |
@@ -2644,58 +2382,56 @@ namespace OpenSim.Region.Framework.Scenes | |||
2644 | if (m_rootPart.LinkNum == 0) | 2382 | if (m_rootPart.LinkNum == 0) |
2645 | m_rootPart.LinkNum = 1; | 2383 | m_rootPart.LinkNum = 1; |
2646 | 2384 | ||
2647 | lockPartsForWrite(true); | 2385 | lock (m_parts.SyncRoot) |
2648 | |||
2649 | m_parts.Add(linkPart.UUID, linkPart); | ||
2650 | |||
2651 | lockPartsForWrite(false); | ||
2652 | |||
2653 | // Insert in terms of link numbers, the new links | ||
2654 | // before the current ones (with the exception of | ||
2655 | // the root prim. Shuffle the old ones up | ||
2656 | lockPartsForRead(true); | ||
2657 | foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) | ||
2658 | { | 2386 | { |
2659 | if (kvp.Value.LinkNum != 1) | 2387 | m_parts.Add(linkPart.UUID, linkPart); |
2388 | |||
2389 | // Insert in terms of link numbers, the new links | ||
2390 | // before the current ones (with the exception of | ||
2391 | // the root prim. Shuffle the old ones up | ||
2392 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
2393 | for (int i = 0; i < parts.Length; i++) | ||
2660 | { | 2394 | { |
2661 | // Don't update root prim link number | 2395 | SceneObjectPart part = parts[i]; |
2662 | kvp.Value.LinkNum += objectGroup.PrimCount; | 2396 | if (part.LinkNum != 1) |
2397 | { | ||
2398 | // Don't update root prim link number | ||
2399 | part.LinkNum += objectGroup.PrimCount; | ||
2400 | } | ||
2663 | } | 2401 | } |
2664 | } | 2402 | } |
2665 | lockPartsForRead(false); | ||
2666 | 2403 | ||
2667 | linkPart.LinkNum = 2; | 2404 | linkPart.LinkNum = 2; |
2668 | 2405 | ||
2669 | linkPart.SetParent(this); | 2406 | linkPart.SetParent(this); |
2670 | linkPart.CreateSelected = true; | 2407 | linkPart.CreateSelected = true; |
2671 | 2408 | ||
2672 | //if (linkPart.PhysActor != null) | 2409 | lock (m_parts.SyncRoot) |
2673 | //{ | ||
2674 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); | ||
2675 | |||
2676 | //linkPart.PhysActor = null; | ||
2677 | //} | ||
2678 | |||
2679 | //TODO: rest of parts | ||
2680 | int linkNum = 3; | ||
2681 | foreach (SceneObjectPart part in objectGroup.Children.Values) | ||
2682 | { | 2410 | { |
2683 | if (part.UUID != objectGroup.m_rootPart.UUID) | 2411 | //if (linkPart.PhysActor != null) |
2412 | //{ | ||
2413 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); | ||
2414 | |||
2415 | //linkPart.PhysActor = null; | ||
2416 | //} | ||
2417 | |||
2418 | //TODO: rest of parts | ||
2419 | int linkNum = 3; | ||
2420 | SceneObjectPart[] ogParts = objectGroup.Parts; | ||
2421 | for (int i = 0; i < ogParts.Length; i++) | ||
2684 | { | 2422 | { |
2685 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | 2423 | SceneObjectPart part = ogParts[i]; |
2424 | if (part.UUID != objectGroup.m_rootPart.UUID) | ||
2425 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | ||
2426 | part.ClearUndoState(); | ||
2686 | } | 2427 | } |
2687 | part.ClearUndoState(); | ||
2688 | } | 2428 | } |
2689 | 2429 | ||
2690 | m_scene.UnlinkSceneObject(objectGroup, true); | 2430 | m_scene.UnlinkSceneObject(objectGroup, true); |
2691 | objectGroup.m_isDeleted = true; | 2431 | objectGroup.m_isDeleted = true; |
2692 | 2432 | ||
2693 | objectGroup.lockPartsForWrite(true); | ||
2694 | |||
2695 | objectGroup.m_parts.Clear(); | 2433 | objectGroup.m_parts.Clear(); |
2696 | 2434 | ||
2697 | objectGroup.lockPartsForWrite(false); | ||
2698 | |||
2699 | // Can't do this yet since backup still makes use of the root part without any synchronization | 2435 | // Can't do this yet since backup still makes use of the root part without any synchronization |
2700 | // objectGroup.m_rootPart = null; | 2436 | // objectGroup.m_rootPart = null; |
2701 | 2437 | ||
@@ -2764,23 +2500,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
2764 | Quaternion worldRot = linkPart.GetWorldRotation(); | 2500 | Quaternion worldRot = linkPart.GetWorldRotation(); |
2765 | 2501 | ||
2766 | // Remove the part from this object | 2502 | // Remove the part from this object |
2767 | lockPartsForWrite(true); | 2503 | lock (m_parts.SyncRoot) |
2768 | { | 2504 | { |
2769 | m_parts.Remove(linkPart.UUID); | 2505 | m_parts.Remove(linkPart.UUID); |
2770 | } | 2506 | |
2771 | lockPartsForWrite(false); | 2507 | SceneObjectPart[] parts = m_parts.GetArray(); |
2772 | lockPartsForRead(true); | 2508 | |
2773 | if (m_parts.Count == 1 && RootPart != null) //Single prim is left | 2509 | if (parts.Length == 1 && RootPart != null) |
2774 | RootPart.LinkNum = 0; | ||
2775 | else | ||
2776 | { | ||
2777 | foreach (SceneObjectPart p in m_parts.Values) | ||
2778 | { | 2510 | { |
2779 | if (p.LinkNum > linkPart.LinkNum) | 2511 | // Single prim left |
2780 | p.LinkNum--; | 2512 | RootPart.LinkNum = 0; |
2513 | } | ||
2514 | else | ||
2515 | { | ||
2516 | for (int i = 0; i < parts.Length; i++) | ||
2517 | { | ||
2518 | SceneObjectPart part = parts[i]; | ||
2519 | if (part.LinkNum > linkPart.LinkNum) | ||
2520 | part.LinkNum--; | ||
2521 | } | ||
2781 | } | 2522 | } |
2782 | } | 2523 | } |
2783 | lockPartsForRead(false); | ||
2784 | 2524 | ||
2785 | linkPart.ParentID = 0; | 2525 | linkPart.ParentID = 0; |
2786 | linkPart.LinkNum = 0; | 2526 | linkPart.LinkNum = 0; |
@@ -2851,7 +2591,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2851 | part.SetParent(this); | 2591 | part.SetParent(this); |
2852 | part.ParentID = m_rootPart.LocalId; | 2592 | part.ParentID = m_rootPart.LocalId; |
2853 | 2593 | ||
2854 | // Caller locks m_parts for us | ||
2855 | m_parts.Add(part.UUID, part); | 2594 | m_parts.Add(part.UUID, part); |
2856 | 2595 | ||
2857 | part.LinkNum = linkNum; | 2596 | part.LinkNum = linkNum; |
@@ -3104,28 +2843,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
3104 | 2843 | ||
3105 | if (selectionPart != null) | 2844 | if (selectionPart != null) |
3106 | { | 2845 | { |
3107 | lockPartsForRead(true); | 2846 | SceneObjectPart[] parts = m_parts.GetArray(); |
3108 | List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values); | 2847 | for (int i = 0; i < parts.Length; i++) |
3109 | lockPartsForRead(false); | ||
3110 | foreach (SceneObjectPart part in parts) | ||
3111 | { | 2848 | { |
3112 | if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0) | 2849 | SceneObjectPart part = parts[i]; |
2850 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || | ||
2851 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || | ||
2852 | part.Scale.Z > m_scene.RegionInfo.PhysPrimMax) | ||
3113 | { | 2853 | { |
3114 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || | 2854 | UsePhysics = false; // Reset physics |
3115 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || | 2855 | break; |
3116 | part.Scale.Z > m_scene.RegionInfo.PhysPrimMax) | ||
3117 | { | ||
3118 | UsePhysics = false; // Reset physics | ||
3119 | break; | ||
3120 | } | ||
3121 | } | 2856 | } |
3122 | } | 2857 | } |
3123 | 2858 | ||
3124 | foreach (SceneObjectPart part in parts) | 2859 | for (int i = 0; i < parts.Length; i++) |
3125 | { | 2860 | parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
3126 | part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | ||
3127 | } | ||
3128 | |||
3129 | } | 2861 | } |
3130 | } | 2862 | } |
3131 | 2863 | ||
@@ -3146,19 +2878,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3146 | /// <returns></returns> | 2878 | /// <returns></returns> |
3147 | public int GetPartCount() | 2879 | public int GetPartCount() |
3148 | { | 2880 | { |
3149 | return Children.Count; | 2881 | return Parts.Count(); |
3150 | } | ||
3151 | |||
3152 | /// <summary> | ||
3153 | /// Get the parts of this scene object | ||
3154 | /// </summary> | ||
3155 | /// <returns></returns> | ||
3156 | public SceneObjectPart[] GetParts() | ||
3157 | { | ||
3158 | int numParts = Children.Count; | ||
3159 | SceneObjectPart[] partArray = new SceneObjectPart[numParts]; | ||
3160 | Children.Values.CopyTo(partArray, 0); | ||
3161 | return partArray; | ||
3162 | } | 2882 | } |
3163 | 2883 | ||
3164 | /// <summary> | 2884 | /// <summary> |
@@ -3178,12 +2898,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3178 | public void UpdatePermissions(UUID AgentID, byte field, uint localID, | 2898 | public void UpdatePermissions(UUID AgentID, byte field, uint localID, |
3179 | uint mask, byte addRemTF) | 2899 | uint mask, byte addRemTF) |
3180 | { | 2900 | { |
3181 | List<SceneObjectPart> partList = null; | 2901 | SceneObjectPart[] parts = m_parts.GetArray(); |
3182 | lock (m_parts) | 2902 | for (int i = 0; i < parts.Length; i++) |
3183 | partList = new List<SceneObjectPart>(m_parts.Values); | 2903 | parts[i].UpdatePermissions(AgentID, field, localID, mask, addRemTF); |
3184 | |||
3185 | foreach (SceneObjectPart part in partList) | ||
3186 | part.UpdatePermissions(AgentID, field, localID, mask, addRemTF); | ||
3187 | 2904 | ||
3188 | HasGroupChanged = true; | 2905 | HasGroupChanged = true; |
3189 | } | 2906 | } |
@@ -3283,15 +3000,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
3283 | float y = (scale.Y / part.Scale.Y); | 3000 | float y = (scale.Y / part.Scale.Y); |
3284 | float z = (scale.Z / part.Scale.Z); | 3001 | float z = (scale.Z / part.Scale.Z); |
3285 | 3002 | ||
3286 | lockPartsForRead(true); | 3003 | SceneObjectPart[] parts; |
3287 | if (x > 1.0f || y > 1.0f || z > 1.0f) | 3004 | if (x > 1.0f || y > 1.0f || z > 1.0f) |
3288 | { | 3005 | { |
3289 | foreach (SceneObjectPart obPart in m_parts.Values) | 3006 | parts = m_parts.GetArray(); |
3007 | for (int i = 0; i < parts.Length; i++) | ||
3290 | { | 3008 | { |
3009 | SceneObjectPart obPart = parts[i]; | ||
3291 | if (obPart.UUID != m_rootPart.UUID) | 3010 | if (obPart.UUID != m_rootPart.UUID) |
3292 | { | 3011 | { |
3293 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
3294 | obPart.IgnoreUndoUpdate = true; | 3012 | obPart.IgnoreUndoUpdate = true; |
3013 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
3295 | 3014 | ||
3296 | float f = 1.0f; | 3015 | float f = 1.0f; |
3297 | float a = 1.0f; | 3016 | float a = 1.0f; |
@@ -3349,12 +3068,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3349 | y *= a; | 3068 | y *= a; |
3350 | z *= a; | 3069 | z *= a; |
3351 | } | 3070 | } |
3352 | |||
3353 | } | 3071 | } |
3072 | obPart.IgnoreUndoUpdate = false; | ||
3354 | } | 3073 | } |
3355 | } | 3074 | } |
3356 | } | 3075 | } |
3357 | lockPartsForRead(false); | ||
3358 | 3076 | ||
3359 | Vector3 prevScale = part.Scale; | 3077 | Vector3 prevScale = part.Scale; |
3360 | prevScale.X *= x; | 3078 | prevScale.X *= x; |
@@ -3367,9 +3085,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3367 | part.Resize(prevScale); | 3085 | part.Resize(prevScale); |
3368 | part.IgnoreUndoUpdate = false; | 3086 | part.IgnoreUndoUpdate = false; |
3369 | 3087 | ||
3370 | lockPartsForRead(true); | 3088 | parts = m_parts.GetArray(); |
3089 | for (int i = 0; i < parts.Length; i++) | ||
3371 | { | 3090 | { |
3372 | foreach (SceneObjectPart obPart in m_parts.Values) | 3091 | SceneObjectPart obPart = parts[i]; |
3092 | obPart.IgnoreUndoUpdate = true; | ||
3093 | if (obPart.UUID != m_rootPart.UUID) | ||
3373 | { | 3094 | { |
3374 | if (obPart.UUID != m_rootPart.UUID) | 3095 | if (obPart.UUID != m_rootPart.UUID) |
3375 | { | 3096 | { |
@@ -3390,8 +3111,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3390 | } | 3111 | } |
3391 | obPart.IgnoreUndoUpdate = false; | 3112 | obPart.IgnoreUndoUpdate = false; |
3392 | } | 3113 | } |
3114 | obPart.IgnoreUndoUpdate = false; | ||
3393 | } | 3115 | } |
3394 | lockPartsForRead(false); | ||
3395 | 3116 | ||
3396 | if (part.PhysActor != null) | 3117 | if (part.PhysActor != null) |
3397 | { | 3118 | { |
@@ -3450,10 +3171,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3450 | public void UpdateSinglePosition(Vector3 pos, uint localID) | 3171 | public void UpdateSinglePosition(Vector3 pos, uint localID) |
3451 | { | 3172 | { |
3452 | SceneObjectPart part = GetChildPart(localID); | 3173 | SceneObjectPart part = GetChildPart(localID); |
3453 | foreach (SceneObjectPart parts in Children.Values) | 3174 | |
3454 | { | 3175 | SceneObjectPart[] parts = m_parts.GetArray(); |
3455 | parts.StoreUndoState(UndoType.STATE_PRIM_POSITION); | 3176 | for (int i = 0; i < parts.Length; i++) |
3456 | } | 3177 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); |
3178 | |||
3457 | if (part != null) | 3179 | if (part != null) |
3458 | { | 3180 | { |
3459 | if (part.UUID == m_rootPart.UUID) | 3181 | if (part.UUID == m_rootPart.UUID) |
@@ -3475,10 +3197,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3475 | /// <param name="pos"></param> | 3197 | /// <param name="pos"></param> |
3476 | private void UpdateRootPosition(Vector3 pos) | 3198 | private void UpdateRootPosition(Vector3 pos) |
3477 | { | 3199 | { |
3478 | foreach (SceneObjectPart part in Children.Values) | 3200 | SceneObjectPart[] parts = m_parts.GetArray(); |
3479 | { | 3201 | for (int i = 0; i < parts.Length; i++) |
3480 | part.StoreUndoState(UndoType.STATE_PRIM_POSITION); | 3202 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); |
3481 | } | 3203 | |
3482 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | 3204 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); |
3483 | Vector3 oldPos = | 3205 | Vector3 oldPos = |
3484 | new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, | 3206 | new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, |
@@ -3490,17 +3212,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3490 | axDiff *= Quaternion.Inverse(partRotation); | 3212 | axDiff *= Quaternion.Inverse(partRotation); |
3491 | diff = axDiff; | 3213 | diff = axDiff; |
3492 | 3214 | ||
3493 | lockPartsForRead(true); | 3215 | parts = m_parts.GetArray(); |
3216 | for (int i = 0; i < parts.Length; i++) | ||
3494 | { | 3217 | { |
3495 | foreach (SceneObjectPart obPart in m_parts.Values) | 3218 | SceneObjectPart obPart = parts[i]; |
3496 | { | 3219 | if (obPart.UUID != m_rootPart.UUID) |
3497 | if (obPart.UUID != m_rootPart.UUID) | 3220 | obPart.OffsetPosition = obPart.OffsetPosition + diff; |
3498 | { | ||
3499 | obPart.OffsetPosition = obPart.OffsetPosition + diff; | ||
3500 | } | ||
3501 | } | ||
3502 | } | 3221 | } |
3503 | lockPartsForRead(false); | ||
3504 | 3222 | ||
3505 | //We have to set undoing here because otherwise an undo state will be saved | 3223 | //We have to set undoing here because otherwise an undo state will be saved |
3506 | if (!m_rootPart.Undoing) | 3224 | if (!m_rootPart.Undoing) |
@@ -3540,10 +3258,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3540 | /// <param name="rot"></param> | 3258 | /// <param name="rot"></param> |
3541 | public void UpdateGroupRotationR(Quaternion rot) | 3259 | public void UpdateGroupRotationR(Quaternion rot) |
3542 | { | 3260 | { |
3543 | foreach (SceneObjectPart parts in Children.Values) | 3261 | SceneObjectPart[] parts = m_parts.GetArray(); |
3544 | { | 3262 | for (int i = 0; i < parts.Length; i++) |
3545 | parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION); | 3263 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
3546 | } | 3264 | |
3547 | m_rootPart.UpdateRotation(rot); | 3265 | m_rootPart.UpdateRotation(rot); |
3548 | 3266 | ||
3549 | PhysicsActor actor = m_rootPart.PhysActor; | 3267 | PhysicsActor actor = m_rootPart.PhysActor; |
@@ -3564,10 +3282,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3564 | /// <param name="rot"></param> | 3282 | /// <param name="rot"></param> |
3565 | public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) | 3283 | public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) |
3566 | { | 3284 | { |
3567 | foreach (SceneObjectPart parts in Children.Values) | 3285 | SceneObjectPart[] parts = m_parts.GetArray(); |
3568 | { | 3286 | for (int i = 0; i < parts.Length; i++) |
3569 | parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION); | 3287 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
3570 | } | 3288 | |
3571 | m_rootPart.UpdateRotation(rot); | 3289 | m_rootPart.UpdateRotation(rot); |
3572 | 3290 | ||
3573 | PhysicsActor actor = m_rootPart.PhysActor; | 3291 | PhysicsActor actor = m_rootPart.PhysActor; |
@@ -3591,10 +3309,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3591 | public void UpdateSingleRotation(Quaternion rot, uint localID) | 3309 | public void UpdateSingleRotation(Quaternion rot, uint localID) |
3592 | { | 3310 | { |
3593 | SceneObjectPart part = GetChildPart(localID); | 3311 | SceneObjectPart part = GetChildPart(localID); |
3594 | foreach (SceneObjectPart parts in Children.Values) | 3312 | SceneObjectPart[] parts = m_parts.GetArray(); |
3595 | { | 3313 | for (int i = 0; i < parts.Length; i++) |
3596 | parts.StoreUndoState(UndoType.STATE_PRIM_ROTATION); | 3314 | parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION); |
3597 | } | 3315 | |
3598 | if (part != null) | 3316 | if (part != null) |
3599 | { | 3317 | { |
3600 | if (part.UUID == m_rootPart.UUID) | 3318 | if (part.UUID == m_rootPart.UUID) |
@@ -3666,10 +3384,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3666 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | 3384 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); |
3667 | } | 3385 | } |
3668 | 3386 | ||
3669 | lockPartsForRead(true); | 3387 | SceneObjectPart[] parts = m_parts.GetArray(); |
3670 | 3388 | for (int i = 0; i < parts.Length; i++) | |
3671 | foreach (SceneObjectPart prim in m_parts.Values) | ||
3672 | { | 3389 | { |
3390 | SceneObjectPart prim = parts[i]; | ||
3673 | if (prim.UUID != m_rootPart.UUID) | 3391 | if (prim.UUID != m_rootPart.UUID) |
3674 | { | 3392 | { |
3675 | prim.IgnoreUndoUpdate = true; | 3393 | prim.IgnoreUndoUpdate = true; |
@@ -3689,7 +3407,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3689 | { | 3407 | { |
3690 | m_rootPart.Undoing = false; | 3408 | m_rootPart.Undoing = false; |
3691 | } | 3409 | } |
3692 | lockPartsForRead(false); | ||
3693 | 3410 | ||
3694 | m_rootPart.ScheduleTerseUpdate(); | 3411 | m_rootPart.ScheduleTerseUpdate(); |
3695 | } | 3412 | } |
@@ -3811,18 +3528,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3811 | 3528 | ||
3812 | if (atTargets.Count > 0) | 3529 | if (atTargets.Count > 0) |
3813 | { | 3530 | { |
3814 | uint[] localids = new uint[0]; | 3531 | SceneObjectPart[] parts = m_parts.GetArray(); |
3815 | lockPartsForRead(true); | 3532 | uint[] localids = new uint[parts.Length]; |
3816 | { | 3533 | for (int i = 0; i < parts.Length; i++) |
3817 | localids = new uint[m_parts.Count]; | 3534 | localids[i] = parts[i].LocalId; |
3818 | int cntr = 0; | ||
3819 | foreach (SceneObjectPart part in m_parts.Values) | ||
3820 | { | ||
3821 | localids[cntr] = part.LocalId; | ||
3822 | cntr++; | ||
3823 | } | ||
3824 | } | ||
3825 | lockPartsForRead(false); | ||
3826 | 3535 | ||
3827 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3536 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3828 | { | 3537 | { |
@@ -3840,19 +3549,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3840 | if (m_scriptListens_notAtTarget && !at_target) | 3549 | if (m_scriptListens_notAtTarget && !at_target) |
3841 | { | 3550 | { |
3842 | //trigger not_at_target | 3551 | //trigger not_at_target |
3843 | uint[] localids = new uint[0]; | 3552 | SceneObjectPart[] parts = m_parts.GetArray(); |
3844 | lockPartsForRead(true); | 3553 | uint[] localids = new uint[parts.Length]; |
3845 | { | 3554 | for (int i = 0; i < parts.Length; i++) |
3846 | localids = new uint[m_parts.Count]; | 3555 | localids[i] = parts[i].LocalId; |
3847 | int cntr = 0; | 3556 | |
3848 | foreach (SceneObjectPart part in m_parts.Values) | ||
3849 | { | ||
3850 | localids[cntr] = part.LocalId; | ||
3851 | cntr++; | ||
3852 | } | ||
3853 | } | ||
3854 | lockPartsForRead(false); | ||
3855 | |||
3856 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3557 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3857 | { | 3558 | { |
3858 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); | 3559 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); |
@@ -3892,22 +3593,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3892 | 3593 | ||
3893 | if (atRotTargets.Count > 0) | 3594 | if (atRotTargets.Count > 0) |
3894 | { | 3595 | { |
3895 | uint[] localids = new uint[0]; | 3596 | SceneObjectPart[] parts = m_parts.GetArray(); |
3896 | lockPartsForRead(true); | 3597 | uint[] localids = new uint[parts.Length]; |
3897 | try | 3598 | for (int i = 0; i < parts.Length; i++) |
3898 | { | 3599 | localids[i] = parts[i].LocalId; |
3899 | localids = new uint[m_parts.Count]; | ||
3900 | int cntr = 0; | ||
3901 | foreach (SceneObjectPart part in m_parts.Values) | ||
3902 | { | ||
3903 | localids[cntr] = part.LocalId; | ||
3904 | cntr++; | ||
3905 | } | ||
3906 | } | ||
3907 | finally | ||
3908 | { | ||
3909 | lockPartsForRead(false); | ||
3910 | } | ||
3911 | 3600 | ||
3912 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3601 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3913 | { | 3602 | { |
@@ -3925,22 +3614,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3925 | if (m_scriptListens_notAtRotTarget && !at_Rottarget) | 3614 | if (m_scriptListens_notAtRotTarget && !at_Rottarget) |
3926 | { | 3615 | { |
3927 | //trigger not_at_target | 3616 | //trigger not_at_target |
3928 | uint[] localids = new uint[0]; | 3617 | SceneObjectPart[] parts = m_parts.GetArray(); |
3929 | lockPartsForRead(true); | 3618 | uint[] localids = new uint[parts.Length]; |
3930 | try | 3619 | for (int i = 0; i < parts.Length; i++) |
3931 | { | 3620 | localids[i] = parts[i].LocalId; |
3932 | localids = new uint[m_parts.Count]; | ||
3933 | int cntr = 0; | ||
3934 | foreach (SceneObjectPart part in m_parts.Values) | ||
3935 | { | ||
3936 | localids[cntr] = part.LocalId; | ||
3937 | cntr++; | ||
3938 | } | ||
3939 | } | ||
3940 | finally | ||
3941 | { | ||
3942 | lockPartsForRead(false); | ||
3943 | } | ||
3944 | 3621 | ||
3945 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3622 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3946 | { | 3623 | { |
@@ -3954,45 +3631,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
3954 | public float GetMass() | 3631 | public float GetMass() |
3955 | { | 3632 | { |
3956 | float retmass = 0f; | 3633 | float retmass = 0f; |
3957 | lockPartsForRead(true); | 3634 | SceneObjectPart[] parts = m_parts.GetArray(); |
3958 | { | 3635 | for (int i = 0; i < parts.Length; i++) |
3959 | foreach (SceneObjectPart part in m_parts.Values) | 3636 | retmass += parts[i].GetMass(); |
3960 | { | 3637 | |
3961 | retmass += part.GetMass(); | ||
3962 | } | ||
3963 | } | ||
3964 | lockPartsForRead(false); | ||
3965 | return retmass; | 3638 | return retmass; |
3966 | } | 3639 | } |
3967 | 3640 | ||
3968 | public void CheckSculptAndLoad() | 3641 | public void CheckSculptAndLoad() |
3969 | { | 3642 | { |
3970 | lockPartsForRead(true); | 3643 | if (IsDeleted) |
3644 | return; | ||
3645 | if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) | ||
3646 | return; | ||
3647 | |||
3648 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
3649 | for (int i = 0; i < parts.Length; i++) | ||
3971 | { | 3650 | { |
3972 | if (!IsDeleted) | 3651 | SceneObjectPart part = parts[i]; |
3652 | if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero) | ||
3973 | { | 3653 | { |
3974 | if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == 0) | 3654 | // check if a previously decoded sculpt map has been cached |
3655 | if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + part.Shape.SculptTexture.ToString()))) | ||
3975 | { | 3656 | { |
3976 | foreach (SceneObjectPart part in m_parts.Values) | 3657 | part.SculptTextureCallback(part.Shape.SculptTexture, null); |
3977 | { | 3658 | } |
3978 | if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero) | 3659 | else |
3979 | { | 3660 | { |
3980 | // check if a previously decoded sculpt map has been cached | 3661 | m_scene.AssetService.Get( |
3981 | if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + part.Shape.SculptTexture.ToString()))) | 3662 | part.Shape.SculptTexture.ToString(), part, AssetReceived); |
3982 | { | ||
3983 | part.SculptTextureCallback(part.Shape.SculptTexture, null); | ||
3984 | } | ||
3985 | else | ||
3986 | { | ||
3987 | m_scene.AssetService.Get( | ||
3988 | part.Shape.SculptTexture.ToString(), part, AssetReceived); | ||
3989 | } | ||
3990 | } | ||
3991 | } | ||
3992 | } | 3663 | } |
3993 | } | 3664 | } |
3994 | } | 3665 | } |
3995 | lockPartsForRead(false); | ||
3996 | } | 3666 | } |
3997 | 3667 | ||
3998 | protected void AssetReceived(string id, Object sender, AssetBase asset) | 3668 | protected void AssetReceived(string id, Object sender, AssetBase asset) |
@@ -4013,17 +3683,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
4013 | /// <param name="client"></param> | 3683 | /// <param name="client"></param> |
4014 | public void SetGroup(UUID GroupID, IClientAPI client) | 3684 | public void SetGroup(UUID GroupID, IClientAPI client) |
4015 | { | 3685 | { |
4016 | lockPartsForRead(true); | 3686 | SceneObjectPart[] parts = m_parts.GetArray(); |
3687 | for (int i = 0; i < parts.Length; i++) | ||
4017 | { | 3688 | { |
4018 | foreach (SceneObjectPart part in m_parts.Values) | 3689 | SceneObjectPart part = parts[i]; |
4019 | { | 3690 | part.SetGroup(GroupID, client); |
4020 | part.SetGroup(GroupID, client); | 3691 | part.Inventory.ChangeInventoryGroup(GroupID); |
4021 | part.Inventory.ChangeInventoryGroup(GroupID); | ||
4022 | } | ||
4023 | |||
4024 | HasGroupChanged = true; | ||
4025 | } | 3692 | } |
4026 | lockPartsForRead(false); | ||
4027 | 3693 | ||
4028 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled | 3694 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled |
4029 | // for the same object with very different properties. The caller must schedule the update. | 3695 | // for the same object with very different properties. The caller must schedule the update. |
@@ -4032,10 +3698,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
4032 | 3698 | ||
4033 | public void TriggerScriptChangedEvent(Changed val) | 3699 | public void TriggerScriptChangedEvent(Changed val) |
4034 | { | 3700 | { |
4035 | foreach (SceneObjectPart part in Children.Values) | 3701 | SceneObjectPart[] parts = m_parts.GetArray(); |
4036 | { | 3702 | for (int i = 0; i < parts.Length; i++) |
4037 | part.TriggerScriptChangedEvent(val); | 3703 | parts[i].TriggerScriptChangedEvent(val); |
4038 | } | ||
4039 | } | 3704 | } |
4040 | 3705 | ||
4041 | public override string ToString() | 3706 | public override string ToString() |
@@ -4045,12 +3710,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
4045 | 3710 | ||
4046 | public void SetAttachmentPoint(byte point) | 3711 | public void SetAttachmentPoint(byte point) |
4047 | { | 3712 | { |
4048 | lockPartsForRead(true); | 3713 | SceneObjectPart[] parts = m_parts.GetArray(); |
4049 | { | 3714 | for (int i = 0; i < parts.Length; i++) |
4050 | foreach (SceneObjectPart part in m_parts.Values) | 3715 | parts[i].SetAttachmentPoint(point); |
4051 | part.SetAttachmentPoint(point); | ||
4052 | } | ||
4053 | lockPartsForRead(false); | ||
4054 | } | 3716 | } |
4055 | 3717 | ||
4056 | #region ISceneObject | 3718 | #region ISceneObject |