aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs1349
1 files changed, 1128 insertions, 221 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 05bea8d..72d96d1 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -42,6 +43,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
42 43
43namespace OpenSim.Region.Framework.Scenes 44namespace OpenSim.Region.Framework.Scenes
44{ 45{
46
45 [Flags] 47 [Flags]
46 public enum scriptEvents 48 public enum scriptEvents
47 { 49 {
@@ -105,8 +107,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 107 /// since the group's last persistent backup
106 /// </summary> 108 /// </summary>
107 private bool m_hasGroupChanged = false; 109 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 110 private long timeFirstChanged = 0;
109 private long timeLastChanged; 111 private long timeLastChanged = 0;
112 private long m_maxPersistTime = 0;
113 private long m_minPersistTime = 0;
114 private Random m_rand;
115 private bool m_suspendUpdates;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
117
118 public bool areUpdatesSuspended
119 {
120 get
121 {
122 return m_suspendUpdates;
123 }
124 set
125 {
126 m_suspendUpdates = value;
127 if (!value)
128 {
129 QueueForUpdateCheck();
130 }
131 }
132 }
110 133
111 public bool HasGroupChanged 134 public bool HasGroupChanged
112 { 135 {
@@ -114,9 +137,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 137 {
115 if (value) 138 if (value)
116 { 139 {
140 if (m_isBackedUp)
141 {
142 m_scene.SceneGraph.FireChangeBackup(this);
143 }
117 timeLastChanged = DateTime.Now.Ticks; 144 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 145 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 146 timeFirstChanged = DateTime.Now.Ticks;
147 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
148 {
149 if (m_rand == null)
150 {
151 byte[] val = new byte[16];
152 m_rootPart.UUID.ToBytes(val, 0);
153 m_rand = new Random(BitConverter.ToInt32(val, 0));
154 }
155
156 if (m_scene.GetRootAgentCount() == 0)
157 {
158 //If the region is empty, this change has been made by an automated process
159 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
160
161 float factor = 1.5f + (float)(m_rand.NextDouble());
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
164 }
165 else
166 {
167 //If the region is not empty, we want to obey the minimum and maximum persist times
168 //but add a random factor so we stagger the object persistance a little
169 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
170 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
171 }
172 }
120 } 173 }
121 m_hasGroupChanged = value; 174 m_hasGroupChanged = value;
122 175
@@ -131,7 +184,7 @@ namespace OpenSim.Region.Framework.Scenes
131 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 184 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
132 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 185 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 186 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 187 public bool HasGroupChangedDueToDelink { get; set; }
135 188
136 private bool isTimeToPersist() 189 private bool isTimeToPersist()
137 { 190 {
@@ -141,8 +194,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 194 return false;
142 if (m_scene.ShuttingDown) 195 if (m_scene.ShuttingDown)
143 return true; 196 return true;
197
198 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
199 {
200 m_maxPersistTime = m_scene.m_persistAfter;
201 m_minPersistTime = m_scene.m_dontPersistBefore;
202 }
203
144 long currentTime = DateTime.Now.Ticks; 204 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 205
206 if (timeLastChanged == 0) timeLastChanged = currentTime;
207 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
208
209 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 210 return true;
147 return false; 211 return false;
148 } 212 }
@@ -245,10 +309,10 @@ namespace OpenSim.Region.Framework.Scenes
245 309
246 private bool m_scriptListens_atTarget; 310 private bool m_scriptListens_atTarget;
247 private bool m_scriptListens_notAtTarget; 311 private bool m_scriptListens_notAtTarget;
248
249 private bool m_scriptListens_atRotTarget; 312 private bool m_scriptListens_atRotTarget;
250 private bool m_scriptListens_notAtRotTarget; 313 private bool m_scriptListens_notAtRotTarget;
251 314
315 public bool m_dupeInProgress = false;
252 internal Dictionary<UUID, string> m_savedScriptState; 316 internal Dictionary<UUID, string> m_savedScriptState;
253 317
254 #region Properties 318 #region Properties
@@ -285,6 +349,16 @@ namespace OpenSim.Region.Framework.Scenes
285 get { return m_parts.Count; } 349 get { return m_parts.Count; }
286 } 350 }
287 351
352// protected Quaternion m_rotation = Quaternion.Identity;
353//
354// public virtual Quaternion Rotation
355// {
356// get { return m_rotation; }
357// set {
358// m_rotation = value;
359// }
360// }
361
288 public Quaternion GroupRotation 362 public Quaternion GroupRotation
289 { 363 {
290 get { return m_rootPart.RotationOffset; } 364 get { return m_rootPart.RotationOffset; }
@@ -391,7 +465,15 @@ namespace OpenSim.Region.Framework.Scenes
391 { 465 {
392 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 466 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
393 } 467 }
394 468
469
470
471 private struct avtocrossInfo
472 {
473 public ScenePresence av;
474 public uint ParentID;
475 }
476
395 /// <summary> 477 /// <summary>
396 /// The absolute position of this scene object in the scene 478 /// The absolute position of this scene object in the scene
397 /// </summary> 479 /// </summary>
@@ -404,14 +486,128 @@ namespace OpenSim.Region.Framework.Scenes
404 486
405 if (Scene != null) 487 if (Scene != null)
406 { 488 {
407 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 489 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
408 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 490 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
491 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
492 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
493 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
409 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 494 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
410 { 495 {
411 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 496 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
497 uint x = 0;
498 uint y = 0;
499 string version = String.Empty;
500 Vector3 newpos = Vector3.Zero;
501 OpenSim.Services.Interfaces.GridRegion destination = null;
502
503 bool canCross = true;
504 foreach (ScenePresence av in m_linkedAvatars)
505 {
506 // We need to cross these agents. First, let's find
507 // out if any of them can't cross for some reason.
508 // We have to deny the crossing entirely if any
509 // of them are banned. Alternatively, we could
510 // unsit banned agents....
511
512
513 // We set the avatar position as being the object
514 // position to get the region to send to
515 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
516 {
517 canCross = false;
518 break;
519 }
520
521 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
522 }
523
524 if (canCross)
525 {
526 // We unparent the SP quietly so that it won't
527 // be made to stand up
528
529 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
530
531 foreach (ScenePresence av in m_linkedAvatars)
532 {
533 avtocrossInfo avinfo = new avtocrossInfo();
534 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
535 if (parentPart != null)
536 av.ParentUUID = parentPart.UUID;
537
538 avinfo.av = av;
539 avinfo.ParentID = av.ParentID;
540 avsToCross.Add(avinfo);
541
542 av.ParentID = 0;
543 }
544
545// m_linkedAvatars.Clear();
546 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
547
548 // Normalize
549 if (val.X >= Constants.RegionSize)
550 val.X -= Constants.RegionSize;
551 if (val.Y >= Constants.RegionSize)
552 val.Y -= Constants.RegionSize;
553 if (val.X < 0)
554 val.X += Constants.RegionSize;
555 if (val.Y < 0)
556 val.Y += Constants.RegionSize;
557
558 // If it's deleted, crossing was successful
559 if (IsDeleted)
560 {
561 // foreach (ScenePresence av in m_linkedAvatars)
562 foreach (avtocrossInfo avinfo in avsToCross)
563 {
564 ScenePresence av = avinfo.av;
565 if (!av.IsInTransit) // just in case...
566 {
567 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
568
569 av.IsInTransit = true;
570
571 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
572 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
573 }
574 else
575 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
576 }
577 avsToCross.Clear();
578 return;
579 }
580 else // cross failed, put avas back ??
581 {
582 foreach (avtocrossInfo avinfo in avsToCross)
583 {
584 ScenePresence av = avinfo.av;
585 av.ParentUUID = UUID.Zero;
586 av.ParentID = avinfo.ParentID;
587// m_linkedAvatars.Add(av);
588 }
589 }
590 avsToCross.Clear();
591
592 }
593 else if (RootPart.PhysActor != null)
594 {
595 RootPart.PhysActor.CrossingFailure();
596 }
597
598 Vector3 oldp = AbsolutePosition;
599 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
600 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
601 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
412 } 602 }
413 } 603 }
414 604
605/* don't see the need but worse don't see where is restored to false if things stay in
606 foreach (SceneObjectPart part in m_parts.GetArray())
607 {
608 part.IgnoreUndoUpdate = true;
609 }
610 */
415 if (RootPart.GetStatusSandbox()) 611 if (RootPart.GetStatusSandbox())
416 { 612 {
417 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 613 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -425,10 +621,30 @@ namespace OpenSim.Region.Framework.Scenes
425 return; 621 return;
426 } 622 }
427 } 623 }
428
429 SceneObjectPart[] parts = m_parts.GetArray(); 624 SceneObjectPart[] parts = m_parts.GetArray();
430 for (int i = 0; i < parts.Length; i++) 625 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
431 parts[i].GroupPosition = val; 626 if (m_dupeInProgress)
627 triggerScriptEvent = false;
628 foreach (SceneObjectPart part in parts)
629 {
630 part.GroupPosition = val;
631 if (triggerScriptEvent)
632 part.TriggerScriptChangedEvent(Changed.POSITION);
633 }
634 if (!m_dupeInProgress)
635 {
636 foreach (ScenePresence av in m_linkedAvatars)
637 {
638 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
639 if (p != null && m_parts.TryGetValue(p.UUID, out p))
640 {
641 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
642 av.AbsolutePosition += offset;
643 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
644 av.SendAvatarDataToAllAgents();
645 }
646 }
647 }
432 648
433 //if (m_rootPart.PhysActor != null) 649 //if (m_rootPart.PhysActor != null)
434 //{ 650 //{
@@ -443,6 +659,40 @@ namespace OpenSim.Region.Framework.Scenes
443 } 659 }
444 } 660 }
445 661
662 public override Vector3 Velocity
663 {
664 get { return RootPart.Velocity; }
665 set { RootPart.Velocity = value; }
666 }
667
668 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
669 {
670 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
671 ScenePresence agent = icon.EndInvoke(iar);
672
673 //// If the cross was successful, this agent is a child agent
674 if (agent.IsChildAgent)
675 {
676 if (agent.ParentUUID != UUID.Zero)
677 {
678 agent.ParentPart = null;
679 agent.ParentPosition = Vector3.Zero;
680 // agent.ParentUUID = UUID.Zero;
681 }
682 }
683
684 agent.ParentUUID = UUID.Zero;
685
686// agent.Reset();
687// else // Not successful
688// agent.RestoreInCurrentScene();
689
690 // In any case
691 agent.IsInTransit = false;
692
693 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
694 }
695
446 public override uint LocalId 696 public override uint LocalId
447 { 697 {
448 get { return m_rootPart.LocalId; } 698 get { return m_rootPart.LocalId; }
@@ -524,6 +774,11 @@ namespace OpenSim.Region.Framework.Scenes
524 m_isSelected = value; 774 m_isSelected = value;
525 // Tell physics engine that group is selected 775 // Tell physics engine that group is selected
526 776
777 // this is not right
778 // but ode engines should only really need to know about root part
779 // so they can put entire object simulation on hold and not colliding
780 // keep as was for now
781
527 PhysicsActor pa = m_rootPart.PhysActor; 782 PhysicsActor pa = m_rootPart.PhysActor;
528 if (pa != null) 783 if (pa != null)
529 { 784 {
@@ -540,6 +795,42 @@ namespace OpenSim.Region.Framework.Scenes
540 childPa.Selected = value; 795 childPa.Selected = value;
541 } 796 }
542 } 797 }
798 if (RootPart.KeyframeMotion != null)
799 RootPart.KeyframeMotion.Selected = value;
800 }
801 }
802
803 public void PartSelectChanged(bool partSelect)
804 {
805 // any part selected makes group selected
806 if (m_isSelected == partSelect)
807 return;
808
809 if (partSelect)
810 {
811 IsSelected = partSelect;
812// if (!IsAttachment)
813// ScheduleGroupForFullUpdate();
814 }
815 else
816 {
817 // bad bad bad 2 heavy for large linksets
818 // since viewer does send lot of (un)selects
819 // this needs to be replaced by a specific list or count ?
820 // but that will require extra code in several places
821
822 SceneObjectPart[] parts = m_parts.GetArray();
823 for (int i = 0; i < parts.Length; i++)
824 {
825 SceneObjectPart part = parts[i];
826 if (part.IsSelected)
827 return;
828 }
829 IsSelected = partSelect;
830 if (!IsAttachment)
831 {
832 ScheduleGroupForFullUpdate();
833 }
543 } 834 }
544 } 835 }
545 836
@@ -617,6 +908,7 @@ namespace OpenSim.Region.Framework.Scenes
617 /// </summary> 908 /// </summary>
618 public SceneObjectGroup() 909 public SceneObjectGroup()
619 { 910 {
911
620 } 912 }
621 913
622 /// <summary> 914 /// <summary>
@@ -633,7 +925,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// Constructor. This object is added to the scene later via AttachToScene() 925 /// Constructor. This object is added to the scene later via AttachToScene()
634 /// </summary> 926 /// </summary>
635 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 927 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
636 { 928 {
637 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 929 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
638 } 930 }
639 931
@@ -669,6 +961,9 @@ namespace OpenSim.Region.Framework.Scenes
669 /// </summary> 961 /// </summary>
670 public virtual void AttachToBackup() 962 public virtual void AttachToBackup()
671 { 963 {
964 if (IsAttachment) return;
965 m_scene.SceneGraph.FireAttachToBackup(this);
966
672 if (InSceneBackup) 967 if (InSceneBackup)
673 { 968 {
674 //m_log.DebugFormat( 969 //m_log.DebugFormat(
@@ -711,6 +1006,13 @@ namespace OpenSim.Region.Framework.Scenes
711 1006
712 ApplyPhysics(); 1007 ApplyPhysics();
713 1008
1009 if (RootPart.PhysActor != null)
1010 RootPart.Force = RootPart.Force;
1011 if (RootPart.PhysActor != null)
1012 RootPart.Torque = RootPart.Torque;
1013 if (RootPart.PhysActor != null)
1014 RootPart.Buoyancy = RootPart.Buoyancy;
1015
714 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1016 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
715 // for the same object with very different properties. The caller must schedule the update. 1017 // for the same object with very different properties. The caller must schedule the update.
716 //ScheduleGroupForFullUpdate(); 1018 //ScheduleGroupForFullUpdate();
@@ -726,6 +1028,10 @@ namespace OpenSim.Region.Framework.Scenes
726 EntityIntersection result = new EntityIntersection(); 1028 EntityIntersection result = new EntityIntersection();
727 1029
728 SceneObjectPart[] parts = m_parts.GetArray(); 1030 SceneObjectPart[] parts = m_parts.GetArray();
1031
1032 // Find closest hit here
1033 float idist = float.MaxValue;
1034
729 for (int i = 0; i < parts.Length; i++) 1035 for (int i = 0; i < parts.Length; i++)
730 { 1036 {
731 SceneObjectPart part = parts[i]; 1037 SceneObjectPart part = parts[i];
@@ -740,11 +1046,6 @@ namespace OpenSim.Region.Framework.Scenes
740 1046
741 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1047 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
742 1048
743 // This may need to be updated to the maximum draw distance possible..
744 // We might (and probably will) be checking for prim creation from other sims
745 // when the camera crosses the border.
746 float idist = Constants.RegionSize;
747
748 if (inter.HitTF) 1049 if (inter.HitTF)
749 { 1050 {
750 // We need to find the closest prim to return to the testcaller along the ray 1051 // We need to find the closest prim to return to the testcaller along the ray
@@ -755,10 +1056,11 @@ namespace OpenSim.Region.Framework.Scenes
755 result.obj = part; 1056 result.obj = part;
756 result.normal = inter.normal; 1057 result.normal = inter.normal;
757 result.distance = inter.distance; 1058 result.distance = inter.distance;
1059
1060 idist = inter.distance;
758 } 1061 }
759 } 1062 }
760 } 1063 }
761
762 return result; 1064 return result;
763 } 1065 }
764 1066
@@ -770,25 +1072,27 @@ namespace OpenSim.Region.Framework.Scenes
770 /// <returns></returns> 1072 /// <returns></returns>
771 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1073 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
772 { 1074 {
773 maxX = -256f; 1075 maxX = float.MinValue;
774 maxY = -256f; 1076 maxY = float.MinValue;
775 maxZ = -256f; 1077 maxZ = float.MinValue;
776 minX = 256f; 1078 minX = float.MaxValue;
777 minY = 256f; 1079 minY = float.MaxValue;
778 minZ = 8192f; 1080 minZ = float.MaxValue;
779 1081
780 SceneObjectPart[] parts = m_parts.GetArray(); 1082 SceneObjectPart[] parts = m_parts.GetArray();
781 for (int i = 0; i < parts.Length; i++) 1083 foreach (SceneObjectPart part in parts)
782 { 1084 {
783 SceneObjectPart part = parts[i];
784
785 Vector3 worldPos = part.GetWorldPosition(); 1085 Vector3 worldPos = part.GetWorldPosition();
786 Vector3 offset = worldPos - AbsolutePosition; 1086 Vector3 offset = worldPos - AbsolutePosition;
787 Quaternion worldRot; 1087 Quaternion worldRot;
788 if (part.ParentID == 0) 1088 if (part.ParentID == 0)
1089 {
789 worldRot = part.RotationOffset; 1090 worldRot = part.RotationOffset;
1091 }
790 else 1092 else
1093 {
791 worldRot = part.GetWorldRotation(); 1094 worldRot = part.GetWorldRotation();
1095 }
792 1096
793 Vector3 frontTopLeft; 1097 Vector3 frontTopLeft;
794 Vector3 frontTopRight; 1098 Vector3 frontTopRight;
@@ -800,6 +1104,8 @@ namespace OpenSim.Region.Framework.Scenes
800 Vector3 backBottomLeft; 1104 Vector3 backBottomLeft;
801 Vector3 backBottomRight; 1105 Vector3 backBottomRight;
802 1106
1107 // Vector3[] corners = new Vector3[8];
1108
803 Vector3 orig = Vector3.Zero; 1109 Vector3 orig = Vector3.Zero;
804 1110
805 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1111 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -834,6 +1140,38 @@ namespace OpenSim.Region.Framework.Scenes
834 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1140 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
835 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1141 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
836 1142
1143
1144
1145 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1146 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1147 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1148 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1149 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1150 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1151 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1152 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1153
1154 //for (int i = 0; i < 8; i++)
1155 //{
1156 // corners[i] = corners[i] * worldRot;
1157 // corners[i] += offset;
1158
1159 // if (corners[i].X > maxX)
1160 // maxX = corners[i].X;
1161 // if (corners[i].X < minX)
1162 // minX = corners[i].X;
1163
1164 // if (corners[i].Y > maxY)
1165 // maxY = corners[i].Y;
1166 // if (corners[i].Y < minY)
1167 // minY = corners[i].Y;
1168
1169 // if (corners[i].Z > maxZ)
1170 // maxZ = corners[i].Y;
1171 // if (corners[i].Z < minZ)
1172 // minZ = corners[i].Z;
1173 //}
1174
837 frontTopLeft = frontTopLeft * worldRot; 1175 frontTopLeft = frontTopLeft * worldRot;
838 frontTopRight = frontTopRight * worldRot; 1176 frontTopRight = frontTopRight * worldRot;
839 frontBottomLeft = frontBottomLeft * worldRot; 1177 frontBottomLeft = frontBottomLeft * worldRot;
@@ -855,6 +1193,15 @@ namespace OpenSim.Region.Framework.Scenes
855 backTopLeft += offset; 1193 backTopLeft += offset;
856 backTopRight += offset; 1194 backTopRight += offset;
857 1195
1196 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1197 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1198 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1199 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1200 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1201 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1202 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1203 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1204
858 if (frontTopRight.X > maxX) 1205 if (frontTopRight.X > maxX)
859 maxX = frontTopRight.X; 1206 maxX = frontTopRight.X;
860 if (frontTopLeft.X > maxX) 1207 if (frontTopLeft.X > maxX)
@@ -998,17 +1345,118 @@ namespace OpenSim.Region.Framework.Scenes
998 1345
999 #endregion 1346 #endregion
1000 1347
1348 public void GetResourcesCosts(SceneObjectPart apart,
1349 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1350 {
1351 // this information may need to be cached
1352
1353 float cost;
1354 float tmpcost;
1355
1356 bool ComplexCost = false;
1357
1358 SceneObjectPart p;
1359 SceneObjectPart[] parts;
1360
1361 lock (m_parts)
1362 {
1363 parts = m_parts.GetArray();
1364 }
1365
1366 int nparts = parts.Length;
1367
1368
1369 for (int i = 0; i < nparts; i++)
1370 {
1371 p = parts[i];
1372
1373 if (p.UsesComplexCost)
1374 {
1375 ComplexCost = true;
1376 break;
1377 }
1378 }
1379
1380 if (ComplexCost)
1381 {
1382 linksetResCost = 0;
1383 linksetPhysCost = 0;
1384 partCost = 0;
1385 partPhysCost = 0;
1386
1387 for (int i = 0; i < nparts; i++)
1388 {
1389 p = parts[i];
1390
1391 cost = p.StreamingCost;
1392 tmpcost = p.SimulationCost;
1393 if (tmpcost > cost)
1394 cost = tmpcost;
1395 tmpcost = p.PhysicsCost;
1396 if (tmpcost > cost)
1397 cost = tmpcost;
1398
1399 linksetPhysCost += tmpcost;
1400 linksetResCost += cost;
1401
1402 if (p == apart)
1403 {
1404 partCost = cost;
1405 partPhysCost = tmpcost;
1406 }
1407 }
1408 }
1409 else
1410 {
1411 partPhysCost = 1.0f;
1412 partCost = 1.0f;
1413 linksetResCost = (float)nparts;
1414 linksetPhysCost = linksetResCost;
1415 }
1416 }
1417
1418 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1419 {
1420 SceneObjectPart p;
1421 SceneObjectPart[] parts;
1422
1423 lock (m_parts)
1424 {
1425 parts = m_parts.GetArray();
1426 }
1427
1428 int nparts = parts.Length;
1429
1430 PhysCost = 0;
1431 StreamCost = 0;
1432 SimulCost = 0;
1433
1434 for (int i = 0; i < nparts; i++)
1435 {
1436 p = parts[i];
1437
1438 StreamCost += p.StreamingCost;
1439 SimulCost += p.SimulationCost;
1440 PhysCost += p.PhysicsCost;
1441 }
1442 }
1443
1001 public void SaveScriptedState(XmlTextWriter writer) 1444 public void SaveScriptedState(XmlTextWriter writer)
1002 { 1445 {
1446 SaveScriptedState(writer, false);
1447 }
1448
1449 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1450 {
1003 XmlDocument doc = new XmlDocument(); 1451 XmlDocument doc = new XmlDocument();
1004 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1452 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1005 1453
1006 SceneObjectPart[] parts = m_parts.GetArray(); 1454 SceneObjectPart[] parts = m_parts.GetArray();
1007 for (int i = 0; i < parts.Length; i++) 1455 for (int i = 0; i < parts.Length; i++)
1008 { 1456 {
1009 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1457 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1010 foreach (KeyValuePair<UUID, string> kvp in pstates) 1458 foreach (KeyValuePair<UUID, string> kvp in pstates)
1011 states.Add(kvp.Key, kvp.Value); 1459 states[kvp.Key] = kvp.Value;
1012 } 1460 }
1013 1461
1014 if (states.Count > 0) 1462 if (states.Count > 0)
@@ -1028,6 +1476,169 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1476 }
1029 1477
1030 /// <summary> 1478 /// <summary>
1479 /// Add the avatar to this linkset (avatar is sat).
1480 /// </summary>
1481 /// <param name="agentID"></param>
1482 public void AddAvatar(UUID agentID)
1483 {
1484 ScenePresence presence;
1485 if (m_scene.TryGetScenePresence(agentID, out presence))
1486 {
1487 if (!m_linkedAvatars.Contains(presence))
1488 {
1489 m_linkedAvatars.Add(presence);
1490 }
1491 }
1492 }
1493
1494 /// <summary>
1495 /// Delete the avatar from this linkset (avatar is unsat).
1496 /// </summary>
1497 /// <param name="agentID"></param>
1498 public void DeleteAvatar(UUID agentID)
1499 {
1500 ScenePresence presence;
1501 if (m_scene.TryGetScenePresence(agentID, out presence))
1502 {
1503 if (m_linkedAvatars.Contains(presence))
1504 {
1505 m_linkedAvatars.Remove(presence);
1506 }
1507 }
1508 }
1509
1510 /// <summary>
1511 /// Returns the list of linked presences (avatars sat on this group)
1512 /// </summary>
1513 /// <param name="agentID"></param>
1514 public List<ScenePresence> GetLinkedAvatars()
1515 {
1516 return m_linkedAvatars;
1517 }
1518
1519 /// <summary>
1520 /// Attach this scene object to the given avatar.
1521 /// </summary>
1522 /// <param name="agentID"></param>
1523 /// <param name="attachmentpoint"></param>
1524 /// <param name="AttachOffset"></param>
1525 private void AttachToAgent(
1526 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1527 {
1528 if (avatar != null)
1529 {
1530 // don't attach attachments to child agents
1531 if (avatar.IsChildAgent) return;
1532
1533 // Remove from database and parcel prim count
1534 m_scene.DeleteFromStorage(so.UUID);
1535 m_scene.EventManager.TriggerParcelPrimCountTainted();
1536
1537 so.AttachedAvatar = avatar.UUID;
1538
1539 if (so.RootPart.PhysActor != null)
1540 {
1541 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1542 so.RootPart.PhysActor = null;
1543 }
1544
1545 so.AbsolutePosition = attachOffset;
1546 so.RootPart.AttachedPos = attachOffset;
1547 so.IsAttachment = true;
1548 so.RootPart.SetParentLocalId(avatar.LocalId);
1549 so.AttachmentPoint = attachmentpoint;
1550
1551 avatar.AddAttachment(this);
1552
1553 if (!silent)
1554 {
1555 // Killing it here will cause the client to deselect it
1556 // It then reappears on the avatar, deselected
1557 // through the full update below
1558 //
1559 if (IsSelected)
1560 {
1561 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1562 }
1563
1564 IsSelected = false; // fudge....
1565 ScheduleGroupForFullUpdate();
1566 }
1567 }
1568 else
1569 {
1570 m_log.WarnFormat(
1571 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1572 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1573 }
1574 }
1575
1576 public byte GetAttachmentPoint()
1577 {
1578 return m_rootPart.Shape.State;
1579 }
1580
1581 public void DetachToGround()
1582 {
1583 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1584 if (avatar == null)
1585 return;
1586
1587 avatar.RemoveAttachment(this);
1588
1589 Vector3 detachedpos = new Vector3(127f,127f,127f);
1590 if (avatar == null)
1591 return;
1592
1593 detachedpos = avatar.AbsolutePosition;
1594 FromItemID = UUID.Zero;
1595
1596 AbsolutePosition = detachedpos;
1597 AttachedAvatar = UUID.Zero;
1598
1599 //SceneObjectPart[] parts = m_parts.GetArray();
1600 //for (int i = 0; i < parts.Length; i++)
1601 // parts[i].AttachedAvatar = UUID.Zero;
1602
1603 m_rootPart.SetParentLocalId(0);
1604 AttachmentPoint = (byte)0;
1605 // must check if buildind should be true or false here
1606 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1607 HasGroupChanged = true;
1608 RootPart.Rezzed = DateTime.Now;
1609 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1610 AttachToBackup();
1611 m_scene.EventManager.TriggerParcelPrimCountTainted();
1612 m_rootPart.ScheduleFullUpdate();
1613 m_rootPart.ClearUndoState();
1614 }
1615
1616 public void DetachToInventoryPrep()
1617 {
1618 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1619 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1620 if (avatar != null)
1621 {
1622 //detachedpos = avatar.AbsolutePosition;
1623 avatar.RemoveAttachment(this);
1624 }
1625
1626 AttachedAvatar = UUID.Zero;
1627
1628 /*SceneObjectPart[] parts = m_parts.GetArray();
1629 for (int i = 0; i < parts.Length; i++)
1630 parts[i].AttachedAvatar = UUID.Zero;*/
1631
1632 m_rootPart.SetParentLocalId(0);
1633 //m_rootPart.SetAttachmentPoint((byte)0);
1634 IsAttachment = false;
1635 AbsolutePosition = m_rootPart.AttachedPos;
1636 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1637 //AttachToBackup();
1638 //m_rootPart.ScheduleFullUpdate();
1639 }
1640
1641 /// <summary>
1031 /// 1642 ///
1032 /// </summary> 1643 /// </summary>
1033 /// <param name="part"></param> 1644 /// <param name="part"></param>
@@ -1077,7 +1688,10 @@ namespace OpenSim.Region.Framework.Scenes
1077 public void AddPart(SceneObjectPart part) 1688 public void AddPart(SceneObjectPart part)
1078 { 1689 {
1079 part.SetParent(this); 1690 part.SetParent(this);
1080 part.LinkNum = m_parts.Add(part.UUID, part); 1691 m_parts.Add(part.UUID, part);
1692
1693 part.LinkNum = m_parts.Count;
1694
1081 if (part.LinkNum == 2) 1695 if (part.LinkNum == 2)
1082 RootPart.LinkNum = 1; 1696 RootPart.LinkNum = 1;
1083 } 1697 }
@@ -1165,7 +1779,7 @@ namespace OpenSim.Region.Framework.Scenes
1165// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1779// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1166// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1780// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1167 1781
1168 part.StoreUndoState(); 1782// part.StoreUndoState();
1169 part.OnGrab(offsetPos, remoteClient); 1783 part.OnGrab(offsetPos, remoteClient);
1170 } 1784 }
1171 1785
@@ -1185,6 +1799,11 @@ namespace OpenSim.Region.Framework.Scenes
1185 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1799 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1186 public void DeleteGroupFromScene(bool silent) 1800 public void DeleteGroupFromScene(bool silent)
1187 { 1801 {
1802 // We need to keep track of this state in case this group is still queued for backup.
1803 IsDeleted = true;
1804
1805 DetachFromBackup();
1806
1188 SceneObjectPart[] parts = m_parts.GetArray(); 1807 SceneObjectPart[] parts = m_parts.GetArray();
1189 for (int i = 0; i < parts.Length; i++) 1808 for (int i = 0; i < parts.Length; i++)
1190 { 1809 {
@@ -1200,13 +1819,14 @@ namespace OpenSim.Region.Framework.Scenes
1200 part.ClearUpdateSchedule(); 1819 part.ClearUpdateSchedule();
1201 if (part == m_rootPart) 1820 if (part == m_rootPart)
1202 { 1821 {
1203 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || 1822 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) ||
1204 (AttachmentPoint < 31) || (AttachmentPoint > 38)) 1823 (AttachmentPoint < 31) || (AttachmentPoint > 38))
1205 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1824 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId });
1206 } 1825 }
1207 } 1826 }
1208 }); 1827 });
1209 } 1828 }
1829
1210 } 1830 }
1211 1831
1212 public void AddScriptLPS(int count) 1832 public void AddScriptLPS(int count)
@@ -1276,28 +1896,43 @@ namespace OpenSim.Region.Framework.Scenes
1276 /// </summary> 1896 /// </summary>
1277 public void ApplyPhysics() 1897 public void ApplyPhysics()
1278 { 1898 {
1279 // Apply physics to the root prim
1280 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1281
1282 // Apply physics to child prims
1283 SceneObjectPart[] parts = m_parts.GetArray(); 1899 SceneObjectPart[] parts = m_parts.GetArray();
1284 if (parts.Length > 1) 1900 if (parts.Length > 1)
1285 { 1901 {
1902 ResetChildPrimPhysicsPositions();
1903
1904 // Apply physics to the root prim
1905 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1906
1907
1286 for (int i = 0; i < parts.Length; i++) 1908 for (int i = 0; i < parts.Length; i++)
1287 { 1909 {
1288 SceneObjectPart part = parts[i]; 1910 SceneObjectPart part = parts[i];
1289 if (part.LocalId != m_rootPart.LocalId) 1911 if (part.LocalId != m_rootPart.LocalId)
1290 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1912 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1291 } 1913 }
1292
1293 // Hack to get the physics scene geometries in the right spot 1914 // Hack to get the physics scene geometries in the right spot
1294 ResetChildPrimPhysicsPositions(); 1915// ResetChildPrimPhysicsPositions();
1916 if (m_rootPart.PhysActor != null)
1917 {
1918 m_rootPart.PhysActor.Building = false;
1919 }
1920 }
1921 else
1922 {
1923 // Apply physics to the root prim
1924 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1295 } 1925 }
1296 } 1926 }
1297 1927
1298 public void SetOwnerId(UUID userId) 1928 public void SetOwnerId(UUID userId)
1299 { 1929 {
1300 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1930 ForEachPart(delegate(SceneObjectPart part)
1931 {
1932
1933 part.OwnerID = userId;
1934
1935 });
1301 } 1936 }
1302 1937
1303 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1938 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1329,11 +1964,17 @@ namespace OpenSim.Region.Framework.Scenes
1329 return; 1964 return;
1330 } 1965 }
1331 1966
1967 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1968 return;
1969
1332 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1970 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1333 // any exception propogate upwards. 1971 // any exception propogate upwards.
1334 try 1972 try
1335 { 1973 {
1336 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1974 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1975 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1976 m_scene.LoadingPrims) // Land may not be valid yet
1977
1337 { 1978 {
1338 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1979 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1339 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1980 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1360,6 +2001,7 @@ namespace OpenSim.Region.Framework.Scenes
1360 } 2001 }
1361 } 2002 }
1362 } 2003 }
2004
1363 } 2005 }
1364 2006
1365 if (m_scene.UseBackup && HasGroupChanged) 2007 if (m_scene.UseBackup && HasGroupChanged)
@@ -1367,10 +2009,30 @@ namespace OpenSim.Region.Framework.Scenes
1367 // don't backup while it's selected or you're asking for changes mid stream. 2009 // don't backup while it's selected or you're asking for changes mid stream.
1368 if (isTimeToPersist() || forcedBackup) 2010 if (isTimeToPersist() || forcedBackup)
1369 { 2011 {
2012 if (m_rootPart.PhysActor != null &&
2013 (!m_rootPart.PhysActor.IsPhysical))
2014 {
2015 // Possible ghost prim
2016 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2017 {
2018 foreach (SceneObjectPart part in m_parts.GetArray())
2019 {
2020 // Re-set physics actor positions and
2021 // orientations
2022 part.GroupPosition = m_rootPart.GroupPosition;
2023 }
2024 }
2025 }
1370// m_log.DebugFormat( 2026// m_log.DebugFormat(
1371// "[SCENE]: Storing {0}, {1} in {2}", 2027// "[SCENE]: Storing {0}, {1} in {2}",
1372// Name, UUID, m_scene.RegionInfo.RegionName); 2028// Name, UUID, m_scene.RegionInfo.RegionName);
1373 2029
2030 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2031 {
2032 RootPart.Shape.State = 0;
2033 ScheduleGroupForFullUpdate();
2034 }
2035
1374 SceneObjectGroup backup_group = Copy(false); 2036 SceneObjectGroup backup_group = Copy(false);
1375 backup_group.RootPart.Velocity = RootPart.Velocity; 2037 backup_group.RootPart.Velocity = RootPart.Velocity;
1376 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2038 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1384,6 +2046,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 2046
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 2047 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 2048 {
2049 if (part.KeyframeMotion != null)
2050 {
2051 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2052 part.KeyframeMotion.UpdateSceneObject(this);
2053 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 2054 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 2055 });
1389 2056
@@ -1436,10 +2103,14 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2103 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2104 public SceneObjectGroup Copy(bool userExposed)
1438 { 2105 {
2106 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2107 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2108 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2109 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1442 2110
2111 // new group as no sitting avatars
2112 dupe.m_linkedAvatars = new List<ScenePresence>();
2113
1443 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2114 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1444 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2115 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1445 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2116 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1450,7 +2121,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2121 // This is only necessary when userExposed is false!
1451 2122
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2123 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2124
1454 if (!userExposed) 2125 if (!userExposed)
1455 dupe.IsAttachment = true; 2126 dupe.IsAttachment = true;
1456 2127
@@ -1468,11 +2139,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2139 dupe.m_rootPart.TrimPermissions();
1469 2140
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2141 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2142
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2143 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2144 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2145 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2146 }
1476 ); 2147 );
1477 2148
1478 foreach (SceneObjectPart part in partList) 2149 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2153,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2153 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2154 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2155 newPart.LinkNum = part.LinkNum;
1485 } 2156 if (userExposed)
2157 newPart.ParentID = dupe.m_rootPart.LocalId;
2158 }
1486 else 2159 else
1487 { 2160 {
1488 newPart = dupe.m_rootPart; 2161 newPart = dupe.m_rootPart;
1489 } 2162 }
2163/*
2164 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2165 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2166
1491 // Need to duplicate the physics actor as well 2167 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2168 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2169 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2170 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2171 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2172 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2173 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2174 pbs,
1501 newPart.AbsolutePosition, 2175 newPart.AbsolutePosition,
1502 newPart.Scale, 2176 newPart.Scale,
1503 newPart.RotationOffset, 2177 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2178 isphys,
2179 isphan,
1505 newPart.LocalId); 2180 newPart.LocalId);
1506 2181
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2182 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2183 */
2184 if (userExposed)
2185 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2186// }
1509 } 2187 }
1510 2188
1511 if (userExposed) 2189 if (userExposed)
1512 { 2190 {
1513 dupe.UpdateParentIDs(); 2191// done above dupe.UpdateParentIDs();
2192
2193 if (dupe.m_rootPart.PhysActor != null)
2194 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2195
1514 dupe.HasGroupChanged = true; 2196 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2197 dupe.AttachToBackup();
1516 2198
1517 ScheduleGroupForFullUpdate(); 2199 ScheduleGroupForFullUpdate();
1518 } 2200 }
1519 2201
2202 m_dupeInProgress = false;
1520 return dupe; 2203 return dupe;
1521 } 2204 }
1522 2205
@@ -1528,11 +2211,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2211 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2212 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2213 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2214 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2215 // give newpart a new local ID lettng old part keep same
2216 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2217 newpart.LocalId = m_scene.AllocateLocalId();
2218
2219 SetRootPart(newpart);
2220 if (userExposed)
2221 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2222 }
1533 2223
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2224 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2225 {
2226 if (usePhysics)
2227 {
2228 if (RootPart.KeyframeMotion != null)
2229 RootPart.KeyframeMotion.Stop();
2230 RootPart.KeyframeMotion = null;
2231 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2232 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2233 }
1538 2234
@@ -1580,13 +2276,14 @@ namespace OpenSim.Region.Framework.Scenes
1580 2276
1581 if (pa != null) 2277 if (pa != null)
1582 { 2278 {
1583 pa.AddForce(impulse, true); 2279 // false to be applied as a impulse
2280 pa.AddForce(impulse, false);
1584 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2281 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1585 } 2282 }
1586 } 2283 }
1587 } 2284 }
1588 2285
1589 public void applyAngularImpulse(Vector3 impulse) 2286 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2287 {
1591 PhysicsActor pa = RootPart.PhysActor; 2288 PhysicsActor pa = RootPart.PhysActor;
1592 2289
@@ -1594,21 +2291,8 @@ namespace OpenSim.Region.Framework.Scenes
1594 { 2291 {
1595 if (!IsAttachment) 2292 if (!IsAttachment)
1596 { 2293 {
1597 pa.AddAngularForce(impulse, true); 2294 // false to be applied as a impulse
1598 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2295 pa.AddAngularForce(impulse, false);
1599 }
1600 }
1601 }
1602
1603 public void setAngularImpulse(Vector3 impulse)
1604 {
1605 PhysicsActor pa = RootPart.PhysActor;
1606
1607 if (pa != null)
1608 {
1609 if (!IsAttachment)
1610 {
1611 pa.Torque = impulse;
1612 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2296 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1613 } 2297 }
1614 } 2298 }
@@ -1616,20 +2300,10 @@ namespace OpenSim.Region.Framework.Scenes
1616 2300
1617 public Vector3 GetTorque() 2301 public Vector3 GetTorque()
1618 { 2302 {
1619 PhysicsActor pa = RootPart.PhysActor; 2303 return RootPart.Torque;
1620
1621 if (pa != null)
1622 {
1623 if (!IsAttachment)
1624 {
1625 Vector3 torque = pa.Torque;
1626 return torque;
1627 }
1628 }
1629
1630 return Vector3.Zero;
1631 } 2304 }
1632 2305
2306 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2307 public void moveToTarget(Vector3 target, float tau)
1634 { 2308 {
1635 if (IsAttachment) 2309 if (IsAttachment)
@@ -1661,6 +2335,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2335 pa.PIDActive = false;
1662 } 2336 }
1663 2337
2338 public void rotLookAt(Quaternion target, float strength, float damping)
2339 {
2340 SceneObjectPart rootpart = m_rootPart;
2341 if (rootpart != null)
2342 {
2343 if (IsAttachment)
2344 {
2345 /*
2346 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2347 if (avatar != null)
2348 {
2349 Rotate the Av?
2350 } */
2351 }
2352 else
2353 {
2354 if (rootpart.PhysActor != null)
2355 { // APID must be implemented in your physics system for this to function.
2356 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2357 rootpart.PhysActor.APIDStrength = strength;
2358 rootpart.PhysActor.APIDDamping = damping;
2359 rootpart.PhysActor.APIDActive = true;
2360 }
2361 }
2362 }
2363 }
2364
2365 public void stopLookAt()
2366 {
2367 SceneObjectPart rootpart = m_rootPart;
2368 if (rootpart != null)
2369 {
2370 if (rootpart.PhysActor != null)
2371 { // APID must be implemented in your physics system for this to function.
2372 rootpart.PhysActor.APIDActive = false;
2373 }
2374 }
2375
2376 }
2377
1664 /// <summary> 2378 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2379 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2380 /// </summary>
@@ -1677,7 +2391,7 @@ namespace OpenSim.Region.Framework.Scenes
1677 { 2391 {
1678 pa.PIDHoverHeight = height; 2392 pa.PIDHoverHeight = height;
1679 pa.PIDHoverType = hoverType; 2393 pa.PIDHoverType = hoverType;
1680 pa.PIDTau = tau; 2394 pa.PIDHoverTau = tau;
1681 pa.PIDHoverActive = true; 2395 pa.PIDHoverActive = true;
1682 } 2396 }
1683 else 2397 else
@@ -1717,7 +2431,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2431 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2432 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2433 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2434 // give new ID to the new part, letting old keep original
2435 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2436 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2437 newPart.LocalId = m_scene.AllocateLocalId();
2438 newPart.SetParent(this);
2439
1721 AddPart(newPart); 2440 AddPart(newPart);
1722 2441
1723 SetPartAsNonRoot(newPart); 2442 SetPartAsNonRoot(newPart);
@@ -1846,11 +2565,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2565 /// Immediately send a full update for this scene object.
1847 /// </summary> 2566 /// </summary>
1848 public void SendGroupFullUpdate() 2567 public void SendGroupFullUpdate()
1849 { 2568 {
1850 if (IsDeleted) 2569 if (IsDeleted)
1851 return; 2570 return;
1852 2571
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2572// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2573
1855 RootPart.SendFullUpdateToAllClients(); 2574 RootPart.SendFullUpdateToAllClients();
1856 2575
@@ -1984,6 +2703,11 @@ namespace OpenSim.Region.Framework.Scenes
1984 2703
1985 SceneObjectPart linkPart = objectGroup.m_rootPart; 2704 SceneObjectPart linkPart = objectGroup.m_rootPart;
1986 2705
2706 if (m_rootPart.PhysActor != null)
2707 m_rootPart.PhysActor.Building = true;
2708 if (linkPart.PhysActor != null)
2709 linkPart.PhysActor.Building = true;
2710
1987 // physics flags from group to be applied to linked parts 2711 // physics flags from group to be applied to linked parts
1988 bool grpusephys = UsesPhysics; 2712 bool grpusephys = UsesPhysics;
1989 bool grptemporary = IsTemporary; 2713 bool grptemporary = IsTemporary;
@@ -1992,19 +2716,21 @@ namespace OpenSim.Region.Framework.Scenes
1992 Quaternion oldRootRotation = linkPart.RotationOffset; 2716 Quaternion oldRootRotation = linkPart.RotationOffset;
1993 2717
1994 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2718 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2719
1995 linkPart.ParentID = m_rootPart.LocalId; 2720 linkPart.ParentID = m_rootPart.LocalId;
1996 linkPart.GroupPosition = AbsolutePosition; 2721
1997 Vector3 axPos = linkPart.OffsetPosition; 2722 linkPart.GroupPosition = AbsolutePosition;
1998 2723
2724 Vector3 axPos = linkPart.OffsetPosition;
1999 Quaternion parentRot = m_rootPart.RotationOffset; 2725 Quaternion parentRot = m_rootPart.RotationOffset;
2000 axPos *= Quaternion.Inverse(parentRot); 2726 axPos *= Quaternion.Conjugate(parentRot);
2001
2002 linkPart.OffsetPosition = axPos; 2727 linkPart.OffsetPosition = axPos;
2728
2003 Quaternion oldRot = linkPart.RotationOffset; 2729 Quaternion oldRot = linkPart.RotationOffset;
2004 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2730 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2005 linkPart.RotationOffset = newRot; 2731 linkPart.RotationOffset = newRot;
2006 2732
2007 linkPart.ParentID = m_rootPart.LocalId; 2733// linkPart.ParentID = m_rootPart.LocalId; done above
2008 2734
2009 if (m_rootPart.LinkNum == 0) 2735 if (m_rootPart.LinkNum == 0)
2010 m_rootPart.LinkNum = 1; 2736 m_rootPart.LinkNum = 1;
@@ -2032,7 +2758,7 @@ namespace OpenSim.Region.Framework.Scenes
2032 linkPart.CreateSelected = true; 2758 linkPart.CreateSelected = true;
2033 2759
2034 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2760 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2035 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2761 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2036 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2762 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2037 { 2763 {
2038 linkPart.PhysActor.link(m_rootPart.PhysActor); 2764 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2040,6 +2766,7 @@ namespace OpenSim.Region.Framework.Scenes
2040 } 2766 }
2041 2767
2042 linkPart.LinkNum = linkNum++; 2768 linkPart.LinkNum = linkNum++;
2769 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2043 2770
2044 SceneObjectPart[] ogParts = objectGroup.Parts; 2771 SceneObjectPart[] ogParts = objectGroup.Parts;
2045 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2772 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2054,7 +2781,7 @@ namespace OpenSim.Region.Framework.Scenes
2054 { 2781 {
2055 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2782 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2056 // let physics know 2783 // let physics know
2057 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2784 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2058 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2785 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2059 { 2786 {
2060 part.PhysActor.link(m_rootPart.PhysActor); 2787 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2069,7 +2796,7 @@ namespace OpenSim.Region.Framework.Scenes
2069 objectGroup.IsDeleted = true; 2796 objectGroup.IsDeleted = true;
2070 2797
2071 objectGroup.m_parts.Clear(); 2798 objectGroup.m_parts.Clear();
2072 2799
2073 // Can't do this yet since backup still makes use of the root part without any synchronization 2800 // Can't do this yet since backup still makes use of the root part without any synchronization
2074// objectGroup.m_rootPart = null; 2801// objectGroup.m_rootPart = null;
2075 2802
@@ -2080,6 +2807,9 @@ namespace OpenSim.Region.Framework.Scenes
2080 // unmoved prims! 2807 // unmoved prims!
2081 ResetChildPrimPhysicsPositions(); 2808 ResetChildPrimPhysicsPositions();
2082 2809
2810 if (m_rootPart.PhysActor != null)
2811 m_rootPart.PhysActor.Building = false;
2812
2083 //HasGroupChanged = true; 2813 //HasGroupChanged = true;
2084 //ScheduleGroupForFullUpdate(); 2814 //ScheduleGroupForFullUpdate();
2085 } 2815 }
@@ -2147,7 +2877,10 @@ namespace OpenSim.Region.Framework.Scenes
2147// m_log.DebugFormat( 2877// m_log.DebugFormat(
2148// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2878// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2149// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2879// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2150 2880
2881 if (m_rootPart.PhysActor != null)
2882 m_rootPart.PhysActor.Building = true;
2883
2151 linkPart.ClearUndoState(); 2884 linkPart.ClearUndoState();
2152 2885
2153 Quaternion worldRot = linkPart.GetWorldRotation(); 2886 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2207,6 +2940,14 @@ namespace OpenSim.Region.Framework.Scenes
2207 2940
2208 // When we delete a group, we currently have to force persist to the database if the object id has changed 2941 // When we delete a group, we currently have to force persist to the database if the object id has changed
2209 // (since delete works by deleting all rows which have a given object id) 2942 // (since delete works by deleting all rows which have a given object id)
2943
2944 // this is as it seems to be in sl now
2945 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2946 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2947
2948 if (m_rootPart.PhysActor != null)
2949 m_rootPart.PhysActor.Building = false;
2950
2210 objectGroup.HasGroupChangedDueToDelink = true; 2951 objectGroup.HasGroupChangedDueToDelink = true;
2211 2952
2212 return objectGroup; 2953 return objectGroup;
@@ -2218,6 +2959,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2959 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2960 public virtual void DetachFromBackup()
2220 { 2961 {
2962 m_scene.SceneGraph.FireDetachFromBackup(this);
2221 if (m_isBackedUp && Scene != null) 2963 if (m_isBackedUp && Scene != null)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2964 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2965
@@ -2236,7 +2978,8 @@ namespace OpenSim.Region.Framework.Scenes
2236 2978
2237 axPos *= parentRot; 2979 axPos *= parentRot;
2238 part.OffsetPosition = axPos; 2980 part.OffsetPosition = axPos;
2239 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2981 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2982 part.GroupPosition = newPos;
2240 part.OffsetPosition = Vector3.Zero; 2983 part.OffsetPosition = Vector3.Zero;
2241 part.RotationOffset = worldRot; 2984 part.RotationOffset = worldRot;
2242 2985
@@ -2247,20 +2990,20 @@ namespace OpenSim.Region.Framework.Scenes
2247 2990
2248 part.LinkNum = linkNum; 2991 part.LinkNum = linkNum;
2249 2992
2250 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2993 part.OffsetPosition = newPos - AbsolutePosition;
2251 2994
2252 Quaternion rootRotation = m_rootPart.RotationOffset; 2995 Quaternion rootRotation = m_rootPart.RotationOffset;
2253 2996
2254 Vector3 pos = part.OffsetPosition; 2997 Vector3 pos = part.OffsetPosition;
2255 pos *= Quaternion.Inverse(rootRotation); 2998 pos *= Quaternion.Conjugate(rootRotation);
2256 part.OffsetPosition = pos; 2999 part.OffsetPosition = pos;
2257 3000
2258 parentRot = m_rootPart.RotationOffset; 3001 parentRot = m_rootPart.RotationOffset;
2259 oldRot = part.RotationOffset; 3002 oldRot = part.RotationOffset;
2260 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3003 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2261 part.RotationOffset = newRot; 3004 part.RotationOffset = newRot;
2262 3005
2263 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3006 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2264 } 3007 }
2265 3008
2266 /// <summary> 3009 /// <summary>
@@ -2511,8 +3254,22 @@ namespace OpenSim.Region.Framework.Scenes
2511 } 3254 }
2512 } 3255 }
2513 3256
2514 for (int i = 0; i < parts.Length; i++) 3257 if (parts.Length > 1)
2515 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3258 {
3259 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3260
3261 for (int i = 0; i < parts.Length; i++)
3262 {
3263
3264 if (parts[i].UUID != m_rootPart.UUID)
3265 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3266 }
3267
3268 if (m_rootPart.PhysActor != null)
3269 m_rootPart.PhysActor.Building = false;
3270 }
3271 else
3272 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2516 } 3273 }
2517 } 3274 }
2518 3275
@@ -2525,6 +3282,17 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 3282 }
2526 } 3283 }
2527 3284
3285
3286
3287 /// <summary>
3288 /// Gets the number of parts
3289 /// </summary>
3290 /// <returns></returns>
3291 public int GetPartCount()
3292 {
3293 return Parts.Count();
3294 }
3295
2528 /// <summary> 3296 /// <summary>
2529 /// Update the texture entry for this part 3297 /// Update the texture entry for this part
2530 /// </summary> 3298 /// </summary>
@@ -2586,11 +3354,6 @@ namespace OpenSim.Region.Framework.Scenes
2586 /// <param name="scale"></param> 3354 /// <param name="scale"></param>
2587 public void GroupResize(Vector3 scale) 3355 public void GroupResize(Vector3 scale)
2588 { 3356 {
2589// m_log.DebugFormat(
2590// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2591
2592 RootPart.StoreUndoState(true);
2593
2594 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3357 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2595 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3358 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2596 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3359 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2617,7 +3380,6 @@ namespace OpenSim.Region.Framework.Scenes
2617 SceneObjectPart obPart = parts[i]; 3380 SceneObjectPart obPart = parts[i];
2618 if (obPart.UUID != m_rootPart.UUID) 3381 if (obPart.UUID != m_rootPart.UUID)
2619 { 3382 {
2620// obPart.IgnoreUndoUpdate = true;
2621 Vector3 oldSize = new Vector3(obPart.Scale); 3383 Vector3 oldSize = new Vector3(obPart.Scale);
2622 3384
2623 float f = 1.0f; 3385 float f = 1.0f;
@@ -2681,8 +3443,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 z *= a; 3443 z *= a;
2682 } 3444 }
2683 } 3445 }
2684
2685// obPart.IgnoreUndoUpdate = false;
2686 } 3446 }
2687 } 3447 }
2688 } 3448 }
@@ -2692,9 +3452,7 @@ namespace OpenSim.Region.Framework.Scenes
2692 prevScale.Y *= y; 3452 prevScale.Y *= y;
2693 prevScale.Z *= z; 3453 prevScale.Z *= z;
2694 3454
2695// RootPart.IgnoreUndoUpdate = true;
2696 RootPart.Resize(prevScale); 3455 RootPart.Resize(prevScale);
2697// RootPart.IgnoreUndoUpdate = false;
2698 3456
2699 parts = m_parts.GetArray(); 3457 parts = m_parts.GetArray();
2700 for (int i = 0; i < parts.Length; i++) 3458 for (int i = 0; i < parts.Length; i++)
@@ -2703,8 +3461,6 @@ namespace OpenSim.Region.Framework.Scenes
2703 3461
2704 if (obPart.UUID != m_rootPart.UUID) 3462 if (obPart.UUID != m_rootPart.UUID)
2705 { 3463 {
2706 obPart.IgnoreUndoUpdate = true;
2707
2708 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3464 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2709 currentpos.X *= x; 3465 currentpos.X *= x;
2710 currentpos.Y *= y; 3466 currentpos.Y *= y;
@@ -2717,16 +3473,12 @@ namespace OpenSim.Region.Framework.Scenes
2717 3473
2718 obPart.Resize(newSize); 3474 obPart.Resize(newSize);
2719 obPart.UpdateOffSet(currentpos); 3475 obPart.UpdateOffSet(currentpos);
2720
2721 obPart.IgnoreUndoUpdate = false;
2722 } 3476 }
2723 3477
2724// obPart.IgnoreUndoUpdate = false; 3478 HasGroupChanged = true;
2725// obPart.StoreUndoState(); 3479 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3480 ScheduleGroupForTerseUpdate();
2726 } 3481 }
2727
2728// m_log.DebugFormat(
2729// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2730 } 3482 }
2731 3483
2732 #endregion 3484 #endregion
@@ -2739,14 +3491,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 /// <param name="pos"></param> 3491 /// <param name="pos"></param>
2740 public void UpdateGroupPosition(Vector3 pos) 3492 public void UpdateGroupPosition(Vector3 pos)
2741 { 3493 {
2742// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2743
2744 RootPart.StoreUndoState(true);
2745
2746// SceneObjectPart[] parts = m_parts.GetArray();
2747// for (int i = 0; i < parts.Length; i++)
2748// parts[i].StoreUndoState();
2749
2750 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3494 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2751 { 3495 {
2752 if (IsAttachment) 3496 if (IsAttachment)
@@ -2779,21 +3523,17 @@ namespace OpenSim.Region.Framework.Scenes
2779 /// </summary> 3523 /// </summary>
2780 /// <param name="pos"></param> 3524 /// <param name="pos"></param>
2781 /// <param name="localID"></param> 3525 /// <param name="localID"></param>
3526 ///
3527
2782 public void UpdateSinglePosition(Vector3 pos, uint localID) 3528 public void UpdateSinglePosition(Vector3 pos, uint localID)
2783 { 3529 {
2784 SceneObjectPart part = GetPart(localID); 3530 SceneObjectPart part = GetPart(localID);
2785 3531
2786// SceneObjectPart[] parts = m_parts.GetArray();
2787// for (int i = 0; i < parts.Length; i++)
2788// parts[i].StoreUndoState();
2789
2790 if (part != null) 3532 if (part != null)
2791 { 3533 {
2792// m_log.DebugFormat( 3534// unlock parts position change
2793// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3535 if (m_rootPart.PhysActor != null)
2794 3536 m_rootPart.PhysActor.Building = true;
2795 part.StoreUndoState(false);
2796 part.IgnoreUndoUpdate = true;
2797 3537
2798 if (part.UUID == m_rootPart.UUID) 3538 if (part.UUID == m_rootPart.UUID)
2799 { 3539 {
@@ -2804,8 +3544,10 @@ namespace OpenSim.Region.Framework.Scenes
2804 part.UpdateOffSet(pos); 3544 part.UpdateOffSet(pos);
2805 } 3545 }
2806 3546
3547 if (m_rootPart.PhysActor != null)
3548 m_rootPart.PhysActor.Building = false;
3549
2807 HasGroupChanged = true; 3550 HasGroupChanged = true;
2808 part.IgnoreUndoUpdate = false;
2809 } 3551 }
2810 } 3552 }
2811 3553
@@ -2815,13 +3557,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 /// <param name="pos"></param> 3557 /// <param name="pos"></param>
2816 public void UpdateRootPosition(Vector3 pos) 3558 public void UpdateRootPosition(Vector3 pos)
2817 { 3559 {
2818// m_log.DebugFormat( 3560 // needs to be called with phys building true
2819// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2820
2821// SceneObjectPart[] parts = m_parts.GetArray();
2822// for (int i = 0; i < parts.Length; i++)
2823// parts[i].StoreUndoState();
2824
2825 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3561 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2826 Vector3 oldPos = 3562 Vector3 oldPos =
2827 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3563 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2844,7 +3580,14 @@ namespace OpenSim.Region.Framework.Scenes
2844 AbsolutePosition = newPos; 3580 AbsolutePosition = newPos;
2845 3581
2846 HasGroupChanged = true; 3582 HasGroupChanged = true;
2847 ScheduleGroupForTerseUpdate(); 3583 if (m_rootPart.Undoing)
3584 {
3585 ScheduleGroupForFullUpdate();
3586 }
3587 else
3588 {
3589 ScheduleGroupForTerseUpdate();
3590 }
2848 } 3591 }
2849 3592
2850 #endregion 3593 #endregion
@@ -2857,24 +3600,16 @@ namespace OpenSim.Region.Framework.Scenes
2857 /// <param name="rot"></param> 3600 /// <param name="rot"></param>
2858 public void UpdateGroupRotationR(Quaternion rot) 3601 public void UpdateGroupRotationR(Quaternion rot)
2859 { 3602 {
2860// m_log.DebugFormat(
2861// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2862
2863// SceneObjectPart[] parts = m_parts.GetArray();
2864// for (int i = 0; i < parts.Length; i++)
2865// parts[i].StoreUndoState();
2866
2867 m_rootPart.StoreUndoState(true);
2868
2869 m_rootPart.UpdateRotation(rot); 3603 m_rootPart.UpdateRotation(rot);
2870 3604
3605/* this is done by rootpart RotationOffset set called by UpdateRotation
2871 PhysicsActor actor = m_rootPart.PhysActor; 3606 PhysicsActor actor = m_rootPart.PhysActor;
2872 if (actor != null) 3607 if (actor != null)
2873 { 3608 {
2874 actor.Orientation = m_rootPart.RotationOffset; 3609 actor.Orientation = m_rootPart.RotationOffset;
2875 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3610 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2876 } 3611 }
2877 3612*/
2878 HasGroupChanged = true; 3613 HasGroupChanged = true;
2879 ScheduleGroupForTerseUpdate(); 3614 ScheduleGroupForTerseUpdate();
2880 } 3615 }
@@ -2886,16 +3621,6 @@ namespace OpenSim.Region.Framework.Scenes
2886 /// <param name="rot"></param> 3621 /// <param name="rot"></param>
2887 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3622 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2888 { 3623 {
2889// m_log.DebugFormat(
2890// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2891
2892// SceneObjectPart[] parts = m_parts.GetArray();
2893// for (int i = 0; i < parts.Length; i++)
2894// parts[i].StoreUndoState();
2895
2896 RootPart.StoreUndoState(true);
2897 RootPart.IgnoreUndoUpdate = true;
2898
2899 m_rootPart.UpdateRotation(rot); 3624 m_rootPart.UpdateRotation(rot);
2900 3625
2901 PhysicsActor actor = m_rootPart.PhysActor; 3626 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2909,8 +3634,6 @@ namespace OpenSim.Region.Framework.Scenes
2909 3634
2910 HasGroupChanged = true; 3635 HasGroupChanged = true;
2911 ScheduleGroupForTerseUpdate(); 3636 ScheduleGroupForTerseUpdate();
2912
2913 RootPart.IgnoreUndoUpdate = false;
2914 } 3637 }
2915 3638
2916 /// <summary> 3639 /// <summary>
@@ -2923,13 +3646,11 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart part = GetPart(localID); 3646 SceneObjectPart part = GetPart(localID);
2924 3647
2925 SceneObjectPart[] parts = m_parts.GetArray(); 3648 SceneObjectPart[] parts = m_parts.GetArray();
2926 for (int i = 0; i < parts.Length; i++)
2927 parts[i].StoreUndoState();
2928 3649
2929 if (part != null) 3650 if (part != null)
2930 { 3651 {
2931// m_log.DebugFormat( 3652 if (m_rootPart.PhysActor != null)
2932// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3653 m_rootPart.PhysActor.Building = true;
2933 3654
2934 if (part.UUID == m_rootPart.UUID) 3655 if (part.UUID == m_rootPart.UUID)
2935 { 3656 {
@@ -2939,6 +3660,9 @@ namespace OpenSim.Region.Framework.Scenes
2939 { 3660 {
2940 part.UpdateRotation(rot); 3661 part.UpdateRotation(rot);
2941 } 3662 }
3663
3664 if (m_rootPart.PhysActor != null)
3665 m_rootPart.PhysActor.Building = false;
2942 } 3666 }
2943 } 3667 }
2944 3668
@@ -2952,12 +3676,8 @@ namespace OpenSim.Region.Framework.Scenes
2952 SceneObjectPart part = GetPart(localID); 3676 SceneObjectPart part = GetPart(localID);
2953 if (part != null) 3677 if (part != null)
2954 { 3678 {
2955// m_log.DebugFormat( 3679 if (m_rootPart.PhysActor != null)
2956// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3680 m_rootPart.PhysActor.Building = true;
2957// part.Name, part.LocalId, rot);
2958
2959 part.StoreUndoState();
2960 part.IgnoreUndoUpdate = true;
2961 3681
2962 if (part.UUID == m_rootPart.UUID) 3682 if (part.UUID == m_rootPart.UUID)
2963 { 3683 {
@@ -2970,7 +3690,8 @@ namespace OpenSim.Region.Framework.Scenes
2970 part.OffsetPosition = pos; 3690 part.OffsetPosition = pos;
2971 } 3691 }
2972 3692
2973 part.IgnoreUndoUpdate = false; 3693 if (m_rootPart.PhysActor != null)
3694 m_rootPart.PhysActor.Building = false;
2974 } 3695 }
2975 } 3696 }
2976 3697
@@ -2980,15 +3701,12 @@ namespace OpenSim.Region.Framework.Scenes
2980 /// <param name="rot"></param> 3701 /// <param name="rot"></param>
2981 public void UpdateRootRotation(Quaternion rot) 3702 public void UpdateRootRotation(Quaternion rot)
2982 { 3703 {
2983// m_log.DebugFormat( 3704 // needs to be called with phys building true
2984// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2985// Name, LocalId, rot);
2986
2987 Quaternion axRot = rot; 3705 Quaternion axRot = rot;
2988 Quaternion oldParentRot = m_rootPart.RotationOffset; 3706 Quaternion oldParentRot = m_rootPart.RotationOffset;
2989 3707
2990 m_rootPart.StoreUndoState(); 3708 //Don't use UpdateRotation because it schedules an update prematurely
2991 m_rootPart.UpdateRotation(rot); 3709 m_rootPart.RotationOffset = rot;
2992 3710
2993 PhysicsActor pa = m_rootPart.PhysActor; 3711 PhysicsActor pa = m_rootPart.PhysActor;
2994 3712
@@ -3004,35 +3722,144 @@ namespace OpenSim.Region.Framework.Scenes
3004 SceneObjectPart prim = parts[i]; 3722 SceneObjectPart prim = parts[i];
3005 if (prim.UUID != m_rootPart.UUID) 3723 if (prim.UUID != m_rootPart.UUID)
3006 { 3724 {
3007 prim.IgnoreUndoUpdate = true; 3725 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3726 NewRot = Quaternion.Inverse(axRot) * NewRot;
3727 prim.RotationOffset = NewRot;
3728
3008 Vector3 axPos = prim.OffsetPosition; 3729 Vector3 axPos = prim.OffsetPosition;
3730
3009 axPos *= oldParentRot; 3731 axPos *= oldParentRot;
3010 axPos *= Quaternion.Inverse(axRot); 3732 axPos *= Quaternion.Inverse(axRot);
3011 prim.OffsetPosition = axPos; 3733 prim.OffsetPosition = axPos;
3012 Quaternion primsRot = prim.RotationOffset; 3734 }
3013 Quaternion newRot = oldParentRot * primsRot; 3735 }
3014 newRot = Quaternion.Inverse(axRot) * newRot;
3015 prim.RotationOffset = newRot;
3016 prim.ScheduleTerseUpdate();
3017 prim.IgnoreUndoUpdate = false;
3018 }
3019 }
3020
3021// for (int i = 0; i < parts.Length; i++)
3022// {
3023// SceneObjectPart childpart = parts[i];
3024// if (childpart != m_rootPart)
3025// {
3026//// childpart.IgnoreUndoUpdate = false;
3027//// childpart.StoreUndoState();
3028// }
3029// }
3030 3736
3031 m_rootPart.ScheduleTerseUpdate(); 3737 HasGroupChanged = true;
3738 ScheduleGroupForFullUpdate();
3739 }
3032 3740
3033// m_log.DebugFormat( 3741 private enum updatetype :int
3034// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3742 {
3035// Name, LocalId, rot); 3743 none = 0,
3744 partterse = 1,
3745 partfull = 2,
3746 groupterse = 3,
3747 groupfull = 4
3748 }
3749
3750 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3751 {
3752 // TODO this still as excessive *.Schedule*Update()s
3753
3754 if (part != null && part.ParentGroup != null)
3755 {
3756 ObjectChangeType change = data.change;
3757 bool togroup = ((change & ObjectChangeType.Group) != 0);
3758 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3759
3760 SceneObjectGroup group = part.ParentGroup;
3761 PhysicsActor pha = group.RootPart.PhysActor;
3762
3763 updatetype updateType = updatetype.none;
3764
3765 if (togroup)
3766 {
3767 // related to group
3768 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3769 {
3770 if ((change & ObjectChangeType.Rotation) != 0)
3771 {
3772 group.RootPart.UpdateRotation(data.rotation);
3773 updateType = updatetype.none;
3774 }
3775 if ((change & ObjectChangeType.Position) != 0)
3776 {
3777 UpdateGroupPosition(data.position);
3778 updateType = updatetype.groupterse;
3779 }
3780 else
3781 // ugly rotation update of all parts
3782 {
3783 group.AbsolutePosition = AbsolutePosition;
3784 }
3785
3786 }
3787 if ((change & ObjectChangeType.Scale) != 0)
3788 {
3789 if (pha != null)
3790 pha.Building = true;
3791
3792 group.GroupResize(data.scale);
3793 updateType = updatetype.none;
3794
3795 if (pha != null)
3796 pha.Building = false;
3797 }
3798 }
3799 else
3800 {
3801 // related to single prim in a link-set ( ie group)
3802 if (pha != null)
3803 pha.Building = true;
3804
3805 // root part is special
3806 // parts offset positions or rotations need to change also
3807
3808 if (part == group.RootPart)
3809 {
3810 if ((change & ObjectChangeType.Rotation) != 0)
3811 group.UpdateRootRotation(data.rotation);
3812 if ((change & ObjectChangeType.Position) != 0)
3813 group.UpdateRootPosition(data.position);
3814 if ((change & ObjectChangeType.Scale) != 0)
3815 part.Resize(data.scale);
3816 }
3817 else
3818 {
3819 if ((change & ObjectChangeType.Position) != 0)
3820 {
3821 part.OffsetPosition = data.position;
3822 updateType = updatetype.partterse;
3823 }
3824 if ((change & ObjectChangeType.Rotation) != 0)
3825 {
3826 part.UpdateRotation(data.rotation);
3827 updateType = updatetype.none;
3828 }
3829 if ((change & ObjectChangeType.Scale) != 0)
3830 {
3831 part.Resize(data.scale);
3832 updateType = updatetype.none;
3833 }
3834 }
3835
3836 if (pha != null)
3837 pha.Building = false;
3838 }
3839
3840 if (updateType != updatetype.none)
3841 {
3842 group.HasGroupChanged = true;
3843
3844 switch (updateType)
3845 {
3846 case updatetype.partterse:
3847 part.ScheduleTerseUpdate();
3848 break;
3849 case updatetype.partfull:
3850 part.ScheduleFullUpdate();
3851 break;
3852 case updatetype.groupterse:
3853 group.ScheduleGroupForTerseUpdate();
3854 break;
3855 case updatetype.groupfull:
3856 group.ScheduleGroupForFullUpdate();
3857 break;
3858 default:
3859 break;
3860 }
3861 }
3862 }
3036 } 3863 }
3037 3864
3038 #endregion 3865 #endregion
@@ -3252,11 +4079,50 @@ namespace OpenSim.Region.Framework.Scenes
3252 } 4079 }
3253 } 4080 }
3254 } 4081 }
3255 4082
4083 public Vector3 GetGeometricCenter()
4084 {
4085 // this is not real geometric center but a average of positions relative to root prim acording to
4086 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4087 // ignoring tortured prims details since sl also seems to ignore
4088 // so no real use in doing it on physics
4089
4090 Vector3 gc = Vector3.Zero;
4091
4092 int nparts = m_parts.Count;
4093 if (nparts <= 1)
4094 return gc;
4095
4096 SceneObjectPart[] parts = m_parts.GetArray();
4097 nparts = parts.Length; // just in case it changed
4098 if (nparts <= 1)
4099 return gc;
4100
4101 Quaternion parentRot = RootPart.RotationOffset;
4102 Vector3 pPos;
4103
4104 // average all parts positions
4105 for (int i = 0; i < nparts; i++)
4106 {
4107 // do it directly
4108 // gc += parts[i].GetWorldPosition();
4109 if (parts[i] != RootPart)
4110 {
4111 pPos = parts[i].OffsetPosition;
4112 gc += pPos;
4113 }
4114
4115 }
4116 gc /= nparts;
4117
4118 // relative to root:
4119// gc -= AbsolutePosition;
4120 return gc;
4121 }
4122
3256 public float GetMass() 4123 public float GetMass()
3257 { 4124 {
3258 float retmass = 0f; 4125 float retmass = 0f;
3259
3260 SceneObjectPart[] parts = m_parts.GetArray(); 4126 SceneObjectPart[] parts = m_parts.GetArray();
3261 for (int i = 0; i < parts.Length; i++) 4127 for (int i = 0; i < parts.Length; i++)
3262 retmass += parts[i].GetMass(); 4128 retmass += parts[i].GetMass();
@@ -3264,6 +4130,39 @@ namespace OpenSim.Region.Framework.Scenes
3264 return retmass; 4130 return retmass;
3265 } 4131 }
3266 4132
4133 // center of mass of full object
4134 public Vector3 GetCenterOfMass()
4135 {
4136 PhysicsActor pa = RootPart.PhysActor;
4137
4138 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4139 {
4140 // physics knows better about center of mass of physical prims
4141 Vector3 tmp = pa.CenterOfMass;
4142 return tmp;
4143 }
4144
4145 Vector3 Ptot = Vector3.Zero;
4146 float totmass = 0f;
4147 float m;
4148
4149 SceneObjectPart[] parts = m_parts.GetArray();
4150 for (int i = 0; i < parts.Length; i++)
4151 {
4152 m = parts[i].GetMass();
4153 Ptot += parts[i].GetPartCenterOfMass() * m;
4154 totmass += m;
4155 }
4156
4157 if (totmass == 0)
4158 totmass = 0;
4159 else
4160 totmass = 1 / totmass;
4161 Ptot *= totmass;
4162
4163 return Ptot;
4164 }
4165
3267 /// <summary> 4166 /// <summary>
3268 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4167 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3269 /// the physics engine can use it. 4168 /// the physics engine can use it.
@@ -3417,6 +4316,14 @@ namespace OpenSim.Region.Framework.Scenes
3417 FromItemID = uuid; 4316 FromItemID = uuid;
3418 } 4317 }
3419 4318
4319 public void ResetOwnerChangeFlag()
4320 {
4321 ForEachPart(delegate(SceneObjectPart part)
4322 {
4323 part.ResetOwnerChangeFlag();
4324 });
4325 }
4326
3420 #endregion 4327 #endregion
3421 } 4328 }
3422} 4329}