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.cs1346
1 files changed, 1127 insertions, 219 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index f6c725b..3726a15 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
@@ -2138,6 +2859,9 @@ namespace OpenSim.Region.Framework.Scenes
2138 // unmoved prims! 2859 // unmoved prims!
2139 ResetChildPrimPhysicsPositions(); 2860 ResetChildPrimPhysicsPositions();
2140 2861
2862 if (m_rootPart.PhysActor != null)
2863 m_rootPart.PhysActor.Building = false;
2864
2141 //HasGroupChanged = true; 2865 //HasGroupChanged = true;
2142 //ScheduleGroupForFullUpdate(); 2866 //ScheduleGroupForFullUpdate();
2143 } 2867 }
@@ -2205,7 +2929,10 @@ namespace OpenSim.Region.Framework.Scenes
2205// m_log.DebugFormat( 2929// m_log.DebugFormat(
2206// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2930// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2207// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2931// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2208 2932
2933 if (m_rootPart.PhysActor != null)
2934 m_rootPart.PhysActor.Building = true;
2935
2209 linkPart.ClearUndoState(); 2936 linkPart.ClearUndoState();
2210 2937
2211 Vector3 worldPos = linkPart.GetWorldPosition(); 2938 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2276,6 +3003,14 @@ namespace OpenSim.Region.Framework.Scenes
2276 3003
2277 // When we delete a group, we currently have to force persist to the database if the object id has changed 3004 // When we delete a group, we currently have to force persist to the database if the object id has changed
2278 // (since delete works by deleting all rows which have a given object id) 3005 // (since delete works by deleting all rows which have a given object id)
3006
3007 // this is as it seems to be in sl now
3008 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3009 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3010
3011 if (m_rootPart.PhysActor != null)
3012 m_rootPart.PhysActor.Building = false;
3013
2279 objectGroup.HasGroupChangedDueToDelink = true; 3014 objectGroup.HasGroupChangedDueToDelink = true;
2280 3015
2281 return objectGroup; 3016 return objectGroup;
@@ -2287,6 +3022,7 @@ namespace OpenSim.Region.Framework.Scenes
2287 /// <param name="objectGroup"></param> 3022 /// <param name="objectGroup"></param>
2288 public virtual void DetachFromBackup() 3023 public virtual void DetachFromBackup()
2289 { 3024 {
3025 m_scene.SceneGraph.FireDetachFromBackup(this);
2290 if (m_isBackedUp && Scene != null) 3026 if (m_isBackedUp && Scene != null)
2291 m_scene.EventManager.OnBackup -= ProcessBackup; 3027 m_scene.EventManager.OnBackup -= ProcessBackup;
2292 3028
@@ -2307,7 +3043,8 @@ namespace OpenSim.Region.Framework.Scenes
2307 Vector3 axPos = part.OffsetPosition; 3043 Vector3 axPos = part.OffsetPosition;
2308 axPos *= parentRot; 3044 axPos *= parentRot;
2309 part.OffsetPosition = axPos; 3045 part.OffsetPosition = axPos;
2310 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3046 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3047 part.GroupPosition = newPos;
2311 part.OffsetPosition = Vector3.Zero; 3048 part.OffsetPosition = Vector3.Zero;
2312 3049
2313 // Compution our rotation to be not relative to the old parent 3050 // Compution our rotation to be not relative to the old parent
@@ -2322,7 +3059,7 @@ namespace OpenSim.Region.Framework.Scenes
2322 part.LinkNum = linkNum; 3059 part.LinkNum = linkNum;
2323 3060
2324 // Compute the new position of this SOP relative to the group position 3061 // Compute the new position of this SOP relative to the group position
2325 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3062 part.OffsetPosition = newPos - AbsolutePosition;
2326 3063
2327 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3064 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2328 // It would have the affect of setting the physics engine position multiple 3065 // It would have the affect of setting the physics engine position multiple
@@ -2332,18 +3069,19 @@ namespace OpenSim.Region.Framework.Scenes
2332 // Rotate the relative position by the rotation of the group 3069 // Rotate the relative position by the rotation of the group
2333 Quaternion rootRotation = m_rootPart.RotationOffset; 3070 Quaternion rootRotation = m_rootPart.RotationOffset;
2334 Vector3 pos = part.OffsetPosition; 3071 Vector3 pos = part.OffsetPosition;
2335 pos *= Quaternion.Inverse(rootRotation); 3072 pos *= Quaternion.Conjugate(rootRotation);
2336 part.OffsetPosition = pos; 3073 part.OffsetPosition = pos;
2337 3074
2338 // Compute the SOP's rotation relative to the rotation of the group. 3075 // Compute the SOP's rotation relative to the rotation of the group.
2339 parentRot = m_rootPart.RotationOffset; 3076 parentRot = m_rootPart.RotationOffset;
2340 oldRot = part.RotationOffset; 3077 oldRot = part.RotationOffset;
2341 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3078 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2342 part.RotationOffset = newRot; 3079 part.RotationOffset = newRot;
2343 3080
2344 // Since this SOP's state has changed, push those changes into the physics engine 3081 // Since this SOP's state has changed, push those changes into the physics engine
2345 // and the simulator. 3082 // and the simulator.
2346 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3083 // done on caller
3084// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2347 } 3085 }
2348 3086
2349 /// <summary> 3087 /// <summary>
@@ -2365,10 +3103,14 @@ namespace OpenSim.Region.Framework.Scenes
2365 { 3103 {
2366 if (!m_rootPart.BlockGrab) 3104 if (!m_rootPart.BlockGrab)
2367 { 3105 {
2368 Vector3 llmoveforce = pos - AbsolutePosition; 3106/* Vector3 llmoveforce = pos - AbsolutePosition;
2369 Vector3 grabforce = llmoveforce; 3107 Vector3 grabforce = llmoveforce;
2370 grabforce = (grabforce / 10) * pa.Mass; 3108 grabforce = (grabforce / 10) * pa.Mass;
2371 pa.AddForce(grabforce, true); 3109 */
3110 // empirically convert distance diference to a impulse
3111 Vector3 grabforce = pos - AbsolutePosition;
3112 grabforce = grabforce * (pa.Mass/ 10.0f);
3113 pa.AddForce(grabforce, false);
2372 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3114 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2373 } 3115 }
2374 } 3116 }
@@ -2594,8 +3336,22 @@ namespace OpenSim.Region.Framework.Scenes
2594 } 3336 }
2595 } 3337 }
2596 3338
2597 for (int i = 0; i < parts.Length; i++) 3339 if (parts.Length > 1)
2598 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3340 {
3341 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3342
3343 for (int i = 0; i < parts.Length; i++)
3344 {
3345
3346 if (parts[i].UUID != m_rootPart.UUID)
3347 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3348 }
3349
3350 if (m_rootPart.PhysActor != null)
3351 m_rootPart.PhysActor.Building = false;
3352 }
3353 else
3354 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2599 } 3355 }
2600 } 3356 }
2601 3357
@@ -2608,6 +3364,17 @@ namespace OpenSim.Region.Framework.Scenes
2608 } 3364 }
2609 } 3365 }
2610 3366
3367
3368
3369 /// <summary>
3370 /// Gets the number of parts
3371 /// </summary>
3372 /// <returns></returns>
3373 public int GetPartCount()
3374 {
3375 return Parts.Count();
3376 }
3377
2611 /// <summary> 3378 /// <summary>
2612 /// Update the texture entry for this part 3379 /// Update the texture entry for this part
2613 /// </summary> 3380 /// </summary>
@@ -2669,11 +3436,6 @@ namespace OpenSim.Region.Framework.Scenes
2669 /// <param name="scale"></param> 3436 /// <param name="scale"></param>
2670 public void GroupResize(Vector3 scale) 3437 public void GroupResize(Vector3 scale)
2671 { 3438 {
2672// m_log.DebugFormat(
2673// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2674
2675 RootPart.StoreUndoState(true);
2676
2677 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3439 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
2678 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); 3440 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
2679 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); 3441 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
@@ -2700,7 +3462,6 @@ namespace OpenSim.Region.Framework.Scenes
2700 SceneObjectPart obPart = parts[i]; 3462 SceneObjectPart obPart = parts[i];
2701 if (obPart.UUID != m_rootPart.UUID) 3463 if (obPart.UUID != m_rootPart.UUID)
2702 { 3464 {
2703// obPart.IgnoreUndoUpdate = true;
2704 Vector3 oldSize = new Vector3(obPart.Scale); 3465 Vector3 oldSize = new Vector3(obPart.Scale);
2705 3466
2706 float f = 1.0f; 3467 float f = 1.0f;
@@ -2812,8 +3573,6 @@ namespace OpenSim.Region.Framework.Scenes
2812 z *= a; 3573 z *= a;
2813 } 3574 }
2814 } 3575 }
2815
2816// obPart.IgnoreUndoUpdate = false;
2817 } 3576 }
2818 } 3577 }
2819 } 3578 }
@@ -2823,9 +3582,7 @@ namespace OpenSim.Region.Framework.Scenes
2823 prevScale.Y *= y; 3582 prevScale.Y *= y;
2824 prevScale.Z *= z; 3583 prevScale.Z *= z;
2825 3584
2826// RootPart.IgnoreUndoUpdate = true;
2827 RootPart.Resize(prevScale); 3585 RootPart.Resize(prevScale);
2828// RootPart.IgnoreUndoUpdate = false;
2829 3586
2830 parts = m_parts.GetArray(); 3587 parts = m_parts.GetArray();
2831 for (int i = 0; i < parts.Length; i++) 3588 for (int i = 0; i < parts.Length; i++)
@@ -2834,8 +3591,6 @@ namespace OpenSim.Region.Framework.Scenes
2834 3591
2835 if (obPart.UUID != m_rootPart.UUID) 3592 if (obPart.UUID != m_rootPart.UUID)
2836 { 3593 {
2837 obPart.IgnoreUndoUpdate = true;
2838
2839 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3594 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2840 currentpos.X *= x; 3595 currentpos.X *= x;
2841 currentpos.Y *= y; 3596 currentpos.Y *= y;
@@ -2848,16 +3603,12 @@ namespace OpenSim.Region.Framework.Scenes
2848 3603
2849 obPart.Resize(newSize); 3604 obPart.Resize(newSize);
2850 obPart.UpdateOffSet(currentpos); 3605 obPart.UpdateOffSet(currentpos);
2851
2852 obPart.IgnoreUndoUpdate = false;
2853 } 3606 }
2854 3607
2855// obPart.IgnoreUndoUpdate = false; 3608 HasGroupChanged = true;
2856// obPart.StoreUndoState(); 3609 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3610 ScheduleGroupForTerseUpdate();
2857 } 3611 }
2858
2859// m_log.DebugFormat(
2860// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2861 } 3612 }
2862 3613
2863 #endregion 3614 #endregion
@@ -2870,14 +3621,6 @@ namespace OpenSim.Region.Framework.Scenes
2870 /// <param name="pos"></param> 3621 /// <param name="pos"></param>
2871 public void UpdateGroupPosition(Vector3 pos) 3622 public void UpdateGroupPosition(Vector3 pos)
2872 { 3623 {
2873// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2874
2875 RootPart.StoreUndoState(true);
2876
2877// SceneObjectPart[] parts = m_parts.GetArray();
2878// for (int i = 0; i < parts.Length; i++)
2879// parts[i].StoreUndoState();
2880
2881 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3624 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2882 { 3625 {
2883 if (IsAttachment) 3626 if (IsAttachment)
@@ -2910,21 +3653,17 @@ namespace OpenSim.Region.Framework.Scenes
2910 /// </summary> 3653 /// </summary>
2911 /// <param name="pos"></param> 3654 /// <param name="pos"></param>
2912 /// <param name="localID"></param> 3655 /// <param name="localID"></param>
3656 ///
3657
2913 public void UpdateSinglePosition(Vector3 pos, uint localID) 3658 public void UpdateSinglePosition(Vector3 pos, uint localID)
2914 { 3659 {
2915 SceneObjectPart part = GetPart(localID); 3660 SceneObjectPart part = GetPart(localID);
2916 3661
2917// SceneObjectPart[] parts = m_parts.GetArray();
2918// for (int i = 0; i < parts.Length; i++)
2919// parts[i].StoreUndoState();
2920
2921 if (part != null) 3662 if (part != null)
2922 { 3663 {
2923// m_log.DebugFormat( 3664// unlock parts position change
2924// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3665 if (m_rootPart.PhysActor != null)
2925 3666 m_rootPart.PhysActor.Building = true;
2926 part.StoreUndoState(false);
2927 part.IgnoreUndoUpdate = true;
2928 3667
2929 if (part.UUID == m_rootPart.UUID) 3668 if (part.UUID == m_rootPart.UUID)
2930 { 3669 {
@@ -2935,8 +3674,10 @@ namespace OpenSim.Region.Framework.Scenes
2935 part.UpdateOffSet(pos); 3674 part.UpdateOffSet(pos);
2936 } 3675 }
2937 3676
3677 if (m_rootPart.PhysActor != null)
3678 m_rootPart.PhysActor.Building = false;
3679
2938 HasGroupChanged = true; 3680 HasGroupChanged = true;
2939 part.IgnoreUndoUpdate = false;
2940 } 3681 }
2941 } 3682 }
2942 3683
@@ -2946,13 +3687,7 @@ namespace OpenSim.Region.Framework.Scenes
2946 /// <param name="pos"></param> 3687 /// <param name="pos"></param>
2947 public void UpdateRootPosition(Vector3 pos) 3688 public void UpdateRootPosition(Vector3 pos)
2948 { 3689 {
2949// m_log.DebugFormat( 3690 // needs to be called with phys building true
2950// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2951
2952// SceneObjectPart[] parts = m_parts.GetArray();
2953// for (int i = 0; i < parts.Length; i++)
2954// parts[i].StoreUndoState();
2955
2956 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3691 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2957 Vector3 oldPos = 3692 Vector3 oldPos =
2958 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3693 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2975,7 +3710,14 @@ namespace OpenSim.Region.Framework.Scenes
2975 AbsolutePosition = newPos; 3710 AbsolutePosition = newPos;
2976 3711
2977 HasGroupChanged = true; 3712 HasGroupChanged = true;
2978 ScheduleGroupForTerseUpdate(); 3713 if (m_rootPart.Undoing)
3714 {
3715 ScheduleGroupForFullUpdate();
3716 }
3717 else
3718 {
3719 ScheduleGroupForTerseUpdate();
3720 }
2979 } 3721 }
2980 3722
2981 #endregion 3723 #endregion
@@ -2988,24 +3730,16 @@ namespace OpenSim.Region.Framework.Scenes
2988 /// <param name="rot"></param> 3730 /// <param name="rot"></param>
2989 public void UpdateGroupRotationR(Quaternion rot) 3731 public void UpdateGroupRotationR(Quaternion rot)
2990 { 3732 {
2991// m_log.DebugFormat(
2992// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2993
2994// SceneObjectPart[] parts = m_parts.GetArray();
2995// for (int i = 0; i < parts.Length; i++)
2996// parts[i].StoreUndoState();
2997
2998 m_rootPart.StoreUndoState(true);
2999
3000 m_rootPart.UpdateRotation(rot); 3733 m_rootPart.UpdateRotation(rot);
3001 3734
3735/* this is done by rootpart RotationOffset set called by UpdateRotation
3002 PhysicsActor actor = m_rootPart.PhysActor; 3736 PhysicsActor actor = m_rootPart.PhysActor;
3003 if (actor != null) 3737 if (actor != null)
3004 { 3738 {
3005 actor.Orientation = m_rootPart.RotationOffset; 3739 actor.Orientation = m_rootPart.RotationOffset;
3006 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3740 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3007 } 3741 }
3008 3742*/
3009 HasGroupChanged = true; 3743 HasGroupChanged = true;
3010 ScheduleGroupForTerseUpdate(); 3744 ScheduleGroupForTerseUpdate();
3011 } 3745 }
@@ -3017,16 +3751,6 @@ namespace OpenSim.Region.Framework.Scenes
3017 /// <param name="rot"></param> 3751 /// <param name="rot"></param>
3018 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3752 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3019 { 3753 {
3020// m_log.DebugFormat(
3021// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3022
3023// SceneObjectPart[] parts = m_parts.GetArray();
3024// for (int i = 0; i < parts.Length; i++)
3025// parts[i].StoreUndoState();
3026
3027 RootPart.StoreUndoState(true);
3028 RootPart.IgnoreUndoUpdate = true;
3029
3030 m_rootPart.UpdateRotation(rot); 3754 m_rootPart.UpdateRotation(rot);
3031 3755
3032 PhysicsActor actor = m_rootPart.PhysActor; 3756 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3045,8 +3769,6 @@ namespace OpenSim.Region.Framework.Scenes
3045 3769
3046 HasGroupChanged = true; 3770 HasGroupChanged = true;
3047 ScheduleGroupForTerseUpdate(); 3771 ScheduleGroupForTerseUpdate();
3048
3049 RootPart.IgnoreUndoUpdate = false;
3050 } 3772 }
3051 3773
3052 /// <summary> 3774 /// <summary>
@@ -3059,13 +3781,11 @@ namespace OpenSim.Region.Framework.Scenes
3059 SceneObjectPart part = GetPart(localID); 3781 SceneObjectPart part = GetPart(localID);
3060 3782
3061 SceneObjectPart[] parts = m_parts.GetArray(); 3783 SceneObjectPart[] parts = m_parts.GetArray();
3062 for (int i = 0; i < parts.Length; i++)
3063 parts[i].StoreUndoState();
3064 3784
3065 if (part != null) 3785 if (part != null)
3066 { 3786 {
3067// m_log.DebugFormat( 3787 if (m_rootPart.PhysActor != null)
3068// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3788 m_rootPart.PhysActor.Building = true;
3069 3789
3070 if (part.UUID == m_rootPart.UUID) 3790 if (part.UUID == m_rootPart.UUID)
3071 { 3791 {
@@ -3075,6 +3795,9 @@ namespace OpenSim.Region.Framework.Scenes
3075 { 3795 {
3076 part.UpdateRotation(rot); 3796 part.UpdateRotation(rot);
3077 } 3797 }
3798
3799 if (m_rootPart.PhysActor != null)
3800 m_rootPart.PhysActor.Building = false;
3078 } 3801 }
3079 } 3802 }
3080 3803
@@ -3088,12 +3811,8 @@ namespace OpenSim.Region.Framework.Scenes
3088 SceneObjectPart part = GetPart(localID); 3811 SceneObjectPart part = GetPart(localID);
3089 if (part != null) 3812 if (part != null)
3090 { 3813 {
3091// m_log.DebugFormat( 3814 if (m_rootPart.PhysActor != null)
3092// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3815 m_rootPart.PhysActor.Building = true;
3093// part.Name, part.LocalId, rot);
3094
3095 part.StoreUndoState();
3096 part.IgnoreUndoUpdate = true;
3097 3816
3098 if (part.UUID == m_rootPart.UUID) 3817 if (part.UUID == m_rootPart.UUID)
3099 { 3818 {
@@ -3106,7 +3825,8 @@ namespace OpenSim.Region.Framework.Scenes
3106 part.OffsetPosition = pos; 3825 part.OffsetPosition = pos;
3107 } 3826 }
3108 3827
3109 part.IgnoreUndoUpdate = false; 3828 if (m_rootPart.PhysActor != null)
3829 m_rootPart.PhysActor.Building = false;
3110 } 3830 }
3111 } 3831 }
3112 3832
@@ -3116,15 +3836,12 @@ namespace OpenSim.Region.Framework.Scenes
3116 /// <param name="rot"></param> 3836 /// <param name="rot"></param>
3117 public void UpdateRootRotation(Quaternion rot) 3837 public void UpdateRootRotation(Quaternion rot)
3118 { 3838 {
3119// m_log.DebugFormat( 3839 // needs to be called with phys building true
3120// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3121// Name, LocalId, rot);
3122
3123 Quaternion axRot = rot; 3840 Quaternion axRot = rot;
3124 Quaternion oldParentRot = m_rootPart.RotationOffset; 3841 Quaternion oldParentRot = m_rootPart.RotationOffset;
3125 3842
3126 m_rootPart.StoreUndoState(); 3843 //Don't use UpdateRotation because it schedules an update prematurely
3127 m_rootPart.UpdateRotation(rot); 3844 m_rootPart.RotationOffset = rot;
3128 3845
3129 PhysicsActor pa = m_rootPart.PhysActor; 3846 PhysicsActor pa = m_rootPart.PhysActor;
3130 3847
@@ -3140,35 +3857,145 @@ namespace OpenSim.Region.Framework.Scenes
3140 SceneObjectPart prim = parts[i]; 3857 SceneObjectPart prim = parts[i];
3141 if (prim.UUID != m_rootPart.UUID) 3858 if (prim.UUID != m_rootPart.UUID)
3142 { 3859 {
3143 prim.IgnoreUndoUpdate = true; 3860 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3861 NewRot = Quaternion.Inverse(axRot) * NewRot;
3862 prim.RotationOffset = NewRot;
3863
3144 Vector3 axPos = prim.OffsetPosition; 3864 Vector3 axPos = prim.OffsetPosition;
3865
3145 axPos *= oldParentRot; 3866 axPos *= oldParentRot;
3146 axPos *= Quaternion.Inverse(axRot); 3867 axPos *= Quaternion.Inverse(axRot);
3147 prim.OffsetPosition = axPos; 3868 prim.OffsetPosition = axPos;
3148 Quaternion primsRot = prim.RotationOffset; 3869 }
3149 Quaternion newRot = oldParentRot * primsRot; 3870 }
3150 newRot = Quaternion.Inverse(axRot) * newRot;
3151 prim.RotationOffset = newRot;
3152 prim.ScheduleTerseUpdate();
3153 prim.IgnoreUndoUpdate = false;
3154 }
3155 }
3156
3157// for (int i = 0; i < parts.Length; i++)
3158// {
3159// SceneObjectPart childpart = parts[i];
3160// if (childpart != m_rootPart)
3161// {
3162//// childpart.IgnoreUndoUpdate = false;
3163//// childpart.StoreUndoState();
3164// }
3165// }
3166 3871
3167 m_rootPart.ScheduleTerseUpdate(); 3872 HasGroupChanged = true;
3873 ScheduleGroupForFullUpdate();
3874 }
3168 3875
3169// m_log.DebugFormat( 3876 private enum updatetype :int
3170// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3877 {
3171// Name, LocalId, rot); 3878 none = 0,
3879 partterse = 1,
3880 partfull = 2,
3881 groupterse = 3,
3882 groupfull = 4
3883 }
3884
3885 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3886 {
3887 // TODO this still as excessive *.Schedule*Update()s
3888
3889 if (part != null && part.ParentGroup != null)
3890 {
3891 ObjectChangeType change = data.change;
3892 bool togroup = ((change & ObjectChangeType.Group) != 0);
3893 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3894
3895 SceneObjectGroup group = part.ParentGroup;
3896 PhysicsActor pha = group.RootPart.PhysActor;
3897
3898 updatetype updateType = updatetype.none;
3899
3900 if (togroup)
3901 {
3902 // related to group
3903 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3904 {
3905 if ((change & ObjectChangeType.Rotation) != 0)
3906 {
3907 group.RootPart.UpdateRotation(data.rotation);
3908 updateType = updatetype.none;
3909 }
3910 if ((change & ObjectChangeType.Position) != 0)
3911 {
3912 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3913 UpdateGroupPosition(data.position);
3914 updateType = updatetype.groupterse;
3915 }
3916 else
3917 // ugly rotation update of all parts
3918 {
3919 group.ResetChildPrimPhysicsPositions();
3920 }
3921
3922 }
3923 if ((change & ObjectChangeType.Scale) != 0)
3924 {
3925 if (pha != null)
3926 pha.Building = true;
3927
3928 group.GroupResize(data.scale);
3929 updateType = updatetype.none;
3930
3931 if (pha != null)
3932 pha.Building = false;
3933 }
3934 }
3935 else
3936 {
3937 // related to single prim in a link-set ( ie group)
3938 if (pha != null)
3939 pha.Building = true;
3940
3941 // root part is special
3942 // parts offset positions or rotations need to change also
3943
3944 if (part == group.RootPart)
3945 {
3946 if ((change & ObjectChangeType.Rotation) != 0)
3947 group.UpdateRootRotation(data.rotation);
3948 if ((change & ObjectChangeType.Position) != 0)
3949 group.UpdateRootPosition(data.position);
3950 if ((change & ObjectChangeType.Scale) != 0)
3951 part.Resize(data.scale);
3952 }
3953 else
3954 {
3955 if ((change & ObjectChangeType.Position) != 0)
3956 {
3957 part.OffsetPosition = data.position;
3958 updateType = updatetype.partterse;
3959 }
3960 if ((change & ObjectChangeType.Rotation) != 0)
3961 {
3962 part.UpdateRotation(data.rotation);
3963 updateType = updatetype.none;
3964 }
3965 if ((change & ObjectChangeType.Scale) != 0)
3966 {
3967 part.Resize(data.scale);
3968 updateType = updatetype.none;
3969 }
3970 }
3971
3972 if (pha != null)
3973 pha.Building = false;
3974 }
3975
3976 if (updateType != updatetype.none)
3977 {
3978 group.HasGroupChanged = true;
3979
3980 switch (updateType)
3981 {
3982 case updatetype.partterse:
3983 part.ScheduleTerseUpdate();
3984 break;
3985 case updatetype.partfull:
3986 part.ScheduleFullUpdate();
3987 break;
3988 case updatetype.groupterse:
3989 group.ScheduleGroupForTerseUpdate();
3990 break;
3991 case updatetype.groupfull:
3992 group.ScheduleGroupForFullUpdate();
3993 break;
3994 default:
3995 break;
3996 }
3997 }
3998 }
3172 } 3999 }
3173 4000
3174 #endregion 4001 #endregion
@@ -3267,10 +4094,11 @@ namespace OpenSim.Region.Framework.Scenes
3267 scriptPosTarget target = m_targets[idx]; 4094 scriptPosTarget target = m_targets[idx];
3268 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4095 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3269 { 4096 {
4097 at_target = true;
4098
3270 // trigger at_target 4099 // trigger at_target
3271 if (m_scriptListens_atTarget) 4100 if (m_scriptListens_atTarget)
3272 { 4101 {
3273 at_target = true;
3274 scriptPosTarget att = new scriptPosTarget(); 4102 scriptPosTarget att = new scriptPosTarget();
3275 att.targetPos = target.targetPos; 4103 att.targetPos = target.targetPos;
3276 att.tolerance = target.tolerance; 4104 att.tolerance = target.tolerance;
@@ -3388,11 +4216,50 @@ namespace OpenSim.Region.Framework.Scenes
3388 } 4216 }
3389 } 4217 }
3390 } 4218 }
3391 4219
4220 public Vector3 GetGeometricCenter()
4221 {
4222 // this is not real geometric center but a average of positions relative to root prim acording to
4223 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4224 // ignoring tortured prims details since sl also seems to ignore
4225 // so no real use in doing it on physics
4226
4227 Vector3 gc = Vector3.Zero;
4228
4229 int nparts = m_parts.Count;
4230 if (nparts <= 1)
4231 return gc;
4232
4233 SceneObjectPart[] parts = m_parts.GetArray();
4234 nparts = parts.Length; // just in case it changed
4235 if (nparts <= 1)
4236 return gc;
4237
4238 Quaternion parentRot = RootPart.RotationOffset;
4239 Vector3 pPos;
4240
4241 // average all parts positions
4242 for (int i = 0; i < nparts; i++)
4243 {
4244 // do it directly
4245 // gc += parts[i].GetWorldPosition();
4246 if (parts[i] != RootPart)
4247 {
4248 pPos = parts[i].OffsetPosition;
4249 gc += pPos;
4250 }
4251
4252 }
4253 gc /= nparts;
4254
4255 // relative to root:
4256// gc -= AbsolutePosition;
4257 return gc;
4258 }
4259
3392 public float GetMass() 4260 public float GetMass()
3393 { 4261 {
3394 float retmass = 0f; 4262 float retmass = 0f;
3395
3396 SceneObjectPart[] parts = m_parts.GetArray(); 4263 SceneObjectPart[] parts = m_parts.GetArray();
3397 for (int i = 0; i < parts.Length; i++) 4264 for (int i = 0; i < parts.Length; i++)
3398 retmass += parts[i].GetMass(); 4265 retmass += parts[i].GetMass();
@@ -3400,6 +4267,39 @@ namespace OpenSim.Region.Framework.Scenes
3400 return retmass; 4267 return retmass;
3401 } 4268 }
3402 4269
4270 // center of mass of full object
4271 public Vector3 GetCenterOfMass()
4272 {
4273 PhysicsActor pa = RootPart.PhysActor;
4274
4275 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4276 {
4277 // physics knows better about center of mass of physical prims
4278 Vector3 tmp = pa.CenterOfMass;
4279 return tmp;
4280 }
4281
4282 Vector3 Ptot = Vector3.Zero;
4283 float totmass = 0f;
4284 float m;
4285
4286 SceneObjectPart[] parts = m_parts.GetArray();
4287 for (int i = 0; i < parts.Length; i++)
4288 {
4289 m = parts[i].GetMass();
4290 Ptot += parts[i].GetPartCenterOfMass() * m;
4291 totmass += m;
4292 }
4293
4294 if (totmass == 0)
4295 totmass = 0;
4296 else
4297 totmass = 1 / totmass;
4298 Ptot *= totmass;
4299
4300 return Ptot;
4301 }
4302
3403 /// <summary> 4303 /// <summary>
3404 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4304 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3405 /// the physics engine can use it. 4305 /// the physics engine can use it.
@@ -3567,6 +4467,14 @@ namespace OpenSim.Region.Framework.Scenes
3567 FromItemID = uuid; 4467 FromItemID = uuid;
3568 } 4468 }
3569 4469
4470 public void ResetOwnerChangeFlag()
4471 {
4472 ForEachPart(delegate(SceneObjectPart part)
4473 {
4474 part.ResetOwnerChangeFlag();
4475 });
4476 }
4477
3570 #endregion 4478 #endregion
3571 } 4479 }
3572} 4480}