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.cs1414
1 files changed, 1184 insertions, 230 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 15795e5..dd8541c 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 }
@@ -264,11 +316,13 @@ namespace OpenSim.Region.Framework.Scenes
264 get { return RootPart.VolumeDetectActive; } 316 get { return RootPart.VolumeDetectActive; }
265 } 317 }
266 318
267 private Vector3 lastPhysGroupPos;
268 private Quaternion lastPhysGroupRot;
269
270 private bool m_isBackedUp; 319 private bool m_isBackedUp;
271 320
321 public bool IsBackedUp
322 {
323 get { return m_isBackedUp; }
324 }
325
272 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 326 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
273 327
274 protected ulong m_regionHandle; 328 protected ulong m_regionHandle;
@@ -280,10 +334,10 @@ namespace OpenSim.Region.Framework.Scenes
280 334
281 private bool m_scriptListens_atTarget; 335 private bool m_scriptListens_atTarget;
282 private bool m_scriptListens_notAtTarget; 336 private bool m_scriptListens_notAtTarget;
283
284 private bool m_scriptListens_atRotTarget; 337 private bool m_scriptListens_atRotTarget;
285 private bool m_scriptListens_notAtRotTarget; 338 private bool m_scriptListens_notAtRotTarget;
286 339
340 public bool m_dupeInProgress = false;
287 internal Dictionary<UUID, string> m_savedScriptState; 341 internal Dictionary<UUID, string> m_savedScriptState;
288 342
289 #region Properties 343 #region Properties
@@ -320,6 +374,16 @@ namespace OpenSim.Region.Framework.Scenes
320 get { return m_parts.Count; } 374 get { return m_parts.Count; }
321 } 375 }
322 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
323 public Quaternion GroupRotation 387 public Quaternion GroupRotation
324 { 388 {
325 get { return m_rootPart.RotationOffset; } 389 get { return m_rootPart.RotationOffset; }
@@ -426,7 +490,15 @@ namespace OpenSim.Region.Framework.Scenes
426 { 490 {
427 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));
428 } 492 }
429 493
494
495
496 private struct avtocrossInfo
497 {
498 public ScenePresence av;
499 public uint ParentID;
500 }
501
430 /// <summary> 502 /// <summary>
431 /// The absolute position of this scene object in the scene 503 /// The absolute position of this scene object in the scene
432 /// </summary> 504 /// </summary>
@@ -454,10 +526,129 @@ namespace OpenSim.Region.Framework.Scenes
454 || Scene.TestBorderCross(val, Cardinals.S)) 526 || Scene.TestBorderCross(val, Cardinals.S))
455 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 527 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
456 { 528 {
457 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 529 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
530 uint x = 0;
531 uint y = 0;
532 string version = String.Empty;
533 Vector3 newpos = Vector3.Zero;
534 OpenSim.Services.Interfaces.GridRegion destination = null;
535
536 if (m_rootPart.KeyframeMotion != null)
537 m_rootPart.KeyframeMotion.StartCrossingCheck();
538
539 bool canCross = true;
540 foreach (ScenePresence av in m_linkedAvatars)
541 {
542 // We need to cross these agents. First, let's find
543 // out if any of them can't cross for some reason.
544 // We have to deny the crossing entirely if any
545 // of them are banned. Alternatively, we could
546 // unsit banned agents....
547
548
549 // We set the avatar position as being the object
550 // position to get the region to send to
551 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
552 {
553 canCross = false;
554 break;
555 }
556
557 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
558 }
559
560 if (canCross)
561 {
562 // We unparent the SP quietly so that it won't
563 // be made to stand up
564
565 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
566
567 foreach (ScenePresence av in m_linkedAvatars)
568 {
569 avtocrossInfo avinfo = new avtocrossInfo();
570 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
571 if (parentPart != null)
572 av.ParentUUID = parentPart.UUID;
573
574 avinfo.av = av;
575 avinfo.ParentID = av.ParentID;
576 avsToCross.Add(avinfo);
577
578 av.ParentID = 0;
579 }
580
581 // m_linkedAvatars.Clear();
582 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
583
584 // Normalize
585 if (val.X >= Constants.RegionSize)
586 val.X -= Constants.RegionSize;
587 if (val.Y >= Constants.RegionSize)
588 val.Y -= Constants.RegionSize;
589 if (val.X < 0)
590 val.X += Constants.RegionSize;
591 if (val.Y < 0)
592 val.Y += Constants.RegionSize;
593
594 // If it's deleted, crossing was successful
595 if (IsDeleted)
596 {
597 // foreach (ScenePresence av in m_linkedAvatars)
598 foreach (avtocrossInfo avinfo in avsToCross)
599 {
600 ScenePresence av = avinfo.av;
601 if (!av.IsInTransit) // just in case...
602 {
603 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
604
605 av.IsInTransit = true;
606
607 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
608 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
609 }
610 else
611 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
612 }
613 avsToCross.Clear();
614 return;
615 }
616 else // cross failed, put avas back ??
617 {
618 foreach (avtocrossInfo avinfo in avsToCross)
619 {
620 ScenePresence av = avinfo.av;
621 av.ParentUUID = UUID.Zero;
622 av.ParentID = avinfo.ParentID;
623// m_linkedAvatars.Add(av);
624 }
625 }
626 avsToCross.Clear();
627
628 }
629 else
630 {
631 if (m_rootPart.KeyframeMotion != null)
632 m_rootPart.KeyframeMotion.CrossingFailure();
633
634 if (RootPart.PhysActor != null)
635 {
636 RootPart.PhysActor.CrossingFailure();
637 }
638 }
639 Vector3 oldp = AbsolutePosition;
640 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
641 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
642 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
458 } 643 }
459 } 644 }
460 645
646/* don't see the need but worse don't see where is restored to false if things stay in
647 foreach (SceneObjectPart part in m_parts.GetArray())
648 {
649 part.IgnoreUndoUpdate = true;
650 }
651 */
461 if (RootPart.GetStatusSandbox()) 652 if (RootPart.GetStatusSandbox())
462 { 653 {
463 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 654 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -475,9 +666,38 @@ namespace OpenSim.Region.Framework.Scenes
475 // Restuff the new GroupPosition into each SOP of the linkset. 666 // Restuff the new GroupPosition into each SOP of the linkset.
476 // This has the affect of resetting and tainting the physics actors. 667 // This has the affect of resetting and tainting the physics actors.
477 SceneObjectPart[] parts = m_parts.GetArray(); 668 SceneObjectPart[] parts = m_parts.GetArray();
478 for (int i = 0; i < parts.Length; i++) 669 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
479 parts[i].GroupPosition = val; 670 if (m_dupeInProgress)
671 triggerScriptEvent = false;
672 foreach (SceneObjectPart part in parts)
673 {
674 part.GroupPosition = val;
675 if (triggerScriptEvent)
676 part.TriggerScriptChangedEvent(Changed.POSITION);
677 }
480 678
679/*
680 This seems not needed and should not be needed:
681 sp absolute position depends on sit part absolute position fixed above.
682 sp ParentPosition is not used anywhere.
683 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
684 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
685
686 if (!m_dupeInProgress)
687 {
688 foreach (ScenePresence av in m_linkedAvatars)
689 {
690 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
691 if (p != null && m_parts.TryGetValue(p.UUID, out p))
692 {
693 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
694 av.AbsolutePosition += offset;
695// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
696 av.SendAvatarDataToAllAgents();
697 }
698 }
699 }
700*/
481 //if (m_rootPart.PhysActor != null) 701 //if (m_rootPart.PhysActor != null)
482 //{ 702 //{
483 //m_rootPart.PhysActor.Position = 703 //m_rootPart.PhysActor.Position =
@@ -491,6 +711,40 @@ namespace OpenSim.Region.Framework.Scenes
491 } 711 }
492 } 712 }
493 713
714 public override Vector3 Velocity
715 {
716 get { return RootPart.Velocity; }
717 set { RootPart.Velocity = value; }
718 }
719
720 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
721 {
722 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
723 ScenePresence agent = icon.EndInvoke(iar);
724
725 //// If the cross was successful, this agent is a child agent
726 if (agent.IsChildAgent)
727 {
728 if (agent.ParentUUID != UUID.Zero)
729 {
730 agent.ParentPart = null;
731// agent.ParentPosition = Vector3.Zero;
732// agent.ParentUUID = UUID.Zero;
733 }
734 }
735
736 agent.ParentUUID = UUID.Zero;
737
738// agent.Reset();
739// else // Not successful
740// agent.RestoreInCurrentScene();
741
742 // In any case
743 agent.IsInTransit = false;
744
745 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
746 }
747
494 public override uint LocalId 748 public override uint LocalId
495 { 749 {
496 get { return m_rootPart.LocalId; } 750 get { return m_rootPart.LocalId; }
@@ -561,6 +815,11 @@ namespace OpenSim.Region.Framework.Scenes
561 m_isSelected = value; 815 m_isSelected = value;
562 // Tell physics engine that group is selected 816 // Tell physics engine that group is selected
563 817
818 // this is not right
819 // but ode engines should only really need to know about root part
820 // so they can put entire object simulation on hold and not colliding
821 // keep as was for now
822
564 PhysicsActor pa = m_rootPart.PhysActor; 823 PhysicsActor pa = m_rootPart.PhysActor;
565 if (pa != null) 824 if (pa != null)
566 { 825 {
@@ -577,6 +836,42 @@ namespace OpenSim.Region.Framework.Scenes
577 childPa.Selected = value; 836 childPa.Selected = value;
578 } 837 }
579 } 838 }
839 if (RootPart.KeyframeMotion != null)
840 RootPart.KeyframeMotion.Selected = value;
841 }
842 }
843
844 public void PartSelectChanged(bool partSelect)
845 {
846 // any part selected makes group selected
847 if (m_isSelected == partSelect)
848 return;
849
850 if (partSelect)
851 {
852 IsSelected = partSelect;
853// if (!IsAttachment)
854// ScheduleGroupForFullUpdate();
855 }
856 else
857 {
858 // bad bad bad 2 heavy for large linksets
859 // since viewer does send lot of (un)selects
860 // this needs to be replaced by a specific list or count ?
861 // but that will require extra code in several places
862
863 SceneObjectPart[] parts = m_parts.GetArray();
864 for (int i = 0; i < parts.Length; i++)
865 {
866 SceneObjectPart part = parts[i];
867 if (part.IsSelected)
868 return;
869 }
870 IsSelected = partSelect;
871 if (!IsAttachment)
872 {
873 ScheduleGroupForFullUpdate();
874 }
580 } 875 }
581 } 876 }
582 877
@@ -674,6 +969,7 @@ namespace OpenSim.Region.Framework.Scenes
674 /// </summary> 969 /// </summary>
675 public SceneObjectGroup() 970 public SceneObjectGroup()
676 { 971 {
972
677 } 973 }
678 974
679 /// <summary> 975 /// <summary>
@@ -691,8 +987,8 @@ namespace OpenSim.Region.Framework.Scenes
691 /// Constructor. This object is added to the scene later via AttachToScene() 987 /// Constructor. This object is added to the scene later via AttachToScene()
692 /// </summary> 988 /// </summary>
693 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 989 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
694 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 990 {
695 { 991 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
696 } 992 }
697 993
698 /// <summary> 994 /// <summary>
@@ -727,6 +1023,9 @@ namespace OpenSim.Region.Framework.Scenes
727 /// </summary> 1023 /// </summary>
728 public virtual void AttachToBackup() 1024 public virtual void AttachToBackup()
729 { 1025 {
1026 if (IsAttachment) return;
1027 m_scene.SceneGraph.FireAttachToBackup(this);
1028
730 if (InSceneBackup) 1029 if (InSceneBackup)
731 { 1030 {
732 //m_log.DebugFormat( 1031 //m_log.DebugFormat(
@@ -769,6 +1068,13 @@ namespace OpenSim.Region.Framework.Scenes
769 1068
770 ApplyPhysics(); 1069 ApplyPhysics();
771 1070
1071 if (RootPart.PhysActor != null)
1072 RootPart.Force = RootPart.Force;
1073 if (RootPart.PhysActor != null)
1074 RootPart.Torque = RootPart.Torque;
1075 if (RootPart.PhysActor != null)
1076 RootPart.Buoyancy = RootPart.Buoyancy;
1077
772 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1078 // 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. 1079 // for the same object with very different properties. The caller must schedule the update.
774 //ScheduleGroupForFullUpdate(); 1080 //ScheduleGroupForFullUpdate();
@@ -784,6 +1090,10 @@ namespace OpenSim.Region.Framework.Scenes
784 EntityIntersection result = new EntityIntersection(); 1090 EntityIntersection result = new EntityIntersection();
785 1091
786 SceneObjectPart[] parts = m_parts.GetArray(); 1092 SceneObjectPart[] parts = m_parts.GetArray();
1093
1094 // Find closest hit here
1095 float idist = float.MaxValue;
1096
787 for (int i = 0; i < parts.Length; i++) 1097 for (int i = 0; i < parts.Length; i++)
788 { 1098 {
789 SceneObjectPart part = parts[i]; 1099 SceneObjectPart part = parts[i];
@@ -798,11 +1108,6 @@ namespace OpenSim.Region.Framework.Scenes
798 1108
799 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1109 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
800 1110
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) 1111 if (inter.HitTF)
807 { 1112 {
808 // We need to find the closest prim to return to the testcaller along the ray 1113 // We need to find the closest prim to return to the testcaller along the ray
@@ -813,10 +1118,11 @@ namespace OpenSim.Region.Framework.Scenes
813 result.obj = part; 1118 result.obj = part;
814 result.normal = inter.normal; 1119 result.normal = inter.normal;
815 result.distance = inter.distance; 1120 result.distance = inter.distance;
1121
1122 idist = inter.distance;
816 } 1123 }
817 } 1124 }
818 } 1125 }
819
820 return result; 1126 return result;
821 } 1127 }
822 1128
@@ -828,25 +1134,27 @@ namespace OpenSim.Region.Framework.Scenes
828 /// <returns></returns> 1134 /// <returns></returns>
829 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1135 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
830 { 1136 {
831 maxX = -256f; 1137 maxX = float.MinValue;
832 maxY = -256f; 1138 maxY = float.MinValue;
833 maxZ = -256f; 1139 maxZ = float.MinValue;
834 minX = 256f; 1140 minX = float.MaxValue;
835 minY = 256f; 1141 minY = float.MaxValue;
836 minZ = 8192f; 1142 minZ = float.MaxValue;
837 1143
838 SceneObjectPart[] parts = m_parts.GetArray(); 1144 SceneObjectPart[] parts = m_parts.GetArray();
839 for (int i = 0; i < parts.Length; i++) 1145 foreach (SceneObjectPart part in parts)
840 { 1146 {
841 SceneObjectPart part = parts[i];
842
843 Vector3 worldPos = part.GetWorldPosition(); 1147 Vector3 worldPos = part.GetWorldPosition();
844 Vector3 offset = worldPos - AbsolutePosition; 1148 Vector3 offset = worldPos - AbsolutePosition;
845 Quaternion worldRot; 1149 Quaternion worldRot;
846 if (part.ParentID == 0) 1150 if (part.ParentID == 0)
1151 {
847 worldRot = part.RotationOffset; 1152 worldRot = part.RotationOffset;
1153 }
848 else 1154 else
1155 {
849 worldRot = part.GetWorldRotation(); 1156 worldRot = part.GetWorldRotation();
1157 }
850 1158
851 Vector3 frontTopLeft; 1159 Vector3 frontTopLeft;
852 Vector3 frontTopRight; 1160 Vector3 frontTopRight;
@@ -858,6 +1166,8 @@ namespace OpenSim.Region.Framework.Scenes
858 Vector3 backBottomLeft; 1166 Vector3 backBottomLeft;
859 Vector3 backBottomRight; 1167 Vector3 backBottomRight;
860 1168
1169 // Vector3[] corners = new Vector3[8];
1170
861 Vector3 orig = Vector3.Zero; 1171 Vector3 orig = Vector3.Zero;
862 1172
863 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1173 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -892,6 +1202,38 @@ namespace OpenSim.Region.Framework.Scenes
892 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1202 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
893 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1203 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
894 1204
1205
1206
1207 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1208 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1209 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1210 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1211 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1212 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1213 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1214 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1215
1216 //for (int i = 0; i < 8; i++)
1217 //{
1218 // corners[i] = corners[i] * worldRot;
1219 // corners[i] += offset;
1220
1221 // if (corners[i].X > maxX)
1222 // maxX = corners[i].X;
1223 // if (corners[i].X < minX)
1224 // minX = corners[i].X;
1225
1226 // if (corners[i].Y > maxY)
1227 // maxY = corners[i].Y;
1228 // if (corners[i].Y < minY)
1229 // minY = corners[i].Y;
1230
1231 // if (corners[i].Z > maxZ)
1232 // maxZ = corners[i].Y;
1233 // if (corners[i].Z < minZ)
1234 // minZ = corners[i].Z;
1235 //}
1236
895 frontTopLeft = frontTopLeft * worldRot; 1237 frontTopLeft = frontTopLeft * worldRot;
896 frontTopRight = frontTopRight * worldRot; 1238 frontTopRight = frontTopRight * worldRot;
897 frontBottomLeft = frontBottomLeft * worldRot; 1239 frontBottomLeft = frontBottomLeft * worldRot;
@@ -913,6 +1255,15 @@ namespace OpenSim.Region.Framework.Scenes
913 backTopLeft += offset; 1255 backTopLeft += offset;
914 backTopRight += offset; 1256 backTopRight += offset;
915 1257
1258 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1259 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1260 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1261 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1262 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1263 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1264 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1265 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1266
916 if (frontTopRight.X > maxX) 1267 if (frontTopRight.X > maxX)
917 maxX = frontTopRight.X; 1268 maxX = frontTopRight.X;
918 if (frontTopLeft.X > maxX) 1269 if (frontTopLeft.X > maxX)
@@ -1056,17 +1407,118 @@ namespace OpenSim.Region.Framework.Scenes
1056 1407
1057 #endregion 1408 #endregion
1058 1409
1410 public void GetResourcesCosts(SceneObjectPart apart,
1411 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1412 {
1413 // this information may need to be cached
1414
1415 float cost;
1416 float tmpcost;
1417
1418 bool ComplexCost = false;
1419
1420 SceneObjectPart p;
1421 SceneObjectPart[] parts;
1422
1423 lock (m_parts)
1424 {
1425 parts = m_parts.GetArray();
1426 }
1427
1428 int nparts = parts.Length;
1429
1430
1431 for (int i = 0; i < nparts; i++)
1432 {
1433 p = parts[i];
1434
1435 if (p.UsesComplexCost)
1436 {
1437 ComplexCost = true;
1438 break;
1439 }
1440 }
1441
1442 if (ComplexCost)
1443 {
1444 linksetResCost = 0;
1445 linksetPhysCost = 0;
1446 partCost = 0;
1447 partPhysCost = 0;
1448
1449 for (int i = 0; i < nparts; i++)
1450 {
1451 p = parts[i];
1452
1453 cost = p.StreamingCost;
1454 tmpcost = p.SimulationCost;
1455 if (tmpcost > cost)
1456 cost = tmpcost;
1457 tmpcost = p.PhysicsCost;
1458 if (tmpcost > cost)
1459 cost = tmpcost;
1460
1461 linksetPhysCost += tmpcost;
1462 linksetResCost += cost;
1463
1464 if (p == apart)
1465 {
1466 partCost = cost;
1467 partPhysCost = tmpcost;
1468 }
1469 }
1470 }
1471 else
1472 {
1473 partPhysCost = 1.0f;
1474 partCost = 1.0f;
1475 linksetResCost = (float)nparts;
1476 linksetPhysCost = linksetResCost;
1477 }
1478 }
1479
1480 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1481 {
1482 SceneObjectPart p;
1483 SceneObjectPart[] parts;
1484
1485 lock (m_parts)
1486 {
1487 parts = m_parts.GetArray();
1488 }
1489
1490 int nparts = parts.Length;
1491
1492 PhysCost = 0;
1493 StreamCost = 0;
1494 SimulCost = 0;
1495
1496 for (int i = 0; i < nparts; i++)
1497 {
1498 p = parts[i];
1499
1500 StreamCost += p.StreamingCost;
1501 SimulCost += p.SimulationCost;
1502 PhysCost += p.PhysicsCost;
1503 }
1504 }
1505
1059 public void SaveScriptedState(XmlTextWriter writer) 1506 public void SaveScriptedState(XmlTextWriter writer)
1060 { 1507 {
1508 SaveScriptedState(writer, false);
1509 }
1510
1511 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1512 {
1061 XmlDocument doc = new XmlDocument(); 1513 XmlDocument doc = new XmlDocument();
1062 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1514 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1063 1515
1064 SceneObjectPart[] parts = m_parts.GetArray(); 1516 SceneObjectPart[] parts = m_parts.GetArray();
1065 for (int i = 0; i < parts.Length; i++) 1517 for (int i = 0; i < parts.Length; i++)
1066 { 1518 {
1067 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1519 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1068 foreach (KeyValuePair<UUID, string> kvp in pstates) 1520 foreach (KeyValuePair<UUID, string> kvp in pstates)
1069 states.Add(kvp.Key, kvp.Value); 1521 states[kvp.Key] = kvp.Value;
1070 } 1522 }
1071 1523
1072 if (states.Count > 0) 1524 if (states.Count > 0)
@@ -1086,6 +1538,169 @@ namespace OpenSim.Region.Framework.Scenes
1086 } 1538 }
1087 1539
1088 /// <summary> 1540 /// <summary>
1541 /// Add the avatar to this linkset (avatar is sat).
1542 /// </summary>
1543 /// <param name="agentID"></param>
1544 public void AddAvatar(UUID agentID)
1545 {
1546 ScenePresence presence;
1547 if (m_scene.TryGetScenePresence(agentID, out presence))
1548 {
1549 if (!m_linkedAvatars.Contains(presence))
1550 {
1551 m_linkedAvatars.Add(presence);
1552 }
1553 }
1554 }
1555
1556 /// <summary>
1557 /// Delete the avatar from this linkset (avatar is unsat).
1558 /// </summary>
1559 /// <param name="agentID"></param>
1560 public void DeleteAvatar(UUID agentID)
1561 {
1562 ScenePresence presence;
1563 if (m_scene.TryGetScenePresence(agentID, out presence))
1564 {
1565 if (m_linkedAvatars.Contains(presence))
1566 {
1567 m_linkedAvatars.Remove(presence);
1568 }
1569 }
1570 }
1571
1572 /// <summary>
1573 /// Returns the list of linked presences (avatars sat on this group)
1574 /// </summary>
1575 /// <param name="agentID"></param>
1576 public List<ScenePresence> GetLinkedAvatars()
1577 {
1578 return m_linkedAvatars;
1579 }
1580
1581 /// <summary>
1582 /// Attach this scene object to the given avatar.
1583 /// </summary>
1584 /// <param name="agentID"></param>
1585 /// <param name="attachmentpoint"></param>
1586 /// <param name="AttachOffset"></param>
1587 private void AttachToAgent(
1588 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1589 {
1590 if (avatar != null)
1591 {
1592 // don't attach attachments to child agents
1593 if (avatar.IsChildAgent) return;
1594
1595 // Remove from database and parcel prim count
1596 m_scene.DeleteFromStorage(so.UUID);
1597 m_scene.EventManager.TriggerParcelPrimCountTainted();
1598
1599 so.AttachedAvatar = avatar.UUID;
1600
1601 if (so.RootPart.PhysActor != null)
1602 {
1603 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1604 so.RootPart.PhysActor = null;
1605 }
1606
1607 so.AbsolutePosition = attachOffset;
1608 so.RootPart.AttachedPos = attachOffset;
1609 so.IsAttachment = true;
1610 so.RootPart.SetParentLocalId(avatar.LocalId);
1611 so.AttachmentPoint = attachmentpoint;
1612
1613 avatar.AddAttachment(this);
1614
1615 if (!silent)
1616 {
1617 // Killing it here will cause the client to deselect it
1618 // It then reappears on the avatar, deselected
1619 // through the full update below
1620 //
1621 if (IsSelected)
1622 {
1623 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1624 }
1625
1626 IsSelected = false; // fudge....
1627 ScheduleGroupForFullUpdate();
1628 }
1629 }
1630 else
1631 {
1632 m_log.WarnFormat(
1633 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1634 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1635 }
1636 }
1637
1638 public byte GetAttachmentPoint()
1639 {
1640 return m_rootPart.Shape.State;
1641 }
1642
1643 public void DetachToGround()
1644 {
1645 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1646 if (avatar == null)
1647 return;
1648
1649 avatar.RemoveAttachment(this);
1650
1651 Vector3 detachedpos = new Vector3(127f,127f,127f);
1652 if (avatar == null)
1653 return;
1654
1655 detachedpos = avatar.AbsolutePosition;
1656 FromItemID = UUID.Zero;
1657
1658 AbsolutePosition = detachedpos;
1659 AttachedAvatar = UUID.Zero;
1660
1661 //SceneObjectPart[] parts = m_parts.GetArray();
1662 //for (int i = 0; i < parts.Length; i++)
1663 // parts[i].AttachedAvatar = UUID.Zero;
1664
1665 m_rootPart.SetParentLocalId(0);
1666 AttachmentPoint = (byte)0;
1667 // must check if buildind should be true or false here
1668 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1669 HasGroupChanged = true;
1670 RootPart.Rezzed = DateTime.Now;
1671 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1672 AttachToBackup();
1673 m_scene.EventManager.TriggerParcelPrimCountTainted();
1674 m_rootPart.ScheduleFullUpdate();
1675 m_rootPart.ClearUndoState();
1676 }
1677
1678 public void DetachToInventoryPrep()
1679 {
1680 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1681 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1682 if (avatar != null)
1683 {
1684 //detachedpos = avatar.AbsolutePosition;
1685 avatar.RemoveAttachment(this);
1686 }
1687
1688 AttachedAvatar = UUID.Zero;
1689
1690 /*SceneObjectPart[] parts = m_parts.GetArray();
1691 for (int i = 0; i < parts.Length; i++)
1692 parts[i].AttachedAvatar = UUID.Zero;*/
1693
1694 m_rootPart.SetParentLocalId(0);
1695 //m_rootPart.SetAttachmentPoint((byte)0);
1696 IsAttachment = false;
1697 AbsolutePosition = m_rootPart.AttachedPos;
1698 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1699 //AttachToBackup();
1700 //m_rootPart.ScheduleFullUpdate();
1701 }
1702
1703 /// <summary>
1089 /// 1704 ///
1090 /// </summary> 1705 /// </summary>
1091 /// <param name="part"></param> 1706 /// <param name="part"></param>
@@ -1125,7 +1740,10 @@ namespace OpenSim.Region.Framework.Scenes
1125 public void AddPart(SceneObjectPart part) 1740 public void AddPart(SceneObjectPart part)
1126 { 1741 {
1127 part.SetParent(this); 1742 part.SetParent(this);
1128 part.LinkNum = m_parts.Add(part.UUID, part); 1743 m_parts.Add(part.UUID, part);
1744
1745 part.LinkNum = m_parts.Count;
1746
1129 if (part.LinkNum == 2) 1747 if (part.LinkNum == 2)
1130 RootPart.LinkNum = 1; 1748 RootPart.LinkNum = 1;
1131 } 1749 }
@@ -1151,6 +1769,14 @@ namespace OpenSim.Region.Framework.Scenes
1151 parts[i].UUID = UUID.Random(); 1769 parts[i].UUID = UUID.Random();
1152 } 1770 }
1153 1771
1772 // helper provided for parts.
1773 public int GetSceneMaxUndo()
1774 {
1775 if (m_scene != null)
1776 return m_scene.MaxUndoCount;
1777 return 5;
1778 }
1779
1154 // justincc: I don't believe this hack is needed any longer, especially since the physics 1780 // 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 1781 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1156 // this method was preventing proper reload of scene objects. 1782 // this method was preventing proper reload of scene objects.
@@ -1208,7 +1834,7 @@ namespace OpenSim.Region.Framework.Scenes
1208// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1834// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1209// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1835// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1210 1836
1211 part.StoreUndoState(); 1837// part.StoreUndoState();
1212 part.OnGrab(offsetPos, remoteClient); 1838 part.OnGrab(offsetPos, remoteClient);
1213 } 1839 }
1214 1840
@@ -1228,6 +1854,11 @@ namespace OpenSim.Region.Framework.Scenes
1228 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1854 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1229 public void DeleteGroupFromScene(bool silent) 1855 public void DeleteGroupFromScene(bool silent)
1230 { 1856 {
1857 // We need to keep track of this state in case this group is still queued for backup.
1858 IsDeleted = true;
1859
1860 DetachFromBackup();
1861
1231 SceneObjectPart[] parts = m_parts.GetArray(); 1862 SceneObjectPart[] parts = m_parts.GetArray();
1232 for (int i = 0; i < parts.Length; i++) 1863 for (int i = 0; i < parts.Length; i++)
1233 { 1864 {
@@ -1251,6 +1882,7 @@ namespace OpenSim.Region.Framework.Scenes
1251 } 1882 }
1252 }); 1883 });
1253 } 1884 }
1885
1254 } 1886 }
1255 1887
1256 public void AddScriptLPS(int count) 1888 public void AddScriptLPS(int count)
@@ -1320,28 +1952,43 @@ namespace OpenSim.Region.Framework.Scenes
1320 /// </summary> 1952 /// </summary>
1321 public void ApplyPhysics() 1953 public void ApplyPhysics()
1322 { 1954 {
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(); 1955 SceneObjectPart[] parts = m_parts.GetArray();
1328 if (parts.Length > 1) 1956 if (parts.Length > 1)
1329 { 1957 {
1958 ResetChildPrimPhysicsPositions();
1959
1960 // Apply physics to the root prim
1961 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1962
1963
1330 for (int i = 0; i < parts.Length; i++) 1964 for (int i = 0; i < parts.Length; i++)
1331 { 1965 {
1332 SceneObjectPart part = parts[i]; 1966 SceneObjectPart part = parts[i];
1333 if (part.LocalId != m_rootPart.LocalId) 1967 if (part.LocalId != m_rootPart.LocalId)
1334 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1968 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1335 } 1969 }
1336
1337 // Hack to get the physics scene geometries in the right spot 1970 // Hack to get the physics scene geometries in the right spot
1338 ResetChildPrimPhysicsPositions(); 1971// ResetChildPrimPhysicsPositions();
1972 if (m_rootPart.PhysActor != null)
1973 {
1974 m_rootPart.PhysActor.Building = false;
1975 }
1976 }
1977 else
1978 {
1979 // Apply physics to the root prim
1980 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1339 } 1981 }
1340 } 1982 }
1341 1983
1342 public void SetOwnerId(UUID userId) 1984 public void SetOwnerId(UUID userId)
1343 { 1985 {
1344 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1986 ForEachPart(delegate(SceneObjectPart part)
1987 {
1988
1989 part.OwnerID = userId;
1990
1991 });
1345 } 1992 }
1346 1993
1347 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1994 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1373,11 +2020,17 @@ namespace OpenSim.Region.Framework.Scenes
1373 return; 2020 return;
1374 } 2021 }
1375 2022
2023 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2024 return;
2025
1376 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2026 // 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. 2027 // any exception propogate upwards.
1378 try 2028 try
1379 { 2029 {
1380 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2030 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2031 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2032 m_scene.LoadingPrims) // Land may not be valid yet
2033
1381 { 2034 {
1382 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2035 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1383 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2036 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1404,6 +2057,7 @@ namespace OpenSim.Region.Framework.Scenes
1404 } 2057 }
1405 } 2058 }
1406 } 2059 }
2060
1407 } 2061 }
1408 2062
1409 if (m_scene.UseBackup && HasGroupChanged) 2063 if (m_scene.UseBackup && HasGroupChanged)
@@ -1411,10 +2065,30 @@ namespace OpenSim.Region.Framework.Scenes
1411 // don't backup while it's selected or you're asking for changes mid stream. 2065 // don't backup while it's selected or you're asking for changes mid stream.
1412 if (isTimeToPersist() || forcedBackup) 2066 if (isTimeToPersist() || forcedBackup)
1413 { 2067 {
2068 if (m_rootPart.PhysActor != null &&
2069 (!m_rootPart.PhysActor.IsPhysical))
2070 {
2071 // Possible ghost prim
2072 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2073 {
2074 foreach (SceneObjectPart part in m_parts.GetArray())
2075 {
2076 // Re-set physics actor positions and
2077 // orientations
2078 part.GroupPosition = m_rootPart.GroupPosition;
2079 }
2080 }
2081 }
1414// m_log.DebugFormat( 2082// m_log.DebugFormat(
1415// "[SCENE]: Storing {0}, {1} in {2}", 2083// "[SCENE]: Storing {0}, {1} in {2}",
1416// Name, UUID, m_scene.RegionInfo.RegionName); 2084// Name, UUID, m_scene.RegionInfo.RegionName);
1417 2085
2086 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2087 {
2088 RootPart.Shape.State = 0;
2089 ScheduleGroupForFullUpdate();
2090 }
2091
1418 SceneObjectGroup backup_group = Copy(false); 2092 SceneObjectGroup backup_group = Copy(false);
1419 backup_group.RootPart.Velocity = RootPart.Velocity; 2093 backup_group.RootPart.Velocity = RootPart.Velocity;
1420 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2094 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1424,6 +2098,16 @@ namespace OpenSim.Region.Framework.Scenes
1424 HasGroupChangedDueToDelink = false; 2098 HasGroupChangedDueToDelink = false;
1425 2099
1426 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2100 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2101/*
2102 backup_group.ForEachPart(delegate(SceneObjectPart part)
2103 {
2104 if (part.KeyframeMotion != null)
2105 {
2106 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2107// part.KeyframeMotion.UpdateSceneObject(this);
2108 }
2109 });
2110*/
1427 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2111 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1428 2112
1429 backup_group.ForEachPart(delegate(SceneObjectPart part) 2113 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1480,10 +2164,14 @@ namespace OpenSim.Region.Framework.Scenes
1480 /// <returns></returns> 2164 /// <returns></returns>
1481 public SceneObjectGroup Copy(bool userExposed) 2165 public SceneObjectGroup Copy(bool userExposed)
1482 { 2166 {
2167 m_dupeInProgress = true;
1483 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2168 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1484 dupe.m_isBackedUp = false; 2169 dupe.m_isBackedUp = false;
1485 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2170 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1486 2171
2172 // new group as no sitting avatars
2173 dupe.m_linkedAvatars = new List<ScenePresence>();
2174
1487 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2175 // 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! 2176 // 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! 2177 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1494,7 +2182,7 @@ namespace OpenSim.Region.Framework.Scenes
1494 // This is only necessary when userExposed is false! 2182 // This is only necessary when userExposed is false!
1495 2183
1496 bool previousAttachmentStatus = dupe.IsAttachment; 2184 bool previousAttachmentStatus = dupe.IsAttachment;
1497 2185
1498 if (!userExposed) 2186 if (!userExposed)
1499 dupe.IsAttachment = true; 2187 dupe.IsAttachment = true;
1500 2188
@@ -1507,16 +2195,17 @@ namespace OpenSim.Region.Framework.Scenes
1507 2195
1508 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2196 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1509 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2197 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2198
1510 2199
1511 if (userExposed) 2200 if (userExposed)
1512 dupe.m_rootPart.TrimPermissions(); 2201 dupe.m_rootPart.TrimPermissions();
1513 2202
1514 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2203 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1515 2204
1516 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2205 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1517 { 2206 {
1518 return p1.LinkNum.CompareTo(p2.LinkNum); 2207 return p1.LinkNum.CompareTo(p2.LinkNum);
1519 } 2208 }
1520 ); 2209 );
1521 2210
1522 foreach (SceneObjectPart part in partList) 2211 foreach (SceneObjectPart part in partList)
@@ -1526,41 +2215,56 @@ namespace OpenSim.Region.Framework.Scenes
1526 { 2215 {
1527 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2216 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1528 newPart.LinkNum = part.LinkNum; 2217 newPart.LinkNum = part.LinkNum;
1529 } 2218 if (userExposed)
2219 newPart.ParentID = dupe.m_rootPart.LocalId;
2220 }
1530 else 2221 else
1531 { 2222 {
1532 newPart = dupe.m_rootPart; 2223 newPart = dupe.m_rootPart;
1533 } 2224 }
2225/*
2226 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2227 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1534 2228
1535 // Need to duplicate the physics actor as well 2229 // Need to duplicate the physics actor as well
1536 PhysicsActor originalPartPa = part.PhysActor; 2230 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1537 if (originalPartPa != null && userExposed)
1538 { 2231 {
1539 PrimitiveBaseShape pbs = newPart.Shape; 2232 PrimitiveBaseShape pbs = newPart.Shape;
1540
1541 newPart.PhysActor 2233 newPart.PhysActor
1542 = m_scene.PhysicsScene.AddPrimShape( 2234 = m_scene.PhysicsScene.AddPrimShape(
1543 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2235 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1544 pbs, 2236 pbs,
1545 newPart.AbsolutePosition, 2237 newPart.AbsolutePosition,
1546 newPart.Scale, 2238 newPart.Scale,
1547 newPart.RotationOffset, 2239 newPart.GetWorldRotation(),
1548 originalPartPa.IsPhysical, 2240 isphys,
2241 isphan,
1549 newPart.LocalId); 2242 newPart.LocalId);
1550 2243
1551 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2244 newPart.DoPhysicsPropertyUpdate(isphys, true);
1552 } 2245 */
2246 if (userExposed)
2247 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2248// }
2249 // copy keyframemotion
2250 if (part.KeyframeMotion != null)
2251 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1553 } 2252 }
1554 2253
1555 if (userExposed) 2254 if (userExposed)
1556 { 2255 {
1557 dupe.UpdateParentIDs(); 2256// done above dupe.UpdateParentIDs();
2257
2258 if (dupe.m_rootPart.PhysActor != null)
2259 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2260
1558 dupe.HasGroupChanged = true; 2261 dupe.HasGroupChanged = true;
1559 dupe.AttachToBackup(); 2262 dupe.AttachToBackup();
1560 2263
1561 ScheduleGroupForFullUpdate(); 2264 ScheduleGroupForFullUpdate();
1562 } 2265 }
1563 2266
2267 m_dupeInProgress = false;
1564 return dupe; 2268 return dupe;
1565 } 2269 }
1566 2270
@@ -1572,11 +2276,24 @@ namespace OpenSim.Region.Framework.Scenes
1572 /// <param name="cGroupID"></param> 2276 /// <param name="cGroupID"></param>
1573 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2277 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1574 { 2278 {
1575 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2279 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2280 // give newpart a new local ID lettng old part keep same
2281 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2282 newpart.LocalId = m_scene.AllocateLocalId();
2283
2284 SetRootPart(newpart);
2285 if (userExposed)
2286 RootPart.Velocity = Vector3.Zero; // In case source is moving
1576 } 2287 }
1577 2288
1578 public void ScriptSetPhysicsStatus(bool usePhysics) 2289 public void ScriptSetPhysicsStatus(bool usePhysics)
1579 { 2290 {
2291 if (usePhysics)
2292 {
2293 if (RootPart.KeyframeMotion != null)
2294 RootPart.KeyframeMotion.Stop();
2295 RootPart.KeyframeMotion = null;
2296 }
1580 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2297 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1581 } 2298 }
1582 2299
@@ -1624,27 +2341,14 @@ namespace OpenSim.Region.Framework.Scenes
1624 2341
1625 if (pa != null) 2342 if (pa != null)
1626 { 2343 {
1627 pa.AddForce(impulse, true); 2344 // false to be applied as a impulse
1628 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2345 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); 2346 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1643 } 2347 }
1644 } 2348 }
1645 } 2349 }
1646 2350
1647 public void setAngularImpulse(Vector3 impulse) 2351 public void ApplyAngularImpulse(Vector3 impulse)
1648 { 2352 {
1649 PhysicsActor pa = RootPart.PhysActor; 2353 PhysicsActor pa = RootPart.PhysActor;
1650 2354
@@ -1652,7 +2356,8 @@ namespace OpenSim.Region.Framework.Scenes
1652 { 2356 {
1653 if (!IsAttachment) 2357 if (!IsAttachment)
1654 { 2358 {
1655 pa.Torque = impulse; 2359 // false to be applied as a impulse
2360 pa.AddAngularForce(impulse, false);
1656 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2361 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1657 } 2362 }
1658 } 2363 }
@@ -1660,20 +2365,10 @@ namespace OpenSim.Region.Framework.Scenes
1660 2365
1661 public Vector3 GetTorque() 2366 public Vector3 GetTorque()
1662 { 2367 {
1663 PhysicsActor pa = RootPart.PhysActor; 2368 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 } 2369 }
1676 2370
2371 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1677 public void moveToTarget(Vector3 target, float tau) 2372 public void moveToTarget(Vector3 target, float tau)
1678 { 2373 {
1679 if (IsAttachment) 2374 if (IsAttachment)
@@ -1705,6 +2400,46 @@ namespace OpenSim.Region.Framework.Scenes
1705 pa.PIDActive = false; 2400 pa.PIDActive = false;
1706 } 2401 }
1707 2402
2403 public void rotLookAt(Quaternion target, float strength, float damping)
2404 {
2405 SceneObjectPart rootpart = m_rootPart;
2406 if (rootpart != null)
2407 {
2408 if (IsAttachment)
2409 {
2410 /*
2411 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2412 if (avatar != null)
2413 {
2414 Rotate the Av?
2415 } */
2416 }
2417 else
2418 {
2419 if (rootpart.PhysActor != null)
2420 { // APID must be implemented in your physics system for this to function.
2421 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2422 rootpart.PhysActor.APIDStrength = strength;
2423 rootpart.PhysActor.APIDDamping = damping;
2424 rootpart.PhysActor.APIDActive = true;
2425 }
2426 }
2427 }
2428 }
2429
2430 public void stopLookAt()
2431 {
2432 SceneObjectPart rootpart = m_rootPart;
2433 if (rootpart != null)
2434 {
2435 if (rootpart.PhysActor != null)
2436 { // APID must be implemented in your physics system for this to function.
2437 rootpart.PhysActor.APIDActive = false;
2438 }
2439 }
2440
2441 }
2442
1708 /// <summary> 2443 /// <summary>
1709 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2444 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1710 /// </summary> 2445 /// </summary>
@@ -1721,7 +2456,7 @@ namespace OpenSim.Region.Framework.Scenes
1721 { 2456 {
1722 pa.PIDHoverHeight = height; 2457 pa.PIDHoverHeight = height;
1723 pa.PIDHoverType = hoverType; 2458 pa.PIDHoverType = hoverType;
1724 pa.PIDTau = tau; 2459 pa.PIDHoverTau = tau;
1725 pa.PIDHoverActive = true; 2460 pa.PIDHoverActive = true;
1726 } 2461 }
1727 else 2462 else
@@ -1761,7 +2496,12 @@ namespace OpenSim.Region.Framework.Scenes
1761 /// <param name="cGroupID"></param> 2496 /// <param name="cGroupID"></param>
1762 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2497 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1763 { 2498 {
1764 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2499 // give new ID to the new part, letting old keep original
2500 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2501 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2502 newPart.LocalId = m_scene.AllocateLocalId();
2503 newPart.SetParent(this);
2504
1765 AddPart(newPart); 2505 AddPart(newPart);
1766 2506
1767 SetPartAsNonRoot(newPart); 2507 SetPartAsNonRoot(newPart);
@@ -1811,6 +2551,7 @@ namespace OpenSim.Region.Framework.Scenes
1811 2551
1812 #endregion 2552 #endregion
1813 2553
2554
1814 public override void Update() 2555 public override void Update()
1815 { 2556 {
1816 // Check that the group was not deleted before the scheduled update 2557 // Check that the group was not deleted before the scheduled update
@@ -1829,19 +2570,8 @@ namespace OpenSim.Region.Framework.Scenes
1829 // check to see if the physical position or rotation warrant an update. 2570 // check to see if the physical position or rotation warrant an update.
1830 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2571 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1831 { 2572 {
1832 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2573 // rootpart SendScheduledUpdates will check if a update is needed
1833 2574 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1834 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
1835 {
1836 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1837 lastPhysGroupPos = AbsolutePosition;
1838 }
1839
1840 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
1841 {
1842 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1843 lastPhysGroupRot = GroupRotation;
1844 }
1845 } 2575 }
1846 2576
1847 SceneObjectPart[] parts = m_parts.GetArray(); 2577 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1900,11 +2630,11 @@ namespace OpenSim.Region.Framework.Scenes
1900 /// Immediately send a full update for this scene object. 2630 /// Immediately send a full update for this scene object.
1901 /// </summary> 2631 /// </summary>
1902 public void SendGroupFullUpdate() 2632 public void SendGroupFullUpdate()
1903 { 2633 {
1904 if (IsDeleted) 2634 if (IsDeleted)
1905 return; 2635 return;
1906 2636
1907// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2637// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1908 2638
1909 RootPart.SendFullUpdateToAllClients(); 2639 RootPart.SendFullUpdateToAllClients();
1910 2640
@@ -2060,6 +2790,11 @@ namespace OpenSim.Region.Framework.Scenes
2060 // 'linkPart' == the root of the group being linked into this group 2790 // 'linkPart' == the root of the group being linked into this group
2061 SceneObjectPart linkPart = objectGroup.m_rootPart; 2791 SceneObjectPart linkPart = objectGroup.m_rootPart;
2062 2792
2793 if (m_rootPart.PhysActor != null)
2794 m_rootPart.PhysActor.Building = true;
2795 if (linkPart.PhysActor != null)
2796 linkPart.PhysActor.Building = true;
2797
2063 // physics flags from group to be applied to linked parts 2798 // physics flags from group to be applied to linked parts
2064 bool grpusephys = UsesPhysics; 2799 bool grpusephys = UsesPhysics;
2065 bool grptemporary = IsTemporary; 2800 bool grptemporary = IsTemporary;
@@ -2085,12 +2820,12 @@ namespace OpenSim.Region.Framework.Scenes
2085 Vector3 axPos = linkPart.OffsetPosition; 2820 Vector3 axPos = linkPart.OffsetPosition;
2086 // Rotate the linking root SOP's position to be relative to the new root prim 2821 // Rotate the linking root SOP's position to be relative to the new root prim
2087 Quaternion parentRot = m_rootPart.RotationOffset; 2822 Quaternion parentRot = m_rootPart.RotationOffset;
2088 axPos *= Quaternion.Inverse(parentRot); 2823 axPos *= Quaternion.Conjugate(parentRot);
2089 linkPart.OffsetPosition = axPos; 2824 linkPart.OffsetPosition = axPos;
2090 2825
2091 // Make the linking root SOP's rotation relative to the new root prim 2826 // Make the linking root SOP's rotation relative to the new root prim
2092 Quaternion oldRot = linkPart.RotationOffset; 2827 Quaternion oldRot = linkPart.RotationOffset;
2093 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2828 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2094 linkPart.RotationOffset = newRot; 2829 linkPart.RotationOffset = newRot;
2095 2830
2096 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2831 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2124,7 +2859,7 @@ namespace OpenSim.Region.Framework.Scenes
2124 linkPart.CreateSelected = true; 2859 linkPart.CreateSelected = true;
2125 2860
2126 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2861 // 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); 2862 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2128 2863
2129 // If the added SOP is physical, also tell the physics engine about the link relationship. 2864 // 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) 2865 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2134,6 +2869,7 @@ namespace OpenSim.Region.Framework.Scenes
2134 } 2869 }
2135 2870
2136 linkPart.LinkNum = linkNum++; 2871 linkPart.LinkNum = linkNum++;
2872 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2137 2873
2138 // Get a list of the SOP's in the old group in order of their linknum's. 2874 // Get a list of the SOP's in the old group in order of their linknum's.
2139 SceneObjectPart[] ogParts = objectGroup.Parts; 2875 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2152,7 +2888,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 2888
2153 // Update the physics flags for the newly added SOP 2889 // Update the physics flags for the newly added SOP
2154 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2890 // (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); 2891 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2156 2892
2157 // If the added SOP is physical, also tell the physics engine about the link relationship. 2893 // 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) 2894 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2170,7 +2906,7 @@ namespace OpenSim.Region.Framework.Scenes
2170 objectGroup.IsDeleted = true; 2906 objectGroup.IsDeleted = true;
2171 2907
2172 objectGroup.m_parts.Clear(); 2908 objectGroup.m_parts.Clear();
2173 2909
2174 // Can't do this yet since backup still makes use of the root part without any synchronization 2910 // Can't do this yet since backup still makes use of the root part without any synchronization
2175// objectGroup.m_rootPart = null; 2911// objectGroup.m_rootPart = null;
2176 2912
@@ -2184,6 +2920,9 @@ namespace OpenSim.Region.Framework.Scenes
2184 // unmoved prims! 2920 // unmoved prims!
2185 ResetChildPrimPhysicsPositions(); 2921 ResetChildPrimPhysicsPositions();
2186 2922
2923 if (m_rootPart.PhysActor != null)
2924 m_rootPart.PhysActor.Building = false;
2925
2187 //HasGroupChanged = true; 2926 //HasGroupChanged = true;
2188 //ScheduleGroupForFullUpdate(); 2927 //ScheduleGroupForFullUpdate();
2189 } 2928 }
@@ -2251,7 +2990,10 @@ namespace OpenSim.Region.Framework.Scenes
2251// m_log.DebugFormat( 2990// m_log.DebugFormat(
2252// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2991// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2253// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2992// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2254 2993
2994 if (m_rootPart.PhysActor != null)
2995 m_rootPart.PhysActor.Building = true;
2996
2255 linkPart.ClearUndoState(); 2997 linkPart.ClearUndoState();
2256 2998
2257 Vector3 worldPos = linkPart.GetWorldPosition(); 2999 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2322,6 +3064,14 @@ namespace OpenSim.Region.Framework.Scenes
2322 3064
2323 // When we delete a group, we currently have to force persist to the database if the object id has changed 3065 // 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) 3066 // (since delete works by deleting all rows which have a given object id)
3067
3068 // this is as it seems to be in sl now
3069 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3070 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3071
3072 if (m_rootPart.PhysActor != null)
3073 m_rootPart.PhysActor.Building = false;
3074
2325 objectGroup.HasGroupChangedDueToDelink = true; 3075 objectGroup.HasGroupChangedDueToDelink = true;
2326 3076
2327 return objectGroup; 3077 return objectGroup;
@@ -2333,6 +3083,8 @@ namespace OpenSim.Region.Framework.Scenes
2333 /// <param name="objectGroup"></param> 3083 /// <param name="objectGroup"></param>
2334 public virtual void DetachFromBackup() 3084 public virtual void DetachFromBackup()
2335 { 3085 {
3086 if (m_scene != null)
3087 m_scene.SceneGraph.FireDetachFromBackup(this);
2336 if (m_isBackedUp && Scene != null) 3088 if (m_isBackedUp && Scene != null)
2337 m_scene.EventManager.OnBackup -= ProcessBackup; 3089 m_scene.EventManager.OnBackup -= ProcessBackup;
2338 3090
@@ -2353,7 +3105,8 @@ namespace OpenSim.Region.Framework.Scenes
2353 Vector3 axPos = part.OffsetPosition; 3105 Vector3 axPos = part.OffsetPosition;
2354 axPos *= parentRot; 3106 axPos *= parentRot;
2355 part.OffsetPosition = axPos; 3107 part.OffsetPosition = axPos;
2356 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3108 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3109 part.GroupPosition = newPos;
2357 part.OffsetPosition = Vector3.Zero; 3110 part.OffsetPosition = Vector3.Zero;
2358 3111
2359 // Compution our rotation to be not relative to the old parent 3112 // Compution our rotation to be not relative to the old parent
@@ -2368,7 +3121,7 @@ namespace OpenSim.Region.Framework.Scenes
2368 part.LinkNum = linkNum; 3121 part.LinkNum = linkNum;
2369 3122
2370 // Compute the new position of this SOP relative to the group position 3123 // Compute the new position of this SOP relative to the group position
2371 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3124 part.OffsetPosition = newPos - AbsolutePosition;
2372 3125
2373 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3126 // (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 3127 // It would have the affect of setting the physics engine position multiple
@@ -2378,18 +3131,19 @@ namespace OpenSim.Region.Framework.Scenes
2378 // Rotate the relative position by the rotation of the group 3131 // Rotate the relative position by the rotation of the group
2379 Quaternion rootRotation = m_rootPart.RotationOffset; 3132 Quaternion rootRotation = m_rootPart.RotationOffset;
2380 Vector3 pos = part.OffsetPosition; 3133 Vector3 pos = part.OffsetPosition;
2381 pos *= Quaternion.Inverse(rootRotation); 3134 pos *= Quaternion.Conjugate(rootRotation);
2382 part.OffsetPosition = pos; 3135 part.OffsetPosition = pos;
2383 3136
2384 // Compute the SOP's rotation relative to the rotation of the group. 3137 // Compute the SOP's rotation relative to the rotation of the group.
2385 parentRot = m_rootPart.RotationOffset; 3138 parentRot = m_rootPart.RotationOffset;
2386 oldRot = part.RotationOffset; 3139 oldRot = part.RotationOffset;
2387 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3140 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2388 part.RotationOffset = newRot; 3141 part.RotationOffset = newRot;
2389 3142
2390 // Since this SOP's state has changed, push those changes into the physics engine 3143 // Since this SOP's state has changed, push those changes into the physics engine
2391 // and the simulator. 3144 // and the simulator.
2392 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3145 // done on caller
3146// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2393 } 3147 }
2394 3148
2395 /// <summary> 3149 /// <summary>
@@ -2411,10 +3165,14 @@ namespace OpenSim.Region.Framework.Scenes
2411 { 3165 {
2412 if (!m_rootPart.BlockGrab) 3166 if (!m_rootPart.BlockGrab)
2413 { 3167 {
2414 Vector3 llmoveforce = pos - AbsolutePosition; 3168/* Vector3 llmoveforce = pos - AbsolutePosition;
2415 Vector3 grabforce = llmoveforce; 3169 Vector3 grabforce = llmoveforce;
2416 grabforce = (grabforce / 10) * pa.Mass; 3170 grabforce = (grabforce / 10) * pa.Mass;
2417 pa.AddForce(grabforce, true); 3171 */
3172 // empirically convert distance diference to a impulse
3173 Vector3 grabforce = pos - AbsolutePosition;
3174 grabforce = grabforce * (pa.Mass/ 10.0f);
3175 pa.AddForce(grabforce, false);
2418 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3176 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2419 } 3177 }
2420 } 3178 }
@@ -2610,6 +3368,8 @@ namespace OpenSim.Region.Framework.Scenes
2610 /// <param name="SetVolumeDetect"></param> 3368 /// <param name="SetVolumeDetect"></param>
2611 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3369 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2612 { 3370 {
3371 HasGroupChanged = true;
3372
2613 SceneObjectPart selectionPart = GetPart(localID); 3373 SceneObjectPart selectionPart = GetPart(localID);
2614 3374
2615 if (SetTemporary && Scene != null) 3375 if (SetTemporary && Scene != null)
@@ -2640,8 +3400,22 @@ namespace OpenSim.Region.Framework.Scenes
2640 } 3400 }
2641 } 3401 }
2642 3402
2643 for (int i = 0; i < parts.Length; i++) 3403 if (parts.Length > 1)
2644 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3404 {
3405 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3406
3407 for (int i = 0; i < parts.Length; i++)
3408 {
3409
3410 if (parts[i].UUID != m_rootPart.UUID)
3411 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3412 }
3413
3414 if (m_rootPart.PhysActor != null)
3415 m_rootPart.PhysActor.Building = false;
3416 }
3417 else
3418 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2645 } 3419 }
2646 } 3420 }
2647 3421
@@ -2654,6 +3428,17 @@ namespace OpenSim.Region.Framework.Scenes
2654 } 3428 }
2655 } 3429 }
2656 3430
3431
3432
3433 /// <summary>
3434 /// Gets the number of parts
3435 /// </summary>
3436 /// <returns></returns>
3437 public int GetPartCount()
3438 {
3439 return Parts.Count();
3440 }
3441
2657 /// <summary> 3442 /// <summary>
2658 /// Update the texture entry for this part 3443 /// Update the texture entry for this part
2659 /// </summary> 3444 /// </summary>
@@ -2670,11 +3455,20 @@ namespace OpenSim.Region.Framework.Scenes
2670 3455
2671 public void AdjustChildPrimPermissions() 3456 public void AdjustChildPrimPermissions()
2672 { 3457 {
3458 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits
3459 uint foldedPerms = RootPart.OwnerMask & 3;
3460
2673 ForEachPart(part => 3461 ForEachPart(part =>
2674 { 3462 {
3463 newOwnerMask &= part.BaseMask;
2675 if (part != RootPart) 3464 if (part != RootPart)
2676 part.ClonePermissions(RootPart); 3465 part.ClonePermissions(RootPart);
2677 }); 3466 });
3467
3468 uint lockMask = ~(uint)PermissionMask.Move;
3469 uint lockBit = RootPart.OwnerMask & (uint)PermissionMask.Move;
3470 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
3471 RootPart.ScheduleFullUpdate();
2678 } 3472 }
2679 3473
2680 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 3474 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2682,8 +3476,24 @@ namespace OpenSim.Region.Framework.Scenes
2682 { 3476 {
2683 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3477 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2684 3478
3479 bool god = Scene.Permissions.IsGod(AgentID);
3480
3481 if (field == 1 && god)
3482 {
3483 ForEachPart(part =>
3484 {
3485 part.BaseMask = RootPart.BaseMask;
3486 });
3487 }
3488
2685 AdjustChildPrimPermissions(); 3489 AdjustChildPrimPermissions();
2686 3490
3491 if (field == 1 && god) // Base mask was set. Update all child part inventories
3492 {
3493 foreach (SceneObjectPart part in Parts)
3494 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3495 }
3496
2687 HasGroupChanged = true; 3497 HasGroupChanged = true;
2688 3498
2689 // Send the group's properties to all clients once all parts are updated 3499 // Send the group's properties to all clients once all parts are updated
@@ -2729,8 +3539,6 @@ namespace OpenSim.Region.Framework.Scenes
2729 3539
2730 PhysicsActor pa = m_rootPart.PhysActor; 3540 PhysicsActor pa = m_rootPart.PhysActor;
2731 3541
2732 RootPart.StoreUndoState(true);
2733
2734 if (Scene != null) 3542 if (Scene != null)
2735 { 3543 {
2736 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3544 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2758,7 +3566,6 @@ namespace OpenSim.Region.Framework.Scenes
2758 SceneObjectPart obPart = parts[i]; 3566 SceneObjectPart obPart = parts[i];
2759 if (obPart.UUID != m_rootPart.UUID) 3567 if (obPart.UUID != m_rootPart.UUID)
2760 { 3568 {
2761// obPart.IgnoreUndoUpdate = true;
2762 Vector3 oldSize = new Vector3(obPart.Scale); 3569 Vector3 oldSize = new Vector3(obPart.Scale);
2763 3570
2764 float f = 1.0f; 3571 float f = 1.0f;
@@ -2870,8 +3677,6 @@ namespace OpenSim.Region.Framework.Scenes
2870 z *= a; 3677 z *= a;
2871 } 3678 }
2872 } 3679 }
2873
2874// obPart.IgnoreUndoUpdate = false;
2875 } 3680 }
2876 } 3681 }
2877 } 3682 }
@@ -2881,9 +3686,7 @@ namespace OpenSim.Region.Framework.Scenes
2881 prevScale.Y *= y; 3686 prevScale.Y *= y;
2882 prevScale.Z *= z; 3687 prevScale.Z *= z;
2883 3688
2884// RootPart.IgnoreUndoUpdate = true;
2885 RootPart.Resize(prevScale); 3689 RootPart.Resize(prevScale);
2886// RootPart.IgnoreUndoUpdate = false;
2887 3690
2888 for (int i = 0; i < parts.Length; i++) 3691 for (int i = 0; i < parts.Length; i++)
2889 { 3692 {
@@ -2891,8 +3694,6 @@ namespace OpenSim.Region.Framework.Scenes
2891 3694
2892 if (obPart.UUID != m_rootPart.UUID) 3695 if (obPart.UUID != m_rootPart.UUID)
2893 { 3696 {
2894 obPart.IgnoreUndoUpdate = true;
2895
2896 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3697 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2897 currentpos.X *= x; 3698 currentpos.X *= x;
2898 currentpos.Y *= y; 3699 currentpos.Y *= y;
@@ -2905,16 +3706,12 @@ namespace OpenSim.Region.Framework.Scenes
2905 3706
2906 obPart.Resize(newSize); 3707 obPart.Resize(newSize);
2907 obPart.UpdateOffSet(currentpos); 3708 obPart.UpdateOffSet(currentpos);
2908
2909 obPart.IgnoreUndoUpdate = false;
2910 } 3709 }
2911 3710
2912// obPart.IgnoreUndoUpdate = false; 3711 HasGroupChanged = true;
2913// obPart.StoreUndoState(); 3712 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3713 ScheduleGroupForTerseUpdate();
2914 } 3714 }
2915
2916// m_log.DebugFormat(
2917// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2918 } 3715 }
2919 3716
2920 #endregion 3717 #endregion
@@ -2927,14 +3724,6 @@ namespace OpenSim.Region.Framework.Scenes
2927 /// <param name="pos"></param> 3724 /// <param name="pos"></param>
2928 public void UpdateGroupPosition(Vector3 pos) 3725 public void UpdateGroupPosition(Vector3 pos)
2929 { 3726 {
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)) 3727 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2939 { 3728 {
2940 if (IsAttachment) 3729 if (IsAttachment)
@@ -2967,21 +3756,17 @@ namespace OpenSim.Region.Framework.Scenes
2967 /// </summary> 3756 /// </summary>
2968 /// <param name="pos"></param> 3757 /// <param name="pos"></param>
2969 /// <param name="localID"></param> 3758 /// <param name="localID"></param>
3759 ///
3760
2970 public void UpdateSinglePosition(Vector3 pos, uint localID) 3761 public void UpdateSinglePosition(Vector3 pos, uint localID)
2971 { 3762 {
2972 SceneObjectPart part = GetPart(localID); 3763 SceneObjectPart part = GetPart(localID);
2973 3764
2974// SceneObjectPart[] parts = m_parts.GetArray();
2975// for (int i = 0; i < parts.Length; i++)
2976// parts[i].StoreUndoState();
2977
2978 if (part != null) 3765 if (part != null)
2979 { 3766 {
2980// m_log.DebugFormat( 3767// unlock parts position change
2981// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3768 if (m_rootPart.PhysActor != null)
2982 3769 m_rootPart.PhysActor.Building = true;
2983 part.StoreUndoState(false);
2984 part.IgnoreUndoUpdate = true;
2985 3770
2986 if (part.UUID == m_rootPart.UUID) 3771 if (part.UUID == m_rootPart.UUID)
2987 { 3772 {
@@ -2992,8 +3777,10 @@ namespace OpenSim.Region.Framework.Scenes
2992 part.UpdateOffSet(pos); 3777 part.UpdateOffSet(pos);
2993 } 3778 }
2994 3779
3780 if (m_rootPart.PhysActor != null)
3781 m_rootPart.PhysActor.Building = false;
3782
2995 HasGroupChanged = true; 3783 HasGroupChanged = true;
2996 part.IgnoreUndoUpdate = false;
2997 } 3784 }
2998 } 3785 }
2999 3786
@@ -3003,13 +3790,7 @@ namespace OpenSim.Region.Framework.Scenes
3003 /// <param name="pos"></param> 3790 /// <param name="pos"></param>
3004 public void UpdateRootPosition(Vector3 pos) 3791 public void UpdateRootPosition(Vector3 pos)
3005 { 3792 {
3006// m_log.DebugFormat( 3793 // 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); 3794 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3014 Vector3 oldPos = 3795 Vector3 oldPos =
3015 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3796 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3032,7 +3813,14 @@ namespace OpenSim.Region.Framework.Scenes
3032 AbsolutePosition = newPos; 3813 AbsolutePosition = newPos;
3033 3814
3034 HasGroupChanged = true; 3815 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3816 if (m_rootPart.Undoing)
3817 {
3818 ScheduleGroupForFullUpdate();
3819 }
3820 else
3821 {
3822 ScheduleGroupForTerseUpdate();
3823 }
3036 } 3824 }
3037 3825
3038 #endregion 3826 #endregion
@@ -3045,24 +3833,16 @@ namespace OpenSim.Region.Framework.Scenes
3045 /// <param name="rot"></param> 3833 /// <param name="rot"></param>
3046 public void UpdateGroupRotationR(Quaternion rot) 3834 public void UpdateGroupRotationR(Quaternion rot)
3047 { 3835 {
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); 3836 m_rootPart.UpdateRotation(rot);
3058 3837
3838/* this is done by rootpart RotationOffset set called by UpdateRotation
3059 PhysicsActor actor = m_rootPart.PhysActor; 3839 PhysicsActor actor = m_rootPart.PhysActor;
3060 if (actor != null) 3840 if (actor != null)
3061 { 3841 {
3062 actor.Orientation = m_rootPart.RotationOffset; 3842 actor.Orientation = m_rootPart.RotationOffset;
3063 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3843 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3064 } 3844 }
3065 3845*/
3066 HasGroupChanged = true; 3846 HasGroupChanged = true;
3067 ScheduleGroupForTerseUpdate(); 3847 ScheduleGroupForTerseUpdate();
3068 } 3848 }
@@ -3074,16 +3854,6 @@ namespace OpenSim.Region.Framework.Scenes
3074 /// <param name="rot"></param> 3854 /// <param name="rot"></param>
3075 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3855 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3076 { 3856 {
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); 3857 m_rootPart.UpdateRotation(rot);
3088 3858
3089 PhysicsActor actor = m_rootPart.PhysActor; 3859 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3102,8 +3872,6 @@ namespace OpenSim.Region.Framework.Scenes
3102 3872
3103 HasGroupChanged = true; 3873 HasGroupChanged = true;
3104 ScheduleGroupForTerseUpdate(); 3874 ScheduleGroupForTerseUpdate();
3105
3106 RootPart.IgnoreUndoUpdate = false;
3107 } 3875 }
3108 3876
3109 /// <summary> 3877 /// <summary>
@@ -3116,13 +3884,11 @@ namespace OpenSim.Region.Framework.Scenes
3116 SceneObjectPart part = GetPart(localID); 3884 SceneObjectPart part = GetPart(localID);
3117 3885
3118 SceneObjectPart[] parts = m_parts.GetArray(); 3886 SceneObjectPart[] parts = m_parts.GetArray();
3119 for (int i = 0; i < parts.Length; i++)
3120 parts[i].StoreUndoState();
3121 3887
3122 if (part != null) 3888 if (part != null)
3123 { 3889 {
3124// m_log.DebugFormat( 3890 if (m_rootPart.PhysActor != null)
3125// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3891 m_rootPart.PhysActor.Building = true;
3126 3892
3127 if (part.UUID == m_rootPart.UUID) 3893 if (part.UUID == m_rootPart.UUID)
3128 { 3894 {
@@ -3132,6 +3898,9 @@ namespace OpenSim.Region.Framework.Scenes
3132 { 3898 {
3133 part.UpdateRotation(rot); 3899 part.UpdateRotation(rot);
3134 } 3900 }
3901
3902 if (m_rootPart.PhysActor != null)
3903 m_rootPart.PhysActor.Building = false;
3135 } 3904 }
3136 } 3905 }
3137 3906
@@ -3145,12 +3914,8 @@ namespace OpenSim.Region.Framework.Scenes
3145 SceneObjectPart part = GetPart(localID); 3914 SceneObjectPart part = GetPart(localID);
3146 if (part != null) 3915 if (part != null)
3147 { 3916 {
3148// m_log.DebugFormat( 3917 if (m_rootPart.PhysActor != null)
3149// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3918 m_rootPart.PhysActor.Building = true;
3150// part.Name, part.LocalId, rot);
3151
3152 part.StoreUndoState();
3153 part.IgnoreUndoUpdate = true;
3154 3919
3155 if (part.UUID == m_rootPart.UUID) 3920 if (part.UUID == m_rootPart.UUID)
3156 { 3921 {
@@ -3163,7 +3928,8 @@ namespace OpenSim.Region.Framework.Scenes
3163 part.OffsetPosition = pos; 3928 part.OffsetPosition = pos;
3164 } 3929 }
3165 3930
3166 part.IgnoreUndoUpdate = false; 3931 if (m_rootPart.PhysActor != null)
3932 m_rootPart.PhysActor.Building = false;
3167 } 3933 }
3168 } 3934 }
3169 3935
@@ -3173,15 +3939,12 @@ namespace OpenSim.Region.Framework.Scenes
3173 /// <param name="rot"></param> 3939 /// <param name="rot"></param>
3174 public void UpdateRootRotation(Quaternion rot) 3940 public void UpdateRootRotation(Quaternion rot)
3175 { 3941 {
3176// m_log.DebugFormat( 3942 // 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; 3943 Quaternion axRot = rot;
3181 Quaternion oldParentRot = m_rootPart.RotationOffset; 3944 Quaternion oldParentRot = m_rootPart.RotationOffset;
3182 3945
3183 m_rootPart.StoreUndoState(); 3946 //Don't use UpdateRotation because it schedules an update prematurely
3184 m_rootPart.UpdateRotation(rot); 3947 m_rootPart.RotationOffset = rot;
3185 3948
3186 PhysicsActor pa = m_rootPart.PhysActor; 3949 PhysicsActor pa = m_rootPart.PhysActor;
3187 3950
@@ -3197,35 +3960,145 @@ namespace OpenSim.Region.Framework.Scenes
3197 SceneObjectPart prim = parts[i]; 3960 SceneObjectPart prim = parts[i];
3198 if (prim.UUID != m_rootPart.UUID) 3961 if (prim.UUID != m_rootPart.UUID)
3199 { 3962 {
3200 prim.IgnoreUndoUpdate = true; 3963 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3964 NewRot = Quaternion.Inverse(axRot) * NewRot;
3965 prim.RotationOffset = NewRot;
3966
3201 Vector3 axPos = prim.OffsetPosition; 3967 Vector3 axPos = prim.OffsetPosition;
3968
3202 axPos *= oldParentRot; 3969 axPos *= oldParentRot;
3203 axPos *= Quaternion.Inverse(axRot); 3970 axPos *= Quaternion.Inverse(axRot);
3204 prim.OffsetPosition = axPos; 3971 prim.OffsetPosition = axPos;
3205 Quaternion primsRot = prim.RotationOffset; 3972 }
3206 Quaternion newRot = oldParentRot * primsRot; 3973 }
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 3974
3224 m_rootPart.ScheduleTerseUpdate(); 3975 HasGroupChanged = true;
3976 ScheduleGroupForFullUpdate();
3977 }
3225 3978
3226// m_log.DebugFormat( 3979 private enum updatetype :int
3227// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3980 {
3228// Name, LocalId, rot); 3981 none = 0,
3982 partterse = 1,
3983 partfull = 2,
3984 groupterse = 3,
3985 groupfull = 4
3986 }
3987
3988 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3989 {
3990 // TODO this still as excessive *.Schedule*Update()s
3991
3992 if (part != null && part.ParentGroup != null)
3993 {
3994 ObjectChangeType change = data.change;
3995 bool togroup = ((change & ObjectChangeType.Group) != 0);
3996 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3997
3998 SceneObjectGroup group = part.ParentGroup;
3999 PhysicsActor pha = group.RootPart.PhysActor;
4000
4001 updatetype updateType = updatetype.none;
4002
4003 if (togroup)
4004 {
4005 // related to group
4006 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4007 {
4008 if ((change & ObjectChangeType.Rotation) != 0)
4009 {
4010 group.RootPart.UpdateRotation(data.rotation);
4011 updateType = updatetype.none;
4012 }
4013 if ((change & ObjectChangeType.Position) != 0)
4014 {
4015 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4016 UpdateGroupPosition(data.position);
4017 updateType = updatetype.groupterse;
4018 }
4019 else
4020 // ugly rotation update of all parts
4021 {
4022 group.ResetChildPrimPhysicsPositions();
4023 }
4024
4025 }
4026 if ((change & ObjectChangeType.Scale) != 0)
4027 {
4028 if (pha != null)
4029 pha.Building = true;
4030
4031 group.GroupResize(data.scale);
4032 updateType = updatetype.none;
4033
4034 if (pha != null)
4035 pha.Building = false;
4036 }
4037 }
4038 else
4039 {
4040 // related to single prim in a link-set ( ie group)
4041 if (pha != null)
4042 pha.Building = true;
4043
4044 // root part is special
4045 // parts offset positions or rotations need to change also
4046
4047 if (part == group.RootPart)
4048 {
4049 if ((change & ObjectChangeType.Rotation) != 0)
4050 group.UpdateRootRotation(data.rotation);
4051 if ((change & ObjectChangeType.Position) != 0)
4052 group.UpdateRootPosition(data.position);
4053 if ((change & ObjectChangeType.Scale) != 0)
4054 part.Resize(data.scale);
4055 }
4056 else
4057 {
4058 if ((change & ObjectChangeType.Position) != 0)
4059 {
4060 part.OffsetPosition = data.position;
4061 updateType = updatetype.partterse;
4062 }
4063 if ((change & ObjectChangeType.Rotation) != 0)
4064 {
4065 part.UpdateRotation(data.rotation);
4066 updateType = updatetype.none;
4067 }
4068 if ((change & ObjectChangeType.Scale) != 0)
4069 {
4070 part.Resize(data.scale);
4071 updateType = updatetype.none;
4072 }
4073 }
4074
4075 if (pha != null)
4076 pha.Building = false;
4077 }
4078
4079 if (updateType != updatetype.none)
4080 {
4081 group.HasGroupChanged = true;
4082
4083 switch (updateType)
4084 {
4085 case updatetype.partterse:
4086 part.ScheduleTerseUpdate();
4087 break;
4088 case updatetype.partfull:
4089 part.ScheduleFullUpdate();
4090 break;
4091 case updatetype.groupterse:
4092 group.ScheduleGroupForTerseUpdate();
4093 break;
4094 case updatetype.groupfull:
4095 group.ScheduleGroupForFullUpdate();
4096 break;
4097 default:
4098 break;
4099 }
4100 }
4101 }
3229 } 4102 }
3230 4103
3231 #endregion 4104 #endregion
@@ -3324,10 +4197,11 @@ namespace OpenSim.Region.Framework.Scenes
3324 scriptPosTarget target = m_targets[idx]; 4197 scriptPosTarget target = m_targets[idx];
3325 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4198 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3326 { 4199 {
4200 at_target = true;
4201
3327 // trigger at_target 4202 // trigger at_target
3328 if (m_scriptListens_atTarget) 4203 if (m_scriptListens_atTarget)
3329 { 4204 {
3330 at_target = true;
3331 scriptPosTarget att = new scriptPosTarget(); 4205 scriptPosTarget att = new scriptPosTarget();
3332 att.targetPos = target.targetPos; 4206 att.targetPos = target.targetPos;
3333 att.tolerance = target.tolerance; 4207 att.tolerance = target.tolerance;
@@ -3445,11 +4319,50 @@ namespace OpenSim.Region.Framework.Scenes
3445 } 4319 }
3446 } 4320 }
3447 } 4321 }
3448 4322
4323 public Vector3 GetGeometricCenter()
4324 {
4325 // this is not real geometric center but a average of positions relative to root prim acording to
4326 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4327 // ignoring tortured prims details since sl also seems to ignore
4328 // so no real use in doing it on physics
4329
4330 Vector3 gc = Vector3.Zero;
4331
4332 int nparts = m_parts.Count;
4333 if (nparts <= 1)
4334 return gc;
4335
4336 SceneObjectPart[] parts = m_parts.GetArray();
4337 nparts = parts.Length; // just in case it changed
4338 if (nparts <= 1)
4339 return gc;
4340
4341 Quaternion parentRot = RootPart.RotationOffset;
4342 Vector3 pPos;
4343
4344 // average all parts positions
4345 for (int i = 0; i < nparts; i++)
4346 {
4347 // do it directly
4348 // gc += parts[i].GetWorldPosition();
4349 if (parts[i] != RootPart)
4350 {
4351 pPos = parts[i].OffsetPosition;
4352 gc += pPos;
4353 }
4354
4355 }
4356 gc /= nparts;
4357
4358 // relative to root:
4359// gc -= AbsolutePosition;
4360 return gc;
4361 }
4362
3449 public float GetMass() 4363 public float GetMass()
3450 { 4364 {
3451 float retmass = 0f; 4365 float retmass = 0f;
3452
3453 SceneObjectPart[] parts = m_parts.GetArray(); 4366 SceneObjectPart[] parts = m_parts.GetArray();
3454 for (int i = 0; i < parts.Length; i++) 4367 for (int i = 0; i < parts.Length; i++)
3455 retmass += parts[i].GetMass(); 4368 retmass += parts[i].GetMass();
@@ -3457,6 +4370,39 @@ namespace OpenSim.Region.Framework.Scenes
3457 return retmass; 4370 return retmass;
3458 } 4371 }
3459 4372
4373 // center of mass of full object
4374 public Vector3 GetCenterOfMass()
4375 {
4376 PhysicsActor pa = RootPart.PhysActor;
4377
4378 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4379 {
4380 // physics knows better about center of mass of physical prims
4381 Vector3 tmp = pa.CenterOfMass;
4382 return tmp;
4383 }
4384
4385 Vector3 Ptot = Vector3.Zero;
4386 float totmass = 0f;
4387 float m;
4388
4389 SceneObjectPart[] parts = m_parts.GetArray();
4390 for (int i = 0; i < parts.Length; i++)
4391 {
4392 m = parts[i].GetMass();
4393 Ptot += parts[i].GetPartCenterOfMass() * m;
4394 totmass += m;
4395 }
4396
4397 if (totmass == 0)
4398 totmass = 0;
4399 else
4400 totmass = 1 / totmass;
4401 Ptot *= totmass;
4402
4403 return Ptot;
4404 }
4405
3460 /// <summary> 4406 /// <summary>
3461 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4407 /// 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. 4408 /// the physics engine can use it.
@@ -3636,6 +4582,14 @@ namespace OpenSim.Region.Framework.Scenes
3636 FromItemID = uuid; 4582 FromItemID = uuid;
3637 } 4583 }
3638 4584
4585 public void ResetOwnerChangeFlag()
4586 {
4587 ForEachPart(delegate(SceneObjectPart part)
4588 {
4589 part.ResetOwnerChangeFlag();
4590 });
4591 }
4592
3639 #endregion 4593 #endregion
3640 } 4594 }
3641} 4595}