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.cs1354
1 files changed, 1137 insertions, 217 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 52469a2..33a2cc5 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -42,6 +43,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
42 43
43namespace OpenSim.Region.Framework.Scenes 44namespace OpenSim.Region.Framework.Scenes
44{ 45{
46
45 [Flags] 47 [Flags]
46 public enum scriptEvents 48 public enum scriptEvents
47 { 49 {
@@ -105,8 +107,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 107 /// since the group's last persistent backup
106 /// </summary> 108 /// </summary>
107 private bool m_hasGroupChanged = false; 109 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 110 private long timeFirstChanged = 0;
109 private long timeLastChanged; 111 private long timeLastChanged = 0;
112 private long m_maxPersistTime = 0;
113 private long m_minPersistTime = 0;
114 private Random m_rand;
115 private bool m_suspendUpdates;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
117
118 public bool areUpdatesSuspended
119 {
120 get
121 {
122 return m_suspendUpdates;
123 }
124 set
125 {
126 m_suspendUpdates = value;
127 if (!value)
128 {
129 QueueForUpdateCheck();
130 }
131 }
132 }
110 133
111 /// <summary> 134 /// <summary>
112 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 135 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -123,9 +146,39 @@ namespace OpenSim.Region.Framework.Scenes
123 { 146 {
124 if (value) 147 if (value)
125 { 148 {
149 if (m_isBackedUp)
150 {
151 m_scene.SceneGraph.FireChangeBackup(this);
152 }
126 timeLastChanged = DateTime.Now.Ticks; 153 timeLastChanged = DateTime.Now.Ticks;
127 if (!m_hasGroupChanged) 154 if (!m_hasGroupChanged)
128 timeFirstChanged = DateTime.Now.Ticks; 155 timeFirstChanged = DateTime.Now.Ticks;
156 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
157 {
158 if (m_rand == null)
159 {
160 byte[] val = new byte[16];
161 m_rootPart.UUID.ToBytes(val, 0);
162 m_rand = new Random(BitConverter.ToInt32(val, 0));
163 }
164
165 if (m_scene.GetRootAgentCount() == 0)
166 {
167 //If the region is empty, this change has been made by an automated process
168 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
169
170 float factor = 1.5f + (float)(m_rand.NextDouble());
171 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
172 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
173 }
174 else
175 {
176 //If the region is not empty, we want to obey the minimum and maximum persist times
177 //but add a random factor so we stagger the object persistance a little
178 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
179 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
180 }
181 }
129 } 182 }
130 m_hasGroupChanged = value; 183 m_hasGroupChanged = value;
131 184
@@ -140,7 +193,7 @@ namespace OpenSim.Region.Framework.Scenes
140 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 193 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
141 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 194 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
142 /// </summary> 195 /// </summary>
143 public bool HasGroupChangedDueToDelink { get; private set; } 196 public bool HasGroupChangedDueToDelink { get; set; }
144 197
145 private bool isTimeToPersist() 198 private bool isTimeToPersist()
146 { 199 {
@@ -150,8 +203,19 @@ namespace OpenSim.Region.Framework.Scenes
150 return false; 203 return false;
151 if (m_scene.ShuttingDown) 204 if (m_scene.ShuttingDown)
152 return true; 205 return true;
206
207 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
208 {
209 m_maxPersistTime = m_scene.m_persistAfter;
210 m_minPersistTime = m_scene.m_dontPersistBefore;
211 }
212
153 long currentTime = DateTime.Now.Ticks; 213 long currentTime = DateTime.Now.Ticks;
154 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 214
215 if (timeLastChanged == 0) timeLastChanged = currentTime;
216 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
217
218 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
155 return true; 219 return true;
156 return false; 220 return false;
157 } 221 }
@@ -270,10 +334,10 @@ namespace OpenSim.Region.Framework.Scenes
270 334
271 private bool m_scriptListens_atTarget; 335 private bool m_scriptListens_atTarget;
272 private bool m_scriptListens_notAtTarget; 336 private bool m_scriptListens_notAtTarget;
273
274 private bool m_scriptListens_atRotTarget; 337 private bool m_scriptListens_atRotTarget;
275 private bool m_scriptListens_notAtRotTarget; 338 private bool m_scriptListens_notAtRotTarget;
276 339
340 public bool m_dupeInProgress = false;
277 internal Dictionary<UUID, string> m_savedScriptState; 341 internal Dictionary<UUID, string> m_savedScriptState;
278 342
279 #region Properties 343 #region Properties
@@ -310,6 +374,16 @@ namespace OpenSim.Region.Framework.Scenes
310 get { return m_parts.Count; } 374 get { return m_parts.Count; }
311 } 375 }
312 376
377// protected Quaternion m_rotation = Quaternion.Identity;
378//
379// public virtual Quaternion Rotation
380// {
381// get { return m_rotation; }
382// set {
383// m_rotation = value;
384// }
385// }
386
313 public Quaternion GroupRotation 387 public Quaternion GroupRotation
314 { 388 {
315 get { return m_rootPart.RotationOffset; } 389 get { return m_rootPart.RotationOffset; }
@@ -416,7 +490,15 @@ namespace OpenSim.Region.Framework.Scenes
416 { 490 {
417 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 491 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
418 } 492 }
419 493
494
495
496 private struct avtocrossInfo
497 {
498 public ScenePresence av;
499 public uint ParentID;
500 }
501
420 /// <summary> 502 /// <summary>
421 /// The absolute position of this scene object in the scene 503 /// The absolute position of this scene object in the scene
422 /// </summary> 504 /// </summary>
@@ -429,14 +511,128 @@ namespace OpenSim.Region.Framework.Scenes
429 511
430 if (Scene != null) 512 if (Scene != null)
431 { 513 {
432 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 514 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
433 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 515 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
516 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
517 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
518 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
434 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 519 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
435 { 520 {
436 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 521 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
522 uint x = 0;
523 uint y = 0;
524 string version = String.Empty;
525 Vector3 newpos = Vector3.Zero;
526 OpenSim.Services.Interfaces.GridRegion destination = null;
527
528 bool canCross = true;
529 foreach (ScenePresence av in m_linkedAvatars)
530 {
531 // We need to cross these agents. First, let's find
532 // out if any of them can't cross for some reason.
533 // We have to deny the crossing entirely if any
534 // of them are banned. Alternatively, we could
535 // unsit banned agents....
536
537
538 // We set the avatar position as being the object
539 // position to get the region to send to
540 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
541 {
542 canCross = false;
543 break;
544 }
545
546 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
547 }
548
549 if (canCross)
550 {
551 // We unparent the SP quietly so that it won't
552 // be made to stand up
553
554 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
555
556 foreach (ScenePresence av in m_linkedAvatars)
557 {
558 avtocrossInfo avinfo = new avtocrossInfo();
559 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
560 if (parentPart != null)
561 av.ParentUUID = parentPart.UUID;
562
563 avinfo.av = av;
564 avinfo.ParentID = av.ParentID;
565 avsToCross.Add(avinfo);
566
567 av.ParentID = 0;
568 }
569
570// m_linkedAvatars.Clear();
571 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
572
573 // Normalize
574 if (val.X >= Constants.RegionSize)
575 val.X -= Constants.RegionSize;
576 if (val.Y >= Constants.RegionSize)
577 val.Y -= Constants.RegionSize;
578 if (val.X < 0)
579 val.X += Constants.RegionSize;
580 if (val.Y < 0)
581 val.Y += Constants.RegionSize;
582
583 // If it's deleted, crossing was successful
584 if (IsDeleted)
585 {
586 // foreach (ScenePresence av in m_linkedAvatars)
587 foreach (avtocrossInfo avinfo in avsToCross)
588 {
589 ScenePresence av = avinfo.av;
590 if (!av.IsInTransit) // just in case...
591 {
592 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
593
594 av.IsInTransit = true;
595
596 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
597 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
598 }
599 else
600 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
601 }
602 avsToCross.Clear();
603 return;
604 }
605 else // cross failed, put avas back ??
606 {
607 foreach (avtocrossInfo avinfo in avsToCross)
608 {
609 ScenePresence av = avinfo.av;
610 av.ParentUUID = UUID.Zero;
611 av.ParentID = avinfo.ParentID;
612// m_linkedAvatars.Add(av);
613 }
614 }
615 avsToCross.Clear();
616
617 }
618 else if (RootPart.PhysActor != null)
619 {
620 RootPart.PhysActor.CrossingFailure();
621 }
622
623 Vector3 oldp = AbsolutePosition;
624 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
625 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
626 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
437 } 627 }
438 } 628 }
439 629
630/* don't see the need but worse don't see where is restored to false if things stay in
631 foreach (SceneObjectPart part in m_parts.GetArray())
632 {
633 part.IgnoreUndoUpdate = true;
634 }
635 */
440 if (RootPart.GetStatusSandbox()) 636 if (RootPart.GetStatusSandbox())
441 { 637 {
442 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 638 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -454,9 +650,38 @@ namespace OpenSim.Region.Framework.Scenes
454 // Restuff the new GroupPosition into each SOP of the linkset. 650 // Restuff the new GroupPosition into each SOP of the linkset.
455 // This has the affect of resetting and tainting the physics actors. 651 // This has the affect of resetting and tainting the physics actors.
456 SceneObjectPart[] parts = m_parts.GetArray(); 652 SceneObjectPart[] parts = m_parts.GetArray();
457 for (int i = 0; i < parts.Length; i++) 653 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
458 parts[i].GroupPosition = val; 654 if (m_dupeInProgress)
655 triggerScriptEvent = false;
656 foreach (SceneObjectPart part in parts)
657 {
658 part.GroupPosition = val;
659 if (triggerScriptEvent)
660 part.TriggerScriptChangedEvent(Changed.POSITION);
661 }
459 662
663/*
664 This seems not needed and should not be needed:
665 sp absolute position depends on sit part absolute position fixed above.
666 sp ParentPosition is not used anywhere.
667 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
668 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
669
670 if (!m_dupeInProgress)
671 {
672 foreach (ScenePresence av in m_linkedAvatars)
673 {
674 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
675 if (p != null && m_parts.TryGetValue(p.UUID, out p))
676 {
677 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
678 av.AbsolutePosition += offset;
679// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
680 av.SendAvatarDataToAllAgents();
681 }
682 }
683 }
684*/
460 //if (m_rootPart.PhysActor != null) 685 //if (m_rootPart.PhysActor != null)
461 //{ 686 //{
462 //m_rootPart.PhysActor.Position = 687 //m_rootPart.PhysActor.Position =
@@ -470,6 +695,40 @@ namespace OpenSim.Region.Framework.Scenes
470 } 695 }
471 } 696 }
472 697
698 public override Vector3 Velocity
699 {
700 get { return RootPart.Velocity; }
701 set { RootPart.Velocity = value; }
702 }
703
704 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
705 {
706 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
707 ScenePresence agent = icon.EndInvoke(iar);
708
709 //// If the cross was successful, this agent is a child agent
710 if (agent.IsChildAgent)
711 {
712 if (agent.ParentUUID != UUID.Zero)
713 {
714 agent.ParentPart = null;
715// agent.ParentPosition = Vector3.Zero;
716// agent.ParentUUID = UUID.Zero;
717 }
718 }
719
720 agent.ParentUUID = UUID.Zero;
721
722// agent.Reset();
723// else // Not successful
724// agent.RestoreInCurrentScene();
725
726 // In any case
727 agent.IsInTransit = false;
728
729 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
730 }
731
473 public override uint LocalId 732 public override uint LocalId
474 { 733 {
475 get { return m_rootPart.LocalId; } 734 get { return m_rootPart.LocalId; }
@@ -540,6 +799,11 @@ namespace OpenSim.Region.Framework.Scenes
540 m_isSelected = value; 799 m_isSelected = value;
541 // Tell physics engine that group is selected 800 // Tell physics engine that group is selected
542 801
802 // this is not right
803 // but ode engines should only really need to know about root part
804 // so they can put entire object simulation on hold and not colliding
805 // keep as was for now
806
543 PhysicsActor pa = m_rootPart.PhysActor; 807 PhysicsActor pa = m_rootPart.PhysActor;
544 if (pa != null) 808 if (pa != null)
545 { 809 {
@@ -556,6 +820,42 @@ namespace OpenSim.Region.Framework.Scenes
556 childPa.Selected = value; 820 childPa.Selected = value;
557 } 821 }
558 } 822 }
823 if (RootPart.KeyframeMotion != null)
824 RootPart.KeyframeMotion.Selected = value;
825 }
826 }
827
828 public void PartSelectChanged(bool partSelect)
829 {
830 // any part selected makes group selected
831 if (m_isSelected == partSelect)
832 return;
833
834 if (partSelect)
835 {
836 IsSelected = partSelect;
837// if (!IsAttachment)
838// ScheduleGroupForFullUpdate();
839 }
840 else
841 {
842 // bad bad bad 2 heavy for large linksets
843 // since viewer does send lot of (un)selects
844 // this needs to be replaced by a specific list or count ?
845 // but that will require extra code in several places
846
847 SceneObjectPart[] parts = m_parts.GetArray();
848 for (int i = 0; i < parts.Length; i++)
849 {
850 SceneObjectPart part = parts[i];
851 if (part.IsSelected)
852 return;
853 }
854 IsSelected = partSelect;
855 if (!IsAttachment)
856 {
857 ScheduleGroupForFullUpdate();
858 }
559 } 859 }
560 } 860 }
561 861
@@ -633,6 +933,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// </summary> 933 /// </summary>
634 public SceneObjectGroup() 934 public SceneObjectGroup()
635 { 935 {
936
636 } 937 }
637 938
638 /// <summary> 939 /// <summary>
@@ -649,7 +950,7 @@ namespace OpenSim.Region.Framework.Scenes
649 /// Constructor. This object is added to the scene later via AttachToScene() 950 /// Constructor. This object is added to the scene later via AttachToScene()
650 /// </summary> 951 /// </summary>
651 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 952 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
652 { 953 {
653 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 954 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
654 } 955 }
655 956
@@ -685,6 +986,9 @@ namespace OpenSim.Region.Framework.Scenes
685 /// </summary> 986 /// </summary>
686 public virtual void AttachToBackup() 987 public virtual void AttachToBackup()
687 { 988 {
989 if (IsAttachment) return;
990 m_scene.SceneGraph.FireAttachToBackup(this);
991
688 if (InSceneBackup) 992 if (InSceneBackup)
689 { 993 {
690 //m_log.DebugFormat( 994 //m_log.DebugFormat(
@@ -727,6 +1031,13 @@ namespace OpenSim.Region.Framework.Scenes
727 1031
728 ApplyPhysics(); 1032 ApplyPhysics();
729 1033
1034 if (RootPart.PhysActor != null)
1035 RootPart.Force = RootPart.Force;
1036 if (RootPart.PhysActor != null)
1037 RootPart.Torque = RootPart.Torque;
1038 if (RootPart.PhysActor != null)
1039 RootPart.Buoyancy = RootPart.Buoyancy;
1040
730 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1041 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
731 // for the same object with very different properties. The caller must schedule the update. 1042 // for the same object with very different properties. The caller must schedule the update.
732 //ScheduleGroupForFullUpdate(); 1043 //ScheduleGroupForFullUpdate();
@@ -742,6 +1053,10 @@ namespace OpenSim.Region.Framework.Scenes
742 EntityIntersection result = new EntityIntersection(); 1053 EntityIntersection result = new EntityIntersection();
743 1054
744 SceneObjectPart[] parts = m_parts.GetArray(); 1055 SceneObjectPart[] parts = m_parts.GetArray();
1056
1057 // Find closest hit here
1058 float idist = float.MaxValue;
1059
745 for (int i = 0; i < parts.Length; i++) 1060 for (int i = 0; i < parts.Length; i++)
746 { 1061 {
747 SceneObjectPart part = parts[i]; 1062 SceneObjectPart part = parts[i];
@@ -756,11 +1071,6 @@ namespace OpenSim.Region.Framework.Scenes
756 1071
757 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1072 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
758 1073
759 // This may need to be updated to the maximum draw distance possible..
760 // We might (and probably will) be checking for prim creation from other sims
761 // when the camera crosses the border.
762 float idist = Constants.RegionSize;
763
764 if (inter.HitTF) 1074 if (inter.HitTF)
765 { 1075 {
766 // We need to find the closest prim to return to the testcaller along the ray 1076 // We need to find the closest prim to return to the testcaller along the ray
@@ -771,10 +1081,11 @@ namespace OpenSim.Region.Framework.Scenes
771 result.obj = part; 1081 result.obj = part;
772 result.normal = inter.normal; 1082 result.normal = inter.normal;
773 result.distance = inter.distance; 1083 result.distance = inter.distance;
1084
1085 idist = inter.distance;
774 } 1086 }
775 } 1087 }
776 } 1088 }
777
778 return result; 1089 return result;
779 } 1090 }
780 1091
@@ -786,25 +1097,27 @@ namespace OpenSim.Region.Framework.Scenes
786 /// <returns></returns> 1097 /// <returns></returns>
787 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1098 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
788 { 1099 {
789 maxX = -256f; 1100 maxX = float.MinValue;
790 maxY = -256f; 1101 maxY = float.MinValue;
791 maxZ = -256f; 1102 maxZ = float.MinValue;
792 minX = 256f; 1103 minX = float.MaxValue;
793 minY = 256f; 1104 minY = float.MaxValue;
794 minZ = 8192f; 1105 minZ = float.MaxValue;
795 1106
796 SceneObjectPart[] parts = m_parts.GetArray(); 1107 SceneObjectPart[] parts = m_parts.GetArray();
797 for (int i = 0; i < parts.Length; i++) 1108 foreach (SceneObjectPart part in parts)
798 { 1109 {
799 SceneObjectPart part = parts[i];
800
801 Vector3 worldPos = part.GetWorldPosition(); 1110 Vector3 worldPos = part.GetWorldPosition();
802 Vector3 offset = worldPos - AbsolutePosition; 1111 Vector3 offset = worldPos - AbsolutePosition;
803 Quaternion worldRot; 1112 Quaternion worldRot;
804 if (part.ParentID == 0) 1113 if (part.ParentID == 0)
1114 {
805 worldRot = part.RotationOffset; 1115 worldRot = part.RotationOffset;
1116 }
806 else 1117 else
1118 {
807 worldRot = part.GetWorldRotation(); 1119 worldRot = part.GetWorldRotation();
1120 }
808 1121
809 Vector3 frontTopLeft; 1122 Vector3 frontTopLeft;
810 Vector3 frontTopRight; 1123 Vector3 frontTopRight;
@@ -816,6 +1129,8 @@ namespace OpenSim.Region.Framework.Scenes
816 Vector3 backBottomLeft; 1129 Vector3 backBottomLeft;
817 Vector3 backBottomRight; 1130 Vector3 backBottomRight;
818 1131
1132 // Vector3[] corners = new Vector3[8];
1133
819 Vector3 orig = Vector3.Zero; 1134 Vector3 orig = Vector3.Zero;
820 1135
821 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1136 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -850,6 +1165,38 @@ namespace OpenSim.Region.Framework.Scenes
850 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1165 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
851 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1166 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
852 1167
1168
1169
1170 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1171 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1172 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1173 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1174 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1175 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1176 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1177 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1178
1179 //for (int i = 0; i < 8; i++)
1180 //{
1181 // corners[i] = corners[i] * worldRot;
1182 // corners[i] += offset;
1183
1184 // if (corners[i].X > maxX)
1185 // maxX = corners[i].X;
1186 // if (corners[i].X < minX)
1187 // minX = corners[i].X;
1188
1189 // if (corners[i].Y > maxY)
1190 // maxY = corners[i].Y;
1191 // if (corners[i].Y < minY)
1192 // minY = corners[i].Y;
1193
1194 // if (corners[i].Z > maxZ)
1195 // maxZ = corners[i].Y;
1196 // if (corners[i].Z < minZ)
1197 // minZ = corners[i].Z;
1198 //}
1199
853 frontTopLeft = frontTopLeft * worldRot; 1200 frontTopLeft = frontTopLeft * worldRot;
854 frontTopRight = frontTopRight * worldRot; 1201 frontTopRight = frontTopRight * worldRot;
855 frontBottomLeft = frontBottomLeft * worldRot; 1202 frontBottomLeft = frontBottomLeft * worldRot;
@@ -871,6 +1218,15 @@ namespace OpenSim.Region.Framework.Scenes
871 backTopLeft += offset; 1218 backTopLeft += offset;
872 backTopRight += offset; 1219 backTopRight += offset;
873 1220
1221 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1222 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1223 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1224 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1225 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1226 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1227 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1228 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1229
874 if (frontTopRight.X > maxX) 1230 if (frontTopRight.X > maxX)
875 maxX = frontTopRight.X; 1231 maxX = frontTopRight.X;
876 if (frontTopLeft.X > maxX) 1232 if (frontTopLeft.X > maxX)
@@ -1014,17 +1370,118 @@ namespace OpenSim.Region.Framework.Scenes
1014 1370
1015 #endregion 1371 #endregion
1016 1372
1373 public void GetResourcesCosts(SceneObjectPart apart,
1374 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1375 {
1376 // this information may need to be cached
1377
1378 float cost;
1379 float tmpcost;
1380
1381 bool ComplexCost = false;
1382
1383 SceneObjectPart p;
1384 SceneObjectPart[] parts;
1385
1386 lock (m_parts)
1387 {
1388 parts = m_parts.GetArray();
1389 }
1390
1391 int nparts = parts.Length;
1392
1393
1394 for (int i = 0; i < nparts; i++)
1395 {
1396 p = parts[i];
1397
1398 if (p.UsesComplexCost)
1399 {
1400 ComplexCost = true;
1401 break;
1402 }
1403 }
1404
1405 if (ComplexCost)
1406 {
1407 linksetResCost = 0;
1408 linksetPhysCost = 0;
1409 partCost = 0;
1410 partPhysCost = 0;
1411
1412 for (int i = 0; i < nparts; i++)
1413 {
1414 p = parts[i];
1415
1416 cost = p.StreamingCost;
1417 tmpcost = p.SimulationCost;
1418 if (tmpcost > cost)
1419 cost = tmpcost;
1420 tmpcost = p.PhysicsCost;
1421 if (tmpcost > cost)
1422 cost = tmpcost;
1423
1424 linksetPhysCost += tmpcost;
1425 linksetResCost += cost;
1426
1427 if (p == apart)
1428 {
1429 partCost = cost;
1430 partPhysCost = tmpcost;
1431 }
1432 }
1433 }
1434 else
1435 {
1436 partPhysCost = 1.0f;
1437 partCost = 1.0f;
1438 linksetResCost = (float)nparts;
1439 linksetPhysCost = linksetResCost;
1440 }
1441 }
1442
1443 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1444 {
1445 SceneObjectPart p;
1446 SceneObjectPart[] parts;
1447
1448 lock (m_parts)
1449 {
1450 parts = m_parts.GetArray();
1451 }
1452
1453 int nparts = parts.Length;
1454
1455 PhysCost = 0;
1456 StreamCost = 0;
1457 SimulCost = 0;
1458
1459 for (int i = 0; i < nparts; i++)
1460 {
1461 p = parts[i];
1462
1463 StreamCost += p.StreamingCost;
1464 SimulCost += p.SimulationCost;
1465 PhysCost += p.PhysicsCost;
1466 }
1467 }
1468
1017 public void SaveScriptedState(XmlTextWriter writer) 1469 public void SaveScriptedState(XmlTextWriter writer)
1018 { 1470 {
1471 SaveScriptedState(writer, false);
1472 }
1473
1474 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1475 {
1019 XmlDocument doc = new XmlDocument(); 1476 XmlDocument doc = new XmlDocument();
1020 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1477 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1021 1478
1022 SceneObjectPart[] parts = m_parts.GetArray(); 1479 SceneObjectPart[] parts = m_parts.GetArray();
1023 for (int i = 0; i < parts.Length; i++) 1480 for (int i = 0; i < parts.Length; i++)
1024 { 1481 {
1025 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1482 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1026 foreach (KeyValuePair<UUID, string> kvp in pstates) 1483 foreach (KeyValuePair<UUID, string> kvp in pstates)
1027 states.Add(kvp.Key, kvp.Value); 1484 states[kvp.Key] = kvp.Value;
1028 } 1485 }
1029 1486
1030 if (states.Count > 0) 1487 if (states.Count > 0)
@@ -1044,6 +1501,169 @@ namespace OpenSim.Region.Framework.Scenes
1044 } 1501 }
1045 1502
1046 /// <summary> 1503 /// <summary>
1504 /// Add the avatar to this linkset (avatar is sat).
1505 /// </summary>
1506 /// <param name="agentID"></param>
1507 public void AddAvatar(UUID agentID)
1508 {
1509 ScenePresence presence;
1510 if (m_scene.TryGetScenePresence(agentID, out presence))
1511 {
1512 if (!m_linkedAvatars.Contains(presence))
1513 {
1514 m_linkedAvatars.Add(presence);
1515 }
1516 }
1517 }
1518
1519 /// <summary>
1520 /// Delete the avatar from this linkset (avatar is unsat).
1521 /// </summary>
1522 /// <param name="agentID"></param>
1523 public void DeleteAvatar(UUID agentID)
1524 {
1525 ScenePresence presence;
1526 if (m_scene.TryGetScenePresence(agentID, out presence))
1527 {
1528 if (m_linkedAvatars.Contains(presence))
1529 {
1530 m_linkedAvatars.Remove(presence);
1531 }
1532 }
1533 }
1534
1535 /// <summary>
1536 /// Returns the list of linked presences (avatars sat on this group)
1537 /// </summary>
1538 /// <param name="agentID"></param>
1539 public List<ScenePresence> GetLinkedAvatars()
1540 {
1541 return m_linkedAvatars;
1542 }
1543
1544 /// <summary>
1545 /// Attach this scene object to the given avatar.
1546 /// </summary>
1547 /// <param name="agentID"></param>
1548 /// <param name="attachmentpoint"></param>
1549 /// <param name="AttachOffset"></param>
1550 private void AttachToAgent(
1551 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1552 {
1553 if (avatar != null)
1554 {
1555 // don't attach attachments to child agents
1556 if (avatar.IsChildAgent) return;
1557
1558 // Remove from database and parcel prim count
1559 m_scene.DeleteFromStorage(so.UUID);
1560 m_scene.EventManager.TriggerParcelPrimCountTainted();
1561
1562 so.AttachedAvatar = avatar.UUID;
1563
1564 if (so.RootPart.PhysActor != null)
1565 {
1566 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1567 so.RootPart.PhysActor = null;
1568 }
1569
1570 so.AbsolutePosition = attachOffset;
1571 so.RootPart.AttachedPos = attachOffset;
1572 so.IsAttachment = true;
1573 so.RootPart.SetParentLocalId(avatar.LocalId);
1574 so.AttachmentPoint = attachmentpoint;
1575
1576 avatar.AddAttachment(this);
1577
1578 if (!silent)
1579 {
1580 // Killing it here will cause the client to deselect it
1581 // It then reappears on the avatar, deselected
1582 // through the full update below
1583 //
1584 if (IsSelected)
1585 {
1586 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1587 }
1588
1589 IsSelected = false; // fudge....
1590 ScheduleGroupForFullUpdate();
1591 }
1592 }
1593 else
1594 {
1595 m_log.WarnFormat(
1596 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1597 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1598 }
1599 }
1600
1601 public byte GetAttachmentPoint()
1602 {
1603 return m_rootPart.Shape.State;
1604 }
1605
1606 public void DetachToGround()
1607 {
1608 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1609 if (avatar == null)
1610 return;
1611
1612 avatar.RemoveAttachment(this);
1613
1614 Vector3 detachedpos = new Vector3(127f,127f,127f);
1615 if (avatar == null)
1616 return;
1617
1618 detachedpos = avatar.AbsolutePosition;
1619 FromItemID = UUID.Zero;
1620
1621 AbsolutePosition = detachedpos;
1622 AttachedAvatar = UUID.Zero;
1623
1624 //SceneObjectPart[] parts = m_parts.GetArray();
1625 //for (int i = 0; i < parts.Length; i++)
1626 // parts[i].AttachedAvatar = UUID.Zero;
1627
1628 m_rootPart.SetParentLocalId(0);
1629 AttachmentPoint = (byte)0;
1630 // must check if buildind should be true or false here
1631 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1632 HasGroupChanged = true;
1633 RootPart.Rezzed = DateTime.Now;
1634 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1635 AttachToBackup();
1636 m_scene.EventManager.TriggerParcelPrimCountTainted();
1637 m_rootPart.ScheduleFullUpdate();
1638 m_rootPart.ClearUndoState();
1639 }
1640
1641 public void DetachToInventoryPrep()
1642 {
1643 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1644 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1645 if (avatar != null)
1646 {
1647 //detachedpos = avatar.AbsolutePosition;
1648 avatar.RemoveAttachment(this);
1649 }
1650
1651 AttachedAvatar = UUID.Zero;
1652
1653 /*SceneObjectPart[] parts = m_parts.GetArray();
1654 for (int i = 0; i < parts.Length; i++)
1655 parts[i].AttachedAvatar = UUID.Zero;*/
1656
1657 m_rootPart.SetParentLocalId(0);
1658 //m_rootPart.SetAttachmentPoint((byte)0);
1659 IsAttachment = false;
1660 AbsolutePosition = m_rootPart.AttachedPos;
1661 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1662 //AttachToBackup();
1663 //m_rootPart.ScheduleFullUpdate();
1664 }
1665
1666 /// <summary>
1047 /// 1667 ///
1048 /// </summary> 1668 /// </summary>
1049 /// <param name="part"></param> 1669 /// <param name="part"></param>
@@ -1083,7 +1703,10 @@ namespace OpenSim.Region.Framework.Scenes
1083 public void AddPart(SceneObjectPart part) 1703 public void AddPart(SceneObjectPart part)
1084 { 1704 {
1085 part.SetParent(this); 1705 part.SetParent(this);
1086 part.LinkNum = m_parts.Add(part.UUID, part); 1706 m_parts.Add(part.UUID, part);
1707
1708 part.LinkNum = m_parts.Count;
1709
1087 if (part.LinkNum == 2) 1710 if (part.LinkNum == 2)
1088 RootPart.LinkNum = 1; 1711 RootPart.LinkNum = 1;
1089 } 1712 }
@@ -1174,7 +1797,7 @@ namespace OpenSim.Region.Framework.Scenes
1174// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1797// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1175// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1798// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1176 1799
1177 part.StoreUndoState(); 1800// part.StoreUndoState();
1178 part.OnGrab(offsetPos, remoteClient); 1801 part.OnGrab(offsetPos, remoteClient);
1179 } 1802 }
1180 1803
@@ -1194,6 +1817,11 @@ namespace OpenSim.Region.Framework.Scenes
1194 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1817 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1195 public void DeleteGroupFromScene(bool silent) 1818 public void DeleteGroupFromScene(bool silent)
1196 { 1819 {
1820 // We need to keep track of this state in case this group is still queued for backup.
1821 IsDeleted = true;
1822
1823 DetachFromBackup();
1824
1197 SceneObjectPart[] parts = m_parts.GetArray(); 1825 SceneObjectPart[] parts = m_parts.GetArray();
1198 for (int i = 0; i < parts.Length; i++) 1826 for (int i = 0; i < parts.Length; i++)
1199 { 1827 {
@@ -1217,6 +1845,7 @@ namespace OpenSim.Region.Framework.Scenes
1217 } 1845 }
1218 }); 1846 });
1219 } 1847 }
1848
1220 } 1849 }
1221 1850
1222 public void AddScriptLPS(int count) 1851 public void AddScriptLPS(int count)
@@ -1286,28 +1915,43 @@ namespace OpenSim.Region.Framework.Scenes
1286 /// </summary> 1915 /// </summary>
1287 public void ApplyPhysics() 1916 public void ApplyPhysics()
1288 { 1917 {
1289 // Apply physics to the root prim
1290 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1291
1292 // Apply physics to child prims
1293 SceneObjectPart[] parts = m_parts.GetArray(); 1918 SceneObjectPart[] parts = m_parts.GetArray();
1294 if (parts.Length > 1) 1919 if (parts.Length > 1)
1295 { 1920 {
1921 ResetChildPrimPhysicsPositions();
1922
1923 // Apply physics to the root prim
1924 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1925
1926
1296 for (int i = 0; i < parts.Length; i++) 1927 for (int i = 0; i < parts.Length; i++)
1297 { 1928 {
1298 SceneObjectPart part = parts[i]; 1929 SceneObjectPart part = parts[i];
1299 if (part.LocalId != m_rootPart.LocalId) 1930 if (part.LocalId != m_rootPart.LocalId)
1300 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1931 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1301 } 1932 }
1302
1303 // Hack to get the physics scene geometries in the right spot 1933 // Hack to get the physics scene geometries in the right spot
1304 ResetChildPrimPhysicsPositions(); 1934// ResetChildPrimPhysicsPositions();
1935 if (m_rootPart.PhysActor != null)
1936 {
1937 m_rootPart.PhysActor.Building = false;
1938 }
1939 }
1940 else
1941 {
1942 // Apply physics to the root prim
1943 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1305 } 1944 }
1306 } 1945 }
1307 1946
1308 public void SetOwnerId(UUID userId) 1947 public void SetOwnerId(UUID userId)
1309 { 1948 {
1310 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1949 ForEachPart(delegate(SceneObjectPart part)
1950 {
1951
1952 part.OwnerID = userId;
1953
1954 });
1311 } 1955 }
1312 1956
1313 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1957 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1339,11 +1983,17 @@ namespace OpenSim.Region.Framework.Scenes
1339 return; 1983 return;
1340 } 1984 }
1341 1985
1986 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1987 return;
1988
1342 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1989 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1343 // any exception propogate upwards. 1990 // any exception propogate upwards.
1344 try 1991 try
1345 { 1992 {
1346 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1993 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1994 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1995 m_scene.LoadingPrims) // Land may not be valid yet
1996
1347 { 1997 {
1348 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1998 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1349 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1999 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1370,6 +2020,7 @@ namespace OpenSim.Region.Framework.Scenes
1370 } 2020 }
1371 } 2021 }
1372 } 2022 }
2023
1373 } 2024 }
1374 2025
1375 if (m_scene.UseBackup && HasGroupChanged) 2026 if (m_scene.UseBackup && HasGroupChanged)
@@ -1377,10 +2028,30 @@ namespace OpenSim.Region.Framework.Scenes
1377 // don't backup while it's selected or you're asking for changes mid stream. 2028 // don't backup while it's selected or you're asking for changes mid stream.
1378 if (isTimeToPersist() || forcedBackup) 2029 if (isTimeToPersist() || forcedBackup)
1379 { 2030 {
2031 if (m_rootPart.PhysActor != null &&
2032 (!m_rootPart.PhysActor.IsPhysical))
2033 {
2034 // Possible ghost prim
2035 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2036 {
2037 foreach (SceneObjectPart part in m_parts.GetArray())
2038 {
2039 // Re-set physics actor positions and
2040 // orientations
2041 part.GroupPosition = m_rootPart.GroupPosition;
2042 }
2043 }
2044 }
1380// m_log.DebugFormat( 2045// m_log.DebugFormat(
1381// "[SCENE]: Storing {0}, {1} in {2}", 2046// "[SCENE]: Storing {0}, {1} in {2}",
1382// Name, UUID, m_scene.RegionInfo.RegionName); 2047// Name, UUID, m_scene.RegionInfo.RegionName);
1383 2048
2049 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2050 {
2051 RootPart.Shape.State = 0;
2052 ScheduleGroupForFullUpdate();
2053 }
2054
1384 SceneObjectGroup backup_group = Copy(false); 2055 SceneObjectGroup backup_group = Copy(false);
1385 backup_group.RootPart.Velocity = RootPart.Velocity; 2056 backup_group.RootPart.Velocity = RootPart.Velocity;
1386 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2057 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1394,6 +2065,11 @@ namespace OpenSim.Region.Framework.Scenes
1394 2065
1395 backup_group.ForEachPart(delegate(SceneObjectPart part) 2066 backup_group.ForEachPart(delegate(SceneObjectPart part)
1396 { 2067 {
2068 if (part.KeyframeMotion != null)
2069 {
2070 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2071 part.KeyframeMotion.UpdateSceneObject(this);
2072 }
1397 part.Inventory.ProcessInventoryBackup(datastore); 2073 part.Inventory.ProcessInventoryBackup(datastore);
1398 }); 2074 });
1399 2075
@@ -1446,10 +2122,14 @@ namespace OpenSim.Region.Framework.Scenes
1446 /// <returns></returns> 2122 /// <returns></returns>
1447 public SceneObjectGroup Copy(bool userExposed) 2123 public SceneObjectGroup Copy(bool userExposed)
1448 { 2124 {
2125 m_dupeInProgress = true;
1449 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2126 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1450 dupe.m_isBackedUp = false; 2127 dupe.m_isBackedUp = false;
1451 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2128 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1452 2129
2130 // new group as no sitting avatars
2131 dupe.m_linkedAvatars = new List<ScenePresence>();
2132
1453 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2133 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1454 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2134 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1455 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2135 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1460,7 +2140,7 @@ namespace OpenSim.Region.Framework.Scenes
1460 // This is only necessary when userExposed is false! 2140 // This is only necessary when userExposed is false!
1461 2141
1462 bool previousAttachmentStatus = dupe.IsAttachment; 2142 bool previousAttachmentStatus = dupe.IsAttachment;
1463 2143
1464 if (!userExposed) 2144 if (!userExposed)
1465 dupe.IsAttachment = true; 2145 dupe.IsAttachment = true;
1466 2146
@@ -1478,11 +2158,11 @@ namespace OpenSim.Region.Framework.Scenes
1478 dupe.m_rootPart.TrimPermissions(); 2158 dupe.m_rootPart.TrimPermissions();
1479 2159
1480 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2160 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1481 2161
1482 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2162 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1483 { 2163 {
1484 return p1.LinkNum.CompareTo(p2.LinkNum); 2164 return p1.LinkNum.CompareTo(p2.LinkNum);
1485 } 2165 }
1486 ); 2166 );
1487 2167
1488 foreach (SceneObjectPart part in partList) 2168 foreach (SceneObjectPart part in partList)
@@ -1492,41 +2172,53 @@ namespace OpenSim.Region.Framework.Scenes
1492 { 2172 {
1493 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2173 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1494 newPart.LinkNum = part.LinkNum; 2174 newPart.LinkNum = part.LinkNum;
1495 } 2175 if (userExposed)
2176 newPart.ParentID = dupe.m_rootPart.LocalId;
2177 }
1496 else 2178 else
1497 { 2179 {
1498 newPart = dupe.m_rootPart; 2180 newPart = dupe.m_rootPart;
1499 } 2181 }
2182/*
2183 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2184 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1500 2185
1501 // Need to duplicate the physics actor as well 2186 // Need to duplicate the physics actor as well
1502 PhysicsActor originalPartPa = part.PhysActor; 2187 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1503 if (originalPartPa != null && userExposed)
1504 { 2188 {
1505 PrimitiveBaseShape pbs = newPart.Shape; 2189 PrimitiveBaseShape pbs = newPart.Shape;
1506
1507 newPart.PhysActor 2190 newPart.PhysActor
1508 = m_scene.PhysicsScene.AddPrimShape( 2191 = m_scene.PhysicsScene.AddPrimShape(
1509 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2192 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1510 pbs, 2193 pbs,
1511 newPart.AbsolutePosition, 2194 newPart.AbsolutePosition,
1512 newPart.Scale, 2195 newPart.Scale,
1513 newPart.RotationOffset, 2196 newPart.GetWorldRotation(),
1514 originalPartPa.IsPhysical, 2197 isphys,
2198 isphan,
1515 newPart.LocalId); 2199 newPart.LocalId);
1516 2200
1517 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2201 newPart.DoPhysicsPropertyUpdate(isphys, true);
1518 } 2202 */
2203 if (userExposed)
2204 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2205// }
1519 } 2206 }
1520 2207
1521 if (userExposed) 2208 if (userExposed)
1522 { 2209 {
1523 dupe.UpdateParentIDs(); 2210// done above dupe.UpdateParentIDs();
2211
2212 if (dupe.m_rootPart.PhysActor != null)
2213 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2214
1524 dupe.HasGroupChanged = true; 2215 dupe.HasGroupChanged = true;
1525 dupe.AttachToBackup(); 2216 dupe.AttachToBackup();
1526 2217
1527 ScheduleGroupForFullUpdate(); 2218 ScheduleGroupForFullUpdate();
1528 } 2219 }
1529 2220
2221 m_dupeInProgress = false;
1530 return dupe; 2222 return dupe;
1531 } 2223 }
1532 2224
@@ -1538,11 +2230,24 @@ namespace OpenSim.Region.Framework.Scenes
1538 /// <param name="cGroupID"></param> 2230 /// <param name="cGroupID"></param>
1539 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2231 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1540 { 2232 {
1541 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2233 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2234 // give newpart a new local ID lettng old part keep same
2235 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2236 newpart.LocalId = m_scene.AllocateLocalId();
2237
2238 SetRootPart(newpart);
2239 if (userExposed)
2240 RootPart.Velocity = Vector3.Zero; // In case source is moving
1542 } 2241 }
1543 2242
1544 public void ScriptSetPhysicsStatus(bool usePhysics) 2243 public void ScriptSetPhysicsStatus(bool usePhysics)
1545 { 2244 {
2245 if (usePhysics)
2246 {
2247 if (RootPart.KeyframeMotion != null)
2248 RootPart.KeyframeMotion.Stop();
2249 RootPart.KeyframeMotion = null;
2250 }
1546 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2251 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1547 } 2252 }
1548 2253
@@ -1590,13 +2295,14 @@ namespace OpenSim.Region.Framework.Scenes
1590 2295
1591 if (pa != null) 2296 if (pa != null)
1592 { 2297 {
1593 pa.AddForce(impulse, true); 2298 // false to be applied as a impulse
2299 pa.AddForce(impulse, false);
1594 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2300 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1595 } 2301 }
1596 } 2302 }
1597 } 2303 }
1598 2304
1599 public void applyAngularImpulse(Vector3 impulse) 2305 public void ApplyAngularImpulse(Vector3 impulse)
1600 { 2306 {
1601 PhysicsActor pa = RootPart.PhysActor; 2307 PhysicsActor pa = RootPart.PhysActor;
1602 2308
@@ -1604,21 +2310,8 @@ namespace OpenSim.Region.Framework.Scenes
1604 { 2310 {
1605 if (!IsAttachment) 2311 if (!IsAttachment)
1606 { 2312 {
1607 pa.AddAngularForce(impulse, true); 2313 // false to be applied as a impulse
1608 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2314 pa.AddAngularForce(impulse, false);
1609 }
1610 }
1611 }
1612
1613 public void setAngularImpulse(Vector3 impulse)
1614 {
1615 PhysicsActor pa = RootPart.PhysActor;
1616
1617 if (pa != null)
1618 {
1619 if (!IsAttachment)
1620 {
1621 pa.Torque = impulse;
1622 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2315 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1623 } 2316 }
1624 } 2317 }
@@ -1626,20 +2319,10 @@ namespace OpenSim.Region.Framework.Scenes
1626 2319
1627 public Vector3 GetTorque() 2320 public Vector3 GetTorque()
1628 { 2321 {
1629 PhysicsActor pa = RootPart.PhysActor; 2322 return RootPart.Torque;
1630
1631 if (pa != null)
1632 {
1633 if (!IsAttachment)
1634 {
1635 Vector3 torque = pa.Torque;
1636 return torque;
1637 }
1638 }
1639
1640 return Vector3.Zero;
1641 } 2323 }
1642 2324
2325 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1643 public void moveToTarget(Vector3 target, float tau) 2326 public void moveToTarget(Vector3 target, float tau)
1644 { 2327 {
1645 if (IsAttachment) 2328 if (IsAttachment)
@@ -1671,6 +2354,46 @@ namespace OpenSim.Region.Framework.Scenes
1671 pa.PIDActive = false; 2354 pa.PIDActive = false;
1672 } 2355 }
1673 2356
2357 public void rotLookAt(Quaternion target, float strength, float damping)
2358 {
2359 SceneObjectPart rootpart = m_rootPart;
2360 if (rootpart != null)
2361 {
2362 if (IsAttachment)
2363 {
2364 /*
2365 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2366 if (avatar != null)
2367 {
2368 Rotate the Av?
2369 } */
2370 }
2371 else
2372 {
2373 if (rootpart.PhysActor != null)
2374 { // APID must be implemented in your physics system for this to function.
2375 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2376 rootpart.PhysActor.APIDStrength = strength;
2377 rootpart.PhysActor.APIDDamping = damping;
2378 rootpart.PhysActor.APIDActive = true;
2379 }
2380 }
2381 }
2382 }
2383
2384 public void stopLookAt()
2385 {
2386 SceneObjectPart rootpart = m_rootPart;
2387 if (rootpart != null)
2388 {
2389 if (rootpart.PhysActor != null)
2390 { // APID must be implemented in your physics system for this to function.
2391 rootpart.PhysActor.APIDActive = false;
2392 }
2393 }
2394
2395 }
2396
1674 /// <summary> 2397 /// <summary>
1675 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2398 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1676 /// </summary> 2399 /// </summary>
@@ -1687,7 +2410,7 @@ namespace OpenSim.Region.Framework.Scenes
1687 { 2410 {
1688 pa.PIDHoverHeight = height; 2411 pa.PIDHoverHeight = height;
1689 pa.PIDHoverType = hoverType; 2412 pa.PIDHoverType = hoverType;
1690 pa.PIDTau = tau; 2413 pa.PIDHoverTau = tau;
1691 pa.PIDHoverActive = true; 2414 pa.PIDHoverActive = true;
1692 } 2415 }
1693 else 2416 else
@@ -1727,7 +2450,12 @@ namespace OpenSim.Region.Framework.Scenes
1727 /// <param name="cGroupID"></param> 2450 /// <param name="cGroupID"></param>
1728 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2451 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1729 { 2452 {
1730 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2453 // give new ID to the new part, letting old keep original
2454 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2455 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2456 newPart.LocalId = m_scene.AllocateLocalId();
2457 newPart.SetParent(this);
2458
1731 AddPart(newPart); 2459 AddPart(newPart);
1732 2460
1733 SetPartAsNonRoot(newPart); 2461 SetPartAsNonRoot(newPart);
@@ -1866,11 +2594,11 @@ namespace OpenSim.Region.Framework.Scenes
1866 /// Immediately send a full update for this scene object. 2594 /// Immediately send a full update for this scene object.
1867 /// </summary> 2595 /// </summary>
1868 public void SendGroupFullUpdate() 2596 public void SendGroupFullUpdate()
1869 { 2597 {
1870 if (IsDeleted) 2598 if (IsDeleted)
1871 return; 2599 return;
1872 2600
1873// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2601// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1874 2602
1875 RootPart.SendFullUpdateToAllClients(); 2603 RootPart.SendFullUpdateToAllClients();
1876 2604
@@ -2007,6 +2735,11 @@ namespace OpenSim.Region.Framework.Scenes
2007 // 'linkPart' == the root of the group being linked into this group 2735 // 'linkPart' == the root of the group being linked into this group
2008 SceneObjectPart linkPart = objectGroup.m_rootPart; 2736 SceneObjectPart linkPart = objectGroup.m_rootPart;
2009 2737
2738 if (m_rootPart.PhysActor != null)
2739 m_rootPart.PhysActor.Building = true;
2740 if (linkPart.PhysActor != null)
2741 linkPart.PhysActor.Building = true;
2742
2010 // physics flags from group to be applied to linked parts 2743 // physics flags from group to be applied to linked parts
2011 bool grpusephys = UsesPhysics; 2744 bool grpusephys = UsesPhysics;
2012 bool grptemporary = IsTemporary; 2745 bool grptemporary = IsTemporary;
@@ -2032,12 +2765,12 @@ namespace OpenSim.Region.Framework.Scenes
2032 Vector3 axPos = linkPart.OffsetPosition; 2765 Vector3 axPos = linkPart.OffsetPosition;
2033 // Rotate the linking root SOP's position to be relative to the new root prim 2766 // Rotate the linking root SOP's position to be relative to the new root prim
2034 Quaternion parentRot = m_rootPart.RotationOffset; 2767 Quaternion parentRot = m_rootPart.RotationOffset;
2035 axPos *= Quaternion.Inverse(parentRot); 2768 axPos *= Quaternion.Conjugate(parentRot);
2036 linkPart.OffsetPosition = axPos; 2769 linkPart.OffsetPosition = axPos;
2037 2770
2038 // Make the linking root SOP's rotation relative to the new root prim 2771 // Make the linking root SOP's rotation relative to the new root prim
2039 Quaternion oldRot = linkPart.RotationOffset; 2772 Quaternion oldRot = linkPart.RotationOffset;
2040 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2773 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2041 linkPart.RotationOffset = newRot; 2774 linkPart.RotationOffset = newRot;
2042 2775
2043 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2776 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2071,7 +2804,7 @@ namespace OpenSim.Region.Framework.Scenes
2071 linkPart.CreateSelected = true; 2804 linkPart.CreateSelected = true;
2072 2805
2073 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2806 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2074 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2807 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2075 2808
2076 // If the added SOP is physical, also tell the physics engine about the link relationship. 2809 // If the added SOP is physical, also tell the physics engine about the link relationship.
2077 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2810 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2081,6 +2814,7 @@ namespace OpenSim.Region.Framework.Scenes
2081 } 2814 }
2082 2815
2083 linkPart.LinkNum = linkNum++; 2816 linkPart.LinkNum = linkNum++;
2817 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2084 2818
2085 // Get a list of the SOP's in the old group in order of their linknum's. 2819 // Get a list of the SOP's in the old group in order of their linknum's.
2086 SceneObjectPart[] ogParts = objectGroup.Parts; 2820 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2099,7 +2833,7 @@ namespace OpenSim.Region.Framework.Scenes
2099 2833
2100 // Update the physics flags for the newly added SOP 2834 // Update the physics flags for the newly added SOP
2101 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2835 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2102 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2836 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2103 2837
2104 // If the added SOP is physical, also tell the physics engine about the link relationship. 2838 // If the added SOP is physical, also tell the physics engine about the link relationship.
2105 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2839 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2117,7 +2851,7 @@ namespace OpenSim.Region.Framework.Scenes
2117 objectGroup.IsDeleted = true; 2851 objectGroup.IsDeleted = true;
2118 2852
2119 objectGroup.m_parts.Clear(); 2853 objectGroup.m_parts.Clear();
2120 2854
2121 // Can't do this yet since backup still makes use of the root part without any synchronization 2855 // Can't do this yet since backup still makes use of the root part without any synchronization
2122// objectGroup.m_rootPart = null; 2856// objectGroup.m_rootPart = null;
2123 2857
@@ -2128,6 +2862,9 @@ namespace OpenSim.Region.Framework.Scenes
2128 // unmoved prims! 2862 // unmoved prims!
2129 ResetChildPrimPhysicsPositions(); 2863 ResetChildPrimPhysicsPositions();
2130 2864
2865 if (m_rootPart.PhysActor != null)
2866 m_rootPart.PhysActor.Building = false;
2867
2131 //HasGroupChanged = true; 2868 //HasGroupChanged = true;
2132 //ScheduleGroupForFullUpdate(); 2869 //ScheduleGroupForFullUpdate();
2133 } 2870 }
@@ -2195,7 +2932,10 @@ namespace OpenSim.Region.Framework.Scenes
2195// m_log.DebugFormat( 2932// m_log.DebugFormat(
2196// "[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}",
2197// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2934// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2198 2935
2936 if (m_rootPart.PhysActor != null)
2937 m_rootPart.PhysActor.Building = true;
2938
2199 linkPart.ClearUndoState(); 2939 linkPart.ClearUndoState();
2200 2940
2201 Vector3 worldPos = linkPart.GetWorldPosition(); 2941 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2266,6 +3006,14 @@ namespace OpenSim.Region.Framework.Scenes
2266 3006
2267 // 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
2268 // (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
2269 objectGroup.HasGroupChangedDueToDelink = true; 3017 objectGroup.HasGroupChangedDueToDelink = true;
2270 3018
2271 return objectGroup; 3019 return objectGroup;
@@ -2277,6 +3025,7 @@ namespace OpenSim.Region.Framework.Scenes
2277 /// <param name="objectGroup"></param> 3025 /// <param name="objectGroup"></param>
2278 public virtual void DetachFromBackup() 3026 public virtual void DetachFromBackup()
2279 { 3027 {
3028 m_scene.SceneGraph.FireDetachFromBackup(this);
2280 if (m_isBackedUp && Scene != null) 3029 if (m_isBackedUp && Scene != null)
2281 m_scene.EventManager.OnBackup -= ProcessBackup; 3030 m_scene.EventManager.OnBackup -= ProcessBackup;
2282 3031
@@ -2297,7 +3046,8 @@ namespace OpenSim.Region.Framework.Scenes
2297 Vector3 axPos = part.OffsetPosition; 3046 Vector3 axPos = part.OffsetPosition;
2298 axPos *= parentRot; 3047 axPos *= parentRot;
2299 part.OffsetPosition = axPos; 3048 part.OffsetPosition = axPos;
2300 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3049 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3050 part.GroupPosition = newPos;
2301 part.OffsetPosition = Vector3.Zero; 3051 part.OffsetPosition = Vector3.Zero;
2302 3052
2303 // Compution our rotation to be not relative to the old parent 3053 // Compution our rotation to be not relative to the old parent
@@ -2322,18 +3072,18 @@ namespace OpenSim.Region.Framework.Scenes
2322 // Rotate the relative position by the rotation of the group 3072 // Rotate the relative position by the rotation of the group
2323 Quaternion rootRotation = m_rootPart.RotationOffset; 3073 Quaternion rootRotation = m_rootPart.RotationOffset;
2324 Vector3 pos = part.OffsetPosition; 3074 Vector3 pos = part.OffsetPosition;
2325 pos *= Quaternion.Inverse(rootRotation); 3075 pos *= Quaternion.Conjugate(rootRotation);
2326 part.OffsetPosition = pos; 3076 part.OffsetPosition = pos;
2327 3077
2328 // 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.
2329 parentRot = m_rootPart.RotationOffset; 3079 parentRot = m_rootPart.RotationOffset;
2330 oldRot = part.RotationOffset; 3080 oldRot = part.RotationOffset;
2331 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3081 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2332 part.RotationOffset = newRot; 3082 part.RotationOffset = newRot;
2333 3083
2334 // 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
2335 // and the simulator. 3085 // and the simulator.
2336 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3086 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2337 } 3087 }
2338 3088
2339 /// <summary> 3089 /// <summary>
@@ -2355,10 +3105,14 @@ namespace OpenSim.Region.Framework.Scenes
2355 { 3105 {
2356 if (!m_rootPart.BlockGrab) 3106 if (!m_rootPart.BlockGrab)
2357 { 3107 {
2358 Vector3 llmoveforce = pos - AbsolutePosition; 3108/* Vector3 llmoveforce = pos - AbsolutePosition;
2359 Vector3 grabforce = llmoveforce; 3109 Vector3 grabforce = llmoveforce;
2360 grabforce = (grabforce / 10) * pa.Mass; 3110 grabforce = (grabforce / 10) * pa.Mass;
2361 pa.AddForce(grabforce, true); 3111 */
3112 // empirically convert distance diference to a impulse
3113 Vector3 grabforce = pos - AbsolutePosition;
3114 grabforce = grabforce * (pa.Mass/ 10.0f);
3115 pa.AddForce(grabforce, false);
2362 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3116 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2363 } 3117 }
2364 } 3118 }
@@ -2584,8 +3338,22 @@ namespace OpenSim.Region.Framework.Scenes
2584 } 3338 }
2585 } 3339 }
2586 3340
2587 for (int i = 0; i < parts.Length; i++) 3341 if (parts.Length > 1)
2588 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3342 {
3343 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3344
3345 for (int i = 0; i < parts.Length; i++)
3346 {
3347
3348 if (parts[i].UUID != m_rootPart.UUID)
3349 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3350 }
3351
3352 if (m_rootPart.PhysActor != null)
3353 m_rootPart.PhysActor.Building = false;
3354 }
3355 else
3356 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2589 } 3357 }
2590 } 3358 }
2591 3359
@@ -2598,6 +3366,17 @@ namespace OpenSim.Region.Framework.Scenes
2598 } 3366 }
2599 } 3367 }
2600 3368
3369
3370
3371 /// <summary>
3372 /// Gets the number of parts
3373 /// </summary>
3374 /// <returns></returns>
3375 public int GetPartCount()
3376 {
3377 return Parts.Count();
3378 }
3379
2601 /// <summary> 3380 /// <summary>
2602 /// Update the texture entry for this part 3381 /// Update the texture entry for this part
2603 /// </summary> 3382 /// </summary>
@@ -2659,11 +3438,6 @@ namespace OpenSim.Region.Framework.Scenes
2659 /// <param name="scale"></param> 3438 /// <param name="scale"></param>
2660 public void GroupResize(Vector3 scale) 3439 public void GroupResize(Vector3 scale)
2661 { 3440 {
2662// m_log.DebugFormat(
2663// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2664
2665 RootPart.StoreUndoState(true);
2666
2667 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3441 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2668 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3442 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2669 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3443 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2690,7 +3464,6 @@ namespace OpenSim.Region.Framework.Scenes
2690 SceneObjectPart obPart = parts[i]; 3464 SceneObjectPart obPart = parts[i];
2691 if (obPart.UUID != m_rootPart.UUID) 3465 if (obPart.UUID != m_rootPart.UUID)
2692 { 3466 {
2693// obPart.IgnoreUndoUpdate = true;
2694 Vector3 oldSize = new Vector3(obPart.Scale); 3467 Vector3 oldSize = new Vector3(obPart.Scale);
2695 3468
2696 float f = 1.0f; 3469 float f = 1.0f;
@@ -2754,8 +3527,6 @@ namespace OpenSim.Region.Framework.Scenes
2754 z *= a; 3527 z *= a;
2755 } 3528 }
2756 } 3529 }
2757
2758// obPart.IgnoreUndoUpdate = false;
2759 } 3530 }
2760 } 3531 }
2761 } 3532 }
@@ -2765,9 +3536,7 @@ namespace OpenSim.Region.Framework.Scenes
2765 prevScale.Y *= y; 3536 prevScale.Y *= y;
2766 prevScale.Z *= z; 3537 prevScale.Z *= z;
2767 3538
2768// RootPart.IgnoreUndoUpdate = true;
2769 RootPart.Resize(prevScale); 3539 RootPart.Resize(prevScale);
2770// RootPart.IgnoreUndoUpdate = false;
2771 3540
2772 parts = m_parts.GetArray(); 3541 parts = m_parts.GetArray();
2773 for (int i = 0; i < parts.Length; i++) 3542 for (int i = 0; i < parts.Length; i++)
@@ -2776,8 +3545,6 @@ namespace OpenSim.Region.Framework.Scenes
2776 3545
2777 if (obPart.UUID != m_rootPart.UUID) 3546 if (obPart.UUID != m_rootPart.UUID)
2778 { 3547 {
2779 obPart.IgnoreUndoUpdate = true;
2780
2781 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3548 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2782 currentpos.X *= x; 3549 currentpos.X *= x;
2783 currentpos.Y *= y; 3550 currentpos.Y *= y;
@@ -2790,16 +3557,12 @@ namespace OpenSim.Region.Framework.Scenes
2790 3557
2791 obPart.Resize(newSize); 3558 obPart.Resize(newSize);
2792 obPart.UpdateOffSet(currentpos); 3559 obPart.UpdateOffSet(currentpos);
2793
2794 obPart.IgnoreUndoUpdate = false;
2795 } 3560 }
2796 3561
2797// obPart.IgnoreUndoUpdate = false; 3562 HasGroupChanged = true;
2798// obPart.StoreUndoState(); 3563 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3564 ScheduleGroupForTerseUpdate();
2799 } 3565 }
2800
2801// m_log.DebugFormat(
2802// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2803 } 3566 }
2804 3567
2805 #endregion 3568 #endregion
@@ -2812,14 +3575,6 @@ namespace OpenSim.Region.Framework.Scenes
2812 /// <param name="pos"></param> 3575 /// <param name="pos"></param>
2813 public void UpdateGroupPosition(Vector3 pos) 3576 public void UpdateGroupPosition(Vector3 pos)
2814 { 3577 {
2815// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2816
2817 RootPart.StoreUndoState(true);
2818
2819// SceneObjectPart[] parts = m_parts.GetArray();
2820// for (int i = 0; i < parts.Length; i++)
2821// parts[i].StoreUndoState();
2822
2823 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3578 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2824 { 3579 {
2825 if (IsAttachment) 3580 if (IsAttachment)
@@ -2852,21 +3607,17 @@ namespace OpenSim.Region.Framework.Scenes
2852 /// </summary> 3607 /// </summary>
2853 /// <param name="pos"></param> 3608 /// <param name="pos"></param>
2854 /// <param name="localID"></param> 3609 /// <param name="localID"></param>
3610 ///
3611
2855 public void UpdateSinglePosition(Vector3 pos, uint localID) 3612 public void UpdateSinglePosition(Vector3 pos, uint localID)
2856 { 3613 {
2857 SceneObjectPart part = GetPart(localID); 3614 SceneObjectPart part = GetPart(localID);
2858 3615
2859// SceneObjectPart[] parts = m_parts.GetArray();
2860// for (int i = 0; i < parts.Length; i++)
2861// parts[i].StoreUndoState();
2862
2863 if (part != null) 3616 if (part != null)
2864 { 3617 {
2865// m_log.DebugFormat( 3618// unlock parts position change
2866// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3619 if (m_rootPart.PhysActor != null)
2867 3620 m_rootPart.PhysActor.Building = true;
2868 part.StoreUndoState(false);
2869 part.IgnoreUndoUpdate = true;
2870 3621
2871 if (part.UUID == m_rootPart.UUID) 3622 if (part.UUID == m_rootPart.UUID)
2872 { 3623 {
@@ -2877,8 +3628,10 @@ namespace OpenSim.Region.Framework.Scenes
2877 part.UpdateOffSet(pos); 3628 part.UpdateOffSet(pos);
2878 } 3629 }
2879 3630
3631 if (m_rootPart.PhysActor != null)
3632 m_rootPart.PhysActor.Building = false;
3633
2880 HasGroupChanged = true; 3634 HasGroupChanged = true;
2881 part.IgnoreUndoUpdate = false;
2882 } 3635 }
2883 } 3636 }
2884 3637
@@ -2888,13 +3641,7 @@ namespace OpenSim.Region.Framework.Scenes
2888 /// <param name="pos"></param> 3641 /// <param name="pos"></param>
2889 public void UpdateRootPosition(Vector3 pos) 3642 public void UpdateRootPosition(Vector3 pos)
2890 { 3643 {
2891// m_log.DebugFormat( 3644 // needs to be called with phys building true
2892// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2893
2894// SceneObjectPart[] parts = m_parts.GetArray();
2895// for (int i = 0; i < parts.Length; i++)
2896// parts[i].StoreUndoState();
2897
2898 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3645 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2899 Vector3 oldPos = 3646 Vector3 oldPos =
2900 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3647 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2917,7 +3664,14 @@ namespace OpenSim.Region.Framework.Scenes
2917 AbsolutePosition = newPos; 3664 AbsolutePosition = newPos;
2918 3665
2919 HasGroupChanged = true; 3666 HasGroupChanged = true;
2920 ScheduleGroupForTerseUpdate(); 3667 if (m_rootPart.Undoing)
3668 {
3669 ScheduleGroupForFullUpdate();
3670 }
3671 else
3672 {
3673 ScheduleGroupForTerseUpdate();
3674 }
2921 } 3675 }
2922 3676
2923 #endregion 3677 #endregion
@@ -2930,24 +3684,16 @@ namespace OpenSim.Region.Framework.Scenes
2930 /// <param name="rot"></param> 3684 /// <param name="rot"></param>
2931 public void UpdateGroupRotationR(Quaternion rot) 3685 public void UpdateGroupRotationR(Quaternion rot)
2932 { 3686 {
2933// m_log.DebugFormat(
2934// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2935
2936// SceneObjectPart[] parts = m_parts.GetArray();
2937// for (int i = 0; i < parts.Length; i++)
2938// parts[i].StoreUndoState();
2939
2940 m_rootPart.StoreUndoState(true);
2941
2942 m_rootPart.UpdateRotation(rot); 3687 m_rootPart.UpdateRotation(rot);
2943 3688
3689/* this is done by rootpart RotationOffset set called by UpdateRotation
2944 PhysicsActor actor = m_rootPart.PhysActor; 3690 PhysicsActor actor = m_rootPart.PhysActor;
2945 if (actor != null) 3691 if (actor != null)
2946 { 3692 {
2947 actor.Orientation = m_rootPart.RotationOffset; 3693 actor.Orientation = m_rootPart.RotationOffset;
2948 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3694 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2949 } 3695 }
2950 3696*/
2951 HasGroupChanged = true; 3697 HasGroupChanged = true;
2952 ScheduleGroupForTerseUpdate(); 3698 ScheduleGroupForTerseUpdate();
2953 } 3699 }
@@ -2959,16 +3705,6 @@ namespace OpenSim.Region.Framework.Scenes
2959 /// <param name="rot"></param> 3705 /// <param name="rot"></param>
2960 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3706 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2961 { 3707 {
2962// m_log.DebugFormat(
2963// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2964
2965// SceneObjectPart[] parts = m_parts.GetArray();
2966// for (int i = 0; i < parts.Length; i++)
2967// parts[i].StoreUndoState();
2968
2969 RootPart.StoreUndoState(true);
2970 RootPart.IgnoreUndoUpdate = true;
2971
2972 m_rootPart.UpdateRotation(rot); 3708 m_rootPart.UpdateRotation(rot);
2973 3709
2974 PhysicsActor actor = m_rootPart.PhysActor; 3710 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2987,8 +3723,6 @@ namespace OpenSim.Region.Framework.Scenes
2987 3723
2988 HasGroupChanged = true; 3724 HasGroupChanged = true;
2989 ScheduleGroupForTerseUpdate(); 3725 ScheduleGroupForTerseUpdate();
2990
2991 RootPart.IgnoreUndoUpdate = false;
2992 } 3726 }
2993 3727
2994 /// <summary> 3728 /// <summary>
@@ -3001,13 +3735,11 @@ namespace OpenSim.Region.Framework.Scenes
3001 SceneObjectPart part = GetPart(localID); 3735 SceneObjectPart part = GetPart(localID);
3002 3736
3003 SceneObjectPart[] parts = m_parts.GetArray(); 3737 SceneObjectPart[] parts = m_parts.GetArray();
3004 for (int i = 0; i < parts.Length; i++)
3005 parts[i].StoreUndoState();
3006 3738
3007 if (part != null) 3739 if (part != null)
3008 { 3740 {
3009// m_log.DebugFormat( 3741 if (m_rootPart.PhysActor != null)
3010// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3742 m_rootPart.PhysActor.Building = true;
3011 3743
3012 if (part.UUID == m_rootPart.UUID) 3744 if (part.UUID == m_rootPart.UUID)
3013 { 3745 {
@@ -3017,6 +3749,9 @@ namespace OpenSim.Region.Framework.Scenes
3017 { 3749 {
3018 part.UpdateRotation(rot); 3750 part.UpdateRotation(rot);
3019 } 3751 }
3752
3753 if (m_rootPart.PhysActor != null)
3754 m_rootPart.PhysActor.Building = false;
3020 } 3755 }
3021 } 3756 }
3022 3757
@@ -3030,12 +3765,8 @@ namespace OpenSim.Region.Framework.Scenes
3030 SceneObjectPart part = GetPart(localID); 3765 SceneObjectPart part = GetPart(localID);
3031 if (part != null) 3766 if (part != null)
3032 { 3767 {
3033// m_log.DebugFormat( 3768 if (m_rootPart.PhysActor != null)
3034// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3769 m_rootPart.PhysActor.Building = true;
3035// part.Name, part.LocalId, rot);
3036
3037 part.StoreUndoState();
3038 part.IgnoreUndoUpdate = true;
3039 3770
3040 if (part.UUID == m_rootPart.UUID) 3771 if (part.UUID == m_rootPart.UUID)
3041 { 3772 {
@@ -3048,7 +3779,8 @@ namespace OpenSim.Region.Framework.Scenes
3048 part.OffsetPosition = pos; 3779 part.OffsetPosition = pos;
3049 } 3780 }
3050 3781
3051 part.IgnoreUndoUpdate = false; 3782 if (m_rootPart.PhysActor != null)
3783 m_rootPart.PhysActor.Building = false;
3052 } 3784 }
3053 } 3785 }
3054 3786
@@ -3058,15 +3790,12 @@ namespace OpenSim.Region.Framework.Scenes
3058 /// <param name="rot"></param> 3790 /// <param name="rot"></param>
3059 public void UpdateRootRotation(Quaternion rot) 3791 public void UpdateRootRotation(Quaternion rot)
3060 { 3792 {
3061// m_log.DebugFormat( 3793 // needs to be called with phys building true
3062// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3063// Name, LocalId, rot);
3064
3065 Quaternion axRot = rot; 3794 Quaternion axRot = rot;
3066 Quaternion oldParentRot = m_rootPart.RotationOffset; 3795 Quaternion oldParentRot = m_rootPart.RotationOffset;
3067 3796
3068 m_rootPart.StoreUndoState(); 3797 //Don't use UpdateRotation because it schedules an update prematurely
3069 m_rootPart.UpdateRotation(rot); 3798 m_rootPart.RotationOffset = rot;
3070 3799
3071 PhysicsActor pa = m_rootPart.PhysActor; 3800 PhysicsActor pa = m_rootPart.PhysActor;
3072 3801
@@ -3082,35 +3811,145 @@ namespace OpenSim.Region.Framework.Scenes
3082 SceneObjectPart prim = parts[i]; 3811 SceneObjectPart prim = parts[i];
3083 if (prim.UUID != m_rootPart.UUID) 3812 if (prim.UUID != m_rootPart.UUID)
3084 { 3813 {
3085 prim.IgnoreUndoUpdate = true; 3814 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3815 NewRot = Quaternion.Inverse(axRot) * NewRot;
3816 prim.RotationOffset = NewRot;
3817
3086 Vector3 axPos = prim.OffsetPosition; 3818 Vector3 axPos = prim.OffsetPosition;
3819
3087 axPos *= oldParentRot; 3820 axPos *= oldParentRot;
3088 axPos *= Quaternion.Inverse(axRot); 3821 axPos *= Quaternion.Inverse(axRot);
3089 prim.OffsetPosition = axPos; 3822 prim.OffsetPosition = axPos;
3090 Quaternion primsRot = prim.RotationOffset; 3823 }
3091 Quaternion newRot = oldParentRot * primsRot; 3824 }
3092 newRot = Quaternion.Inverse(axRot) * newRot;
3093 prim.RotationOffset = newRot;
3094 prim.ScheduleTerseUpdate();
3095 prim.IgnoreUndoUpdate = false;
3096 }
3097 }
3098
3099// for (int i = 0; i < parts.Length; i++)
3100// {
3101// SceneObjectPart childpart = parts[i];
3102// if (childpart != m_rootPart)
3103// {
3104//// childpart.IgnoreUndoUpdate = false;
3105//// childpart.StoreUndoState();
3106// }
3107// }
3108 3825
3109 m_rootPart.ScheduleTerseUpdate(); 3826 HasGroupChanged = true;
3827 ScheduleGroupForFullUpdate();
3828 }
3110 3829
3111// m_log.DebugFormat( 3830 private enum updatetype :int
3112// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3831 {
3113// Name, LocalId, rot); 3832 none = 0,
3833 partterse = 1,
3834 partfull = 2,
3835 groupterse = 3,
3836 groupfull = 4
3837 }
3838
3839 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3840 {
3841 // TODO this still as excessive *.Schedule*Update()s
3842
3843 if (part != null && part.ParentGroup != null)
3844 {
3845 ObjectChangeType change = data.change;
3846 bool togroup = ((change & ObjectChangeType.Group) != 0);
3847 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3848
3849 SceneObjectGroup group = part.ParentGroup;
3850 PhysicsActor pha = group.RootPart.PhysActor;
3851
3852 updatetype updateType = updatetype.none;
3853
3854 if (togroup)
3855 {
3856 // related to group
3857 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3858 {
3859 if ((change & ObjectChangeType.Rotation) != 0)
3860 {
3861 group.RootPart.UpdateRotation(data.rotation);
3862 updateType = updatetype.none;
3863 }
3864 if ((change & ObjectChangeType.Position) != 0)
3865 {
3866 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3867 UpdateGroupPosition(data.position);
3868 updateType = updatetype.groupterse;
3869 }
3870 else
3871 // ugly rotation update of all parts
3872 {
3873 group.ResetChildPrimPhysicsPositions();
3874 }
3875
3876 }
3877 if ((change & ObjectChangeType.Scale) != 0)
3878 {
3879 if (pha != null)
3880 pha.Building = true;
3881
3882 group.GroupResize(data.scale);
3883 updateType = updatetype.none;
3884
3885 if (pha != null)
3886 pha.Building = false;
3887 }
3888 }
3889 else
3890 {
3891 // related to single prim in a link-set ( ie group)
3892 if (pha != null)
3893 pha.Building = true;
3894
3895 // root part is special
3896 // parts offset positions or rotations need to change also
3897
3898 if (part == group.RootPart)
3899 {
3900 if ((change & ObjectChangeType.Rotation) != 0)
3901 group.UpdateRootRotation(data.rotation);
3902 if ((change & ObjectChangeType.Position) != 0)
3903 group.UpdateRootPosition(data.position);
3904 if ((change & ObjectChangeType.Scale) != 0)
3905 part.Resize(data.scale);
3906 }
3907 else
3908 {
3909 if ((change & ObjectChangeType.Position) != 0)
3910 {
3911 part.OffsetPosition = data.position;
3912 updateType = updatetype.partterse;
3913 }
3914 if ((change & ObjectChangeType.Rotation) != 0)
3915 {
3916 part.UpdateRotation(data.rotation);
3917 updateType = updatetype.none;
3918 }
3919 if ((change & ObjectChangeType.Scale) != 0)
3920 {
3921 part.Resize(data.scale);
3922 updateType = updatetype.none;
3923 }
3924 }
3925
3926 if (pha != null)
3927 pha.Building = false;
3928 }
3929
3930 if (updateType != updatetype.none)
3931 {
3932 group.HasGroupChanged = true;
3933
3934 switch (updateType)
3935 {
3936 case updatetype.partterse:
3937 part.ScheduleTerseUpdate();
3938 break;
3939 case updatetype.partfull:
3940 part.ScheduleFullUpdate();
3941 break;
3942 case updatetype.groupterse:
3943 group.ScheduleGroupForTerseUpdate();
3944 break;
3945 case updatetype.groupfull:
3946 group.ScheduleGroupForFullUpdate();
3947 break;
3948 default:
3949 break;
3950 }
3951 }
3952 }
3114 } 3953 }
3115 3954
3116 #endregion 3955 #endregion
@@ -3209,10 +4048,11 @@ namespace OpenSim.Region.Framework.Scenes
3209 scriptPosTarget target = m_targets[idx]; 4048 scriptPosTarget target = m_targets[idx];
3210 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4049 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3211 { 4050 {
4051 at_target = true;
4052
3212 // trigger at_target 4053 // trigger at_target
3213 if (m_scriptListens_atTarget) 4054 if (m_scriptListens_atTarget)
3214 { 4055 {
3215 at_target = true;
3216 scriptPosTarget att = new scriptPosTarget(); 4056 scriptPosTarget att = new scriptPosTarget();
3217 att.targetPos = target.targetPos; 4057 att.targetPos = target.targetPos;
3218 att.tolerance = target.tolerance; 4058 att.tolerance = target.tolerance;
@@ -3330,11 +4170,50 @@ namespace OpenSim.Region.Framework.Scenes
3330 } 4170 }
3331 } 4171 }
3332 } 4172 }
3333 4173
4174 public Vector3 GetGeometricCenter()
4175 {
4176 // this is not real geometric center but a average of positions relative to root prim acording to
4177 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4178 // ignoring tortured prims details since sl also seems to ignore
4179 // so no real use in doing it on physics
4180
4181 Vector3 gc = Vector3.Zero;
4182
4183 int nparts = m_parts.Count;
4184 if (nparts <= 1)
4185 return gc;
4186
4187 SceneObjectPart[] parts = m_parts.GetArray();
4188 nparts = parts.Length; // just in case it changed
4189 if (nparts <= 1)
4190 return gc;
4191
4192 Quaternion parentRot = RootPart.RotationOffset;
4193 Vector3 pPos;
4194
4195 // average all parts positions
4196 for (int i = 0; i < nparts; i++)
4197 {
4198 // do it directly
4199 // gc += parts[i].GetWorldPosition();
4200 if (parts[i] != RootPart)
4201 {
4202 pPos = parts[i].OffsetPosition;
4203 gc += pPos;
4204 }
4205
4206 }
4207 gc /= nparts;
4208
4209 // relative to root:
4210// gc -= AbsolutePosition;
4211 return gc;
4212 }
4213
3334 public float GetMass() 4214 public float GetMass()
3335 { 4215 {
3336 float retmass = 0f; 4216 float retmass = 0f;
3337
3338 SceneObjectPart[] parts = m_parts.GetArray(); 4217 SceneObjectPart[] parts = m_parts.GetArray();
3339 for (int i = 0; i < parts.Length; i++) 4218 for (int i = 0; i < parts.Length; i++)
3340 retmass += parts[i].GetMass(); 4219 retmass += parts[i].GetMass();
@@ -3342,6 +4221,39 @@ namespace OpenSim.Region.Framework.Scenes
3342 return retmass; 4221 return retmass;
3343 } 4222 }
3344 4223
4224 // center of mass of full object
4225 public Vector3 GetCenterOfMass()
4226 {
4227 PhysicsActor pa = RootPart.PhysActor;
4228
4229 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4230 {
4231 // physics knows better about center of mass of physical prims
4232 Vector3 tmp = pa.CenterOfMass;
4233 return tmp;
4234 }
4235
4236 Vector3 Ptot = Vector3.Zero;
4237 float totmass = 0f;
4238 float m;
4239
4240 SceneObjectPart[] parts = m_parts.GetArray();
4241 for (int i = 0; i < parts.Length; i++)
4242 {
4243 m = parts[i].GetMass();
4244 Ptot += parts[i].GetPartCenterOfMass() * m;
4245 totmass += m;
4246 }
4247
4248 if (totmass == 0)
4249 totmass = 0;
4250 else
4251 totmass = 1 / totmass;
4252 Ptot *= totmass;
4253
4254 return Ptot;
4255 }
4256
3345 /// <summary> 4257 /// <summary>
3346 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4258 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3347 /// the physics engine can use it. 4259 /// the physics engine can use it.
@@ -3509,6 +4421,14 @@ namespace OpenSim.Region.Framework.Scenes
3509 FromItemID = uuid; 4421 FromItemID = uuid;
3510 } 4422 }
3511 4423
4424 public void ResetOwnerChangeFlag()
4425 {
4426 ForEachPart(delegate(SceneObjectPart part)
4427 {
4428 part.ResetOwnerChangeFlag();
4429 });
4430 }
4431
3512 #endregion 4432 #endregion
3513 } 4433 }
3514} 4434}