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.cs1395
1 files changed, 1181 insertions, 214 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 15795e5..7490ac8 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,12 +24,13 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.ComponentModel; 29using System.ComponentModel;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing; 31using System.Drawing;
32using System.IO; 32using System.IO;
33using System.Diagnostics;
33using System.Linq; 34using System.Linq;
34using System.Threading; 35using System.Threading;
35using System.Xml; 36using System.Xml;
@@ -43,6 +44,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
43 44
44namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
45{ 46{
47
46 [Flags] 48 [Flags]
47 public enum scriptEvents 49 public enum scriptEvents
48 { 50 {
@@ -115,8 +117,12 @@ namespace OpenSim.Region.Framework.Scenes
115 /// since the group's last persistent backup 117 /// since the group's last persistent backup
116 /// </summary> 118 /// </summary>
117 private bool m_hasGroupChanged = false; 119 private bool m_hasGroupChanged = false;
118 private long timeFirstChanged; 120 private long timeFirstChanged = 0;
119 private long timeLastChanged; 121 private long timeLastChanged = 0;
122 private long m_maxPersistTime = 0;
123 private long m_minPersistTime = 0;
124// private Random m_rand;
125 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
120 126
121 /// <summary> 127 /// <summary>
122 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 128 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -133,9 +139,44 @@ namespace OpenSim.Region.Framework.Scenes
133 { 139 {
134 if (value) 140 if (value)
135 { 141 {
142
143 if (m_isBackedUp)
144 {
145 m_scene.SceneGraph.FireChangeBackup(this);
146 }
136 timeLastChanged = DateTime.Now.Ticks; 147 timeLastChanged = DateTime.Now.Ticks;
137 if (!m_hasGroupChanged) 148 if (!m_hasGroupChanged)
138 timeFirstChanged = DateTime.Now.Ticks; 149 timeFirstChanged = DateTime.Now.Ticks;
150 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
151 {
152/*
153 if (m_rand == null)
154 {
155 byte[] val = new byte[16];
156 m_rootPart.UUID.ToBytes(val, 0);
157 m_rand = new Random(BitConverter.ToInt32(val, 0));
158 }
159 */
160 if (m_scene.GetRootAgentCount() == 0)
161 {
162 //If the region is empty, this change has been made by an automated process
163 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
164
165// float factor = 1.5f + (float)(m_rand.NextDouble());
166 float factor = 2.0f;
167 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
168 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
169 }
170 else
171 {
172 //If the region is not empty, we want to obey the minimum and maximum persist times
173 //but add a random factor so we stagger the object persistance a little
174// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
175// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
176 m_maxPersistTime = m_scene.m_persistAfter;
177 m_minPersistTime = m_scene.m_dontPersistBefore;
178 }
179 }
139 } 180 }
140 m_hasGroupChanged = value; 181 m_hasGroupChanged = value;
141 182
@@ -150,7 +191,7 @@ namespace OpenSim.Region.Framework.Scenes
150 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 191 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
151 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 192 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
152 /// </summary> 193 /// </summary>
153 public bool HasGroupChangedDueToDelink { get; private set; } 194 public bool HasGroupChangedDueToDelink { get; set; }
154 195
155 private bool isTimeToPersist() 196 private bool isTimeToPersist()
156 { 197 {
@@ -160,8 +201,19 @@ namespace OpenSim.Region.Framework.Scenes
160 return false; 201 return false;
161 if (m_scene.ShuttingDown) 202 if (m_scene.ShuttingDown)
162 return true; 203 return true;
204
205 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
206 {
207 m_maxPersistTime = m_scene.m_persistAfter;
208 m_minPersistTime = m_scene.m_dontPersistBefore;
209 }
210
163 long currentTime = DateTime.Now.Ticks; 211 long currentTime = DateTime.Now.Ticks;
164 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 212
213 if (timeLastChanged == 0) timeLastChanged = currentTime;
214 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
215
216 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
165 return true; 217 return true;
166 return false; 218 return false;
167 } 219 }
@@ -269,6 +321,11 @@ namespace OpenSim.Region.Framework.Scenes
269 321
270 private bool m_isBackedUp; 322 private bool m_isBackedUp;
271 323
324 public bool IsBackedUp
325 {
326 get { return m_isBackedUp; }
327 }
328
272 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 329 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
273 330
274 protected ulong m_regionHandle; 331 protected ulong m_regionHandle;
@@ -280,10 +337,10 @@ namespace OpenSim.Region.Framework.Scenes
280 337
281 private bool m_scriptListens_atTarget; 338 private bool m_scriptListens_atTarget;
282 private bool m_scriptListens_notAtTarget; 339 private bool m_scriptListens_notAtTarget;
283
284 private bool m_scriptListens_atRotTarget; 340 private bool m_scriptListens_atRotTarget;
285 private bool m_scriptListens_notAtRotTarget; 341 private bool m_scriptListens_notAtRotTarget;
286 342
343 public bool m_dupeInProgress = false;
287 internal Dictionary<UUID, string> m_savedScriptState; 344 internal Dictionary<UUID, string> m_savedScriptState;
288 345
289 #region Properties 346 #region Properties
@@ -320,6 +377,16 @@ namespace OpenSim.Region.Framework.Scenes
320 get { return m_parts.Count; } 377 get { return m_parts.Count; }
321 } 378 }
322 379
380// protected Quaternion m_rotation = Quaternion.Identity;
381//
382// public virtual Quaternion Rotation
383// {
384// get { return m_rotation; }
385// set {
386// m_rotation = value;
387// }
388// }
389
323 public Quaternion GroupRotation 390 public Quaternion GroupRotation
324 { 391 {
325 get { return m_rootPart.RotationOffset; } 392 get { return m_rootPart.RotationOffset; }
@@ -426,7 +493,15 @@ namespace OpenSim.Region.Framework.Scenes
426 { 493 {
427 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 494 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
428 } 495 }
429 496
497
498
499 private struct avtocrossInfo
500 {
501 public ScenePresence av;
502 public uint ParentID;
503 }
504
430 /// <summary> 505 /// <summary>
431 /// The absolute position of this scene object in the scene 506 /// The absolute position of this scene object in the scene
432 /// </summary> 507 /// </summary>
@@ -454,10 +529,129 @@ namespace OpenSim.Region.Framework.Scenes
454 || Scene.TestBorderCross(val, Cardinals.S)) 529 || Scene.TestBorderCross(val, Cardinals.S))
455 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 530 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
456 { 531 {
457 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 532 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
533 uint x = 0;
534 uint y = 0;
535 string version = String.Empty;
536 Vector3 newpos = Vector3.Zero;
537 OpenSim.Services.Interfaces.GridRegion destination = null;
538
539 if (m_rootPart.KeyframeMotion != null)
540 m_rootPart.KeyframeMotion.StartCrossingCheck();
541
542 bool canCross = true;
543 foreach (ScenePresence av in m_linkedAvatars)
544 {
545 // We need to cross these agents. First, let's find
546 // out if any of them can't cross for some reason.
547 // We have to deny the crossing entirely if any
548 // of them are banned. Alternatively, we could
549 // unsit banned agents....
550
551
552 // We set the avatar position as being the object
553 // position to get the region to send to
554 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
555 {
556 canCross = false;
557 break;
558 }
559
560 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
561 }
562
563 if (canCross)
564 {
565 // We unparent the SP quietly so that it won't
566 // be made to stand up
567
568 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
569
570 foreach (ScenePresence av in m_linkedAvatars)
571 {
572 avtocrossInfo avinfo = new avtocrossInfo();
573 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
574 if (parentPart != null)
575 av.ParentUUID = parentPart.UUID;
576
577 avinfo.av = av;
578 avinfo.ParentID = av.ParentID;
579 avsToCross.Add(avinfo);
580
581 av.ParentID = 0;
582 }
583
584 // m_linkedAvatars.Clear();
585 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
586
587 // Normalize
588 if (val.X >= Constants.RegionSize)
589 val.X -= Constants.RegionSize;
590 if (val.Y >= Constants.RegionSize)
591 val.Y -= Constants.RegionSize;
592 if (val.X < 0)
593 val.X += Constants.RegionSize;
594 if (val.Y < 0)
595 val.Y += Constants.RegionSize;
596
597 // If it's deleted, crossing was successful
598 if (IsDeleted)
599 {
600 // foreach (ScenePresence av in m_linkedAvatars)
601 foreach (avtocrossInfo avinfo in avsToCross)
602 {
603 ScenePresence av = avinfo.av;
604 if (!av.IsInTransit) // just in case...
605 {
606 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
607
608 av.IsInTransit = true;
609
610 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
611 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
612 }
613 else
614 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
615 }
616 avsToCross.Clear();
617 return;
618 }
619 else // cross failed, put avas back ??
620 {
621 foreach (avtocrossInfo avinfo in avsToCross)
622 {
623 ScenePresence av = avinfo.av;
624 av.ParentUUID = UUID.Zero;
625 av.ParentID = avinfo.ParentID;
626// m_linkedAvatars.Add(av);
627 }
628 }
629 avsToCross.Clear();
630
631 }
632 else
633 {
634 if (m_rootPart.KeyframeMotion != null)
635 m_rootPart.KeyframeMotion.CrossingFailure();
636
637 if (RootPart.PhysActor != null)
638 {
639 RootPart.PhysActor.CrossingFailure();
640 }
641 }
642 Vector3 oldp = AbsolutePosition;
643 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
644 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
645 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
458 } 646 }
459 } 647 }
460 648
649/* don't see the need but worse don't see where is restored to false if things stay in
650 foreach (SceneObjectPart part in m_parts.GetArray())
651 {
652 part.IgnoreUndoUpdate = true;
653 }
654 */
461 if (RootPart.GetStatusSandbox()) 655 if (RootPart.GetStatusSandbox())
462 { 656 {
463 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 657 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -475,9 +669,38 @@ namespace OpenSim.Region.Framework.Scenes
475 // Restuff the new GroupPosition into each SOP of the linkset. 669 // Restuff the new GroupPosition into each SOP of the linkset.
476 // This has the affect of resetting and tainting the physics actors. 670 // This has the affect of resetting and tainting the physics actors.
477 SceneObjectPart[] parts = m_parts.GetArray(); 671 SceneObjectPart[] parts = m_parts.GetArray();
478 for (int i = 0; i < parts.Length; i++) 672 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
479 parts[i].GroupPosition = val; 673 if (m_dupeInProgress)
674 triggerScriptEvent = false;
675 foreach (SceneObjectPart part in parts)
676 {
677 part.GroupPosition = val;
678 if (triggerScriptEvent)
679 part.TriggerScriptChangedEvent(Changed.POSITION);
680 }
480 681
682/*
683 This seems not needed and should not be needed:
684 sp absolute position depends on sit part absolute position fixed above.
685 sp ParentPosition is not used anywhere.
686 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
687 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
688
689 if (!m_dupeInProgress)
690 {
691 foreach (ScenePresence av in m_linkedAvatars)
692 {
693 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
694 if (p != null && m_parts.TryGetValue(p.UUID, out p))
695 {
696 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
697 av.AbsolutePosition += offset;
698// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
699 av.SendAvatarDataToAllAgents();
700 }
701 }
702 }
703*/
481 //if (m_rootPart.PhysActor != null) 704 //if (m_rootPart.PhysActor != null)
482 //{ 705 //{
483 //m_rootPart.PhysActor.Position = 706 //m_rootPart.PhysActor.Position =
@@ -491,6 +714,40 @@ namespace OpenSim.Region.Framework.Scenes
491 } 714 }
492 } 715 }
493 716
717 public override Vector3 Velocity
718 {
719 get { return RootPart.Velocity; }
720 set { RootPart.Velocity = value; }
721 }
722
723 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
724 {
725 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
726 ScenePresence agent = icon.EndInvoke(iar);
727
728 //// If the cross was successful, this agent is a child agent
729 if (agent.IsChildAgent)
730 {
731 if (agent.ParentUUID != UUID.Zero)
732 {
733 agent.ParentPart = null;
734// agent.ParentPosition = Vector3.Zero;
735// agent.ParentUUID = UUID.Zero;
736 }
737 }
738
739 agent.ParentUUID = UUID.Zero;
740
741// agent.Reset();
742// else // Not successful
743// agent.RestoreInCurrentScene();
744
745 // In any case
746 agent.IsInTransit = false;
747
748 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
749 }
750
494 public override uint LocalId 751 public override uint LocalId
495 { 752 {
496 get { return m_rootPart.LocalId; } 753 get { return m_rootPart.LocalId; }
@@ -561,6 +818,11 @@ namespace OpenSim.Region.Framework.Scenes
561 m_isSelected = value; 818 m_isSelected = value;
562 // Tell physics engine that group is selected 819 // Tell physics engine that group is selected
563 820
821 // this is not right
822 // but ode engines should only really need to know about root part
823 // so they can put entire object simulation on hold and not colliding
824 // keep as was for now
825
564 PhysicsActor pa = m_rootPart.PhysActor; 826 PhysicsActor pa = m_rootPart.PhysActor;
565 if (pa != null) 827 if (pa != null)
566 { 828 {
@@ -577,6 +839,42 @@ namespace OpenSim.Region.Framework.Scenes
577 childPa.Selected = value; 839 childPa.Selected = value;
578 } 840 }
579 } 841 }
842 if (RootPart.KeyframeMotion != null)
843 RootPart.KeyframeMotion.Selected = value;
844 }
845 }
846
847 public void PartSelectChanged(bool partSelect)
848 {
849 // any part selected makes group selected
850 if (m_isSelected == partSelect)
851 return;
852
853 if (partSelect)
854 {
855 IsSelected = partSelect;
856// if (!IsAttachment)
857// ScheduleGroupForFullUpdate();
858 }
859 else
860 {
861 // bad bad bad 2 heavy for large linksets
862 // since viewer does send lot of (un)selects
863 // this needs to be replaced by a specific list or count ?
864 // but that will require extra code in several places
865
866 SceneObjectPart[] parts = m_parts.GetArray();
867 for (int i = 0; i < parts.Length; i++)
868 {
869 SceneObjectPart part = parts[i];
870 if (part.IsSelected)
871 return;
872 }
873 IsSelected = partSelect;
874 if (!IsAttachment)
875 {
876 ScheduleGroupForFullUpdate();
877 }
580 } 878 }
581 } 879 }
582 880
@@ -674,6 +972,7 @@ namespace OpenSim.Region.Framework.Scenes
674 /// </summary> 972 /// </summary>
675 public SceneObjectGroup() 973 public SceneObjectGroup()
676 { 974 {
975
677 } 976 }
678 977
679 /// <summary> 978 /// <summary>
@@ -691,8 +990,8 @@ namespace OpenSim.Region.Framework.Scenes
691 /// Constructor. This object is added to the scene later via AttachToScene() 990 /// Constructor. This object is added to the scene later via AttachToScene()
692 /// </summary> 991 /// </summary>
693 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 992 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
694 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 993 {
695 { 994 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
696 } 995 }
697 996
698 /// <summary> 997 /// <summary>
@@ -727,6 +1026,9 @@ namespace OpenSim.Region.Framework.Scenes
727 /// </summary> 1026 /// </summary>
728 public virtual void AttachToBackup() 1027 public virtual void AttachToBackup()
729 { 1028 {
1029 if (IsAttachment) return;
1030 m_scene.SceneGraph.FireAttachToBackup(this);
1031
730 if (InSceneBackup) 1032 if (InSceneBackup)
731 { 1033 {
732 //m_log.DebugFormat( 1034 //m_log.DebugFormat(
@@ -769,6 +1071,13 @@ namespace OpenSim.Region.Framework.Scenes
769 1071
770 ApplyPhysics(); 1072 ApplyPhysics();
771 1073
1074 if (RootPart.PhysActor != null)
1075 RootPart.Force = RootPart.Force;
1076 if (RootPart.PhysActor != null)
1077 RootPart.Torque = RootPart.Torque;
1078 if (RootPart.PhysActor != null)
1079 RootPart.Buoyancy = RootPart.Buoyancy;
1080
772 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1081 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
773 // for the same object with very different properties. The caller must schedule the update. 1082 // for the same object with very different properties. The caller must schedule the update.
774 //ScheduleGroupForFullUpdate(); 1083 //ScheduleGroupForFullUpdate();
@@ -784,6 +1093,10 @@ namespace OpenSim.Region.Framework.Scenes
784 EntityIntersection result = new EntityIntersection(); 1093 EntityIntersection result = new EntityIntersection();
785 1094
786 SceneObjectPart[] parts = m_parts.GetArray(); 1095 SceneObjectPart[] parts = m_parts.GetArray();
1096
1097 // Find closest hit here
1098 float idist = float.MaxValue;
1099
787 for (int i = 0; i < parts.Length; i++) 1100 for (int i = 0; i < parts.Length; i++)
788 { 1101 {
789 SceneObjectPart part = parts[i]; 1102 SceneObjectPart part = parts[i];
@@ -798,11 +1111,6 @@ namespace OpenSim.Region.Framework.Scenes
798 1111
799 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1112 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
800 1113
801 // This may need to be updated to the maximum draw distance possible..
802 // We might (and probably will) be checking for prim creation from other sims
803 // when the camera crosses the border.
804 float idist = Constants.RegionSize;
805
806 if (inter.HitTF) 1114 if (inter.HitTF)
807 { 1115 {
808 // We need to find the closest prim to return to the testcaller along the ray 1116 // We need to find the closest prim to return to the testcaller along the ray
@@ -813,10 +1121,11 @@ namespace OpenSim.Region.Framework.Scenes
813 result.obj = part; 1121 result.obj = part;
814 result.normal = inter.normal; 1122 result.normal = inter.normal;
815 result.distance = inter.distance; 1123 result.distance = inter.distance;
1124
1125 idist = inter.distance;
816 } 1126 }
817 } 1127 }
818 } 1128 }
819
820 return result; 1129 return result;
821 } 1130 }
822 1131
@@ -828,25 +1137,27 @@ namespace OpenSim.Region.Framework.Scenes
828 /// <returns></returns> 1137 /// <returns></returns>
829 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1138 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
830 { 1139 {
831 maxX = -256f; 1140 maxX = float.MinValue;
832 maxY = -256f; 1141 maxY = float.MinValue;
833 maxZ = -256f; 1142 maxZ = float.MinValue;
834 minX = 256f; 1143 minX = float.MaxValue;
835 minY = 256f; 1144 minY = float.MaxValue;
836 minZ = 8192f; 1145 minZ = float.MaxValue;
837 1146
838 SceneObjectPart[] parts = m_parts.GetArray(); 1147 SceneObjectPart[] parts = m_parts.GetArray();
839 for (int i = 0; i < parts.Length; i++) 1148 foreach (SceneObjectPart part in parts)
840 { 1149 {
841 SceneObjectPart part = parts[i];
842
843 Vector3 worldPos = part.GetWorldPosition(); 1150 Vector3 worldPos = part.GetWorldPosition();
844 Vector3 offset = worldPos - AbsolutePosition; 1151 Vector3 offset = worldPos - AbsolutePosition;
845 Quaternion worldRot; 1152 Quaternion worldRot;
846 if (part.ParentID == 0) 1153 if (part.ParentID == 0)
1154 {
847 worldRot = part.RotationOffset; 1155 worldRot = part.RotationOffset;
1156 }
848 else 1157 else
1158 {
849 worldRot = part.GetWorldRotation(); 1159 worldRot = part.GetWorldRotation();
1160 }
850 1161
851 Vector3 frontTopLeft; 1162 Vector3 frontTopLeft;
852 Vector3 frontTopRight; 1163 Vector3 frontTopRight;
@@ -858,6 +1169,8 @@ namespace OpenSim.Region.Framework.Scenes
858 Vector3 backBottomLeft; 1169 Vector3 backBottomLeft;
859 Vector3 backBottomRight; 1170 Vector3 backBottomRight;
860 1171
1172 // Vector3[] corners = new Vector3[8];
1173
861 Vector3 orig = Vector3.Zero; 1174 Vector3 orig = Vector3.Zero;
862 1175
863 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1176 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -892,6 +1205,38 @@ namespace OpenSim.Region.Framework.Scenes
892 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1205 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
893 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1206 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
894 1207
1208
1209
1210 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1211 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1212 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1213 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1214 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1215 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1216 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1217 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1218
1219 //for (int i = 0; i < 8; i++)
1220 //{
1221 // corners[i] = corners[i] * worldRot;
1222 // corners[i] += offset;
1223
1224 // if (corners[i].X > maxX)
1225 // maxX = corners[i].X;
1226 // if (corners[i].X < minX)
1227 // minX = corners[i].X;
1228
1229 // if (corners[i].Y > maxY)
1230 // maxY = corners[i].Y;
1231 // if (corners[i].Y < minY)
1232 // minY = corners[i].Y;
1233
1234 // if (corners[i].Z > maxZ)
1235 // maxZ = corners[i].Y;
1236 // if (corners[i].Z < minZ)
1237 // minZ = corners[i].Z;
1238 //}
1239
895 frontTopLeft = frontTopLeft * worldRot; 1240 frontTopLeft = frontTopLeft * worldRot;
896 frontTopRight = frontTopRight * worldRot; 1241 frontTopRight = frontTopRight * worldRot;
897 frontBottomLeft = frontBottomLeft * worldRot; 1242 frontBottomLeft = frontBottomLeft * worldRot;
@@ -913,6 +1258,15 @@ namespace OpenSim.Region.Framework.Scenes
913 backTopLeft += offset; 1258 backTopLeft += offset;
914 backTopRight += offset; 1259 backTopRight += offset;
915 1260
1261 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1262 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1263 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1264 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1265 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1266 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1267 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1268 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1269
916 if (frontTopRight.X > maxX) 1270 if (frontTopRight.X > maxX)
917 maxX = frontTopRight.X; 1271 maxX = frontTopRight.X;
918 if (frontTopLeft.X > maxX) 1272 if (frontTopLeft.X > maxX)
@@ -1056,17 +1410,118 @@ namespace OpenSim.Region.Framework.Scenes
1056 1410
1057 #endregion 1411 #endregion
1058 1412
1413 public void GetResourcesCosts(SceneObjectPart apart,
1414 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1415 {
1416 // this information may need to be cached
1417
1418 float cost;
1419 float tmpcost;
1420
1421 bool ComplexCost = false;
1422
1423 SceneObjectPart p;
1424 SceneObjectPart[] parts;
1425
1426 lock (m_parts)
1427 {
1428 parts = m_parts.GetArray();
1429 }
1430
1431 int nparts = parts.Length;
1432
1433
1434 for (int i = 0; i < nparts; i++)
1435 {
1436 p = parts[i];
1437
1438 if (p.UsesComplexCost)
1439 {
1440 ComplexCost = true;
1441 break;
1442 }
1443 }
1444
1445 if (ComplexCost)
1446 {
1447 linksetResCost = 0;
1448 linksetPhysCost = 0;
1449 partCost = 0;
1450 partPhysCost = 0;
1451
1452 for (int i = 0; i < nparts; i++)
1453 {
1454 p = parts[i];
1455
1456 cost = p.StreamingCost;
1457 tmpcost = p.SimulationCost;
1458 if (tmpcost > cost)
1459 cost = tmpcost;
1460 tmpcost = p.PhysicsCost;
1461 if (tmpcost > cost)
1462 cost = tmpcost;
1463
1464 linksetPhysCost += tmpcost;
1465 linksetResCost += cost;
1466
1467 if (p == apart)
1468 {
1469 partCost = cost;
1470 partPhysCost = tmpcost;
1471 }
1472 }
1473 }
1474 else
1475 {
1476 partPhysCost = 1.0f;
1477 partCost = 1.0f;
1478 linksetResCost = (float)nparts;
1479 linksetPhysCost = linksetResCost;
1480 }
1481 }
1482
1483 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1484 {
1485 SceneObjectPart p;
1486 SceneObjectPart[] parts;
1487
1488 lock (m_parts)
1489 {
1490 parts = m_parts.GetArray();
1491 }
1492
1493 int nparts = parts.Length;
1494
1495 PhysCost = 0;
1496 StreamCost = 0;
1497 SimulCost = 0;
1498
1499 for (int i = 0; i < nparts; i++)
1500 {
1501 p = parts[i];
1502
1503 StreamCost += p.StreamingCost;
1504 SimulCost += p.SimulationCost;
1505 PhysCost += p.PhysicsCost;
1506 }
1507 }
1508
1059 public void SaveScriptedState(XmlTextWriter writer) 1509 public void SaveScriptedState(XmlTextWriter writer)
1060 { 1510 {
1511 SaveScriptedState(writer, false);
1512 }
1513
1514 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1515 {
1061 XmlDocument doc = new XmlDocument(); 1516 XmlDocument doc = new XmlDocument();
1062 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1517 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1063 1518
1064 SceneObjectPart[] parts = m_parts.GetArray(); 1519 SceneObjectPart[] parts = m_parts.GetArray();
1065 for (int i = 0; i < parts.Length; i++) 1520 for (int i = 0; i < parts.Length; i++)
1066 { 1521 {
1067 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1522 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1068 foreach (KeyValuePair<UUID, string> kvp in pstates) 1523 foreach (KeyValuePair<UUID, string> kvp in pstates)
1069 states.Add(kvp.Key, kvp.Value); 1524 states[kvp.Key] = kvp.Value;
1070 } 1525 }
1071 1526
1072 if (states.Count > 0) 1527 if (states.Count > 0)
@@ -1086,6 +1541,169 @@ namespace OpenSim.Region.Framework.Scenes
1086 } 1541 }
1087 1542
1088 /// <summary> 1543 /// <summary>
1544 /// Add the avatar to this linkset (avatar is sat).
1545 /// </summary>
1546 /// <param name="agentID"></param>
1547 public void AddAvatar(UUID agentID)
1548 {
1549 ScenePresence presence;
1550 if (m_scene.TryGetScenePresence(agentID, out presence))
1551 {
1552 if (!m_linkedAvatars.Contains(presence))
1553 {
1554 m_linkedAvatars.Add(presence);
1555 }
1556 }
1557 }
1558
1559 /// <summary>
1560 /// Delete the avatar from this linkset (avatar is unsat).
1561 /// </summary>
1562 /// <param name="agentID"></param>
1563 public void DeleteAvatar(UUID agentID)
1564 {
1565 ScenePresence presence;
1566 if (m_scene.TryGetScenePresence(agentID, out presence))
1567 {
1568 if (m_linkedAvatars.Contains(presence))
1569 {
1570 m_linkedAvatars.Remove(presence);
1571 }
1572 }
1573 }
1574
1575 /// <summary>
1576 /// Returns the list of linked presences (avatars sat on this group)
1577 /// </summary>
1578 /// <param name="agentID"></param>
1579 public List<ScenePresence> GetLinkedAvatars()
1580 {
1581 return m_linkedAvatars;
1582 }
1583
1584 /// <summary>
1585 /// Attach this scene object to the given avatar.
1586 /// </summary>
1587 /// <param name="agentID"></param>
1588 /// <param name="attachmentpoint"></param>
1589 /// <param name="AttachOffset"></param>
1590 private void AttachToAgent(
1591 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1592 {
1593 if (avatar != null)
1594 {
1595 // don't attach attachments to child agents
1596 if (avatar.IsChildAgent) return;
1597
1598 // Remove from database and parcel prim count
1599 m_scene.DeleteFromStorage(so.UUID);
1600 m_scene.EventManager.TriggerParcelPrimCountTainted();
1601
1602 so.AttachedAvatar = avatar.UUID;
1603
1604 if (so.RootPart.PhysActor != null)
1605 {
1606 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1607 so.RootPart.PhysActor = null;
1608 }
1609
1610 so.AbsolutePosition = attachOffset;
1611 so.RootPart.AttachedPos = attachOffset;
1612 so.IsAttachment = true;
1613 so.RootPart.SetParentLocalId(avatar.LocalId);
1614 so.AttachmentPoint = attachmentpoint;
1615
1616 avatar.AddAttachment(this);
1617
1618 if (!silent)
1619 {
1620 // Killing it here will cause the client to deselect it
1621 // It then reappears on the avatar, deselected
1622 // through the full update below
1623 //
1624 if (IsSelected)
1625 {
1626 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1627 }
1628
1629 IsSelected = false; // fudge....
1630 ScheduleGroupForFullUpdate();
1631 }
1632 }
1633 else
1634 {
1635 m_log.WarnFormat(
1636 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1637 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1638 }
1639 }
1640
1641 public byte GetAttachmentPoint()
1642 {
1643 return m_rootPart.Shape.State;
1644 }
1645
1646 public void DetachToGround()
1647 {
1648 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1649 if (avatar == null)
1650 return;
1651
1652 avatar.RemoveAttachment(this);
1653
1654 Vector3 detachedpos = new Vector3(127f,127f,127f);
1655 if (avatar == null)
1656 return;
1657
1658 detachedpos = avatar.AbsolutePosition;
1659 FromItemID = UUID.Zero;
1660
1661 AbsolutePosition = detachedpos;
1662 AttachedAvatar = UUID.Zero;
1663
1664 //SceneObjectPart[] parts = m_parts.GetArray();
1665 //for (int i = 0; i < parts.Length; i++)
1666 // parts[i].AttachedAvatar = UUID.Zero;
1667
1668 m_rootPart.SetParentLocalId(0);
1669 AttachmentPoint = (byte)0;
1670 // must check if buildind should be true or false here
1671 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1672 HasGroupChanged = true;
1673 RootPart.Rezzed = DateTime.Now;
1674 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1675 AttachToBackup();
1676 m_scene.EventManager.TriggerParcelPrimCountTainted();
1677 m_rootPart.ScheduleFullUpdate();
1678 m_rootPart.ClearUndoState();
1679 }
1680
1681 public void DetachToInventoryPrep()
1682 {
1683 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1684 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1685 if (avatar != null)
1686 {
1687 //detachedpos = avatar.AbsolutePosition;
1688 avatar.RemoveAttachment(this);
1689 }
1690
1691 AttachedAvatar = UUID.Zero;
1692
1693 /*SceneObjectPart[] parts = m_parts.GetArray();
1694 for (int i = 0; i < parts.Length; i++)
1695 parts[i].AttachedAvatar = UUID.Zero;*/
1696
1697 m_rootPart.SetParentLocalId(0);
1698 //m_rootPart.SetAttachmentPoint((byte)0);
1699 IsAttachment = false;
1700 AbsolutePosition = m_rootPart.AttachedPos;
1701 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1702 //AttachToBackup();
1703 //m_rootPart.ScheduleFullUpdate();
1704 }
1705
1706 /// <summary>
1089 /// 1707 ///
1090 /// </summary> 1708 /// </summary>
1091 /// <param name="part"></param> 1709 /// <param name="part"></param>
@@ -1125,7 +1743,10 @@ namespace OpenSim.Region.Framework.Scenes
1125 public void AddPart(SceneObjectPart part) 1743 public void AddPart(SceneObjectPart part)
1126 { 1744 {
1127 part.SetParent(this); 1745 part.SetParent(this);
1128 part.LinkNum = m_parts.Add(part.UUID, part); 1746 m_parts.Add(part.UUID, part);
1747
1748 part.LinkNum = m_parts.Count;
1749
1129 if (part.LinkNum == 2) 1750 if (part.LinkNum == 2)
1130 RootPart.LinkNum = 1; 1751 RootPart.LinkNum = 1;
1131 } 1752 }
@@ -1151,6 +1772,14 @@ namespace OpenSim.Region.Framework.Scenes
1151 parts[i].UUID = UUID.Random(); 1772 parts[i].UUID = UUID.Random();
1152 } 1773 }
1153 1774
1775 // helper provided for parts.
1776 public int GetSceneMaxUndo()
1777 {
1778 if (m_scene != null)
1779 return m_scene.MaxUndoCount;
1780 return 5;
1781 }
1782
1154 // justincc: I don't believe this hack is needed any longer, especially since the physics 1783 // justincc: I don't believe this hack is needed any longer, especially since the physics
1155 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1784 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1156 // this method was preventing proper reload of scene objects. 1785 // this method was preventing proper reload of scene objects.
@@ -1208,7 +1837,7 @@ namespace OpenSim.Region.Framework.Scenes
1208// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1837// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1209// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1838// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1210 1839
1211 part.StoreUndoState(); 1840// part.StoreUndoState();
1212 part.OnGrab(offsetPos, remoteClient); 1841 part.OnGrab(offsetPos, remoteClient);
1213 } 1842 }
1214 1843
@@ -1228,6 +1857,11 @@ namespace OpenSim.Region.Framework.Scenes
1228 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1857 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1229 public void DeleteGroupFromScene(bool silent) 1858 public void DeleteGroupFromScene(bool silent)
1230 { 1859 {
1860 // We need to keep track of this state in case this group is still queued for backup.
1861 IsDeleted = true;
1862
1863 DetachFromBackup();
1864
1231 SceneObjectPart[] parts = m_parts.GetArray(); 1865 SceneObjectPart[] parts = m_parts.GetArray();
1232 for (int i = 0; i < parts.Length; i++) 1866 for (int i = 0; i < parts.Length; i++)
1233 { 1867 {
@@ -1251,6 +1885,7 @@ namespace OpenSim.Region.Framework.Scenes
1251 } 1885 }
1252 }); 1886 });
1253 } 1887 }
1888
1254 } 1889 }
1255 1890
1256 public void AddScriptLPS(int count) 1891 public void AddScriptLPS(int count)
@@ -1320,28 +1955,43 @@ namespace OpenSim.Region.Framework.Scenes
1320 /// </summary> 1955 /// </summary>
1321 public void ApplyPhysics() 1956 public void ApplyPhysics()
1322 { 1957 {
1323 // Apply physics to the root prim
1324 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1325
1326 // Apply physics to child prims
1327 SceneObjectPart[] parts = m_parts.GetArray(); 1958 SceneObjectPart[] parts = m_parts.GetArray();
1328 if (parts.Length > 1) 1959 if (parts.Length > 1)
1329 { 1960 {
1961 ResetChildPrimPhysicsPositions();
1962
1963 // Apply physics to the root prim
1964 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1965
1966
1330 for (int i = 0; i < parts.Length; i++) 1967 for (int i = 0; i < parts.Length; i++)
1331 { 1968 {
1332 SceneObjectPart part = parts[i]; 1969 SceneObjectPart part = parts[i];
1333 if (part.LocalId != m_rootPart.LocalId) 1970 if (part.LocalId != m_rootPart.LocalId)
1334 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1971 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1335 } 1972 }
1336
1337 // Hack to get the physics scene geometries in the right spot 1973 // Hack to get the physics scene geometries in the right spot
1338 ResetChildPrimPhysicsPositions(); 1974// ResetChildPrimPhysicsPositions();
1975 if (m_rootPart.PhysActor != null)
1976 {
1977 m_rootPart.PhysActor.Building = false;
1978 }
1979 }
1980 else
1981 {
1982 // Apply physics to the root prim
1983 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1339 } 1984 }
1340 } 1985 }
1341 1986
1342 public void SetOwnerId(UUID userId) 1987 public void SetOwnerId(UUID userId)
1343 { 1988 {
1344 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1989 ForEachPart(delegate(SceneObjectPart part)
1990 {
1991
1992 part.OwnerID = userId;
1993
1994 });
1345 } 1995 }
1346 1996
1347 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1997 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1373,11 +2023,17 @@ namespace OpenSim.Region.Framework.Scenes
1373 return; 2023 return;
1374 } 2024 }
1375 2025
2026 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2027 return;
2028
1376 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2029 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1377 // any exception propogate upwards. 2030 // any exception propogate upwards.
1378 try 2031 try
1379 { 2032 {
1380 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2033 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2034 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2035 m_scene.LoadingPrims) // Land may not be valid yet
2036
1381 { 2037 {
1382 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2038 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1383 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2039 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1404,6 +2060,7 @@ namespace OpenSim.Region.Framework.Scenes
1404 } 2060 }
1405 } 2061 }
1406 } 2062 }
2063
1407 } 2064 }
1408 2065
1409 if (m_scene.UseBackup && HasGroupChanged) 2066 if (m_scene.UseBackup && HasGroupChanged)
@@ -1411,10 +2068,30 @@ namespace OpenSim.Region.Framework.Scenes
1411 // don't backup while it's selected or you're asking for changes mid stream. 2068 // don't backup while it's selected or you're asking for changes mid stream.
1412 if (isTimeToPersist() || forcedBackup) 2069 if (isTimeToPersist() || forcedBackup)
1413 { 2070 {
2071 if (m_rootPart.PhysActor != null &&
2072 (!m_rootPart.PhysActor.IsPhysical))
2073 {
2074 // Possible ghost prim
2075 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2076 {
2077 foreach (SceneObjectPart part in m_parts.GetArray())
2078 {
2079 // Re-set physics actor positions and
2080 // orientations
2081 part.GroupPosition = m_rootPart.GroupPosition;
2082 }
2083 }
2084 }
1414// m_log.DebugFormat( 2085// m_log.DebugFormat(
1415// "[SCENE]: Storing {0}, {1} in {2}", 2086// "[SCENE]: Storing {0}, {1} in {2}",
1416// Name, UUID, m_scene.RegionInfo.RegionName); 2087// Name, UUID, m_scene.RegionInfo.RegionName);
1417 2088
2089 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2090 {
2091 RootPart.Shape.State = 0;
2092 ScheduleGroupForFullUpdate();
2093 }
2094
1418 SceneObjectGroup backup_group = Copy(false); 2095 SceneObjectGroup backup_group = Copy(false);
1419 backup_group.RootPart.Velocity = RootPart.Velocity; 2096 backup_group.RootPart.Velocity = RootPart.Velocity;
1420 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2097 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1424,6 +2101,16 @@ namespace OpenSim.Region.Framework.Scenes
1424 HasGroupChangedDueToDelink = false; 2101 HasGroupChangedDueToDelink = false;
1425 2102
1426 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2103 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2104/*
2105 backup_group.ForEachPart(delegate(SceneObjectPart part)
2106 {
2107 if (part.KeyframeMotion != null)
2108 {
2109 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2110// part.KeyframeMotion.UpdateSceneObject(this);
2111 }
2112 });
2113*/
1427 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2114 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1428 2115
1429 backup_group.ForEachPart(delegate(SceneObjectPart part) 2116 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1480,10 +2167,14 @@ namespace OpenSim.Region.Framework.Scenes
1480 /// <returns></returns> 2167 /// <returns></returns>
1481 public SceneObjectGroup Copy(bool userExposed) 2168 public SceneObjectGroup Copy(bool userExposed)
1482 { 2169 {
2170 m_dupeInProgress = true;
1483 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2171 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1484 dupe.m_isBackedUp = false; 2172 dupe.m_isBackedUp = false;
1485 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2173 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1486 2174
2175 // new group as no sitting avatars
2176 dupe.m_linkedAvatars = new List<ScenePresence>();
2177
1487 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2178 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1488 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2179 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1489 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2180 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1494,7 +2185,7 @@ namespace OpenSim.Region.Framework.Scenes
1494 // This is only necessary when userExposed is false! 2185 // This is only necessary when userExposed is false!
1495 2186
1496 bool previousAttachmentStatus = dupe.IsAttachment; 2187 bool previousAttachmentStatus = dupe.IsAttachment;
1497 2188
1498 if (!userExposed) 2189 if (!userExposed)
1499 dupe.IsAttachment = true; 2190 dupe.IsAttachment = true;
1500 2191
@@ -1507,16 +2198,17 @@ namespace OpenSim.Region.Framework.Scenes
1507 2198
1508 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2199 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1509 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2200 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2201
1510 2202
1511 if (userExposed) 2203 if (userExposed)
1512 dupe.m_rootPart.TrimPermissions(); 2204 dupe.m_rootPart.TrimPermissions();
1513 2205
1514 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2206 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1515 2207
1516 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2208 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1517 { 2209 {
1518 return p1.LinkNum.CompareTo(p2.LinkNum); 2210 return p1.LinkNum.CompareTo(p2.LinkNum);
1519 } 2211 }
1520 ); 2212 );
1521 2213
1522 foreach (SceneObjectPart part in partList) 2214 foreach (SceneObjectPart part in partList)
@@ -1526,41 +2218,56 @@ namespace OpenSim.Region.Framework.Scenes
1526 { 2218 {
1527 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2219 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1528 newPart.LinkNum = part.LinkNum; 2220 newPart.LinkNum = part.LinkNum;
1529 } 2221 if (userExposed)
2222 newPart.ParentID = dupe.m_rootPart.LocalId;
2223 }
1530 else 2224 else
1531 { 2225 {
1532 newPart = dupe.m_rootPart; 2226 newPart = dupe.m_rootPart;
1533 } 2227 }
2228/*
2229 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2230 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1534 2231
1535 // Need to duplicate the physics actor as well 2232 // Need to duplicate the physics actor as well
1536 PhysicsActor originalPartPa = part.PhysActor; 2233 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1537 if (originalPartPa != null && userExposed)
1538 { 2234 {
1539 PrimitiveBaseShape pbs = newPart.Shape; 2235 PrimitiveBaseShape pbs = newPart.Shape;
1540
1541 newPart.PhysActor 2236 newPart.PhysActor
1542 = m_scene.PhysicsScene.AddPrimShape( 2237 = m_scene.PhysicsScene.AddPrimShape(
1543 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2238 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1544 pbs, 2239 pbs,
1545 newPart.AbsolutePosition, 2240 newPart.AbsolutePosition,
1546 newPart.Scale, 2241 newPart.Scale,
1547 newPart.RotationOffset, 2242 newPart.GetWorldRotation(),
1548 originalPartPa.IsPhysical, 2243 isphys,
2244 isphan,
1549 newPart.LocalId); 2245 newPart.LocalId);
1550 2246
1551 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2247 newPart.DoPhysicsPropertyUpdate(isphys, true);
1552 } 2248 */
2249 if (userExposed)
2250 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2251// }
2252 // copy keyframemotion
2253 if (part.KeyframeMotion != null)
2254 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1553 } 2255 }
1554 2256
1555 if (userExposed) 2257 if (userExposed)
1556 { 2258 {
1557 dupe.UpdateParentIDs(); 2259// done above dupe.UpdateParentIDs();
2260
2261 if (dupe.m_rootPart.PhysActor != null)
2262 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2263
1558 dupe.HasGroupChanged = true; 2264 dupe.HasGroupChanged = true;
1559 dupe.AttachToBackup(); 2265 dupe.AttachToBackup();
1560 2266
1561 ScheduleGroupForFullUpdate(); 2267 ScheduleGroupForFullUpdate();
1562 } 2268 }
1563 2269
2270 m_dupeInProgress = false;
1564 return dupe; 2271 return dupe;
1565 } 2272 }
1566 2273
@@ -1572,11 +2279,24 @@ namespace OpenSim.Region.Framework.Scenes
1572 /// <param name="cGroupID"></param> 2279 /// <param name="cGroupID"></param>
1573 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2280 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1574 { 2281 {
1575 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2282 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2283 // give newpart a new local ID lettng old part keep same
2284 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2285 newpart.LocalId = m_scene.AllocateLocalId();
2286
2287 SetRootPart(newpart);
2288 if (userExposed)
2289 RootPart.Velocity = Vector3.Zero; // In case source is moving
1576 } 2290 }
1577 2291
1578 public void ScriptSetPhysicsStatus(bool usePhysics) 2292 public void ScriptSetPhysicsStatus(bool usePhysics)
1579 { 2293 {
2294 if (usePhysics)
2295 {
2296 if (RootPart.KeyframeMotion != null)
2297 RootPart.KeyframeMotion.Stop();
2298 RootPart.KeyframeMotion = null;
2299 }
1580 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2300 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1581 } 2301 }
1582 2302
@@ -1624,27 +2344,14 @@ namespace OpenSim.Region.Framework.Scenes
1624 2344
1625 if (pa != null) 2345 if (pa != null)
1626 { 2346 {
1627 pa.AddForce(impulse, true); 2347 // false to be applied as a impulse
1628 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2348 pa.AddForce(impulse, false);
1629 }
1630 }
1631 }
1632
1633 public void applyAngularImpulse(Vector3 impulse)
1634 {
1635 PhysicsActor pa = RootPart.PhysActor;
1636
1637 if (pa != null)
1638 {
1639 if (!IsAttachment)
1640 {
1641 pa.AddAngularForce(impulse, true);
1642 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2349 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1643 } 2350 }
1644 } 2351 }
1645 } 2352 }
1646 2353
1647 public void setAngularImpulse(Vector3 impulse) 2354 public void ApplyAngularImpulse(Vector3 impulse)
1648 { 2355 {
1649 PhysicsActor pa = RootPart.PhysActor; 2356 PhysicsActor pa = RootPart.PhysActor;
1650 2357
@@ -1652,7 +2359,8 @@ namespace OpenSim.Region.Framework.Scenes
1652 { 2359 {
1653 if (!IsAttachment) 2360 if (!IsAttachment)
1654 { 2361 {
1655 pa.Torque = impulse; 2362 // false to be applied as a impulse
2363 pa.AddAngularForce(impulse, false);
1656 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2364 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1657 } 2365 }
1658 } 2366 }
@@ -1660,20 +2368,10 @@ namespace OpenSim.Region.Framework.Scenes
1660 2368
1661 public Vector3 GetTorque() 2369 public Vector3 GetTorque()
1662 { 2370 {
1663 PhysicsActor pa = RootPart.PhysActor; 2371 return RootPart.Torque;
1664
1665 if (pa != null)
1666 {
1667 if (!IsAttachment)
1668 {
1669 Vector3 torque = pa.Torque;
1670 return torque;
1671 }
1672 }
1673
1674 return Vector3.Zero;
1675 } 2372 }
1676 2373
2374 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1677 public void moveToTarget(Vector3 target, float tau) 2375 public void moveToTarget(Vector3 target, float tau)
1678 { 2376 {
1679 if (IsAttachment) 2377 if (IsAttachment)
@@ -1705,6 +2403,46 @@ namespace OpenSim.Region.Framework.Scenes
1705 pa.PIDActive = false; 2403 pa.PIDActive = false;
1706 } 2404 }
1707 2405
2406 public void rotLookAt(Quaternion target, float strength, float damping)
2407 {
2408 SceneObjectPart rootpart = m_rootPart;
2409 if (rootpart != null)
2410 {
2411 if (IsAttachment)
2412 {
2413 /*
2414 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2415 if (avatar != null)
2416 {
2417 Rotate the Av?
2418 } */
2419 }
2420 else
2421 {
2422 if (rootpart.PhysActor != null)
2423 { // APID must be implemented in your physics system for this to function.
2424 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2425 rootpart.PhysActor.APIDStrength = strength;
2426 rootpart.PhysActor.APIDDamping = damping;
2427 rootpart.PhysActor.APIDActive = true;
2428 }
2429 }
2430 }
2431 }
2432
2433 public void stopLookAt()
2434 {
2435 SceneObjectPart rootpart = m_rootPart;
2436 if (rootpart != null)
2437 {
2438 if (rootpart.PhysActor != null)
2439 { // APID must be implemented in your physics system for this to function.
2440 rootpart.PhysActor.APIDActive = false;
2441 }
2442 }
2443
2444 }
2445
1708 /// <summary> 2446 /// <summary>
1709 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2447 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1710 /// </summary> 2448 /// </summary>
@@ -1721,7 +2459,7 @@ namespace OpenSim.Region.Framework.Scenes
1721 { 2459 {
1722 pa.PIDHoverHeight = height; 2460 pa.PIDHoverHeight = height;
1723 pa.PIDHoverType = hoverType; 2461 pa.PIDHoverType = hoverType;
1724 pa.PIDTau = tau; 2462 pa.PIDHoverTau = tau;
1725 pa.PIDHoverActive = true; 2463 pa.PIDHoverActive = true;
1726 } 2464 }
1727 else 2465 else
@@ -1761,7 +2499,12 @@ namespace OpenSim.Region.Framework.Scenes
1761 /// <param name="cGroupID"></param> 2499 /// <param name="cGroupID"></param>
1762 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2500 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1763 { 2501 {
1764 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2502 // give new ID to the new part, letting old keep original
2503 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2504 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2505 newPart.LocalId = m_scene.AllocateLocalId();
2506 newPart.SetParent(this);
2507
1765 AddPart(newPart); 2508 AddPart(newPart);
1766 2509
1767 SetPartAsNonRoot(newPart); 2510 SetPartAsNonRoot(newPart);
@@ -1900,11 +2643,11 @@ namespace OpenSim.Region.Framework.Scenes
1900 /// Immediately send a full update for this scene object. 2643 /// Immediately send a full update for this scene object.
1901 /// </summary> 2644 /// </summary>
1902 public void SendGroupFullUpdate() 2645 public void SendGroupFullUpdate()
1903 { 2646 {
1904 if (IsDeleted) 2647 if (IsDeleted)
1905 return; 2648 return;
1906 2649
1907// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2650// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1908 2651
1909 RootPart.SendFullUpdateToAllClients(); 2652 RootPart.SendFullUpdateToAllClients();
1910 2653
@@ -2060,6 +2803,11 @@ namespace OpenSim.Region.Framework.Scenes
2060 // 'linkPart' == the root of the group being linked into this group 2803 // 'linkPart' == the root of the group being linked into this group
2061 SceneObjectPart linkPart = objectGroup.m_rootPart; 2804 SceneObjectPart linkPart = objectGroup.m_rootPart;
2062 2805
2806 if (m_rootPart.PhysActor != null)
2807 m_rootPart.PhysActor.Building = true;
2808 if (linkPart.PhysActor != null)
2809 linkPart.PhysActor.Building = true;
2810
2063 // physics flags from group to be applied to linked parts 2811 // physics flags from group to be applied to linked parts
2064 bool grpusephys = UsesPhysics; 2812 bool grpusephys = UsesPhysics;
2065 bool grptemporary = IsTemporary; 2813 bool grptemporary = IsTemporary;
@@ -2085,12 +2833,12 @@ namespace OpenSim.Region.Framework.Scenes
2085 Vector3 axPos = linkPart.OffsetPosition; 2833 Vector3 axPos = linkPart.OffsetPosition;
2086 // Rotate the linking root SOP's position to be relative to the new root prim 2834 // Rotate the linking root SOP's position to be relative to the new root prim
2087 Quaternion parentRot = m_rootPart.RotationOffset; 2835 Quaternion parentRot = m_rootPart.RotationOffset;
2088 axPos *= Quaternion.Inverse(parentRot); 2836 axPos *= Quaternion.Conjugate(parentRot);
2089 linkPart.OffsetPosition = axPos; 2837 linkPart.OffsetPosition = axPos;
2090 2838
2091 // Make the linking root SOP's rotation relative to the new root prim 2839 // Make the linking root SOP's rotation relative to the new root prim
2092 Quaternion oldRot = linkPart.RotationOffset; 2840 Quaternion oldRot = linkPart.RotationOffset;
2093 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2841 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2094 linkPart.RotationOffset = newRot; 2842 linkPart.RotationOffset = newRot;
2095 2843
2096 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2844 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2124,7 +2872,7 @@ namespace OpenSim.Region.Framework.Scenes
2124 linkPart.CreateSelected = true; 2872 linkPart.CreateSelected = true;
2125 2873
2126 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2874 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2127 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2875 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2128 2876
2129 // If the added SOP is physical, also tell the physics engine about the link relationship. 2877 // If the added SOP is physical, also tell the physics engine about the link relationship.
2130 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2878 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2134,6 +2882,7 @@ namespace OpenSim.Region.Framework.Scenes
2134 } 2882 }
2135 2883
2136 linkPart.LinkNum = linkNum++; 2884 linkPart.LinkNum = linkNum++;
2885 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2137 2886
2138 // Get a list of the SOP's in the old group in order of their linknum's. 2887 // Get a list of the SOP's in the old group in order of their linknum's.
2139 SceneObjectPart[] ogParts = objectGroup.Parts; 2888 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2152,7 +2901,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 2901
2153 // Update the physics flags for the newly added SOP 2902 // Update the physics flags for the newly added SOP
2154 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2903 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2155 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2904 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2156 2905
2157 // If the added SOP is physical, also tell the physics engine about the link relationship. 2906 // If the added SOP is physical, also tell the physics engine about the link relationship.
2158 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2907 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2170,7 +2919,7 @@ namespace OpenSim.Region.Framework.Scenes
2170 objectGroup.IsDeleted = true; 2919 objectGroup.IsDeleted = true;
2171 2920
2172 objectGroup.m_parts.Clear(); 2921 objectGroup.m_parts.Clear();
2173 2922
2174 // Can't do this yet since backup still makes use of the root part without any synchronization 2923 // Can't do this yet since backup still makes use of the root part without any synchronization
2175// objectGroup.m_rootPart = null; 2924// objectGroup.m_rootPart = null;
2176 2925
@@ -2184,6 +2933,9 @@ namespace OpenSim.Region.Framework.Scenes
2184 // unmoved prims! 2933 // unmoved prims!
2185 ResetChildPrimPhysicsPositions(); 2934 ResetChildPrimPhysicsPositions();
2186 2935
2936 if (m_rootPart.PhysActor != null)
2937 m_rootPart.PhysActor.Building = false;
2938
2187 //HasGroupChanged = true; 2939 //HasGroupChanged = true;
2188 //ScheduleGroupForFullUpdate(); 2940 //ScheduleGroupForFullUpdate();
2189 } 2941 }
@@ -2251,7 +3003,10 @@ namespace OpenSim.Region.Framework.Scenes
2251// m_log.DebugFormat( 3003// m_log.DebugFormat(
2252// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3004// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2253// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3005// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2254 3006
3007 if (m_rootPart.PhysActor != null)
3008 m_rootPart.PhysActor.Building = true;
3009
2255 linkPart.ClearUndoState(); 3010 linkPart.ClearUndoState();
2256 3011
2257 Vector3 worldPos = linkPart.GetWorldPosition(); 3012 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2322,6 +3077,14 @@ namespace OpenSim.Region.Framework.Scenes
2322 3077
2323 // When we delete a group, we currently have to force persist to the database if the object id has changed 3078 // When we delete a group, we currently have to force persist to the database if the object id has changed
2324 // (since delete works by deleting all rows which have a given object id) 3079 // (since delete works by deleting all rows which have a given object id)
3080
3081 // this is as it seems to be in sl now
3082 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3083 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3084
3085 if (m_rootPart.PhysActor != null)
3086 m_rootPart.PhysActor.Building = false;
3087
2325 objectGroup.HasGroupChangedDueToDelink = true; 3088 objectGroup.HasGroupChangedDueToDelink = true;
2326 3089
2327 return objectGroup; 3090 return objectGroup;
@@ -2333,6 +3096,8 @@ namespace OpenSim.Region.Framework.Scenes
2333 /// <param name="objectGroup"></param> 3096 /// <param name="objectGroup"></param>
2334 public virtual void DetachFromBackup() 3097 public virtual void DetachFromBackup()
2335 { 3098 {
3099 if (m_scene != null)
3100 m_scene.SceneGraph.FireDetachFromBackup(this);
2336 if (m_isBackedUp && Scene != null) 3101 if (m_isBackedUp && Scene != null)
2337 m_scene.EventManager.OnBackup -= ProcessBackup; 3102 m_scene.EventManager.OnBackup -= ProcessBackup;
2338 3103
@@ -2353,7 +3118,8 @@ namespace OpenSim.Region.Framework.Scenes
2353 Vector3 axPos = part.OffsetPosition; 3118 Vector3 axPos = part.OffsetPosition;
2354 axPos *= parentRot; 3119 axPos *= parentRot;
2355 part.OffsetPosition = axPos; 3120 part.OffsetPosition = axPos;
2356 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3121 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3122 part.GroupPosition = newPos;
2357 part.OffsetPosition = Vector3.Zero; 3123 part.OffsetPosition = Vector3.Zero;
2358 3124
2359 // Compution our rotation to be not relative to the old parent 3125 // Compution our rotation to be not relative to the old parent
@@ -2368,7 +3134,7 @@ namespace OpenSim.Region.Framework.Scenes
2368 part.LinkNum = linkNum; 3134 part.LinkNum = linkNum;
2369 3135
2370 // Compute the new position of this SOP relative to the group position 3136 // Compute the new position of this SOP relative to the group position
2371 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3137 part.OffsetPosition = newPos - AbsolutePosition;
2372 3138
2373 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3139 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2374 // It would have the affect of setting the physics engine position multiple 3140 // It would have the affect of setting the physics engine position multiple
@@ -2378,18 +3144,19 @@ namespace OpenSim.Region.Framework.Scenes
2378 // Rotate the relative position by the rotation of the group 3144 // Rotate the relative position by the rotation of the group
2379 Quaternion rootRotation = m_rootPart.RotationOffset; 3145 Quaternion rootRotation = m_rootPart.RotationOffset;
2380 Vector3 pos = part.OffsetPosition; 3146 Vector3 pos = part.OffsetPosition;
2381 pos *= Quaternion.Inverse(rootRotation); 3147 pos *= Quaternion.Conjugate(rootRotation);
2382 part.OffsetPosition = pos; 3148 part.OffsetPosition = pos;
2383 3149
2384 // Compute the SOP's rotation relative to the rotation of the group. 3150 // Compute the SOP's rotation relative to the rotation of the group.
2385 parentRot = m_rootPart.RotationOffset; 3151 parentRot = m_rootPart.RotationOffset;
2386 oldRot = part.RotationOffset; 3152 oldRot = part.RotationOffset;
2387 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3153 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2388 part.RotationOffset = newRot; 3154 part.RotationOffset = newRot;
2389 3155
2390 // Since this SOP's state has changed, push those changes into the physics engine 3156 // Since this SOP's state has changed, push those changes into the physics engine
2391 // and the simulator. 3157 // and the simulator.
2392 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3158 // done on caller
3159// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2393 } 3160 }
2394 3161
2395 /// <summary> 3162 /// <summary>
@@ -2411,10 +3178,14 @@ namespace OpenSim.Region.Framework.Scenes
2411 { 3178 {
2412 if (!m_rootPart.BlockGrab) 3179 if (!m_rootPart.BlockGrab)
2413 { 3180 {
2414 Vector3 llmoveforce = pos - AbsolutePosition; 3181/* Vector3 llmoveforce = pos - AbsolutePosition;
2415 Vector3 grabforce = llmoveforce; 3182 Vector3 grabforce = llmoveforce;
2416 grabforce = (grabforce / 10) * pa.Mass; 3183 grabforce = (grabforce / 10) * pa.Mass;
2417 pa.AddForce(grabforce, true); 3184 */
3185 // empirically convert distance diference to a impulse
3186 Vector3 grabforce = pos - AbsolutePosition;
3187 grabforce = grabforce * (pa.Mass/ 10.0f);
3188 pa.AddForce(grabforce, false);
2418 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3189 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2419 } 3190 }
2420 } 3191 }
@@ -2610,6 +3381,8 @@ namespace OpenSim.Region.Framework.Scenes
2610 /// <param name="SetVolumeDetect"></param> 3381 /// <param name="SetVolumeDetect"></param>
2611 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3382 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2612 { 3383 {
3384 HasGroupChanged = true;
3385
2613 SceneObjectPart selectionPart = GetPart(localID); 3386 SceneObjectPart selectionPart = GetPart(localID);
2614 3387
2615 if (SetTemporary && Scene != null) 3388 if (SetTemporary && Scene != null)
@@ -2640,8 +3413,22 @@ namespace OpenSim.Region.Framework.Scenes
2640 } 3413 }
2641 } 3414 }
2642 3415
2643 for (int i = 0; i < parts.Length; i++) 3416 if (parts.Length > 1)
2644 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3417 {
3418 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3419
3420 for (int i = 0; i < parts.Length; i++)
3421 {
3422
3423 if (parts[i].UUID != m_rootPart.UUID)
3424 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3425 }
3426
3427 if (m_rootPart.PhysActor != null)
3428 m_rootPart.PhysActor.Building = false;
3429 }
3430 else
3431 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2645 } 3432 }
2646 } 3433 }
2647 3434
@@ -2654,6 +3441,17 @@ namespace OpenSim.Region.Framework.Scenes
2654 } 3441 }
2655 } 3442 }
2656 3443
3444
3445
3446 /// <summary>
3447 /// Gets the number of parts
3448 /// </summary>
3449 /// <returns></returns>
3450 public int GetPartCount()
3451 {
3452 return Parts.Count();
3453 }
3454
2657 /// <summary> 3455 /// <summary>
2658 /// Update the texture entry for this part 3456 /// Update the texture entry for this part
2659 /// </summary> 3457 /// </summary>
@@ -2670,11 +3468,20 @@ namespace OpenSim.Region.Framework.Scenes
2670 3468
2671 public void AdjustChildPrimPermissions() 3469 public void AdjustChildPrimPermissions()
2672 { 3470 {
3471 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits
3472 uint foldedPerms = RootPart.OwnerMask & 3;
3473
2673 ForEachPart(part => 3474 ForEachPart(part =>
2674 { 3475 {
3476 newOwnerMask &= part.BaseMask;
2675 if (part != RootPart) 3477 if (part != RootPart)
2676 part.ClonePermissions(RootPart); 3478 part.ClonePermissions(RootPart);
2677 }); 3479 });
3480
3481 uint lockMask = ~(uint)PermissionMask.Move;
3482 uint lockBit = RootPart.OwnerMask & (uint)PermissionMask.Move;
3483 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
3484 RootPart.ScheduleFullUpdate();
2678 } 3485 }
2679 3486
2680 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 3487 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2682,8 +3489,24 @@ namespace OpenSim.Region.Framework.Scenes
2682 { 3489 {
2683 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3490 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2684 3491
3492 bool god = Scene.Permissions.IsGod(AgentID);
3493
3494 if (field == 1 && god)
3495 {
3496 ForEachPart(part =>
3497 {
3498 part.BaseMask = RootPart.BaseMask;
3499 });
3500 }
3501
2685 AdjustChildPrimPermissions(); 3502 AdjustChildPrimPermissions();
2686 3503
3504 if (field == 1 && god) // Base mask was set. Update all child part inventories
3505 {
3506 foreach (SceneObjectPart part in Parts)
3507 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3508 }
3509
2687 HasGroupChanged = true; 3510 HasGroupChanged = true;
2688 3511
2689 // Send the group's properties to all clients once all parts are updated 3512 // Send the group's properties to all clients once all parts are updated
@@ -2729,8 +3552,6 @@ namespace OpenSim.Region.Framework.Scenes
2729 3552
2730 PhysicsActor pa = m_rootPart.PhysActor; 3553 PhysicsActor pa = m_rootPart.PhysActor;
2731 3554
2732 RootPart.StoreUndoState(true);
2733
2734 if (Scene != null) 3555 if (Scene != null)
2735 { 3556 {
2736 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3557 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2758,7 +3579,6 @@ namespace OpenSim.Region.Framework.Scenes
2758 SceneObjectPart obPart = parts[i]; 3579 SceneObjectPart obPart = parts[i];
2759 if (obPart.UUID != m_rootPart.UUID) 3580 if (obPart.UUID != m_rootPart.UUID)
2760 { 3581 {
2761// obPart.IgnoreUndoUpdate = true;
2762 Vector3 oldSize = new Vector3(obPart.Scale); 3582 Vector3 oldSize = new Vector3(obPart.Scale);
2763 3583
2764 float f = 1.0f; 3584 float f = 1.0f;
@@ -2870,8 +3690,6 @@ namespace OpenSim.Region.Framework.Scenes
2870 z *= a; 3690 z *= a;
2871 } 3691 }
2872 } 3692 }
2873
2874// obPart.IgnoreUndoUpdate = false;
2875 } 3693 }
2876 } 3694 }
2877 } 3695 }
@@ -2881,9 +3699,7 @@ namespace OpenSim.Region.Framework.Scenes
2881 prevScale.Y *= y; 3699 prevScale.Y *= y;
2882 prevScale.Z *= z; 3700 prevScale.Z *= z;
2883 3701
2884// RootPart.IgnoreUndoUpdate = true;
2885 RootPart.Resize(prevScale); 3702 RootPart.Resize(prevScale);
2886// RootPart.IgnoreUndoUpdate = false;
2887 3703
2888 for (int i = 0; i < parts.Length; i++) 3704 for (int i = 0; i < parts.Length; i++)
2889 { 3705 {
@@ -2891,8 +3707,6 @@ namespace OpenSim.Region.Framework.Scenes
2891 3707
2892 if (obPart.UUID != m_rootPart.UUID) 3708 if (obPart.UUID != m_rootPart.UUID)
2893 { 3709 {
2894 obPart.IgnoreUndoUpdate = true;
2895
2896 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3710 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2897 currentpos.X *= x; 3711 currentpos.X *= x;
2898 currentpos.Y *= y; 3712 currentpos.Y *= y;
@@ -2905,16 +3719,12 @@ namespace OpenSim.Region.Framework.Scenes
2905 3719
2906 obPart.Resize(newSize); 3720 obPart.Resize(newSize);
2907 obPart.UpdateOffSet(currentpos); 3721 obPart.UpdateOffSet(currentpos);
2908
2909 obPart.IgnoreUndoUpdate = false;
2910 } 3722 }
2911 3723
2912// obPart.IgnoreUndoUpdate = false; 3724 HasGroupChanged = true;
2913// obPart.StoreUndoState(); 3725 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3726 ScheduleGroupForTerseUpdate();
2914 } 3727 }
2915
2916// m_log.DebugFormat(
2917// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2918 } 3728 }
2919 3729
2920 #endregion 3730 #endregion
@@ -2927,14 +3737,6 @@ namespace OpenSim.Region.Framework.Scenes
2927 /// <param name="pos"></param> 3737 /// <param name="pos"></param>
2928 public void UpdateGroupPosition(Vector3 pos) 3738 public void UpdateGroupPosition(Vector3 pos)
2929 { 3739 {
2930// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2931
2932 RootPart.StoreUndoState(true);
2933
2934// SceneObjectPart[] parts = m_parts.GetArray();
2935// for (int i = 0; i < parts.Length; i++)
2936// parts[i].StoreUndoState();
2937
2938 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3740 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2939 { 3741 {
2940 if (IsAttachment) 3742 if (IsAttachment)
@@ -2967,21 +3769,17 @@ namespace OpenSim.Region.Framework.Scenes
2967 /// </summary> 3769 /// </summary>
2968 /// <param name="pos"></param> 3770 /// <param name="pos"></param>
2969 /// <param name="localID"></param> 3771 /// <param name="localID"></param>
3772 ///
3773
2970 public void UpdateSinglePosition(Vector3 pos, uint localID) 3774 public void UpdateSinglePosition(Vector3 pos, uint localID)
2971 { 3775 {
2972 SceneObjectPart part = GetPart(localID); 3776 SceneObjectPart part = GetPart(localID);
2973 3777
2974// SceneObjectPart[] parts = m_parts.GetArray();
2975// for (int i = 0; i < parts.Length; i++)
2976// parts[i].StoreUndoState();
2977
2978 if (part != null) 3778 if (part != null)
2979 { 3779 {
2980// m_log.DebugFormat( 3780// unlock parts position change
2981// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3781 if (m_rootPart.PhysActor != null)
2982 3782 m_rootPart.PhysActor.Building = true;
2983 part.StoreUndoState(false);
2984 part.IgnoreUndoUpdate = true;
2985 3783
2986 if (part.UUID == m_rootPart.UUID) 3784 if (part.UUID == m_rootPart.UUID)
2987 { 3785 {
@@ -2992,8 +3790,10 @@ namespace OpenSim.Region.Framework.Scenes
2992 part.UpdateOffSet(pos); 3790 part.UpdateOffSet(pos);
2993 } 3791 }
2994 3792
3793 if (m_rootPart.PhysActor != null)
3794 m_rootPart.PhysActor.Building = false;
3795
2995 HasGroupChanged = true; 3796 HasGroupChanged = true;
2996 part.IgnoreUndoUpdate = false;
2997 } 3797 }
2998 } 3798 }
2999 3799
@@ -3003,13 +3803,7 @@ namespace OpenSim.Region.Framework.Scenes
3003 /// <param name="pos"></param> 3803 /// <param name="pos"></param>
3004 public void UpdateRootPosition(Vector3 pos) 3804 public void UpdateRootPosition(Vector3 pos)
3005 { 3805 {
3006// m_log.DebugFormat( 3806 // needs to be called with phys building true
3007// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3008
3009// SceneObjectPart[] parts = m_parts.GetArray();
3010// for (int i = 0; i < parts.Length; i++)
3011// parts[i].StoreUndoState();
3012
3013 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3807 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3014 Vector3 oldPos = 3808 Vector3 oldPos =
3015 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3809 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3032,7 +3826,14 @@ namespace OpenSim.Region.Framework.Scenes
3032 AbsolutePosition = newPos; 3826 AbsolutePosition = newPos;
3033 3827
3034 HasGroupChanged = true; 3828 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3829 if (m_rootPart.Undoing)
3830 {
3831 ScheduleGroupForFullUpdate();
3832 }
3833 else
3834 {
3835 ScheduleGroupForTerseUpdate();
3836 }
3036 } 3837 }
3037 3838
3038 #endregion 3839 #endregion
@@ -3045,24 +3846,16 @@ namespace OpenSim.Region.Framework.Scenes
3045 /// <param name="rot"></param> 3846 /// <param name="rot"></param>
3046 public void UpdateGroupRotationR(Quaternion rot) 3847 public void UpdateGroupRotationR(Quaternion rot)
3047 { 3848 {
3048// m_log.DebugFormat(
3049// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3050
3051// SceneObjectPart[] parts = m_parts.GetArray();
3052// for (int i = 0; i < parts.Length; i++)
3053// parts[i].StoreUndoState();
3054
3055 m_rootPart.StoreUndoState(true);
3056
3057 m_rootPart.UpdateRotation(rot); 3849 m_rootPart.UpdateRotation(rot);
3058 3850
3851/* this is done by rootpart RotationOffset set called by UpdateRotation
3059 PhysicsActor actor = m_rootPart.PhysActor; 3852 PhysicsActor actor = m_rootPart.PhysActor;
3060 if (actor != null) 3853 if (actor != null)
3061 { 3854 {
3062 actor.Orientation = m_rootPart.RotationOffset; 3855 actor.Orientation = m_rootPart.RotationOffset;
3063 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3856 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3064 } 3857 }
3065 3858*/
3066 HasGroupChanged = true; 3859 HasGroupChanged = true;
3067 ScheduleGroupForTerseUpdate(); 3860 ScheduleGroupForTerseUpdate();
3068 } 3861 }
@@ -3074,16 +3867,6 @@ namespace OpenSim.Region.Framework.Scenes
3074 /// <param name="rot"></param> 3867 /// <param name="rot"></param>
3075 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3868 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3076 { 3869 {
3077// m_log.DebugFormat(
3078// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3079
3080// SceneObjectPart[] parts = m_parts.GetArray();
3081// for (int i = 0; i < parts.Length; i++)
3082// parts[i].StoreUndoState();
3083
3084 RootPart.StoreUndoState(true);
3085 RootPart.IgnoreUndoUpdate = true;
3086
3087 m_rootPart.UpdateRotation(rot); 3870 m_rootPart.UpdateRotation(rot);
3088 3871
3089 PhysicsActor actor = m_rootPart.PhysActor; 3872 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3102,8 +3885,6 @@ namespace OpenSim.Region.Framework.Scenes
3102 3885
3103 HasGroupChanged = true; 3886 HasGroupChanged = true;
3104 ScheduleGroupForTerseUpdate(); 3887 ScheduleGroupForTerseUpdate();
3105
3106 RootPart.IgnoreUndoUpdate = false;
3107 } 3888 }
3108 3889
3109 /// <summary> 3890 /// <summary>
@@ -3116,13 +3897,11 @@ namespace OpenSim.Region.Framework.Scenes
3116 SceneObjectPart part = GetPart(localID); 3897 SceneObjectPart part = GetPart(localID);
3117 3898
3118 SceneObjectPart[] parts = m_parts.GetArray(); 3899 SceneObjectPart[] parts = m_parts.GetArray();
3119 for (int i = 0; i < parts.Length; i++)
3120 parts[i].StoreUndoState();
3121 3900
3122 if (part != null) 3901 if (part != null)
3123 { 3902 {
3124// m_log.DebugFormat( 3903 if (m_rootPart.PhysActor != null)
3125// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3904 m_rootPart.PhysActor.Building = true;
3126 3905
3127 if (part.UUID == m_rootPart.UUID) 3906 if (part.UUID == m_rootPart.UUID)
3128 { 3907 {
@@ -3132,6 +3911,9 @@ namespace OpenSim.Region.Framework.Scenes
3132 { 3911 {
3133 part.UpdateRotation(rot); 3912 part.UpdateRotation(rot);
3134 } 3913 }
3914
3915 if (m_rootPart.PhysActor != null)
3916 m_rootPart.PhysActor.Building = false;
3135 } 3917 }
3136 } 3918 }
3137 3919
@@ -3145,12 +3927,8 @@ namespace OpenSim.Region.Framework.Scenes
3145 SceneObjectPart part = GetPart(localID); 3927 SceneObjectPart part = GetPart(localID);
3146 if (part != null) 3928 if (part != null)
3147 { 3929 {
3148// m_log.DebugFormat( 3930 if (m_rootPart.PhysActor != null)
3149// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3931 m_rootPart.PhysActor.Building = true;
3150// part.Name, part.LocalId, rot);
3151
3152 part.StoreUndoState();
3153 part.IgnoreUndoUpdate = true;
3154 3932
3155 if (part.UUID == m_rootPart.UUID) 3933 if (part.UUID == m_rootPart.UUID)
3156 { 3934 {
@@ -3163,7 +3941,8 @@ namespace OpenSim.Region.Framework.Scenes
3163 part.OffsetPosition = pos; 3941 part.OffsetPosition = pos;
3164 } 3942 }
3165 3943
3166 part.IgnoreUndoUpdate = false; 3944 if (m_rootPart.PhysActor != null)
3945 m_rootPart.PhysActor.Building = false;
3167 } 3946 }
3168 } 3947 }
3169 3948
@@ -3173,15 +3952,12 @@ namespace OpenSim.Region.Framework.Scenes
3173 /// <param name="rot"></param> 3952 /// <param name="rot"></param>
3174 public void UpdateRootRotation(Quaternion rot) 3953 public void UpdateRootRotation(Quaternion rot)
3175 { 3954 {
3176// m_log.DebugFormat( 3955 // needs to be called with phys building true
3177// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3178// Name, LocalId, rot);
3179
3180 Quaternion axRot = rot; 3956 Quaternion axRot = rot;
3181 Quaternion oldParentRot = m_rootPart.RotationOffset; 3957 Quaternion oldParentRot = m_rootPart.RotationOffset;
3182 3958
3183 m_rootPart.StoreUndoState(); 3959 //Don't use UpdateRotation because it schedules an update prematurely
3184 m_rootPart.UpdateRotation(rot); 3960 m_rootPart.RotationOffset = rot;
3185 3961
3186 PhysicsActor pa = m_rootPart.PhysActor; 3962 PhysicsActor pa = m_rootPart.PhysActor;
3187 3963
@@ -3197,35 +3973,145 @@ namespace OpenSim.Region.Framework.Scenes
3197 SceneObjectPart prim = parts[i]; 3973 SceneObjectPart prim = parts[i];
3198 if (prim.UUID != m_rootPart.UUID) 3974 if (prim.UUID != m_rootPart.UUID)
3199 { 3975 {
3200 prim.IgnoreUndoUpdate = true; 3976 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3977 NewRot = Quaternion.Inverse(axRot) * NewRot;
3978 prim.RotationOffset = NewRot;
3979
3201 Vector3 axPos = prim.OffsetPosition; 3980 Vector3 axPos = prim.OffsetPosition;
3981
3202 axPos *= oldParentRot; 3982 axPos *= oldParentRot;
3203 axPos *= Quaternion.Inverse(axRot); 3983 axPos *= Quaternion.Inverse(axRot);
3204 prim.OffsetPosition = axPos; 3984 prim.OffsetPosition = axPos;
3205 Quaternion primsRot = prim.RotationOffset; 3985 }
3206 Quaternion newRot = oldParentRot * primsRot; 3986 }
3207 newRot = Quaternion.Inverse(axRot) * newRot;
3208 prim.RotationOffset = newRot;
3209 prim.ScheduleTerseUpdate();
3210 prim.IgnoreUndoUpdate = false;
3211 }
3212 }
3213
3214// for (int i = 0; i < parts.Length; i++)
3215// {
3216// SceneObjectPart childpart = parts[i];
3217// if (childpart != m_rootPart)
3218// {
3219//// childpart.IgnoreUndoUpdate = false;
3220//// childpart.StoreUndoState();
3221// }
3222// }
3223 3987
3224 m_rootPart.ScheduleTerseUpdate(); 3988 HasGroupChanged = true;
3989 ScheduleGroupForFullUpdate();
3990 }
3225 3991
3226// m_log.DebugFormat( 3992 private enum updatetype :int
3227// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3993 {
3228// Name, LocalId, rot); 3994 none = 0,
3995 partterse = 1,
3996 partfull = 2,
3997 groupterse = 3,
3998 groupfull = 4
3999 }
4000
4001 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4002 {
4003 // TODO this still as excessive *.Schedule*Update()s
4004
4005 if (part != null && part.ParentGroup != null)
4006 {
4007 ObjectChangeType change = data.change;
4008 bool togroup = ((change & ObjectChangeType.Group) != 0);
4009 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4010
4011 SceneObjectGroup group = part.ParentGroup;
4012 PhysicsActor pha = group.RootPart.PhysActor;
4013
4014 updatetype updateType = updatetype.none;
4015
4016 if (togroup)
4017 {
4018 // related to group
4019 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4020 {
4021 if ((change & ObjectChangeType.Rotation) != 0)
4022 {
4023 group.RootPart.UpdateRotation(data.rotation);
4024 updateType = updatetype.none;
4025 }
4026 if ((change & ObjectChangeType.Position) != 0)
4027 {
4028 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4029 UpdateGroupPosition(data.position);
4030 updateType = updatetype.groupterse;
4031 }
4032 else
4033 // ugly rotation update of all parts
4034 {
4035 group.ResetChildPrimPhysicsPositions();
4036 }
4037
4038 }
4039 if ((change & ObjectChangeType.Scale) != 0)
4040 {
4041 if (pha != null)
4042 pha.Building = true;
4043
4044 group.GroupResize(data.scale);
4045 updateType = updatetype.none;
4046
4047 if (pha != null)
4048 pha.Building = false;
4049 }
4050 }
4051 else
4052 {
4053 // related to single prim in a link-set ( ie group)
4054 if (pha != null)
4055 pha.Building = true;
4056
4057 // root part is special
4058 // parts offset positions or rotations need to change also
4059
4060 if (part == group.RootPart)
4061 {
4062 if ((change & ObjectChangeType.Rotation) != 0)
4063 group.UpdateRootRotation(data.rotation);
4064 if ((change & ObjectChangeType.Position) != 0)
4065 group.UpdateRootPosition(data.position);
4066 if ((change & ObjectChangeType.Scale) != 0)
4067 part.Resize(data.scale);
4068 }
4069 else
4070 {
4071 if ((change & ObjectChangeType.Position) != 0)
4072 {
4073 part.OffsetPosition = data.position;
4074 updateType = updatetype.partterse;
4075 }
4076 if ((change & ObjectChangeType.Rotation) != 0)
4077 {
4078 part.UpdateRotation(data.rotation);
4079 updateType = updatetype.none;
4080 }
4081 if ((change & ObjectChangeType.Scale) != 0)
4082 {
4083 part.Resize(data.scale);
4084 updateType = updatetype.none;
4085 }
4086 }
4087
4088 if (pha != null)
4089 pha.Building = false;
4090 }
4091
4092 if (updateType != updatetype.none)
4093 {
4094 group.HasGroupChanged = true;
4095
4096 switch (updateType)
4097 {
4098 case updatetype.partterse:
4099 part.ScheduleTerseUpdate();
4100 break;
4101 case updatetype.partfull:
4102 part.ScheduleFullUpdate();
4103 break;
4104 case updatetype.groupterse:
4105 group.ScheduleGroupForTerseUpdate();
4106 break;
4107 case updatetype.groupfull:
4108 group.ScheduleGroupForFullUpdate();
4109 break;
4110 default:
4111 break;
4112 }
4113 }
4114 }
3229 } 4115 }
3230 4116
3231 #endregion 4117 #endregion
@@ -3324,10 +4210,11 @@ namespace OpenSim.Region.Framework.Scenes
3324 scriptPosTarget target = m_targets[idx]; 4210 scriptPosTarget target = m_targets[idx];
3325 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4211 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3326 { 4212 {
4213 at_target = true;
4214
3327 // trigger at_target 4215 // trigger at_target
3328 if (m_scriptListens_atTarget) 4216 if (m_scriptListens_atTarget)
3329 { 4217 {
3330 at_target = true;
3331 scriptPosTarget att = new scriptPosTarget(); 4218 scriptPosTarget att = new scriptPosTarget();
3332 att.targetPos = target.targetPos; 4219 att.targetPos = target.targetPos;
3333 att.tolerance = target.tolerance; 4220 att.tolerance = target.tolerance;
@@ -3445,11 +4332,50 @@ namespace OpenSim.Region.Framework.Scenes
3445 } 4332 }
3446 } 4333 }
3447 } 4334 }
3448 4335
4336 public Vector3 GetGeometricCenter()
4337 {
4338 // this is not real geometric center but a average of positions relative to root prim acording to
4339 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4340 // ignoring tortured prims details since sl also seems to ignore
4341 // so no real use in doing it on physics
4342
4343 Vector3 gc = Vector3.Zero;
4344
4345 int nparts = m_parts.Count;
4346 if (nparts <= 1)
4347 return gc;
4348
4349 SceneObjectPart[] parts = m_parts.GetArray();
4350 nparts = parts.Length; // just in case it changed
4351 if (nparts <= 1)
4352 return gc;
4353
4354 Quaternion parentRot = RootPart.RotationOffset;
4355 Vector3 pPos;
4356
4357 // average all parts positions
4358 for (int i = 0; i < nparts; i++)
4359 {
4360 // do it directly
4361 // gc += parts[i].GetWorldPosition();
4362 if (parts[i] != RootPart)
4363 {
4364 pPos = parts[i].OffsetPosition;
4365 gc += pPos;
4366 }
4367
4368 }
4369 gc /= nparts;
4370
4371 // relative to root:
4372// gc -= AbsolutePosition;
4373 return gc;
4374 }
4375
3449 public float GetMass() 4376 public float GetMass()
3450 { 4377 {
3451 float retmass = 0f; 4378 float retmass = 0f;
3452
3453 SceneObjectPart[] parts = m_parts.GetArray(); 4379 SceneObjectPart[] parts = m_parts.GetArray();
3454 for (int i = 0; i < parts.Length; i++) 4380 for (int i = 0; i < parts.Length; i++)
3455 retmass += parts[i].GetMass(); 4381 retmass += parts[i].GetMass();
@@ -3457,6 +4383,39 @@ namespace OpenSim.Region.Framework.Scenes
3457 return retmass; 4383 return retmass;
3458 } 4384 }
3459 4385
4386 // center of mass of full object
4387 public Vector3 GetCenterOfMass()
4388 {
4389 PhysicsActor pa = RootPart.PhysActor;
4390
4391 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4392 {
4393 // physics knows better about center of mass of physical prims
4394 Vector3 tmp = pa.CenterOfMass;
4395 return tmp;
4396 }
4397
4398 Vector3 Ptot = Vector3.Zero;
4399 float totmass = 0f;
4400 float m;
4401
4402 SceneObjectPart[] parts = m_parts.GetArray();
4403 for (int i = 0; i < parts.Length; i++)
4404 {
4405 m = parts[i].GetMass();
4406 Ptot += parts[i].GetPartCenterOfMass() * m;
4407 totmass += m;
4408 }
4409
4410 if (totmass == 0)
4411 totmass = 0;
4412 else
4413 totmass = 1 / totmass;
4414 Ptot *= totmass;
4415
4416 return Ptot;
4417 }
4418
3460 /// <summary> 4419 /// <summary>
3461 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4420 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3462 /// the physics engine can use it. 4421 /// the physics engine can use it.
@@ -3636,6 +4595,14 @@ namespace OpenSim.Region.Framework.Scenes
3636 FromItemID = uuid; 4595 FromItemID = uuid;
3637 } 4596 }
3638 4597
4598 public void ResetOwnerChangeFlag()
4599 {
4600 ForEachPart(delegate(SceneObjectPart part)
4601 {
4602 part.ResetOwnerChangeFlag();
4603 });
4604 }
4605
3639 #endregion 4606 #endregion
3640 } 4607 }
3641} 4608}