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.cs1348
1 files changed, 1129 insertions, 219 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index b4a155e..fcb1571 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,12 +24,13 @@
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.ComponentModel; 29using System.ComponentModel;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing; 31using System.Drawing;
32using System.IO; 32using System.IO;
33using System.Diagnostics;
33using System.Linq; 34using System.Linq;
34using System.Threading; 35using System.Threading;
35using System.Xml; 36using System.Xml;
@@ -43,6 +44,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
43 44
44namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
45{ 46{
47
46 [Flags] 48 [Flags]
47 public enum scriptEvents 49 public enum scriptEvents
48 { 50 {
@@ -106,8 +108,12 @@ namespace OpenSim.Region.Framework.Scenes
106 /// since the group's last persistent backup 108 /// since the group's last persistent backup
107 /// </summary> 109 /// </summary>
108 private bool m_hasGroupChanged = false; 110 private bool m_hasGroupChanged = false;
109 private long timeFirstChanged; 111 private long timeFirstChanged = 0;
110 private long timeLastChanged; 112 private long timeLastChanged = 0;
113 private long m_maxPersistTime = 0;
114 private long m_minPersistTime = 0;
115 private Random m_rand;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
111 117
112 /// <summary> 118 /// <summary>
113 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 119 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -124,9 +130,39 @@ namespace OpenSim.Region.Framework.Scenes
124 { 130 {
125 if (value) 131 if (value)
126 { 132 {
133 if (m_isBackedUp)
134 {
135 m_scene.SceneGraph.FireChangeBackup(this);
136 }
127 timeLastChanged = DateTime.Now.Ticks; 137 timeLastChanged = DateTime.Now.Ticks;
128 if (!m_hasGroupChanged) 138 if (!m_hasGroupChanged)
129 timeFirstChanged = DateTime.Now.Ticks; 139 timeFirstChanged = DateTime.Now.Ticks;
140 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
141 {
142 if (m_rand == null)
143 {
144 byte[] val = new byte[16];
145 m_rootPart.UUID.ToBytes(val, 0);
146 m_rand = new Random(BitConverter.ToInt32(val, 0));
147 }
148
149 if (m_scene.GetRootAgentCount() == 0)
150 {
151 //If the region is empty, this change has been made by an automated process
152 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
153
154 float factor = 1.5f + (float)(m_rand.NextDouble());
155 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
156 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
157 }
158 else
159 {
160 //If the region is not empty, we want to obey the minimum and maximum persist times
161 //but add a random factor so we stagger the object persistance a little
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
164 }
165 }
130 } 166 }
131 m_hasGroupChanged = value; 167 m_hasGroupChanged = value;
132 168
@@ -141,7 +177,7 @@ namespace OpenSim.Region.Framework.Scenes
141 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 177 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
142 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 178 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
143 /// </summary> 179 /// </summary>
144 public bool HasGroupChangedDueToDelink { get; private set; } 180 public bool HasGroupChangedDueToDelink { get; set; }
145 181
146 private bool isTimeToPersist() 182 private bool isTimeToPersist()
147 { 183 {
@@ -151,8 +187,19 @@ namespace OpenSim.Region.Framework.Scenes
151 return false; 187 return false;
152 if (m_scene.ShuttingDown) 188 if (m_scene.ShuttingDown)
153 return true; 189 return true;
190
191 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
192 {
193 m_maxPersistTime = m_scene.m_persistAfter;
194 m_minPersistTime = m_scene.m_dontPersistBefore;
195 }
196
154 long currentTime = DateTime.Now.Ticks; 197 long currentTime = DateTime.Now.Ticks;
155 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 198
199 if (timeLastChanged == 0) timeLastChanged = currentTime;
200 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
201
202 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
156 return true; 203 return true;
157 return false; 204 return false;
158 } 205 }
@@ -271,10 +318,10 @@ namespace OpenSim.Region.Framework.Scenes
271 318
272 private bool m_scriptListens_atTarget; 319 private bool m_scriptListens_atTarget;
273 private bool m_scriptListens_notAtTarget; 320 private bool m_scriptListens_notAtTarget;
274
275 private bool m_scriptListens_atRotTarget; 321 private bool m_scriptListens_atRotTarget;
276 private bool m_scriptListens_notAtRotTarget; 322 private bool m_scriptListens_notAtRotTarget;
277 323
324 public bool m_dupeInProgress = false;
278 internal Dictionary<UUID, string> m_savedScriptState; 325 internal Dictionary<UUID, string> m_savedScriptState;
279 326
280 #region Properties 327 #region Properties
@@ -311,6 +358,16 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_parts.Count; } 358 get { return m_parts.Count; }
312 } 359 }
313 360
361// protected Quaternion m_rotation = Quaternion.Identity;
362//
363// public virtual Quaternion Rotation
364// {
365// get { return m_rotation; }
366// set {
367// m_rotation = value;
368// }
369// }
370
314 public Quaternion GroupRotation 371 public Quaternion GroupRotation
315 { 372 {
316 get { return m_rootPart.RotationOffset; } 373 get { return m_rootPart.RotationOffset; }
@@ -417,7 +474,15 @@ namespace OpenSim.Region.Framework.Scenes
417 { 474 {
418 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 475 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
419 } 476 }
420 477
478
479
480 private struct avtocrossInfo
481 {
482 public ScenePresence av;
483 public uint ParentID;
484 }
485
421 /// <summary> 486 /// <summary>
422 /// The absolute position of this scene object in the scene 487 /// The absolute position of this scene object in the scene
423 /// </summary> 488 /// </summary>
@@ -430,14 +495,128 @@ namespace OpenSim.Region.Framework.Scenes
430 495
431 if (Scene != null) 496 if (Scene != null)
432 { 497 {
433 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 498 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
434 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 499 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
500 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
501 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
502 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
435 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 503 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
436 { 504 {
437 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 505 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
506 uint x = 0;
507 uint y = 0;
508 string version = String.Empty;
509 Vector3 newpos = Vector3.Zero;
510 OpenSim.Services.Interfaces.GridRegion destination = null;
511
512 bool canCross = true;
513 foreach (ScenePresence av in m_linkedAvatars)
514 {
515 // We need to cross these agents. First, let's find
516 // out if any of them can't cross for some reason.
517 // We have to deny the crossing entirely if any
518 // of them are banned. Alternatively, we could
519 // unsit banned agents....
520
521
522 // We set the avatar position as being the object
523 // position to get the region to send to
524 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
525 {
526 canCross = false;
527 break;
528 }
529
530 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
531 }
532
533 if (canCross)
534 {
535 // We unparent the SP quietly so that it won't
536 // be made to stand up
537
538 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
539
540 foreach (ScenePresence av in m_linkedAvatars)
541 {
542 avtocrossInfo avinfo = new avtocrossInfo();
543 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
544 if (parentPart != null)
545 av.ParentUUID = parentPart.UUID;
546
547 avinfo.av = av;
548 avinfo.ParentID = av.ParentID;
549 avsToCross.Add(avinfo);
550
551 av.ParentID = 0;
552 }
553
554// m_linkedAvatars.Clear();
555 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
556
557 // Normalize
558 if (val.X >= Constants.RegionSize)
559 val.X -= Constants.RegionSize;
560 if (val.Y >= Constants.RegionSize)
561 val.Y -= Constants.RegionSize;
562 if (val.X < 0)
563 val.X += Constants.RegionSize;
564 if (val.Y < 0)
565 val.Y += Constants.RegionSize;
566
567 // If it's deleted, crossing was successful
568 if (IsDeleted)
569 {
570 // foreach (ScenePresence av in m_linkedAvatars)
571 foreach (avtocrossInfo avinfo in avsToCross)
572 {
573 ScenePresence av = avinfo.av;
574 if (!av.IsInTransit) // just in case...
575 {
576 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
577
578 av.IsInTransit = true;
579
580 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
581 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
582 }
583 else
584 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
585 }
586 avsToCross.Clear();
587 return;
588 }
589 else // cross failed, put avas back ??
590 {
591 foreach (avtocrossInfo avinfo in avsToCross)
592 {
593 ScenePresence av = avinfo.av;
594 av.ParentUUID = UUID.Zero;
595 av.ParentID = avinfo.ParentID;
596// m_linkedAvatars.Add(av);
597 }
598 }
599 avsToCross.Clear();
600
601 }
602 else if (RootPart.PhysActor != null)
603 {
604 RootPart.PhysActor.CrossingFailure();
605 }
606
607 Vector3 oldp = AbsolutePosition;
608 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
609 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
610 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
438 } 611 }
439 } 612 }
440 613
614/* don't see the need but worse don't see where is restored to false if things stay in
615 foreach (SceneObjectPart part in m_parts.GetArray())
616 {
617 part.IgnoreUndoUpdate = true;
618 }
619 */
441 if (RootPart.GetStatusSandbox()) 620 if (RootPart.GetStatusSandbox())
442 { 621 {
443 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 622 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -455,9 +634,38 @@ namespace OpenSim.Region.Framework.Scenes
455 // Restuff the new GroupPosition into each SOP of the linkset. 634 // Restuff the new GroupPosition into each SOP of the linkset.
456 // This has the affect of resetting and tainting the physics actors. 635 // This has the affect of resetting and tainting the physics actors.
457 SceneObjectPart[] parts = m_parts.GetArray(); 636 SceneObjectPart[] parts = m_parts.GetArray();
458 for (int i = 0; i < parts.Length; i++) 637 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
459 parts[i].GroupPosition = val; 638 if (m_dupeInProgress)
639 triggerScriptEvent = false;
640 foreach (SceneObjectPart part in parts)
641 {
642 part.GroupPosition = val;
643 if (triggerScriptEvent)
644 part.TriggerScriptChangedEvent(Changed.POSITION);
645 }
460 646
647/*
648 This seems not needed and should not be needed:
649 sp absolute position depends on sit part absolute position fixed above.
650 sp ParentPosition is not used anywhere.
651 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
652 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
653
654 if (!m_dupeInProgress)
655 {
656 foreach (ScenePresence av in m_linkedAvatars)
657 {
658 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
659 if (p != null && m_parts.TryGetValue(p.UUID, out p))
660 {
661 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
662 av.AbsolutePosition += offset;
663// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
664 av.SendAvatarDataToAllAgents();
665 }
666 }
667 }
668*/
461 //if (m_rootPart.PhysActor != null) 669 //if (m_rootPart.PhysActor != null)
462 //{ 670 //{
463 //m_rootPart.PhysActor.Position = 671 //m_rootPart.PhysActor.Position =
@@ -471,6 +679,40 @@ namespace OpenSim.Region.Framework.Scenes
471 } 679 }
472 } 680 }
473 681
682 public override Vector3 Velocity
683 {
684 get { return RootPart.Velocity; }
685 set { RootPart.Velocity = value; }
686 }
687
688 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
689 {
690 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
691 ScenePresence agent = icon.EndInvoke(iar);
692
693 //// If the cross was successful, this agent is a child agent
694 if (agent.IsChildAgent)
695 {
696 if (agent.ParentUUID != UUID.Zero)
697 {
698 agent.ParentPart = null;
699// agent.ParentPosition = Vector3.Zero;
700// agent.ParentUUID = UUID.Zero;
701 }
702 }
703
704 agent.ParentUUID = UUID.Zero;
705
706// agent.Reset();
707// else // Not successful
708// agent.RestoreInCurrentScene();
709
710 // In any case
711 agent.IsInTransit = false;
712
713 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
714 }
715
474 public override uint LocalId 716 public override uint LocalId
475 { 717 {
476 get { return m_rootPart.LocalId; } 718 get { return m_rootPart.LocalId; }
@@ -541,6 +783,11 @@ namespace OpenSim.Region.Framework.Scenes
541 m_isSelected = value; 783 m_isSelected = value;
542 // Tell physics engine that group is selected 784 // Tell physics engine that group is selected
543 785
786 // this is not right
787 // but ode engines should only really need to know about root part
788 // so they can put entire object simulation on hold and not colliding
789 // keep as was for now
790
544 PhysicsActor pa = m_rootPart.PhysActor; 791 PhysicsActor pa = m_rootPart.PhysActor;
545 if (pa != null) 792 if (pa != null)
546 { 793 {
@@ -557,6 +804,42 @@ namespace OpenSim.Region.Framework.Scenes
557 childPa.Selected = value; 804 childPa.Selected = value;
558 } 805 }
559 } 806 }
807 if (RootPart.KeyframeMotion != null)
808 RootPart.KeyframeMotion.Selected = value;
809 }
810 }
811
812 public void PartSelectChanged(bool partSelect)
813 {
814 // any part selected makes group selected
815 if (m_isSelected == partSelect)
816 return;
817
818 if (partSelect)
819 {
820 IsSelected = partSelect;
821// if (!IsAttachment)
822// ScheduleGroupForFullUpdate();
823 }
824 else
825 {
826 // bad bad bad 2 heavy for large linksets
827 // since viewer does send lot of (un)selects
828 // this needs to be replaced by a specific list or count ?
829 // but that will require extra code in several places
830
831 SceneObjectPart[] parts = m_parts.GetArray();
832 for (int i = 0; i < parts.Length; i++)
833 {
834 SceneObjectPart part = parts[i];
835 if (part.IsSelected)
836 return;
837 }
838 IsSelected = partSelect;
839 if (!IsAttachment)
840 {
841 ScheduleGroupForFullUpdate();
842 }
560 } 843 }
561 } 844 }
562 845
@@ -642,6 +925,7 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 925 /// </summary>
643 public SceneObjectGroup() 926 public SceneObjectGroup()
644 { 927 {
928
645 } 929 }
646 930
647 /// <summary> 931 /// <summary>
@@ -659,8 +943,8 @@ namespace OpenSim.Region.Framework.Scenes
659 /// Constructor. This object is added to the scene later via AttachToScene() 943 /// Constructor. This object is added to the scene later via AttachToScene()
660 /// </summary> 944 /// </summary>
661 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 945 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
662 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 946 {
663 { 947 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
664 } 948 }
665 949
666 /// <summary> 950 /// <summary>
@@ -695,6 +979,9 @@ namespace OpenSim.Region.Framework.Scenes
695 /// </summary> 979 /// </summary>
696 public virtual void AttachToBackup() 980 public virtual void AttachToBackup()
697 { 981 {
982 if (IsAttachment) return;
983 m_scene.SceneGraph.FireAttachToBackup(this);
984
698 if (InSceneBackup) 985 if (InSceneBackup)
699 { 986 {
700 //m_log.DebugFormat( 987 //m_log.DebugFormat(
@@ -737,6 +1024,13 @@ namespace OpenSim.Region.Framework.Scenes
737 1024
738 ApplyPhysics(); 1025 ApplyPhysics();
739 1026
1027 if (RootPart.PhysActor != null)
1028 RootPart.Force = RootPart.Force;
1029 if (RootPart.PhysActor != null)
1030 RootPart.Torque = RootPart.Torque;
1031 if (RootPart.PhysActor != null)
1032 RootPart.Buoyancy = RootPart.Buoyancy;
1033
740 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1034 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
741 // for the same object with very different properties. The caller must schedule the update. 1035 // for the same object with very different properties. The caller must schedule the update.
742 //ScheduleGroupForFullUpdate(); 1036 //ScheduleGroupForFullUpdate();
@@ -752,6 +1046,10 @@ namespace OpenSim.Region.Framework.Scenes
752 EntityIntersection result = new EntityIntersection(); 1046 EntityIntersection result = new EntityIntersection();
753 1047
754 SceneObjectPart[] parts = m_parts.GetArray(); 1048 SceneObjectPart[] parts = m_parts.GetArray();
1049
1050 // Find closest hit here
1051 float idist = float.MaxValue;
1052
755 for (int i = 0; i < parts.Length; i++) 1053 for (int i = 0; i < parts.Length; i++)
756 { 1054 {
757 SceneObjectPart part = parts[i]; 1055 SceneObjectPart part = parts[i];
@@ -766,11 +1064,6 @@ namespace OpenSim.Region.Framework.Scenes
766 1064
767 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1065 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
768 1066
769 // This may need to be updated to the maximum draw distance possible..
770 // We might (and probably will) be checking for prim creation from other sims
771 // when the camera crosses the border.
772 float idist = Constants.RegionSize;
773
774 if (inter.HitTF) 1067 if (inter.HitTF)
775 { 1068 {
776 // We need to find the closest prim to return to the testcaller along the ray 1069 // We need to find the closest prim to return to the testcaller along the ray
@@ -781,10 +1074,11 @@ namespace OpenSim.Region.Framework.Scenes
781 result.obj = part; 1074 result.obj = part;
782 result.normal = inter.normal; 1075 result.normal = inter.normal;
783 result.distance = inter.distance; 1076 result.distance = inter.distance;
1077
1078 idist = inter.distance;
784 } 1079 }
785 } 1080 }
786 } 1081 }
787
788 return result; 1082 return result;
789 } 1083 }
790 1084
@@ -796,25 +1090,27 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <returns></returns> 1090 /// <returns></returns>
797 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1091 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
798 { 1092 {
799 maxX = -256f; 1093 maxX = float.MinValue;
800 maxY = -256f; 1094 maxY = float.MinValue;
801 maxZ = -256f; 1095 maxZ = float.MinValue;
802 minX = 256f; 1096 minX = float.MaxValue;
803 minY = 256f; 1097 minY = float.MaxValue;
804 minZ = 8192f; 1098 minZ = float.MaxValue;
805 1099
806 SceneObjectPart[] parts = m_parts.GetArray(); 1100 SceneObjectPart[] parts = m_parts.GetArray();
807 for (int i = 0; i < parts.Length; i++) 1101 foreach (SceneObjectPart part in parts)
808 { 1102 {
809 SceneObjectPart part = parts[i];
810
811 Vector3 worldPos = part.GetWorldPosition(); 1103 Vector3 worldPos = part.GetWorldPosition();
812 Vector3 offset = worldPos - AbsolutePosition; 1104 Vector3 offset = worldPos - AbsolutePosition;
813 Quaternion worldRot; 1105 Quaternion worldRot;
814 if (part.ParentID == 0) 1106 if (part.ParentID == 0)
1107 {
815 worldRot = part.RotationOffset; 1108 worldRot = part.RotationOffset;
1109 }
816 else 1110 else
1111 {
817 worldRot = part.GetWorldRotation(); 1112 worldRot = part.GetWorldRotation();
1113 }
818 1114
819 Vector3 frontTopLeft; 1115 Vector3 frontTopLeft;
820 Vector3 frontTopRight; 1116 Vector3 frontTopRight;
@@ -826,6 +1122,8 @@ namespace OpenSim.Region.Framework.Scenes
826 Vector3 backBottomLeft; 1122 Vector3 backBottomLeft;
827 Vector3 backBottomRight; 1123 Vector3 backBottomRight;
828 1124
1125 // Vector3[] corners = new Vector3[8];
1126
829 Vector3 orig = Vector3.Zero; 1127 Vector3 orig = Vector3.Zero;
830 1128
831 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1129 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -860,6 +1158,38 @@ namespace OpenSim.Region.Framework.Scenes
860 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1158 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
861 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1159 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
862 1160
1161
1162
1163 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1164 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1165 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1166 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1167 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1168 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1169 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1170 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1171
1172 //for (int i = 0; i < 8; i++)
1173 //{
1174 // corners[i] = corners[i] * worldRot;
1175 // corners[i] += offset;
1176
1177 // if (corners[i].X > maxX)
1178 // maxX = corners[i].X;
1179 // if (corners[i].X < minX)
1180 // minX = corners[i].X;
1181
1182 // if (corners[i].Y > maxY)
1183 // maxY = corners[i].Y;
1184 // if (corners[i].Y < minY)
1185 // minY = corners[i].Y;
1186
1187 // if (corners[i].Z > maxZ)
1188 // maxZ = corners[i].Y;
1189 // if (corners[i].Z < minZ)
1190 // minZ = corners[i].Z;
1191 //}
1192
863 frontTopLeft = frontTopLeft * worldRot; 1193 frontTopLeft = frontTopLeft * worldRot;
864 frontTopRight = frontTopRight * worldRot; 1194 frontTopRight = frontTopRight * worldRot;
865 frontBottomLeft = frontBottomLeft * worldRot; 1195 frontBottomLeft = frontBottomLeft * worldRot;
@@ -881,6 +1211,15 @@ namespace OpenSim.Region.Framework.Scenes
881 backTopLeft += offset; 1211 backTopLeft += offset;
882 backTopRight += offset; 1212 backTopRight += offset;
883 1213
1214 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1215 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1216 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1217 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1218 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1219 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1220 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1221 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1222
884 if (frontTopRight.X > maxX) 1223 if (frontTopRight.X > maxX)
885 maxX = frontTopRight.X; 1224 maxX = frontTopRight.X;
886 if (frontTopLeft.X > maxX) 1225 if (frontTopLeft.X > maxX)
@@ -1024,17 +1363,118 @@ namespace OpenSim.Region.Framework.Scenes
1024 1363
1025 #endregion 1364 #endregion
1026 1365
1366 public void GetResourcesCosts(SceneObjectPart apart,
1367 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1368 {
1369 // this information may need to be cached
1370
1371 float cost;
1372 float tmpcost;
1373
1374 bool ComplexCost = false;
1375
1376 SceneObjectPart p;
1377 SceneObjectPart[] parts;
1378
1379 lock (m_parts)
1380 {
1381 parts = m_parts.GetArray();
1382 }
1383
1384 int nparts = parts.Length;
1385
1386
1387 for (int i = 0; i < nparts; i++)
1388 {
1389 p = parts[i];
1390
1391 if (p.UsesComplexCost)
1392 {
1393 ComplexCost = true;
1394 break;
1395 }
1396 }
1397
1398 if (ComplexCost)
1399 {
1400 linksetResCost = 0;
1401 linksetPhysCost = 0;
1402 partCost = 0;
1403 partPhysCost = 0;
1404
1405 for (int i = 0; i < nparts; i++)
1406 {
1407 p = parts[i];
1408
1409 cost = p.StreamingCost;
1410 tmpcost = p.SimulationCost;
1411 if (tmpcost > cost)
1412 cost = tmpcost;
1413 tmpcost = p.PhysicsCost;
1414 if (tmpcost > cost)
1415 cost = tmpcost;
1416
1417 linksetPhysCost += tmpcost;
1418 linksetResCost += cost;
1419
1420 if (p == apart)
1421 {
1422 partCost = cost;
1423 partPhysCost = tmpcost;
1424 }
1425 }
1426 }
1427 else
1428 {
1429 partPhysCost = 1.0f;
1430 partCost = 1.0f;
1431 linksetResCost = (float)nparts;
1432 linksetPhysCost = linksetResCost;
1433 }
1434 }
1435
1436 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1437 {
1438 SceneObjectPart p;
1439 SceneObjectPart[] parts;
1440
1441 lock (m_parts)
1442 {
1443 parts = m_parts.GetArray();
1444 }
1445
1446 int nparts = parts.Length;
1447
1448 PhysCost = 0;
1449 StreamCost = 0;
1450 SimulCost = 0;
1451
1452 for (int i = 0; i < nparts; i++)
1453 {
1454 p = parts[i];
1455
1456 StreamCost += p.StreamingCost;
1457 SimulCost += p.SimulationCost;
1458 PhysCost += p.PhysicsCost;
1459 }
1460 }
1461
1027 public void SaveScriptedState(XmlTextWriter writer) 1462 public void SaveScriptedState(XmlTextWriter writer)
1028 { 1463 {
1464 SaveScriptedState(writer, false);
1465 }
1466
1467 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1468 {
1029 XmlDocument doc = new XmlDocument(); 1469 XmlDocument doc = new XmlDocument();
1030 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1470 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1031 1471
1032 SceneObjectPart[] parts = m_parts.GetArray(); 1472 SceneObjectPart[] parts = m_parts.GetArray();
1033 for (int i = 0; i < parts.Length; i++) 1473 for (int i = 0; i < parts.Length; i++)
1034 { 1474 {
1035 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1475 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1036 foreach (KeyValuePair<UUID, string> kvp in pstates) 1476 foreach (KeyValuePair<UUID, string> kvp in pstates)
1037 states.Add(kvp.Key, kvp.Value); 1477 states[kvp.Key] = kvp.Value;
1038 } 1478 }
1039 1479
1040 if (states.Count > 0) 1480 if (states.Count > 0)
@@ -1054,6 +1494,169 @@ namespace OpenSim.Region.Framework.Scenes
1054 } 1494 }
1055 1495
1056 /// <summary> 1496 /// <summary>
1497 /// Add the avatar to this linkset (avatar is sat).
1498 /// </summary>
1499 /// <param name="agentID"></param>
1500 public void AddAvatar(UUID agentID)
1501 {
1502 ScenePresence presence;
1503 if (m_scene.TryGetScenePresence(agentID, out presence))
1504 {
1505 if (!m_linkedAvatars.Contains(presence))
1506 {
1507 m_linkedAvatars.Add(presence);
1508 }
1509 }
1510 }
1511
1512 /// <summary>
1513 /// Delete the avatar from this linkset (avatar is unsat).
1514 /// </summary>
1515 /// <param name="agentID"></param>
1516 public void DeleteAvatar(UUID agentID)
1517 {
1518 ScenePresence presence;
1519 if (m_scene.TryGetScenePresence(agentID, out presence))
1520 {
1521 if (m_linkedAvatars.Contains(presence))
1522 {
1523 m_linkedAvatars.Remove(presence);
1524 }
1525 }
1526 }
1527
1528 /// <summary>
1529 /// Returns the list of linked presences (avatars sat on this group)
1530 /// </summary>
1531 /// <param name="agentID"></param>
1532 public List<ScenePresence> GetLinkedAvatars()
1533 {
1534 return m_linkedAvatars;
1535 }
1536
1537 /// <summary>
1538 /// Attach this scene object to the given avatar.
1539 /// </summary>
1540 /// <param name="agentID"></param>
1541 /// <param name="attachmentpoint"></param>
1542 /// <param name="AttachOffset"></param>
1543 private void AttachToAgent(
1544 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1545 {
1546 if (avatar != null)
1547 {
1548 // don't attach attachments to child agents
1549 if (avatar.IsChildAgent) return;
1550
1551 // Remove from database and parcel prim count
1552 m_scene.DeleteFromStorage(so.UUID);
1553 m_scene.EventManager.TriggerParcelPrimCountTainted();
1554
1555 so.AttachedAvatar = avatar.UUID;
1556
1557 if (so.RootPart.PhysActor != null)
1558 {
1559 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1560 so.RootPart.PhysActor = null;
1561 }
1562
1563 so.AbsolutePosition = attachOffset;
1564 so.RootPart.AttachedPos = attachOffset;
1565 so.IsAttachment = true;
1566 so.RootPart.SetParentLocalId(avatar.LocalId);
1567 so.AttachmentPoint = attachmentpoint;
1568
1569 avatar.AddAttachment(this);
1570
1571 if (!silent)
1572 {
1573 // Killing it here will cause the client to deselect it
1574 // It then reappears on the avatar, deselected
1575 // through the full update below
1576 //
1577 if (IsSelected)
1578 {
1579 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1580 }
1581
1582 IsSelected = false; // fudge....
1583 ScheduleGroupForFullUpdate();
1584 }
1585 }
1586 else
1587 {
1588 m_log.WarnFormat(
1589 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1590 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1591 }
1592 }
1593
1594 public byte GetAttachmentPoint()
1595 {
1596 return m_rootPart.Shape.State;
1597 }
1598
1599 public void DetachToGround()
1600 {
1601 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1602 if (avatar == null)
1603 return;
1604
1605 avatar.RemoveAttachment(this);
1606
1607 Vector3 detachedpos = new Vector3(127f,127f,127f);
1608 if (avatar == null)
1609 return;
1610
1611 detachedpos = avatar.AbsolutePosition;
1612 FromItemID = UUID.Zero;
1613
1614 AbsolutePosition = detachedpos;
1615 AttachedAvatar = UUID.Zero;
1616
1617 //SceneObjectPart[] parts = m_parts.GetArray();
1618 //for (int i = 0; i < parts.Length; i++)
1619 // parts[i].AttachedAvatar = UUID.Zero;
1620
1621 m_rootPart.SetParentLocalId(0);
1622 AttachmentPoint = (byte)0;
1623 // must check if buildind should be true or false here
1624 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1625 HasGroupChanged = true;
1626 RootPart.Rezzed = DateTime.Now;
1627 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1628 AttachToBackup();
1629 m_scene.EventManager.TriggerParcelPrimCountTainted();
1630 m_rootPart.ScheduleFullUpdate();
1631 m_rootPart.ClearUndoState();
1632 }
1633
1634 public void DetachToInventoryPrep()
1635 {
1636 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1637 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1638 if (avatar != null)
1639 {
1640 //detachedpos = avatar.AbsolutePosition;
1641 avatar.RemoveAttachment(this);
1642 }
1643
1644 AttachedAvatar = UUID.Zero;
1645
1646 /*SceneObjectPart[] parts = m_parts.GetArray();
1647 for (int i = 0; i < parts.Length; i++)
1648 parts[i].AttachedAvatar = UUID.Zero;*/
1649
1650 m_rootPart.SetParentLocalId(0);
1651 //m_rootPart.SetAttachmentPoint((byte)0);
1652 IsAttachment = false;
1653 AbsolutePosition = m_rootPart.AttachedPos;
1654 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1655 //AttachToBackup();
1656 //m_rootPart.ScheduleFullUpdate();
1657 }
1658
1659 /// <summary>
1057 /// 1660 ///
1058 /// </summary> 1661 /// </summary>
1059 /// <param name="part"></param> 1662 /// <param name="part"></param>
@@ -1093,7 +1696,10 @@ namespace OpenSim.Region.Framework.Scenes
1093 public void AddPart(SceneObjectPart part) 1696 public void AddPart(SceneObjectPart part)
1094 { 1697 {
1095 part.SetParent(this); 1698 part.SetParent(this);
1096 part.LinkNum = m_parts.Add(part.UUID, part); 1699 m_parts.Add(part.UUID, part);
1700
1701 part.LinkNum = m_parts.Count;
1702
1097 if (part.LinkNum == 2) 1703 if (part.LinkNum == 2)
1098 RootPart.LinkNum = 1; 1704 RootPart.LinkNum = 1;
1099 } 1705 }
@@ -1184,7 +1790,7 @@ namespace OpenSim.Region.Framework.Scenes
1184// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1790// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1185// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1791// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1186 1792
1187 part.StoreUndoState(); 1793// part.StoreUndoState();
1188 part.OnGrab(offsetPos, remoteClient); 1794 part.OnGrab(offsetPos, remoteClient);
1189 } 1795 }
1190 1796
@@ -1204,6 +1810,11 @@ namespace OpenSim.Region.Framework.Scenes
1204 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1810 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1205 public void DeleteGroupFromScene(bool silent) 1811 public void DeleteGroupFromScene(bool silent)
1206 { 1812 {
1813 // We need to keep track of this state in case this group is still queued for backup.
1814 IsDeleted = true;
1815
1816 DetachFromBackup();
1817
1207 SceneObjectPart[] parts = m_parts.GetArray(); 1818 SceneObjectPart[] parts = m_parts.GetArray();
1208 for (int i = 0; i < parts.Length; i++) 1819 for (int i = 0; i < parts.Length; i++)
1209 { 1820 {
@@ -1227,6 +1838,7 @@ namespace OpenSim.Region.Framework.Scenes
1227 } 1838 }
1228 }); 1839 });
1229 } 1840 }
1841
1230 } 1842 }
1231 1843
1232 public void AddScriptLPS(int count) 1844 public void AddScriptLPS(int count)
@@ -1296,28 +1908,43 @@ namespace OpenSim.Region.Framework.Scenes
1296 /// </summary> 1908 /// </summary>
1297 public void ApplyPhysics() 1909 public void ApplyPhysics()
1298 { 1910 {
1299 // Apply physics to the root prim
1300 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1301
1302 // Apply physics to child prims
1303 SceneObjectPart[] parts = m_parts.GetArray(); 1911 SceneObjectPart[] parts = m_parts.GetArray();
1304 if (parts.Length > 1) 1912 if (parts.Length > 1)
1305 { 1913 {
1914 ResetChildPrimPhysicsPositions();
1915
1916 // Apply physics to the root prim
1917 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1918
1919
1306 for (int i = 0; i < parts.Length; i++) 1920 for (int i = 0; i < parts.Length; i++)
1307 { 1921 {
1308 SceneObjectPart part = parts[i]; 1922 SceneObjectPart part = parts[i];
1309 if (part.LocalId != m_rootPart.LocalId) 1923 if (part.LocalId != m_rootPart.LocalId)
1310 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1924 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1311 } 1925 }
1312
1313 // Hack to get the physics scene geometries in the right spot 1926 // Hack to get the physics scene geometries in the right spot
1314 ResetChildPrimPhysicsPositions(); 1927// ResetChildPrimPhysicsPositions();
1928 if (m_rootPart.PhysActor != null)
1929 {
1930 m_rootPart.PhysActor.Building = false;
1931 }
1932 }
1933 else
1934 {
1935 // Apply physics to the root prim
1936 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1315 } 1937 }
1316 } 1938 }
1317 1939
1318 public void SetOwnerId(UUID userId) 1940 public void SetOwnerId(UUID userId)
1319 { 1941 {
1320 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1942 ForEachPart(delegate(SceneObjectPart part)
1943 {
1944
1945 part.OwnerID = userId;
1946
1947 });
1321 } 1948 }
1322 1949
1323 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1950 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1349,11 +1976,17 @@ namespace OpenSim.Region.Framework.Scenes
1349 return; 1976 return;
1350 } 1977 }
1351 1978
1979 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1980 return;
1981
1352 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1982 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1353 // any exception propogate upwards. 1983 // any exception propogate upwards.
1354 try 1984 try
1355 { 1985 {
1356 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1986 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1987 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
1988 m_scene.LoadingPrims) // Land may not be valid yet
1989
1357 { 1990 {
1358 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1991 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1359 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1992 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1380,6 +2013,7 @@ namespace OpenSim.Region.Framework.Scenes
1380 } 2013 }
1381 } 2014 }
1382 } 2015 }
2016
1383 } 2017 }
1384 2018
1385 if (m_scene.UseBackup && HasGroupChanged) 2019 if (m_scene.UseBackup && HasGroupChanged)
@@ -1387,10 +2021,30 @@ namespace OpenSim.Region.Framework.Scenes
1387 // don't backup while it's selected or you're asking for changes mid stream. 2021 // don't backup while it's selected or you're asking for changes mid stream.
1388 if (isTimeToPersist() || forcedBackup) 2022 if (isTimeToPersist() || forcedBackup)
1389 { 2023 {
2024 if (m_rootPart.PhysActor != null &&
2025 (!m_rootPart.PhysActor.IsPhysical))
2026 {
2027 // Possible ghost prim
2028 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2029 {
2030 foreach (SceneObjectPart part in m_parts.GetArray())
2031 {
2032 // Re-set physics actor positions and
2033 // orientations
2034 part.GroupPosition = m_rootPart.GroupPosition;
2035 }
2036 }
2037 }
1390// m_log.DebugFormat( 2038// m_log.DebugFormat(
1391// "[SCENE]: Storing {0}, {1} in {2}", 2039// "[SCENE]: Storing {0}, {1} in {2}",
1392// Name, UUID, m_scene.RegionInfo.RegionName); 2040// Name, UUID, m_scene.RegionInfo.RegionName);
1393 2041
2042 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2043 {
2044 RootPart.Shape.State = 0;
2045 ScheduleGroupForFullUpdate();
2046 }
2047
1394 SceneObjectGroup backup_group = Copy(false); 2048 SceneObjectGroup backup_group = Copy(false);
1395 backup_group.RootPart.Velocity = RootPart.Velocity; 2049 backup_group.RootPart.Velocity = RootPart.Velocity;
1396 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2050 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1400,6 +2054,15 @@ namespace OpenSim.Region.Framework.Scenes
1400 HasGroupChangedDueToDelink = false; 2054 HasGroupChangedDueToDelink = false;
1401 2055
1402 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2056 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2057 backup_group.ForEachPart(delegate(SceneObjectPart part)
2058 {
2059 if (part.KeyframeMotion != null)
2060 {
2061 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2062 part.KeyframeMotion.UpdateSceneObject(this);
2063 }
2064 });
2065
1403 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2066 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1404 2067
1405 backup_group.ForEachPart(delegate(SceneObjectPart part) 2068 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1456,10 +2119,14 @@ namespace OpenSim.Region.Framework.Scenes
1456 /// <returns></returns> 2119 /// <returns></returns>
1457 public SceneObjectGroup Copy(bool userExposed) 2120 public SceneObjectGroup Copy(bool userExposed)
1458 { 2121 {
2122 m_dupeInProgress = true;
1459 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2123 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1460 dupe.m_isBackedUp = false; 2124 dupe.m_isBackedUp = false;
1461 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2125 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1462 2126
2127 // new group as no sitting avatars
2128 dupe.m_linkedAvatars = new List<ScenePresence>();
2129
1463 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2130 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1464 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2131 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1465 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2132 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1470,7 +2137,7 @@ namespace OpenSim.Region.Framework.Scenes
1470 // This is only necessary when userExposed is false! 2137 // This is only necessary when userExposed is false!
1471 2138
1472 bool previousAttachmentStatus = dupe.IsAttachment; 2139 bool previousAttachmentStatus = dupe.IsAttachment;
1473 2140
1474 if (!userExposed) 2141 if (!userExposed)
1475 dupe.IsAttachment = true; 2142 dupe.IsAttachment = true;
1476 2143
@@ -1488,11 +2155,11 @@ namespace OpenSim.Region.Framework.Scenes
1488 dupe.m_rootPart.TrimPermissions(); 2155 dupe.m_rootPart.TrimPermissions();
1489 2156
1490 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2157 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1491 2158
1492 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2159 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1493 { 2160 {
1494 return p1.LinkNum.CompareTo(p2.LinkNum); 2161 return p1.LinkNum.CompareTo(p2.LinkNum);
1495 } 2162 }
1496 ); 2163 );
1497 2164
1498 foreach (SceneObjectPart part in partList) 2165 foreach (SceneObjectPart part in partList)
@@ -1502,41 +2169,53 @@ namespace OpenSim.Region.Framework.Scenes
1502 { 2169 {
1503 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2170 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1504 newPart.LinkNum = part.LinkNum; 2171 newPart.LinkNum = part.LinkNum;
1505 } 2172 if (userExposed)
2173 newPart.ParentID = dupe.m_rootPart.LocalId;
2174 }
1506 else 2175 else
1507 { 2176 {
1508 newPart = dupe.m_rootPart; 2177 newPart = dupe.m_rootPart;
1509 } 2178 }
2179/*
2180 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2181 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1510 2182
1511 // Need to duplicate the physics actor as well 2183 // Need to duplicate the physics actor as well
1512 PhysicsActor originalPartPa = part.PhysActor; 2184 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1513 if (originalPartPa != null && userExposed)
1514 { 2185 {
1515 PrimitiveBaseShape pbs = newPart.Shape; 2186 PrimitiveBaseShape pbs = newPart.Shape;
1516
1517 newPart.PhysActor 2187 newPart.PhysActor
1518 = m_scene.PhysicsScene.AddPrimShape( 2188 = m_scene.PhysicsScene.AddPrimShape(
1519 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2189 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1520 pbs, 2190 pbs,
1521 newPart.AbsolutePosition, 2191 newPart.AbsolutePosition,
1522 newPart.Scale, 2192 newPart.Scale,
1523 newPart.RotationOffset, 2193 newPart.GetWorldRotation(),
1524 originalPartPa.IsPhysical, 2194 isphys,
2195 isphan,
1525 newPart.LocalId); 2196 newPart.LocalId);
1526 2197
1527 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2198 newPart.DoPhysicsPropertyUpdate(isphys, true);
1528 } 2199 */
2200 if (userExposed)
2201 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2202// }
1529 } 2203 }
1530 2204
1531 if (userExposed) 2205 if (userExposed)
1532 { 2206 {
1533 dupe.UpdateParentIDs(); 2207// done above dupe.UpdateParentIDs();
2208
2209 if (dupe.m_rootPart.PhysActor != null)
2210 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2211
1534 dupe.HasGroupChanged = true; 2212 dupe.HasGroupChanged = true;
1535 dupe.AttachToBackup(); 2213 dupe.AttachToBackup();
1536 2214
1537 ScheduleGroupForFullUpdate(); 2215 ScheduleGroupForFullUpdate();
1538 } 2216 }
1539 2217
2218 m_dupeInProgress = false;
1540 return dupe; 2219 return dupe;
1541 } 2220 }
1542 2221
@@ -1548,11 +2227,24 @@ namespace OpenSim.Region.Framework.Scenes
1548 /// <param name="cGroupID"></param> 2227 /// <param name="cGroupID"></param>
1549 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2228 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1550 { 2229 {
1551 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2230 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2231 // give newpart a new local ID lettng old part keep same
2232 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2233 newpart.LocalId = m_scene.AllocateLocalId();
2234
2235 SetRootPart(newpart);
2236 if (userExposed)
2237 RootPart.Velocity = Vector3.Zero; // In case source is moving
1552 } 2238 }
1553 2239
1554 public void ScriptSetPhysicsStatus(bool usePhysics) 2240 public void ScriptSetPhysicsStatus(bool usePhysics)
1555 { 2241 {
2242 if (usePhysics)
2243 {
2244 if (RootPart.KeyframeMotion != null)
2245 RootPart.KeyframeMotion.Stop();
2246 RootPart.KeyframeMotion = null;
2247 }
1556 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2248 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1557 } 2249 }
1558 2250
@@ -1600,27 +2292,14 @@ namespace OpenSim.Region.Framework.Scenes
1600 2292
1601 if (pa != null) 2293 if (pa != null)
1602 { 2294 {
1603 pa.AddForce(impulse, true); 2295 // false to be applied as a impulse
1604 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2296 pa.AddForce(impulse, false);
1605 }
1606 }
1607 }
1608
1609 public void applyAngularImpulse(Vector3 impulse)
1610 {
1611 PhysicsActor pa = RootPart.PhysActor;
1612
1613 if (pa != null)
1614 {
1615 if (!IsAttachment)
1616 {
1617 pa.AddAngularForce(impulse, true);
1618 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2297 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1619 } 2298 }
1620 } 2299 }
1621 } 2300 }
1622 2301
1623 public void setAngularImpulse(Vector3 impulse) 2302 public void ApplyAngularImpulse(Vector3 impulse)
1624 { 2303 {
1625 PhysicsActor pa = RootPart.PhysActor; 2304 PhysicsActor pa = RootPart.PhysActor;
1626 2305
@@ -1628,7 +2307,8 @@ namespace OpenSim.Region.Framework.Scenes
1628 { 2307 {
1629 if (!IsAttachment) 2308 if (!IsAttachment)
1630 { 2309 {
1631 pa.Torque = impulse; 2310 // false to be applied as a impulse
2311 pa.AddAngularForce(impulse, false);
1632 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2312 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1633 } 2313 }
1634 } 2314 }
@@ -1636,20 +2316,10 @@ namespace OpenSim.Region.Framework.Scenes
1636 2316
1637 public Vector3 GetTorque() 2317 public Vector3 GetTorque()
1638 { 2318 {
1639 PhysicsActor pa = RootPart.PhysActor; 2319 return RootPart.Torque;
1640
1641 if (pa != null)
1642 {
1643 if (!IsAttachment)
1644 {
1645 Vector3 torque = pa.Torque;
1646 return torque;
1647 }
1648 }
1649
1650 return Vector3.Zero;
1651 } 2320 }
1652 2321
2322 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1653 public void moveToTarget(Vector3 target, float tau) 2323 public void moveToTarget(Vector3 target, float tau)
1654 { 2324 {
1655 if (IsAttachment) 2325 if (IsAttachment)
@@ -1681,6 +2351,46 @@ namespace OpenSim.Region.Framework.Scenes
1681 pa.PIDActive = false; 2351 pa.PIDActive = false;
1682 } 2352 }
1683 2353
2354 public void rotLookAt(Quaternion target, float strength, float damping)
2355 {
2356 SceneObjectPart rootpart = m_rootPart;
2357 if (rootpart != null)
2358 {
2359 if (IsAttachment)
2360 {
2361 /*
2362 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2363 if (avatar != null)
2364 {
2365 Rotate the Av?
2366 } */
2367 }
2368 else
2369 {
2370 if (rootpart.PhysActor != null)
2371 { // APID must be implemented in your physics system for this to function.
2372 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2373 rootpart.PhysActor.APIDStrength = strength;
2374 rootpart.PhysActor.APIDDamping = damping;
2375 rootpart.PhysActor.APIDActive = true;
2376 }
2377 }
2378 }
2379 }
2380
2381 public void stopLookAt()
2382 {
2383 SceneObjectPart rootpart = m_rootPart;
2384 if (rootpart != null)
2385 {
2386 if (rootpart.PhysActor != null)
2387 { // APID must be implemented in your physics system for this to function.
2388 rootpart.PhysActor.APIDActive = false;
2389 }
2390 }
2391
2392 }
2393
1684 /// <summary> 2394 /// <summary>
1685 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2395 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1686 /// </summary> 2396 /// </summary>
@@ -1697,7 +2407,7 @@ namespace OpenSim.Region.Framework.Scenes
1697 { 2407 {
1698 pa.PIDHoverHeight = height; 2408 pa.PIDHoverHeight = height;
1699 pa.PIDHoverType = hoverType; 2409 pa.PIDHoverType = hoverType;
1700 pa.PIDTau = tau; 2410 pa.PIDHoverTau = tau;
1701 pa.PIDHoverActive = true; 2411 pa.PIDHoverActive = true;
1702 } 2412 }
1703 else 2413 else
@@ -1737,7 +2447,12 @@ namespace OpenSim.Region.Framework.Scenes
1737 /// <param name="cGroupID"></param> 2447 /// <param name="cGroupID"></param>
1738 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2448 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1739 { 2449 {
1740 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2450 // give new ID to the new part, letting old keep original
2451 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2452 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2453 newPart.LocalId = m_scene.AllocateLocalId();
2454 newPart.SetParent(this);
2455
1741 AddPart(newPart); 2456 AddPart(newPart);
1742 2457
1743 SetPartAsNonRoot(newPart); 2458 SetPartAsNonRoot(newPart);
@@ -1876,11 +2591,11 @@ namespace OpenSim.Region.Framework.Scenes
1876 /// Immediately send a full update for this scene object. 2591 /// Immediately send a full update for this scene object.
1877 /// </summary> 2592 /// </summary>
1878 public void SendGroupFullUpdate() 2593 public void SendGroupFullUpdate()
1879 { 2594 {
1880 if (IsDeleted) 2595 if (IsDeleted)
1881 return; 2596 return;
1882 2597
1883// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2598// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1884 2599
1885 RootPart.SendFullUpdateToAllClients(); 2600 RootPart.SendFullUpdateToAllClients();
1886 2601
@@ -2017,6 +2732,11 @@ namespace OpenSim.Region.Framework.Scenes
2017 // 'linkPart' == the root of the group being linked into this group 2732 // 'linkPart' == the root of the group being linked into this group
2018 SceneObjectPart linkPart = objectGroup.m_rootPart; 2733 SceneObjectPart linkPart = objectGroup.m_rootPart;
2019 2734
2735 if (m_rootPart.PhysActor != null)
2736 m_rootPart.PhysActor.Building = true;
2737 if (linkPart.PhysActor != null)
2738 linkPart.PhysActor.Building = true;
2739
2020 // physics flags from group to be applied to linked parts 2740 // physics flags from group to be applied to linked parts
2021 bool grpusephys = UsesPhysics; 2741 bool grpusephys = UsesPhysics;
2022 bool grptemporary = IsTemporary; 2742 bool grptemporary = IsTemporary;
@@ -2042,12 +2762,12 @@ namespace OpenSim.Region.Framework.Scenes
2042 Vector3 axPos = linkPart.OffsetPosition; 2762 Vector3 axPos = linkPart.OffsetPosition;
2043 // Rotate the linking root SOP's position to be relative to the new root prim 2763 // Rotate the linking root SOP's position to be relative to the new root prim
2044 Quaternion parentRot = m_rootPart.RotationOffset; 2764 Quaternion parentRot = m_rootPart.RotationOffset;
2045 axPos *= Quaternion.Inverse(parentRot); 2765 axPos *= Quaternion.Conjugate(parentRot);
2046 linkPart.OffsetPosition = axPos; 2766 linkPart.OffsetPosition = axPos;
2047 2767
2048 // Make the linking root SOP's rotation relative to the new root prim 2768 // Make the linking root SOP's rotation relative to the new root prim
2049 Quaternion oldRot = linkPart.RotationOffset; 2769 Quaternion oldRot = linkPart.RotationOffset;
2050 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2770 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2051 linkPart.RotationOffset = newRot; 2771 linkPart.RotationOffset = newRot;
2052 2772
2053 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2773 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2081,7 +2801,7 @@ namespace OpenSim.Region.Framework.Scenes
2081 linkPart.CreateSelected = true; 2801 linkPart.CreateSelected = true;
2082 2802
2083 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2803 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2084 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2804 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2085 2805
2086 // If the added SOP is physical, also tell the physics engine about the link relationship. 2806 // If the added SOP is physical, also tell the physics engine about the link relationship.
2087 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2807 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2091,6 +2811,7 @@ namespace OpenSim.Region.Framework.Scenes
2091 } 2811 }
2092 2812
2093 linkPart.LinkNum = linkNum++; 2813 linkPart.LinkNum = linkNum++;
2814 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2094 2815
2095 // Get a list of the SOP's in the old group in order of their linknum's. 2816 // Get a list of the SOP's in the old group in order of their linknum's.
2096 SceneObjectPart[] ogParts = objectGroup.Parts; 2817 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2109,7 +2830,7 @@ namespace OpenSim.Region.Framework.Scenes
2109 2830
2110 // Update the physics flags for the newly added SOP 2831 // Update the physics flags for the newly added SOP
2111 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2832 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2112 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2833 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2113 2834
2114 // If the added SOP is physical, also tell the physics engine about the link relationship. 2835 // If the added SOP is physical, also tell the physics engine about the link relationship.
2115 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2836 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2127,7 +2848,7 @@ namespace OpenSim.Region.Framework.Scenes
2127 objectGroup.IsDeleted = true; 2848 objectGroup.IsDeleted = true;
2128 2849
2129 objectGroup.m_parts.Clear(); 2850 objectGroup.m_parts.Clear();
2130 2851
2131 // Can't do this yet since backup still makes use of the root part without any synchronization 2852 // Can't do this yet since backup still makes use of the root part without any synchronization
2132// objectGroup.m_rootPart = null; 2853// objectGroup.m_rootPart = null;
2133 2854
@@ -2141,6 +2862,9 @@ namespace OpenSim.Region.Framework.Scenes
2141 // unmoved prims! 2862 // unmoved prims!
2142 ResetChildPrimPhysicsPositions(); 2863 ResetChildPrimPhysicsPositions();
2143 2864
2865 if (m_rootPart.PhysActor != null)
2866 m_rootPart.PhysActor.Building = false;
2867
2144 //HasGroupChanged = true; 2868 //HasGroupChanged = true;
2145 //ScheduleGroupForFullUpdate(); 2869 //ScheduleGroupForFullUpdate();
2146 } 2870 }
@@ -2208,7 +2932,10 @@ namespace OpenSim.Region.Framework.Scenes
2208// m_log.DebugFormat( 2932// m_log.DebugFormat(
2209// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2933// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2210// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2934// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2211 2935
2936 if (m_rootPart.PhysActor != null)
2937 m_rootPart.PhysActor.Building = true;
2938
2212 linkPart.ClearUndoState(); 2939 linkPart.ClearUndoState();
2213 2940
2214 Vector3 worldPos = linkPart.GetWorldPosition(); 2941 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2279,6 +3006,14 @@ namespace OpenSim.Region.Framework.Scenes
2279 3006
2280 // When we delete a group, we currently have to force persist to the database if the object id has changed 3007 // When we delete a group, we currently have to force persist to the database if the object id has changed
2281 // (since delete works by deleting all rows which have a given object id) 3008 // (since delete works by deleting all rows which have a given object id)
3009
3010 // this is as it seems to be in sl now
3011 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3012 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3013
3014 if (m_rootPart.PhysActor != null)
3015 m_rootPart.PhysActor.Building = false;
3016
2282 objectGroup.HasGroupChangedDueToDelink = true; 3017 objectGroup.HasGroupChangedDueToDelink = true;
2283 3018
2284 return objectGroup; 3019 return objectGroup;
@@ -2290,6 +3025,7 @@ namespace OpenSim.Region.Framework.Scenes
2290 /// <param name="objectGroup"></param> 3025 /// <param name="objectGroup"></param>
2291 public virtual void DetachFromBackup() 3026 public virtual void DetachFromBackup()
2292 { 3027 {
3028 m_scene.SceneGraph.FireDetachFromBackup(this);
2293 if (m_isBackedUp && Scene != null) 3029 if (m_isBackedUp && Scene != null)
2294 m_scene.EventManager.OnBackup -= ProcessBackup; 3030 m_scene.EventManager.OnBackup -= ProcessBackup;
2295 3031
@@ -2310,7 +3046,8 @@ namespace OpenSim.Region.Framework.Scenes
2310 Vector3 axPos = part.OffsetPosition; 3046 Vector3 axPos = part.OffsetPosition;
2311 axPos *= parentRot; 3047 axPos *= parentRot;
2312 part.OffsetPosition = axPos; 3048 part.OffsetPosition = axPos;
2313 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3049 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3050 part.GroupPosition = newPos;
2314 part.OffsetPosition = Vector3.Zero; 3051 part.OffsetPosition = Vector3.Zero;
2315 3052
2316 // Compution our rotation to be not relative to the old parent 3053 // Compution our rotation to be not relative to the old parent
@@ -2325,7 +3062,7 @@ namespace OpenSim.Region.Framework.Scenes
2325 part.LinkNum = linkNum; 3062 part.LinkNum = linkNum;
2326 3063
2327 // Compute the new position of this SOP relative to the group position 3064 // Compute the new position of this SOP relative to the group position
2328 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3065 part.OffsetPosition = newPos - AbsolutePosition;
2329 3066
2330 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3067 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2331 // It would have the affect of setting the physics engine position multiple 3068 // It would have the affect of setting the physics engine position multiple
@@ -2335,18 +3072,19 @@ namespace OpenSim.Region.Framework.Scenes
2335 // Rotate the relative position by the rotation of the group 3072 // Rotate the relative position by the rotation of the group
2336 Quaternion rootRotation = m_rootPart.RotationOffset; 3073 Quaternion rootRotation = m_rootPart.RotationOffset;
2337 Vector3 pos = part.OffsetPosition; 3074 Vector3 pos = part.OffsetPosition;
2338 pos *= Quaternion.Inverse(rootRotation); 3075 pos *= Quaternion.Conjugate(rootRotation);
2339 part.OffsetPosition = pos; 3076 part.OffsetPosition = pos;
2340 3077
2341 // Compute the SOP's rotation relative to the rotation of the group. 3078 // Compute the SOP's rotation relative to the rotation of the group.
2342 parentRot = m_rootPart.RotationOffset; 3079 parentRot = m_rootPart.RotationOffset;
2343 oldRot = part.RotationOffset; 3080 oldRot = part.RotationOffset;
2344 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3081 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2345 part.RotationOffset = newRot; 3082 part.RotationOffset = newRot;
2346 3083
2347 // Since this SOP's state has changed, push those changes into the physics engine 3084 // Since this SOP's state has changed, push those changes into the physics engine
2348 // and the simulator. 3085 // and the simulator.
2349 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3086 // done on caller
3087// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2350 } 3088 }
2351 3089
2352 /// <summary> 3090 /// <summary>
@@ -2368,10 +3106,14 @@ namespace OpenSim.Region.Framework.Scenes
2368 { 3106 {
2369 if (!m_rootPart.BlockGrab) 3107 if (!m_rootPart.BlockGrab)
2370 { 3108 {
2371 Vector3 llmoveforce = pos - AbsolutePosition; 3109/* Vector3 llmoveforce = pos - AbsolutePosition;
2372 Vector3 grabforce = llmoveforce; 3110 Vector3 grabforce = llmoveforce;
2373 grabforce = (grabforce / 10) * pa.Mass; 3111 grabforce = (grabforce / 10) * pa.Mass;
2374 pa.AddForce(grabforce, true); 3112 */
3113 // empirically convert distance diference to a impulse
3114 Vector3 grabforce = pos - AbsolutePosition;
3115 grabforce = grabforce * (pa.Mass/ 10.0f);
3116 pa.AddForce(grabforce, false);
2375 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3117 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2376 } 3118 }
2377 } 3119 }
@@ -2567,6 +3309,8 @@ namespace OpenSim.Region.Framework.Scenes
2567 /// <param name="SetVolumeDetect"></param> 3309 /// <param name="SetVolumeDetect"></param>
2568 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3310 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2569 { 3311 {
3312 HasGroupChanged = true;
3313
2570 SceneObjectPart selectionPart = GetPart(localID); 3314 SceneObjectPart selectionPart = GetPart(localID);
2571 3315
2572 if (SetTemporary && Scene != null) 3316 if (SetTemporary && Scene != null)
@@ -2597,8 +3341,22 @@ namespace OpenSim.Region.Framework.Scenes
2597 } 3341 }
2598 } 3342 }
2599 3343
2600 for (int i = 0; i < parts.Length; i++) 3344 if (parts.Length > 1)
2601 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3345 {
3346 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3347
3348 for (int i = 0; i < parts.Length; i++)
3349 {
3350
3351 if (parts[i].UUID != m_rootPart.UUID)
3352 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3353 }
3354
3355 if (m_rootPart.PhysActor != null)
3356 m_rootPart.PhysActor.Building = false;
3357 }
3358 else
3359 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2602 } 3360 }
2603 } 3361 }
2604 3362
@@ -2611,6 +3369,17 @@ namespace OpenSim.Region.Framework.Scenes
2611 } 3369 }
2612 } 3370 }
2613 3371
3372
3373
3374 /// <summary>
3375 /// Gets the number of parts
3376 /// </summary>
3377 /// <returns></returns>
3378 public int GetPartCount()
3379 {
3380 return Parts.Count();
3381 }
3382
2614 /// <summary> 3383 /// <summary>
2615 /// Update the texture entry for this part 3384 /// Update the texture entry for this part
2616 /// </summary> 3385 /// </summary>
@@ -2681,11 +3450,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 /// <param name="scale"></param> 3450 /// <param name="scale"></param>
2682 public void GroupResize(Vector3 scale) 3451 public void GroupResize(Vector3 scale)
2683 { 3452 {
2684// m_log.DebugFormat(
2685// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2686
2687 RootPart.StoreUndoState(true);
2688
2689 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3453 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
2690 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); 3454 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
2691 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); 3455 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
@@ -2712,7 +3476,6 @@ namespace OpenSim.Region.Framework.Scenes
2712 SceneObjectPart obPart = parts[i]; 3476 SceneObjectPart obPart = parts[i];
2713 if (obPart.UUID != m_rootPart.UUID) 3477 if (obPart.UUID != m_rootPart.UUID)
2714 { 3478 {
2715// obPart.IgnoreUndoUpdate = true;
2716 Vector3 oldSize = new Vector3(obPart.Scale); 3479 Vector3 oldSize = new Vector3(obPart.Scale);
2717 3480
2718 float f = 1.0f; 3481 float f = 1.0f;
@@ -2824,8 +3587,6 @@ namespace OpenSim.Region.Framework.Scenes
2824 z *= a; 3587 z *= a;
2825 } 3588 }
2826 } 3589 }
2827
2828// obPart.IgnoreUndoUpdate = false;
2829 } 3590 }
2830 } 3591 }
2831 } 3592 }
@@ -2835,9 +3596,7 @@ namespace OpenSim.Region.Framework.Scenes
2835 prevScale.Y *= y; 3596 prevScale.Y *= y;
2836 prevScale.Z *= z; 3597 prevScale.Z *= z;
2837 3598
2838// RootPart.IgnoreUndoUpdate = true;
2839 RootPart.Resize(prevScale); 3599 RootPart.Resize(prevScale);
2840// RootPart.IgnoreUndoUpdate = false;
2841 3600
2842 parts = m_parts.GetArray(); 3601 parts = m_parts.GetArray();
2843 for (int i = 0; i < parts.Length; i++) 3602 for (int i = 0; i < parts.Length; i++)
@@ -2846,8 +3605,6 @@ namespace OpenSim.Region.Framework.Scenes
2846 3605
2847 if (obPart.UUID != m_rootPart.UUID) 3606 if (obPart.UUID != m_rootPart.UUID)
2848 { 3607 {
2849 obPart.IgnoreUndoUpdate = true;
2850
2851 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3608 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2852 currentpos.X *= x; 3609 currentpos.X *= x;
2853 currentpos.Y *= y; 3610 currentpos.Y *= y;
@@ -2860,16 +3617,12 @@ namespace OpenSim.Region.Framework.Scenes
2860 3617
2861 obPart.Resize(newSize); 3618 obPart.Resize(newSize);
2862 obPart.UpdateOffSet(currentpos); 3619 obPart.UpdateOffSet(currentpos);
2863
2864 obPart.IgnoreUndoUpdate = false;
2865 } 3620 }
2866 3621
2867// obPart.IgnoreUndoUpdate = false; 3622 HasGroupChanged = true;
2868// obPart.StoreUndoState(); 3623 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3624 ScheduleGroupForTerseUpdate();
2869 } 3625 }
2870
2871// m_log.DebugFormat(
2872// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2873 } 3626 }
2874 3627
2875 #endregion 3628 #endregion
@@ -2882,14 +3635,6 @@ namespace OpenSim.Region.Framework.Scenes
2882 /// <param name="pos"></param> 3635 /// <param name="pos"></param>
2883 public void UpdateGroupPosition(Vector3 pos) 3636 public void UpdateGroupPosition(Vector3 pos)
2884 { 3637 {
2885// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2886
2887 RootPart.StoreUndoState(true);
2888
2889// SceneObjectPart[] parts = m_parts.GetArray();
2890// for (int i = 0; i < parts.Length; i++)
2891// parts[i].StoreUndoState();
2892
2893 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3638 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2894 { 3639 {
2895 if (IsAttachment) 3640 if (IsAttachment)
@@ -2922,21 +3667,17 @@ namespace OpenSim.Region.Framework.Scenes
2922 /// </summary> 3667 /// </summary>
2923 /// <param name="pos"></param> 3668 /// <param name="pos"></param>
2924 /// <param name="localID"></param> 3669 /// <param name="localID"></param>
3670 ///
3671
2925 public void UpdateSinglePosition(Vector3 pos, uint localID) 3672 public void UpdateSinglePosition(Vector3 pos, uint localID)
2926 { 3673 {
2927 SceneObjectPart part = GetPart(localID); 3674 SceneObjectPart part = GetPart(localID);
2928 3675
2929// SceneObjectPart[] parts = m_parts.GetArray();
2930// for (int i = 0; i < parts.Length; i++)
2931// parts[i].StoreUndoState();
2932
2933 if (part != null) 3676 if (part != null)
2934 { 3677 {
2935// m_log.DebugFormat( 3678// unlock parts position change
2936// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3679 if (m_rootPart.PhysActor != null)
2937 3680 m_rootPart.PhysActor.Building = true;
2938 part.StoreUndoState(false);
2939 part.IgnoreUndoUpdate = true;
2940 3681
2941 if (part.UUID == m_rootPart.UUID) 3682 if (part.UUID == m_rootPart.UUID)
2942 { 3683 {
@@ -2947,8 +3688,10 @@ namespace OpenSim.Region.Framework.Scenes
2947 part.UpdateOffSet(pos); 3688 part.UpdateOffSet(pos);
2948 } 3689 }
2949 3690
3691 if (m_rootPart.PhysActor != null)
3692 m_rootPart.PhysActor.Building = false;
3693
2950 HasGroupChanged = true; 3694 HasGroupChanged = true;
2951 part.IgnoreUndoUpdate = false;
2952 } 3695 }
2953 } 3696 }
2954 3697
@@ -2958,13 +3701,7 @@ namespace OpenSim.Region.Framework.Scenes
2958 /// <param name="pos"></param> 3701 /// <param name="pos"></param>
2959 public void UpdateRootPosition(Vector3 pos) 3702 public void UpdateRootPosition(Vector3 pos)
2960 { 3703 {
2961// m_log.DebugFormat( 3704 // needs to be called with phys building true
2962// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2963
2964// SceneObjectPart[] parts = m_parts.GetArray();
2965// for (int i = 0; i < parts.Length; i++)
2966// parts[i].StoreUndoState();
2967
2968 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3705 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2969 Vector3 oldPos = 3706 Vector3 oldPos =
2970 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3707 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2987,7 +3724,14 @@ namespace OpenSim.Region.Framework.Scenes
2987 AbsolutePosition = newPos; 3724 AbsolutePosition = newPos;
2988 3725
2989 HasGroupChanged = true; 3726 HasGroupChanged = true;
2990 ScheduleGroupForTerseUpdate(); 3727 if (m_rootPart.Undoing)
3728 {
3729 ScheduleGroupForFullUpdate();
3730 }
3731 else
3732 {
3733 ScheduleGroupForTerseUpdate();
3734 }
2991 } 3735 }
2992 3736
2993 #endregion 3737 #endregion
@@ -3000,24 +3744,16 @@ namespace OpenSim.Region.Framework.Scenes
3000 /// <param name="rot"></param> 3744 /// <param name="rot"></param>
3001 public void UpdateGroupRotationR(Quaternion rot) 3745 public void UpdateGroupRotationR(Quaternion rot)
3002 { 3746 {
3003// m_log.DebugFormat(
3004// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3005
3006// SceneObjectPart[] parts = m_parts.GetArray();
3007// for (int i = 0; i < parts.Length; i++)
3008// parts[i].StoreUndoState();
3009
3010 m_rootPart.StoreUndoState(true);
3011
3012 m_rootPart.UpdateRotation(rot); 3747 m_rootPart.UpdateRotation(rot);
3013 3748
3749/* this is done by rootpart RotationOffset set called by UpdateRotation
3014 PhysicsActor actor = m_rootPart.PhysActor; 3750 PhysicsActor actor = m_rootPart.PhysActor;
3015 if (actor != null) 3751 if (actor != null)
3016 { 3752 {
3017 actor.Orientation = m_rootPart.RotationOffset; 3753 actor.Orientation = m_rootPart.RotationOffset;
3018 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3754 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3019 } 3755 }
3020 3756*/
3021 HasGroupChanged = true; 3757 HasGroupChanged = true;
3022 ScheduleGroupForTerseUpdate(); 3758 ScheduleGroupForTerseUpdate();
3023 } 3759 }
@@ -3029,16 +3765,6 @@ namespace OpenSim.Region.Framework.Scenes
3029 /// <param name="rot"></param> 3765 /// <param name="rot"></param>
3030 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3766 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3031 { 3767 {
3032// m_log.DebugFormat(
3033// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3034
3035// SceneObjectPart[] parts = m_parts.GetArray();
3036// for (int i = 0; i < parts.Length; i++)
3037// parts[i].StoreUndoState();
3038
3039 RootPart.StoreUndoState(true);
3040 RootPart.IgnoreUndoUpdate = true;
3041
3042 m_rootPart.UpdateRotation(rot); 3768 m_rootPart.UpdateRotation(rot);
3043 3769
3044 PhysicsActor actor = m_rootPart.PhysActor; 3770 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3057,8 +3783,6 @@ namespace OpenSim.Region.Framework.Scenes
3057 3783
3058 HasGroupChanged = true; 3784 HasGroupChanged = true;
3059 ScheduleGroupForTerseUpdate(); 3785 ScheduleGroupForTerseUpdate();
3060
3061 RootPart.IgnoreUndoUpdate = false;
3062 } 3786 }
3063 3787
3064 /// <summary> 3788 /// <summary>
@@ -3071,13 +3795,11 @@ namespace OpenSim.Region.Framework.Scenes
3071 SceneObjectPart part = GetPart(localID); 3795 SceneObjectPart part = GetPart(localID);
3072 3796
3073 SceneObjectPart[] parts = m_parts.GetArray(); 3797 SceneObjectPart[] parts = m_parts.GetArray();
3074 for (int i = 0; i < parts.Length; i++)
3075 parts[i].StoreUndoState();
3076 3798
3077 if (part != null) 3799 if (part != null)
3078 { 3800 {
3079// m_log.DebugFormat( 3801 if (m_rootPart.PhysActor != null)
3080// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3802 m_rootPart.PhysActor.Building = true;
3081 3803
3082 if (part.UUID == m_rootPart.UUID) 3804 if (part.UUID == m_rootPart.UUID)
3083 { 3805 {
@@ -3087,6 +3809,9 @@ namespace OpenSim.Region.Framework.Scenes
3087 { 3809 {
3088 part.UpdateRotation(rot); 3810 part.UpdateRotation(rot);
3089 } 3811 }
3812
3813 if (m_rootPart.PhysActor != null)
3814 m_rootPart.PhysActor.Building = false;
3090 } 3815 }
3091 } 3816 }
3092 3817
@@ -3100,12 +3825,8 @@ namespace OpenSim.Region.Framework.Scenes
3100 SceneObjectPart part = GetPart(localID); 3825 SceneObjectPart part = GetPart(localID);
3101 if (part != null) 3826 if (part != null)
3102 { 3827 {
3103// m_log.DebugFormat( 3828 if (m_rootPart.PhysActor != null)
3104// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3829 m_rootPart.PhysActor.Building = true;
3105// part.Name, part.LocalId, rot);
3106
3107 part.StoreUndoState();
3108 part.IgnoreUndoUpdate = true;
3109 3830
3110 if (part.UUID == m_rootPart.UUID) 3831 if (part.UUID == m_rootPart.UUID)
3111 { 3832 {
@@ -3118,7 +3839,8 @@ namespace OpenSim.Region.Framework.Scenes
3118 part.OffsetPosition = pos; 3839 part.OffsetPosition = pos;
3119 } 3840 }
3120 3841
3121 part.IgnoreUndoUpdate = false; 3842 if (m_rootPart.PhysActor != null)
3843 m_rootPart.PhysActor.Building = false;
3122 } 3844 }
3123 } 3845 }
3124 3846
@@ -3128,15 +3850,12 @@ namespace OpenSim.Region.Framework.Scenes
3128 /// <param name="rot"></param> 3850 /// <param name="rot"></param>
3129 public void UpdateRootRotation(Quaternion rot) 3851 public void UpdateRootRotation(Quaternion rot)
3130 { 3852 {
3131// m_log.DebugFormat( 3853 // needs to be called with phys building true
3132// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3133// Name, LocalId, rot);
3134
3135 Quaternion axRot = rot; 3854 Quaternion axRot = rot;
3136 Quaternion oldParentRot = m_rootPart.RotationOffset; 3855 Quaternion oldParentRot = m_rootPart.RotationOffset;
3137 3856
3138 m_rootPart.StoreUndoState(); 3857 //Don't use UpdateRotation because it schedules an update prematurely
3139 m_rootPart.UpdateRotation(rot); 3858 m_rootPart.RotationOffset = rot;
3140 3859
3141 PhysicsActor pa = m_rootPart.PhysActor; 3860 PhysicsActor pa = m_rootPart.PhysActor;
3142 3861
@@ -3152,35 +3871,145 @@ namespace OpenSim.Region.Framework.Scenes
3152 SceneObjectPart prim = parts[i]; 3871 SceneObjectPart prim = parts[i];
3153 if (prim.UUID != m_rootPart.UUID) 3872 if (prim.UUID != m_rootPart.UUID)
3154 { 3873 {
3155 prim.IgnoreUndoUpdate = true; 3874 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3875 NewRot = Quaternion.Inverse(axRot) * NewRot;
3876 prim.RotationOffset = NewRot;
3877
3156 Vector3 axPos = prim.OffsetPosition; 3878 Vector3 axPos = prim.OffsetPosition;
3879
3157 axPos *= oldParentRot; 3880 axPos *= oldParentRot;
3158 axPos *= Quaternion.Inverse(axRot); 3881 axPos *= Quaternion.Inverse(axRot);
3159 prim.OffsetPosition = axPos; 3882 prim.OffsetPosition = axPos;
3160 Quaternion primsRot = prim.RotationOffset; 3883 }
3161 Quaternion newRot = oldParentRot * primsRot; 3884 }
3162 newRot = Quaternion.Inverse(axRot) * newRot;
3163 prim.RotationOffset = newRot;
3164 prim.ScheduleTerseUpdate();
3165 prim.IgnoreUndoUpdate = false;
3166 }
3167 }
3168
3169// for (int i = 0; i < parts.Length; i++)
3170// {
3171// SceneObjectPart childpart = parts[i];
3172// if (childpart != m_rootPart)
3173// {
3174//// childpart.IgnoreUndoUpdate = false;
3175//// childpart.StoreUndoState();
3176// }
3177// }
3178 3885
3179 m_rootPart.ScheduleTerseUpdate(); 3886 HasGroupChanged = true;
3887 ScheduleGroupForFullUpdate();
3888 }
3180 3889
3181// m_log.DebugFormat( 3890 private enum updatetype :int
3182// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3891 {
3183// Name, LocalId, rot); 3892 none = 0,
3893 partterse = 1,
3894 partfull = 2,
3895 groupterse = 3,
3896 groupfull = 4
3897 }
3898
3899 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3900 {
3901 // TODO this still as excessive *.Schedule*Update()s
3902
3903 if (part != null && part.ParentGroup != null)
3904 {
3905 ObjectChangeType change = data.change;
3906 bool togroup = ((change & ObjectChangeType.Group) != 0);
3907 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3908
3909 SceneObjectGroup group = part.ParentGroup;
3910 PhysicsActor pha = group.RootPart.PhysActor;
3911
3912 updatetype updateType = updatetype.none;
3913
3914 if (togroup)
3915 {
3916 // related to group
3917 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3918 {
3919 if ((change & ObjectChangeType.Rotation) != 0)
3920 {
3921 group.RootPart.UpdateRotation(data.rotation);
3922 updateType = updatetype.none;
3923 }
3924 if ((change & ObjectChangeType.Position) != 0)
3925 {
3926 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3927 UpdateGroupPosition(data.position);
3928 updateType = updatetype.groupterse;
3929 }
3930 else
3931 // ugly rotation update of all parts
3932 {
3933 group.ResetChildPrimPhysicsPositions();
3934 }
3935
3936 }
3937 if ((change & ObjectChangeType.Scale) != 0)
3938 {
3939 if (pha != null)
3940 pha.Building = true;
3941
3942 group.GroupResize(data.scale);
3943 updateType = updatetype.none;
3944
3945 if (pha != null)
3946 pha.Building = false;
3947 }
3948 }
3949 else
3950 {
3951 // related to single prim in a link-set ( ie group)
3952 if (pha != null)
3953 pha.Building = true;
3954
3955 // root part is special
3956 // parts offset positions or rotations need to change also
3957
3958 if (part == group.RootPart)
3959 {
3960 if ((change & ObjectChangeType.Rotation) != 0)
3961 group.UpdateRootRotation(data.rotation);
3962 if ((change & ObjectChangeType.Position) != 0)
3963 group.UpdateRootPosition(data.position);
3964 if ((change & ObjectChangeType.Scale) != 0)
3965 part.Resize(data.scale);
3966 }
3967 else
3968 {
3969 if ((change & ObjectChangeType.Position) != 0)
3970 {
3971 part.OffsetPosition = data.position;
3972 updateType = updatetype.partterse;
3973 }
3974 if ((change & ObjectChangeType.Rotation) != 0)
3975 {
3976 part.UpdateRotation(data.rotation);
3977 updateType = updatetype.none;
3978 }
3979 if ((change & ObjectChangeType.Scale) != 0)
3980 {
3981 part.Resize(data.scale);
3982 updateType = updatetype.none;
3983 }
3984 }
3985
3986 if (pha != null)
3987 pha.Building = false;
3988 }
3989
3990 if (updateType != updatetype.none)
3991 {
3992 group.HasGroupChanged = true;
3993
3994 switch (updateType)
3995 {
3996 case updatetype.partterse:
3997 part.ScheduleTerseUpdate();
3998 break;
3999 case updatetype.partfull:
4000 part.ScheduleFullUpdate();
4001 break;
4002 case updatetype.groupterse:
4003 group.ScheduleGroupForTerseUpdate();
4004 break;
4005 case updatetype.groupfull:
4006 group.ScheduleGroupForFullUpdate();
4007 break;
4008 default:
4009 break;
4010 }
4011 }
4012 }
3184 } 4013 }
3185 4014
3186 #endregion 4015 #endregion
@@ -3279,10 +4108,11 @@ namespace OpenSim.Region.Framework.Scenes
3279 scriptPosTarget target = m_targets[idx]; 4108 scriptPosTarget target = m_targets[idx];
3280 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4109 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3281 { 4110 {
4111 at_target = true;
4112
3282 // trigger at_target 4113 // trigger at_target
3283 if (m_scriptListens_atTarget) 4114 if (m_scriptListens_atTarget)
3284 { 4115 {
3285 at_target = true;
3286 scriptPosTarget att = new scriptPosTarget(); 4116 scriptPosTarget att = new scriptPosTarget();
3287 att.targetPos = target.targetPos; 4117 att.targetPos = target.targetPos;
3288 att.tolerance = target.tolerance; 4118 att.tolerance = target.tolerance;
@@ -3400,11 +4230,50 @@ namespace OpenSim.Region.Framework.Scenes
3400 } 4230 }
3401 } 4231 }
3402 } 4232 }
3403 4233
4234 public Vector3 GetGeometricCenter()
4235 {
4236 // this is not real geometric center but a average of positions relative to root prim acording to
4237 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4238 // ignoring tortured prims details since sl also seems to ignore
4239 // so no real use in doing it on physics
4240
4241 Vector3 gc = Vector3.Zero;
4242
4243 int nparts = m_parts.Count;
4244 if (nparts <= 1)
4245 return gc;
4246
4247 SceneObjectPart[] parts = m_parts.GetArray();
4248 nparts = parts.Length; // just in case it changed
4249 if (nparts <= 1)
4250 return gc;
4251
4252 Quaternion parentRot = RootPart.RotationOffset;
4253 Vector3 pPos;
4254
4255 // average all parts positions
4256 for (int i = 0; i < nparts; i++)
4257 {
4258 // do it directly
4259 // gc += parts[i].GetWorldPosition();
4260 if (parts[i] != RootPart)
4261 {
4262 pPos = parts[i].OffsetPosition;
4263 gc += pPos;
4264 }
4265
4266 }
4267 gc /= nparts;
4268
4269 // relative to root:
4270// gc -= AbsolutePosition;
4271 return gc;
4272 }
4273
3404 public float GetMass() 4274 public float GetMass()
3405 { 4275 {
3406 float retmass = 0f; 4276 float retmass = 0f;
3407
3408 SceneObjectPart[] parts = m_parts.GetArray(); 4277 SceneObjectPart[] parts = m_parts.GetArray();
3409 for (int i = 0; i < parts.Length; i++) 4278 for (int i = 0; i < parts.Length; i++)
3410 retmass += parts[i].GetMass(); 4279 retmass += parts[i].GetMass();
@@ -3412,6 +4281,39 @@ namespace OpenSim.Region.Framework.Scenes
3412 return retmass; 4281 return retmass;
3413 } 4282 }
3414 4283
4284 // center of mass of full object
4285 public Vector3 GetCenterOfMass()
4286 {
4287 PhysicsActor pa = RootPart.PhysActor;
4288
4289 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4290 {
4291 // physics knows better about center of mass of physical prims
4292 Vector3 tmp = pa.CenterOfMass;
4293 return tmp;
4294 }
4295
4296 Vector3 Ptot = Vector3.Zero;
4297 float totmass = 0f;
4298 float m;
4299
4300 SceneObjectPart[] parts = m_parts.GetArray();
4301 for (int i = 0; i < parts.Length; i++)
4302 {
4303 m = parts[i].GetMass();
4304 Ptot += parts[i].GetPartCenterOfMass() * m;
4305 totmass += m;
4306 }
4307
4308 if (totmass == 0)
4309 totmass = 0;
4310 else
4311 totmass = 1 / totmass;
4312 Ptot *= totmass;
4313
4314 return Ptot;
4315 }
4316
3415 /// <summary> 4317 /// <summary>
3416 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4318 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3417 /// the physics engine can use it. 4319 /// the physics engine can use it.
@@ -3579,6 +4481,14 @@ namespace OpenSim.Region.Framework.Scenes
3579 FromItemID = uuid; 4481 FromItemID = uuid;
3580 } 4482 }
3581 4483
4484 public void ResetOwnerChangeFlag()
4485 {
4486 ForEachPart(delegate(SceneObjectPart part)
4487 {
4488 part.ResetOwnerChangeFlag();
4489 });
4490 }
4491
3582 #endregion 4492 #endregion
3583 } 4493 }
3584} 4494}