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.cs1361
1 files changed, 1143 insertions, 218 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 52469a2..08c7a58 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.LoginsEnabled || // 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;
@@ -1390,6 +2061,15 @@ namespace OpenSim.Region.Framework.Scenes
1390 HasGroupChangedDueToDelink = false; 2061 HasGroupChangedDueToDelink = false;
1391 2062
1392 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2063 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2064 backup_group.ForEachPart(delegate(SceneObjectPart part)
2065 {
2066 if (part.KeyframeMotion != null)
2067 {
2068 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2069 part.KeyframeMotion.UpdateSceneObject(this);
2070 }
2071 });
2072
1393 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2073 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1394 2074
1395 backup_group.ForEachPart(delegate(SceneObjectPart part) 2075 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1446,10 +2126,14 @@ namespace OpenSim.Region.Framework.Scenes
1446 /// <returns></returns> 2126 /// <returns></returns>
1447 public SceneObjectGroup Copy(bool userExposed) 2127 public SceneObjectGroup Copy(bool userExposed)
1448 { 2128 {
2129 m_dupeInProgress = true;
1449 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2130 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1450 dupe.m_isBackedUp = false; 2131 dupe.m_isBackedUp = false;
1451 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2132 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1452 2133
2134 // new group as no sitting avatars
2135 dupe.m_linkedAvatars = new List<ScenePresence>();
2136
1453 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2137 // 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! 2138 // 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! 2139 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1460,7 +2144,7 @@ namespace OpenSim.Region.Framework.Scenes
1460 // This is only necessary when userExposed is false! 2144 // This is only necessary when userExposed is false!
1461 2145
1462 bool previousAttachmentStatus = dupe.IsAttachment; 2146 bool previousAttachmentStatus = dupe.IsAttachment;
1463 2147
1464 if (!userExposed) 2148 if (!userExposed)
1465 dupe.IsAttachment = true; 2149 dupe.IsAttachment = true;
1466 2150
@@ -1478,11 +2162,11 @@ namespace OpenSim.Region.Framework.Scenes
1478 dupe.m_rootPart.TrimPermissions(); 2162 dupe.m_rootPart.TrimPermissions();
1479 2163
1480 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2164 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1481 2165
1482 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2166 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1483 { 2167 {
1484 return p1.LinkNum.CompareTo(p2.LinkNum); 2168 return p1.LinkNum.CompareTo(p2.LinkNum);
1485 } 2169 }
1486 ); 2170 );
1487 2171
1488 foreach (SceneObjectPart part in partList) 2172 foreach (SceneObjectPart part in partList)
@@ -1492,41 +2176,53 @@ namespace OpenSim.Region.Framework.Scenes
1492 { 2176 {
1493 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2177 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1494 newPart.LinkNum = part.LinkNum; 2178 newPart.LinkNum = part.LinkNum;
1495 } 2179 if (userExposed)
2180 newPart.ParentID = dupe.m_rootPart.LocalId;
2181 }
1496 else 2182 else
1497 { 2183 {
1498 newPart = dupe.m_rootPart; 2184 newPart = dupe.m_rootPart;
1499 } 2185 }
2186/*
2187 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2188 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1500 2189
1501 // Need to duplicate the physics actor as well 2190 // Need to duplicate the physics actor as well
1502 PhysicsActor originalPartPa = part.PhysActor; 2191 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1503 if (originalPartPa != null && userExposed)
1504 { 2192 {
1505 PrimitiveBaseShape pbs = newPart.Shape; 2193 PrimitiveBaseShape pbs = newPart.Shape;
1506
1507 newPart.PhysActor 2194 newPart.PhysActor
1508 = m_scene.PhysicsScene.AddPrimShape( 2195 = m_scene.PhysicsScene.AddPrimShape(
1509 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2196 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1510 pbs, 2197 pbs,
1511 newPart.AbsolutePosition, 2198 newPart.AbsolutePosition,
1512 newPart.Scale, 2199 newPart.Scale,
1513 newPart.RotationOffset, 2200 newPart.GetWorldRotation(),
1514 originalPartPa.IsPhysical, 2201 isphys,
2202 isphan,
1515 newPart.LocalId); 2203 newPart.LocalId);
1516 2204
1517 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2205 newPart.DoPhysicsPropertyUpdate(isphys, true);
1518 } 2206 */
2207 if (userExposed)
2208 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2209// }
1519 } 2210 }
1520 2211
1521 if (userExposed) 2212 if (userExposed)
1522 { 2213 {
1523 dupe.UpdateParentIDs(); 2214// done above dupe.UpdateParentIDs();
2215
2216 if (dupe.m_rootPart.PhysActor != null)
2217 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2218
1524 dupe.HasGroupChanged = true; 2219 dupe.HasGroupChanged = true;
1525 dupe.AttachToBackup(); 2220 dupe.AttachToBackup();
1526 2221
1527 ScheduleGroupForFullUpdate(); 2222 ScheduleGroupForFullUpdate();
1528 } 2223 }
1529 2224
2225 m_dupeInProgress = false;
1530 return dupe; 2226 return dupe;
1531 } 2227 }
1532 2228
@@ -1538,11 +2234,24 @@ namespace OpenSim.Region.Framework.Scenes
1538 /// <param name="cGroupID"></param> 2234 /// <param name="cGroupID"></param>
1539 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2235 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1540 { 2236 {
1541 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2237 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2238 // give newpart a new local ID lettng old part keep same
2239 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2240 newpart.LocalId = m_scene.AllocateLocalId();
2241
2242 SetRootPart(newpart);
2243 if (userExposed)
2244 RootPart.Velocity = Vector3.Zero; // In case source is moving
1542 } 2245 }
1543 2246
1544 public void ScriptSetPhysicsStatus(bool usePhysics) 2247 public void ScriptSetPhysicsStatus(bool usePhysics)
1545 { 2248 {
2249 if (usePhysics)
2250 {
2251 if (RootPart.KeyframeMotion != null)
2252 RootPart.KeyframeMotion.Stop();
2253 RootPart.KeyframeMotion = null;
2254 }
1546 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2255 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1547 } 2256 }
1548 2257
@@ -1590,13 +2299,14 @@ namespace OpenSim.Region.Framework.Scenes
1590 2299
1591 if (pa != null) 2300 if (pa != null)
1592 { 2301 {
1593 pa.AddForce(impulse, true); 2302 // false to be applied as a impulse
2303 pa.AddForce(impulse, false);
1594 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2304 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1595 } 2305 }
1596 } 2306 }
1597 } 2307 }
1598 2308
1599 public void applyAngularImpulse(Vector3 impulse) 2309 public void ApplyAngularImpulse(Vector3 impulse)
1600 { 2310 {
1601 PhysicsActor pa = RootPart.PhysActor; 2311 PhysicsActor pa = RootPart.PhysActor;
1602 2312
@@ -1604,21 +2314,8 @@ namespace OpenSim.Region.Framework.Scenes
1604 { 2314 {
1605 if (!IsAttachment) 2315 if (!IsAttachment)
1606 { 2316 {
1607 pa.AddAngularForce(impulse, true); 2317 // false to be applied as a impulse
1608 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2318 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); 2319 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1623 } 2320 }
1624 } 2321 }
@@ -1626,20 +2323,10 @@ namespace OpenSim.Region.Framework.Scenes
1626 2323
1627 public Vector3 GetTorque() 2324 public Vector3 GetTorque()
1628 { 2325 {
1629 PhysicsActor pa = RootPart.PhysActor; 2326 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 } 2327 }
1642 2328
2329 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1643 public void moveToTarget(Vector3 target, float tau) 2330 public void moveToTarget(Vector3 target, float tau)
1644 { 2331 {
1645 if (IsAttachment) 2332 if (IsAttachment)
@@ -1671,6 +2358,46 @@ namespace OpenSim.Region.Framework.Scenes
1671 pa.PIDActive = false; 2358 pa.PIDActive = false;
1672 } 2359 }
1673 2360
2361 public void rotLookAt(Quaternion target, float strength, float damping)
2362 {
2363 SceneObjectPart rootpart = m_rootPart;
2364 if (rootpart != null)
2365 {
2366 if (IsAttachment)
2367 {
2368 /*
2369 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2370 if (avatar != null)
2371 {
2372 Rotate the Av?
2373 } */
2374 }
2375 else
2376 {
2377 if (rootpart.PhysActor != null)
2378 { // APID must be implemented in your physics system for this to function.
2379 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2380 rootpart.PhysActor.APIDStrength = strength;
2381 rootpart.PhysActor.APIDDamping = damping;
2382 rootpart.PhysActor.APIDActive = true;
2383 }
2384 }
2385 }
2386 }
2387
2388 public void stopLookAt()
2389 {
2390 SceneObjectPart rootpart = m_rootPart;
2391 if (rootpart != null)
2392 {
2393 if (rootpart.PhysActor != null)
2394 { // APID must be implemented in your physics system for this to function.
2395 rootpart.PhysActor.APIDActive = false;
2396 }
2397 }
2398
2399 }
2400
1674 /// <summary> 2401 /// <summary>
1675 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2402 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1676 /// </summary> 2403 /// </summary>
@@ -1687,7 +2414,7 @@ namespace OpenSim.Region.Framework.Scenes
1687 { 2414 {
1688 pa.PIDHoverHeight = height; 2415 pa.PIDHoverHeight = height;
1689 pa.PIDHoverType = hoverType; 2416 pa.PIDHoverType = hoverType;
1690 pa.PIDTau = tau; 2417 pa.PIDHoverTau = tau;
1691 pa.PIDHoverActive = true; 2418 pa.PIDHoverActive = true;
1692 } 2419 }
1693 else 2420 else
@@ -1727,7 +2454,12 @@ namespace OpenSim.Region.Framework.Scenes
1727 /// <param name="cGroupID"></param> 2454 /// <param name="cGroupID"></param>
1728 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2455 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1729 { 2456 {
1730 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2457 // give new ID to the new part, letting old keep original
2458 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2459 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2460 newPart.LocalId = m_scene.AllocateLocalId();
2461 newPart.SetParent(this);
2462
1731 AddPart(newPart); 2463 AddPart(newPart);
1732 2464
1733 SetPartAsNonRoot(newPart); 2465 SetPartAsNonRoot(newPart);
@@ -1866,11 +2598,11 @@ namespace OpenSim.Region.Framework.Scenes
1866 /// Immediately send a full update for this scene object. 2598 /// Immediately send a full update for this scene object.
1867 /// </summary> 2599 /// </summary>
1868 public void SendGroupFullUpdate() 2600 public void SendGroupFullUpdate()
1869 { 2601 {
1870 if (IsDeleted) 2602 if (IsDeleted)
1871 return; 2603 return;
1872 2604
1873// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2605// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1874 2606
1875 RootPart.SendFullUpdateToAllClients(); 2607 RootPart.SendFullUpdateToAllClients();
1876 2608
@@ -2007,6 +2739,11 @@ namespace OpenSim.Region.Framework.Scenes
2007 // 'linkPart' == the root of the group being linked into this group 2739 // 'linkPart' == the root of the group being linked into this group
2008 SceneObjectPart linkPart = objectGroup.m_rootPart; 2740 SceneObjectPart linkPart = objectGroup.m_rootPart;
2009 2741
2742 if (m_rootPart.PhysActor != null)
2743 m_rootPart.PhysActor.Building = true;
2744 if (linkPart.PhysActor != null)
2745 linkPart.PhysActor.Building = true;
2746
2010 // physics flags from group to be applied to linked parts 2747 // physics flags from group to be applied to linked parts
2011 bool grpusephys = UsesPhysics; 2748 bool grpusephys = UsesPhysics;
2012 bool grptemporary = IsTemporary; 2749 bool grptemporary = IsTemporary;
@@ -2032,12 +2769,12 @@ namespace OpenSim.Region.Framework.Scenes
2032 Vector3 axPos = linkPart.OffsetPosition; 2769 Vector3 axPos = linkPart.OffsetPosition;
2033 // Rotate the linking root SOP's position to be relative to the new root prim 2770 // Rotate the linking root SOP's position to be relative to the new root prim
2034 Quaternion parentRot = m_rootPart.RotationOffset; 2771 Quaternion parentRot = m_rootPart.RotationOffset;
2035 axPos *= Quaternion.Inverse(parentRot); 2772 axPos *= Quaternion.Conjugate(parentRot);
2036 linkPart.OffsetPosition = axPos; 2773 linkPart.OffsetPosition = axPos;
2037 2774
2038 // Make the linking root SOP's rotation relative to the new root prim 2775 // Make the linking root SOP's rotation relative to the new root prim
2039 Quaternion oldRot = linkPart.RotationOffset; 2776 Quaternion oldRot = linkPart.RotationOffset;
2040 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2777 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2041 linkPart.RotationOffset = newRot; 2778 linkPart.RotationOffset = newRot;
2042 2779
2043 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2780 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2071,7 +2808,7 @@ namespace OpenSim.Region.Framework.Scenes
2071 linkPart.CreateSelected = true; 2808 linkPart.CreateSelected = true;
2072 2809
2073 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2810 // 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); 2811 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2075 2812
2076 // If the added SOP is physical, also tell the physics engine about the link relationship. 2813 // 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) 2814 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2081,6 +2818,7 @@ namespace OpenSim.Region.Framework.Scenes
2081 } 2818 }
2082 2819
2083 linkPart.LinkNum = linkNum++; 2820 linkPart.LinkNum = linkNum++;
2821 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2084 2822
2085 // Get a list of the SOP's in the old group in order of their linknum's. 2823 // Get a list of the SOP's in the old group in order of their linknum's.
2086 SceneObjectPart[] ogParts = objectGroup.Parts; 2824 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2099,7 +2837,7 @@ namespace OpenSim.Region.Framework.Scenes
2099 2837
2100 // Update the physics flags for the newly added SOP 2838 // Update the physics flags for the newly added SOP
2101 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2839 // (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); 2840 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2103 2841
2104 // If the added SOP is physical, also tell the physics engine about the link relationship. 2842 // 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) 2843 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2117,7 +2855,7 @@ namespace OpenSim.Region.Framework.Scenes
2117 objectGroup.IsDeleted = true; 2855 objectGroup.IsDeleted = true;
2118 2856
2119 objectGroup.m_parts.Clear(); 2857 objectGroup.m_parts.Clear();
2120 2858
2121 // Can't do this yet since backup still makes use of the root part without any synchronization 2859 // Can't do this yet since backup still makes use of the root part without any synchronization
2122// objectGroup.m_rootPart = null; 2860// objectGroup.m_rootPart = null;
2123 2861
@@ -2128,6 +2866,9 @@ namespace OpenSim.Region.Framework.Scenes
2128 // unmoved prims! 2866 // unmoved prims!
2129 ResetChildPrimPhysicsPositions(); 2867 ResetChildPrimPhysicsPositions();
2130 2868
2869 if (m_rootPart.PhysActor != null)
2870 m_rootPart.PhysActor.Building = false;
2871
2131 //HasGroupChanged = true; 2872 //HasGroupChanged = true;
2132 //ScheduleGroupForFullUpdate(); 2873 //ScheduleGroupForFullUpdate();
2133 } 2874 }
@@ -2195,7 +2936,10 @@ namespace OpenSim.Region.Framework.Scenes
2195// m_log.DebugFormat( 2936// m_log.DebugFormat(
2196// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2937// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2197// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2938// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2198 2939
2940 if (m_rootPart.PhysActor != null)
2941 m_rootPart.PhysActor.Building = true;
2942
2199 linkPart.ClearUndoState(); 2943 linkPart.ClearUndoState();
2200 2944
2201 Vector3 worldPos = linkPart.GetWorldPosition(); 2945 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2266,6 +3010,14 @@ namespace OpenSim.Region.Framework.Scenes
2266 3010
2267 // When we delete a group, we currently have to force persist to the database if the object id has changed 3011 // 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) 3012 // (since delete works by deleting all rows which have a given object id)
3013
3014 // this is as it seems to be in sl now
3015 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3016 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3017
3018 if (m_rootPart.PhysActor != null)
3019 m_rootPart.PhysActor.Building = false;
3020
2269 objectGroup.HasGroupChangedDueToDelink = true; 3021 objectGroup.HasGroupChangedDueToDelink = true;
2270 3022
2271 return objectGroup; 3023 return objectGroup;
@@ -2277,6 +3029,7 @@ namespace OpenSim.Region.Framework.Scenes
2277 /// <param name="objectGroup"></param> 3029 /// <param name="objectGroup"></param>
2278 public virtual void DetachFromBackup() 3030 public virtual void DetachFromBackup()
2279 { 3031 {
3032 m_scene.SceneGraph.FireDetachFromBackup(this);
2280 if (m_isBackedUp && Scene != null) 3033 if (m_isBackedUp && Scene != null)
2281 m_scene.EventManager.OnBackup -= ProcessBackup; 3034 m_scene.EventManager.OnBackup -= ProcessBackup;
2282 3035
@@ -2297,7 +3050,8 @@ namespace OpenSim.Region.Framework.Scenes
2297 Vector3 axPos = part.OffsetPosition; 3050 Vector3 axPos = part.OffsetPosition;
2298 axPos *= parentRot; 3051 axPos *= parentRot;
2299 part.OffsetPosition = axPos; 3052 part.OffsetPosition = axPos;
2300 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3053 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3054 part.GroupPosition = newPos;
2301 part.OffsetPosition = Vector3.Zero; 3055 part.OffsetPosition = Vector3.Zero;
2302 3056
2303 // Compution our rotation to be not relative to the old parent 3057 // Compution our rotation to be not relative to the old parent
@@ -2312,7 +3066,7 @@ namespace OpenSim.Region.Framework.Scenes
2312 part.LinkNum = linkNum; 3066 part.LinkNum = linkNum;
2313 3067
2314 // Compute the new position of this SOP relative to the group position 3068 // Compute the new position of this SOP relative to the group position
2315 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3069 part.OffsetPosition = newPos - AbsolutePosition;
2316 3070
2317 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3071 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2318 // It would have the affect of setting the physics engine position multiple 3072 // It would have the affect of setting the physics engine position multiple
@@ -2322,18 +3076,19 @@ namespace OpenSim.Region.Framework.Scenes
2322 // Rotate the relative position by the rotation of the group 3076 // Rotate the relative position by the rotation of the group
2323 Quaternion rootRotation = m_rootPart.RotationOffset; 3077 Quaternion rootRotation = m_rootPart.RotationOffset;
2324 Vector3 pos = part.OffsetPosition; 3078 Vector3 pos = part.OffsetPosition;
2325 pos *= Quaternion.Inverse(rootRotation); 3079 pos *= Quaternion.Conjugate(rootRotation);
2326 part.OffsetPosition = pos; 3080 part.OffsetPosition = pos;
2327 3081
2328 // Compute the SOP's rotation relative to the rotation of the group. 3082 // Compute the SOP's rotation relative to the rotation of the group.
2329 parentRot = m_rootPart.RotationOffset; 3083 parentRot = m_rootPart.RotationOffset;
2330 oldRot = part.RotationOffset; 3084 oldRot = part.RotationOffset;
2331 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3085 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2332 part.RotationOffset = newRot; 3086 part.RotationOffset = newRot;
2333 3087
2334 // Since this SOP's state has changed, push those changes into the physics engine 3088 // Since this SOP's state has changed, push those changes into the physics engine
2335 // and the simulator. 3089 // and the simulator.
2336 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3090 // done on caller
3091// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2337 } 3092 }
2338 3093
2339 /// <summary> 3094 /// <summary>
@@ -2355,10 +3110,14 @@ namespace OpenSim.Region.Framework.Scenes
2355 { 3110 {
2356 if (!m_rootPart.BlockGrab) 3111 if (!m_rootPart.BlockGrab)
2357 { 3112 {
2358 Vector3 llmoveforce = pos - AbsolutePosition; 3113/* Vector3 llmoveforce = pos - AbsolutePosition;
2359 Vector3 grabforce = llmoveforce; 3114 Vector3 grabforce = llmoveforce;
2360 grabforce = (grabforce / 10) * pa.Mass; 3115 grabforce = (grabforce / 10) * pa.Mass;
2361 pa.AddForce(grabforce, true); 3116 */
3117 // empirically convert distance diference to a impulse
3118 Vector3 grabforce = pos - AbsolutePosition;
3119 grabforce = grabforce * (pa.Mass/ 10.0f);
3120 pa.AddForce(grabforce, false);
2362 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3121 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2363 } 3122 }
2364 } 3123 }
@@ -2584,8 +3343,22 @@ namespace OpenSim.Region.Framework.Scenes
2584 } 3343 }
2585 } 3344 }
2586 3345
2587 for (int i = 0; i < parts.Length; i++) 3346 if (parts.Length > 1)
2588 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3347 {
3348 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3349
3350 for (int i = 0; i < parts.Length; i++)
3351 {
3352
3353 if (parts[i].UUID != m_rootPart.UUID)
3354 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3355 }
3356
3357 if (m_rootPart.PhysActor != null)
3358 m_rootPart.PhysActor.Building = false;
3359 }
3360 else
3361 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2589 } 3362 }
2590 } 3363 }
2591 3364
@@ -2598,6 +3371,17 @@ namespace OpenSim.Region.Framework.Scenes
2598 } 3371 }
2599 } 3372 }
2600 3373
3374
3375
3376 /// <summary>
3377 /// Gets the number of parts
3378 /// </summary>
3379 /// <returns></returns>
3380 public int GetPartCount()
3381 {
3382 return Parts.Count();
3383 }
3384
2601 /// <summary> 3385 /// <summary>
2602 /// Update the texture entry for this part 3386 /// Update the texture entry for this part
2603 /// </summary> 3387 /// </summary>
@@ -2659,11 +3443,6 @@ namespace OpenSim.Region.Framework.Scenes
2659 /// <param name="scale"></param> 3443 /// <param name="scale"></param>
2660 public void GroupResize(Vector3 scale) 3444 public void GroupResize(Vector3 scale)
2661 { 3445 {
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); 3446 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2668 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3447 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2669 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3448 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2690,7 +3469,6 @@ namespace OpenSim.Region.Framework.Scenes
2690 SceneObjectPart obPart = parts[i]; 3469 SceneObjectPart obPart = parts[i];
2691 if (obPart.UUID != m_rootPart.UUID) 3470 if (obPart.UUID != m_rootPart.UUID)
2692 { 3471 {
2693// obPart.IgnoreUndoUpdate = true;
2694 Vector3 oldSize = new Vector3(obPart.Scale); 3472 Vector3 oldSize = new Vector3(obPart.Scale);
2695 3473
2696 float f = 1.0f; 3474 float f = 1.0f;
@@ -2754,8 +3532,6 @@ namespace OpenSim.Region.Framework.Scenes
2754 z *= a; 3532 z *= a;
2755 } 3533 }
2756 } 3534 }
2757
2758// obPart.IgnoreUndoUpdate = false;
2759 } 3535 }
2760 } 3536 }
2761 } 3537 }
@@ -2765,9 +3541,7 @@ namespace OpenSim.Region.Framework.Scenes
2765 prevScale.Y *= y; 3541 prevScale.Y *= y;
2766 prevScale.Z *= z; 3542 prevScale.Z *= z;
2767 3543
2768// RootPart.IgnoreUndoUpdate = true;
2769 RootPart.Resize(prevScale); 3544 RootPart.Resize(prevScale);
2770// RootPart.IgnoreUndoUpdate = false;
2771 3545
2772 parts = m_parts.GetArray(); 3546 parts = m_parts.GetArray();
2773 for (int i = 0; i < parts.Length; i++) 3547 for (int i = 0; i < parts.Length; i++)
@@ -2776,8 +3550,6 @@ namespace OpenSim.Region.Framework.Scenes
2776 3550
2777 if (obPart.UUID != m_rootPart.UUID) 3551 if (obPart.UUID != m_rootPart.UUID)
2778 { 3552 {
2779 obPart.IgnoreUndoUpdate = true;
2780
2781 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3553 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2782 currentpos.X *= x; 3554 currentpos.X *= x;
2783 currentpos.Y *= y; 3555 currentpos.Y *= y;
@@ -2790,16 +3562,12 @@ namespace OpenSim.Region.Framework.Scenes
2790 3562
2791 obPart.Resize(newSize); 3563 obPart.Resize(newSize);
2792 obPart.UpdateOffSet(currentpos); 3564 obPart.UpdateOffSet(currentpos);
2793
2794 obPart.IgnoreUndoUpdate = false;
2795 } 3565 }
2796 3566
2797// obPart.IgnoreUndoUpdate = false; 3567 HasGroupChanged = true;
2798// obPart.StoreUndoState(); 3568 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3569 ScheduleGroupForTerseUpdate();
2799 } 3570 }
2800
2801// m_log.DebugFormat(
2802// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2803 } 3571 }
2804 3572
2805 #endregion 3573 #endregion
@@ -2812,14 +3580,6 @@ namespace OpenSim.Region.Framework.Scenes
2812 /// <param name="pos"></param> 3580 /// <param name="pos"></param>
2813 public void UpdateGroupPosition(Vector3 pos) 3581 public void UpdateGroupPosition(Vector3 pos)
2814 { 3582 {
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)) 3583 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2824 { 3584 {
2825 if (IsAttachment) 3585 if (IsAttachment)
@@ -2852,21 +3612,17 @@ namespace OpenSim.Region.Framework.Scenes
2852 /// </summary> 3612 /// </summary>
2853 /// <param name="pos"></param> 3613 /// <param name="pos"></param>
2854 /// <param name="localID"></param> 3614 /// <param name="localID"></param>
3615 ///
3616
2855 public void UpdateSinglePosition(Vector3 pos, uint localID) 3617 public void UpdateSinglePosition(Vector3 pos, uint localID)
2856 { 3618 {
2857 SceneObjectPart part = GetPart(localID); 3619 SceneObjectPart part = GetPart(localID);
2858 3620
2859// SceneObjectPart[] parts = m_parts.GetArray();
2860// for (int i = 0; i < parts.Length; i++)
2861// parts[i].StoreUndoState();
2862
2863 if (part != null) 3621 if (part != null)
2864 { 3622 {
2865// m_log.DebugFormat( 3623// unlock parts position change
2866// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3624 if (m_rootPart.PhysActor != null)
2867 3625 m_rootPart.PhysActor.Building = true;
2868 part.StoreUndoState(false);
2869 part.IgnoreUndoUpdate = true;
2870 3626
2871 if (part.UUID == m_rootPart.UUID) 3627 if (part.UUID == m_rootPart.UUID)
2872 { 3628 {
@@ -2877,8 +3633,10 @@ namespace OpenSim.Region.Framework.Scenes
2877 part.UpdateOffSet(pos); 3633 part.UpdateOffSet(pos);
2878 } 3634 }
2879 3635
3636 if (m_rootPart.PhysActor != null)
3637 m_rootPart.PhysActor.Building = false;
3638
2880 HasGroupChanged = true; 3639 HasGroupChanged = true;
2881 part.IgnoreUndoUpdate = false;
2882 } 3640 }
2883 } 3641 }
2884 3642
@@ -2888,13 +3646,7 @@ namespace OpenSim.Region.Framework.Scenes
2888 /// <param name="pos"></param> 3646 /// <param name="pos"></param>
2889 public void UpdateRootPosition(Vector3 pos) 3647 public void UpdateRootPosition(Vector3 pos)
2890 { 3648 {
2891// m_log.DebugFormat( 3649 // 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); 3650 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2899 Vector3 oldPos = 3651 Vector3 oldPos =
2900 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3652 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2917,7 +3669,14 @@ namespace OpenSim.Region.Framework.Scenes
2917 AbsolutePosition = newPos; 3669 AbsolutePosition = newPos;
2918 3670
2919 HasGroupChanged = true; 3671 HasGroupChanged = true;
2920 ScheduleGroupForTerseUpdate(); 3672 if (m_rootPart.Undoing)
3673 {
3674 ScheduleGroupForFullUpdate();
3675 }
3676 else
3677 {
3678 ScheduleGroupForTerseUpdate();
3679 }
2921 } 3680 }
2922 3681
2923 #endregion 3682 #endregion
@@ -2930,24 +3689,16 @@ namespace OpenSim.Region.Framework.Scenes
2930 /// <param name="rot"></param> 3689 /// <param name="rot"></param>
2931 public void UpdateGroupRotationR(Quaternion rot) 3690 public void UpdateGroupRotationR(Quaternion rot)
2932 { 3691 {
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); 3692 m_rootPart.UpdateRotation(rot);
2943 3693
3694/* this is done by rootpart RotationOffset set called by UpdateRotation
2944 PhysicsActor actor = m_rootPart.PhysActor; 3695 PhysicsActor actor = m_rootPart.PhysActor;
2945 if (actor != null) 3696 if (actor != null)
2946 { 3697 {
2947 actor.Orientation = m_rootPart.RotationOffset; 3698 actor.Orientation = m_rootPart.RotationOffset;
2948 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3699 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2949 } 3700 }
2950 3701*/
2951 HasGroupChanged = true; 3702 HasGroupChanged = true;
2952 ScheduleGroupForTerseUpdate(); 3703 ScheduleGroupForTerseUpdate();
2953 } 3704 }
@@ -2959,16 +3710,6 @@ namespace OpenSim.Region.Framework.Scenes
2959 /// <param name="rot"></param> 3710 /// <param name="rot"></param>
2960 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3711 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2961 { 3712 {
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); 3713 m_rootPart.UpdateRotation(rot);
2973 3714
2974 PhysicsActor actor = m_rootPart.PhysActor; 3715 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2987,8 +3728,6 @@ namespace OpenSim.Region.Framework.Scenes
2987 3728
2988 HasGroupChanged = true; 3729 HasGroupChanged = true;
2989 ScheduleGroupForTerseUpdate(); 3730 ScheduleGroupForTerseUpdate();
2990
2991 RootPart.IgnoreUndoUpdate = false;
2992 } 3731 }
2993 3732
2994 /// <summary> 3733 /// <summary>
@@ -3001,13 +3740,11 @@ namespace OpenSim.Region.Framework.Scenes
3001 SceneObjectPart part = GetPart(localID); 3740 SceneObjectPart part = GetPart(localID);
3002 3741
3003 SceneObjectPart[] parts = m_parts.GetArray(); 3742 SceneObjectPart[] parts = m_parts.GetArray();
3004 for (int i = 0; i < parts.Length; i++)
3005 parts[i].StoreUndoState();
3006 3743
3007 if (part != null) 3744 if (part != null)
3008 { 3745 {
3009// m_log.DebugFormat( 3746 if (m_rootPart.PhysActor != null)
3010// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3747 m_rootPart.PhysActor.Building = true;
3011 3748
3012 if (part.UUID == m_rootPart.UUID) 3749 if (part.UUID == m_rootPart.UUID)
3013 { 3750 {
@@ -3017,6 +3754,9 @@ namespace OpenSim.Region.Framework.Scenes
3017 { 3754 {
3018 part.UpdateRotation(rot); 3755 part.UpdateRotation(rot);
3019 } 3756 }
3757
3758 if (m_rootPart.PhysActor != null)
3759 m_rootPart.PhysActor.Building = false;
3020 } 3760 }
3021 } 3761 }
3022 3762
@@ -3030,12 +3770,8 @@ namespace OpenSim.Region.Framework.Scenes
3030 SceneObjectPart part = GetPart(localID); 3770 SceneObjectPart part = GetPart(localID);
3031 if (part != null) 3771 if (part != null)
3032 { 3772 {
3033// m_log.DebugFormat( 3773 if (m_rootPart.PhysActor != null)
3034// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3774 m_rootPart.PhysActor.Building = true;
3035// part.Name, part.LocalId, rot);
3036
3037 part.StoreUndoState();
3038 part.IgnoreUndoUpdate = true;
3039 3775
3040 if (part.UUID == m_rootPart.UUID) 3776 if (part.UUID == m_rootPart.UUID)
3041 { 3777 {
@@ -3048,7 +3784,8 @@ namespace OpenSim.Region.Framework.Scenes
3048 part.OffsetPosition = pos; 3784 part.OffsetPosition = pos;
3049 } 3785 }
3050 3786
3051 part.IgnoreUndoUpdate = false; 3787 if (m_rootPart.PhysActor != null)
3788 m_rootPart.PhysActor.Building = false;
3052 } 3789 }
3053 } 3790 }
3054 3791
@@ -3058,15 +3795,12 @@ namespace OpenSim.Region.Framework.Scenes
3058 /// <param name="rot"></param> 3795 /// <param name="rot"></param>
3059 public void UpdateRootRotation(Quaternion rot) 3796 public void UpdateRootRotation(Quaternion rot)
3060 { 3797 {
3061// m_log.DebugFormat( 3798 // 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; 3799 Quaternion axRot = rot;
3066 Quaternion oldParentRot = m_rootPart.RotationOffset; 3800 Quaternion oldParentRot = m_rootPart.RotationOffset;
3067 3801
3068 m_rootPart.StoreUndoState(); 3802 //Don't use UpdateRotation because it schedules an update prematurely
3069 m_rootPart.UpdateRotation(rot); 3803 m_rootPart.RotationOffset = rot;
3070 3804
3071 PhysicsActor pa = m_rootPart.PhysActor; 3805 PhysicsActor pa = m_rootPart.PhysActor;
3072 3806
@@ -3082,35 +3816,145 @@ namespace OpenSim.Region.Framework.Scenes
3082 SceneObjectPart prim = parts[i]; 3816 SceneObjectPart prim = parts[i];
3083 if (prim.UUID != m_rootPart.UUID) 3817 if (prim.UUID != m_rootPart.UUID)
3084 { 3818 {
3085 prim.IgnoreUndoUpdate = true; 3819 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3820 NewRot = Quaternion.Inverse(axRot) * NewRot;
3821 prim.RotationOffset = NewRot;
3822
3086 Vector3 axPos = prim.OffsetPosition; 3823 Vector3 axPos = prim.OffsetPosition;
3824
3087 axPos *= oldParentRot; 3825 axPos *= oldParentRot;
3088 axPos *= Quaternion.Inverse(axRot); 3826 axPos *= Quaternion.Inverse(axRot);
3089 prim.OffsetPosition = axPos; 3827 prim.OffsetPosition = axPos;
3090 Quaternion primsRot = prim.RotationOffset; 3828 }
3091 Quaternion newRot = oldParentRot * primsRot; 3829 }
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 3830
3109 m_rootPart.ScheduleTerseUpdate(); 3831 HasGroupChanged = true;
3832 ScheduleGroupForFullUpdate();
3833 }
3110 3834
3111// m_log.DebugFormat( 3835 private enum updatetype :int
3112// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3836 {
3113// Name, LocalId, rot); 3837 none = 0,
3838 partterse = 1,
3839 partfull = 2,
3840 groupterse = 3,
3841 groupfull = 4
3842 }
3843
3844 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3845 {
3846 // TODO this still as excessive *.Schedule*Update()s
3847
3848 if (part != null && part.ParentGroup != null)
3849 {
3850 ObjectChangeType change = data.change;
3851 bool togroup = ((change & ObjectChangeType.Group) != 0);
3852 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3853
3854 SceneObjectGroup group = part.ParentGroup;
3855 PhysicsActor pha = group.RootPart.PhysActor;
3856
3857 updatetype updateType = updatetype.none;
3858
3859 if (togroup)
3860 {
3861 // related to group
3862 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3863 {
3864 if ((change & ObjectChangeType.Rotation) != 0)
3865 {
3866 group.RootPart.UpdateRotation(data.rotation);
3867 updateType = updatetype.none;
3868 }
3869 if ((change & ObjectChangeType.Position) != 0)
3870 {
3871 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3872 UpdateGroupPosition(data.position);
3873 updateType = updatetype.groupterse;
3874 }
3875 else
3876 // ugly rotation update of all parts
3877 {
3878 group.ResetChildPrimPhysicsPositions();
3879 }
3880
3881 }
3882 if ((change & ObjectChangeType.Scale) != 0)
3883 {
3884 if (pha != null)
3885 pha.Building = true;
3886
3887 group.GroupResize(data.scale);
3888 updateType = updatetype.none;
3889
3890 if (pha != null)
3891 pha.Building = false;
3892 }
3893 }
3894 else
3895 {
3896 // related to single prim in a link-set ( ie group)
3897 if (pha != null)
3898 pha.Building = true;
3899
3900 // root part is special
3901 // parts offset positions or rotations need to change also
3902
3903 if (part == group.RootPart)
3904 {
3905 if ((change & ObjectChangeType.Rotation) != 0)
3906 group.UpdateRootRotation(data.rotation);
3907 if ((change & ObjectChangeType.Position) != 0)
3908 group.UpdateRootPosition(data.position);
3909 if ((change & ObjectChangeType.Scale) != 0)
3910 part.Resize(data.scale);
3911 }
3912 else
3913 {
3914 if ((change & ObjectChangeType.Position) != 0)
3915 {
3916 part.OffsetPosition = data.position;
3917 updateType = updatetype.partterse;
3918 }
3919 if ((change & ObjectChangeType.Rotation) != 0)
3920 {
3921 part.UpdateRotation(data.rotation);
3922 updateType = updatetype.none;
3923 }
3924 if ((change & ObjectChangeType.Scale) != 0)
3925 {
3926 part.Resize(data.scale);
3927 updateType = updatetype.none;
3928 }
3929 }
3930
3931 if (pha != null)
3932 pha.Building = false;
3933 }
3934
3935 if (updateType != updatetype.none)
3936 {
3937 group.HasGroupChanged = true;
3938
3939 switch (updateType)
3940 {
3941 case updatetype.partterse:
3942 part.ScheduleTerseUpdate();
3943 break;
3944 case updatetype.partfull:
3945 part.ScheduleFullUpdate();
3946 break;
3947 case updatetype.groupterse:
3948 group.ScheduleGroupForTerseUpdate();
3949 break;
3950 case updatetype.groupfull:
3951 group.ScheduleGroupForFullUpdate();
3952 break;
3953 default:
3954 break;
3955 }
3956 }
3957 }
3114 } 3958 }
3115 3959
3116 #endregion 3960 #endregion
@@ -3209,10 +4053,11 @@ namespace OpenSim.Region.Framework.Scenes
3209 scriptPosTarget target = m_targets[idx]; 4053 scriptPosTarget target = m_targets[idx];
3210 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4054 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3211 { 4055 {
4056 at_target = true;
4057
3212 // trigger at_target 4058 // trigger at_target
3213 if (m_scriptListens_atTarget) 4059 if (m_scriptListens_atTarget)
3214 { 4060 {
3215 at_target = true;
3216 scriptPosTarget att = new scriptPosTarget(); 4061 scriptPosTarget att = new scriptPosTarget();
3217 att.targetPos = target.targetPos; 4062 att.targetPos = target.targetPos;
3218 att.tolerance = target.tolerance; 4063 att.tolerance = target.tolerance;
@@ -3330,11 +4175,50 @@ namespace OpenSim.Region.Framework.Scenes
3330 } 4175 }
3331 } 4176 }
3332 } 4177 }
3333 4178
4179 public Vector3 GetGeometricCenter()
4180 {
4181 // this is not real geometric center but a average of positions relative to root prim acording to
4182 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4183 // ignoring tortured prims details since sl also seems to ignore
4184 // so no real use in doing it on physics
4185
4186 Vector3 gc = Vector3.Zero;
4187
4188 int nparts = m_parts.Count;
4189 if (nparts <= 1)
4190 return gc;
4191
4192 SceneObjectPart[] parts = m_parts.GetArray();
4193 nparts = parts.Length; // just in case it changed
4194 if (nparts <= 1)
4195 return gc;
4196
4197 Quaternion parentRot = RootPart.RotationOffset;
4198 Vector3 pPos;
4199
4200 // average all parts positions
4201 for (int i = 0; i < nparts; i++)
4202 {
4203 // do it directly
4204 // gc += parts[i].GetWorldPosition();
4205 if (parts[i] != RootPart)
4206 {
4207 pPos = parts[i].OffsetPosition;
4208 gc += pPos;
4209 }
4210
4211 }
4212 gc /= nparts;
4213
4214 // relative to root:
4215// gc -= AbsolutePosition;
4216 return gc;
4217 }
4218
3334 public float GetMass() 4219 public float GetMass()
3335 { 4220 {
3336 float retmass = 0f; 4221 float retmass = 0f;
3337
3338 SceneObjectPart[] parts = m_parts.GetArray(); 4222 SceneObjectPart[] parts = m_parts.GetArray();
3339 for (int i = 0; i < parts.Length; i++) 4223 for (int i = 0; i < parts.Length; i++)
3340 retmass += parts[i].GetMass(); 4224 retmass += parts[i].GetMass();
@@ -3342,6 +4226,39 @@ namespace OpenSim.Region.Framework.Scenes
3342 return retmass; 4226 return retmass;
3343 } 4227 }
3344 4228
4229 // center of mass of full object
4230 public Vector3 GetCenterOfMass()
4231 {
4232 PhysicsActor pa = RootPart.PhysActor;
4233
4234 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4235 {
4236 // physics knows better about center of mass of physical prims
4237 Vector3 tmp = pa.CenterOfMass;
4238 return tmp;
4239 }
4240
4241 Vector3 Ptot = Vector3.Zero;
4242 float totmass = 0f;
4243 float m;
4244
4245 SceneObjectPart[] parts = m_parts.GetArray();
4246 for (int i = 0; i < parts.Length; i++)
4247 {
4248 m = parts[i].GetMass();
4249 Ptot += parts[i].GetPartCenterOfMass() * m;
4250 totmass += m;
4251 }
4252
4253 if (totmass == 0)
4254 totmass = 0;
4255 else
4256 totmass = 1 / totmass;
4257 Ptot *= totmass;
4258
4259 return Ptot;
4260 }
4261
3345 /// <summary> 4262 /// <summary>
3346 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4263 /// 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. 4264 /// the physics engine can use it.
@@ -3509,6 +4426,14 @@ namespace OpenSim.Region.Framework.Scenes
3509 FromItemID = uuid; 4426 FromItemID = uuid;
3510 } 4427 }
3511 4428
4429 public void ResetOwnerChangeFlag()
4430 {
4431 ForEachPart(delegate(SceneObjectPart part)
4432 {
4433 part.ResetOwnerChangeFlag();
4434 });
4435 }
4436
3512 #endregion 4437 #endregion
3513 } 4438 }
3514} 4439}