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.cs1416
1 files changed, 1186 insertions, 230 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 15795e5..9c6a94b 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)
@@ -1703,8 +2398,50 @@ namespace OpenSim.Region.Framework.Scenes
1703 2398
1704 if (pa != null) 2399 if (pa != null)
1705 pa.PIDActive = false; 2400 pa.PIDActive = false;
2401
2402 RootPart.ScheduleTerseUpdate(); // send a stop information
1706 } 2403 }
1707 2404
2405 public void rotLookAt(Quaternion target, float strength, float damping)
2406 {
2407 SceneObjectPart rootpart = m_rootPart;
2408 if (rootpart != null)
2409 {
2410 if (IsAttachment)
2411 {
2412 /*
2413 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2414 if (avatar != null)
2415 {
2416 Rotate the Av?
2417 } */
2418 }
2419 else
2420 {
2421 if (rootpart.PhysActor != null)
2422 { // APID must be implemented in your physics system for this to function.
2423 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2424 rootpart.PhysActor.APIDStrength = strength;
2425 rootpart.PhysActor.APIDDamping = damping;
2426 rootpart.PhysActor.APIDActive = true;
2427 }
2428 }
2429 }
2430 }
2431
2432 public void stopLookAt()
2433 {
2434 SceneObjectPart rootpart = m_rootPart;
2435 if (rootpart != null)
2436 {
2437 if (rootpart.PhysActor != null)
2438 { // APID must be implemented in your physics system for this to function.
2439 rootpart.PhysActor.APIDActive = false;
2440 }
2441 }
2442
2443 }
2444
1708 /// <summary> 2445 /// <summary>
1709 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2446 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1710 /// </summary> 2447 /// </summary>
@@ -1721,7 +2458,7 @@ namespace OpenSim.Region.Framework.Scenes
1721 { 2458 {
1722 pa.PIDHoverHeight = height; 2459 pa.PIDHoverHeight = height;
1723 pa.PIDHoverType = hoverType; 2460 pa.PIDHoverType = hoverType;
1724 pa.PIDTau = tau; 2461 pa.PIDHoverTau = tau;
1725 pa.PIDHoverActive = true; 2462 pa.PIDHoverActive = true;
1726 } 2463 }
1727 else 2464 else
@@ -1761,7 +2498,12 @@ namespace OpenSim.Region.Framework.Scenes
1761 /// <param name="cGroupID"></param> 2498 /// <param name="cGroupID"></param>
1762 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2499 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1763 { 2500 {
1764 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2501 // give new ID to the new part, letting old keep original
2502 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2503 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2504 newPart.LocalId = m_scene.AllocateLocalId();
2505 newPart.SetParent(this);
2506
1765 AddPart(newPart); 2507 AddPart(newPart);
1766 2508
1767 SetPartAsNonRoot(newPart); 2509 SetPartAsNonRoot(newPart);
@@ -1811,6 +2553,7 @@ namespace OpenSim.Region.Framework.Scenes
1811 2553
1812 #endregion 2554 #endregion
1813 2555
2556
1814 public override void Update() 2557 public override void Update()
1815 { 2558 {
1816 // Check that the group was not deleted before the scheduled update 2559 // Check that the group was not deleted before the scheduled update
@@ -1829,19 +2572,8 @@ namespace OpenSim.Region.Framework.Scenes
1829 // check to see if the physical position or rotation warrant an update. 2572 // check to see if the physical position or rotation warrant an update.
1830 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2573 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1831 { 2574 {
1832 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2575 // rootpart SendScheduledUpdates will check if a update is needed
1833 2576 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 } 2577 }
1846 2578
1847 SceneObjectPart[] parts = m_parts.GetArray(); 2579 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1900,11 +2632,11 @@ namespace OpenSim.Region.Framework.Scenes
1900 /// Immediately send a full update for this scene object. 2632 /// Immediately send a full update for this scene object.
1901 /// </summary> 2633 /// </summary>
1902 public void SendGroupFullUpdate() 2634 public void SendGroupFullUpdate()
1903 { 2635 {
1904 if (IsDeleted) 2636 if (IsDeleted)
1905 return; 2637 return;
1906 2638
1907// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2639// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1908 2640
1909 RootPart.SendFullUpdateToAllClients(); 2641 RootPart.SendFullUpdateToAllClients();
1910 2642
@@ -2060,6 +2792,11 @@ namespace OpenSim.Region.Framework.Scenes
2060 // 'linkPart' == the root of the group being linked into this group 2792 // 'linkPart' == the root of the group being linked into this group
2061 SceneObjectPart linkPart = objectGroup.m_rootPart; 2793 SceneObjectPart linkPart = objectGroup.m_rootPart;
2062 2794
2795 if (m_rootPart.PhysActor != null)
2796 m_rootPart.PhysActor.Building = true;
2797 if (linkPart.PhysActor != null)
2798 linkPart.PhysActor.Building = true;
2799
2063 // physics flags from group to be applied to linked parts 2800 // physics flags from group to be applied to linked parts
2064 bool grpusephys = UsesPhysics; 2801 bool grpusephys = UsesPhysics;
2065 bool grptemporary = IsTemporary; 2802 bool grptemporary = IsTemporary;
@@ -2085,12 +2822,12 @@ namespace OpenSim.Region.Framework.Scenes
2085 Vector3 axPos = linkPart.OffsetPosition; 2822 Vector3 axPos = linkPart.OffsetPosition;
2086 // Rotate the linking root SOP's position to be relative to the new root prim 2823 // Rotate the linking root SOP's position to be relative to the new root prim
2087 Quaternion parentRot = m_rootPart.RotationOffset; 2824 Quaternion parentRot = m_rootPart.RotationOffset;
2088 axPos *= Quaternion.Inverse(parentRot); 2825 axPos *= Quaternion.Conjugate(parentRot);
2089 linkPart.OffsetPosition = axPos; 2826 linkPart.OffsetPosition = axPos;
2090 2827
2091 // Make the linking root SOP's rotation relative to the new root prim 2828 // Make the linking root SOP's rotation relative to the new root prim
2092 Quaternion oldRot = linkPart.RotationOffset; 2829 Quaternion oldRot = linkPart.RotationOffset;
2093 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2830 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2094 linkPart.RotationOffset = newRot; 2831 linkPart.RotationOffset = newRot;
2095 2832
2096 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2833 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2124,7 +2861,7 @@ namespace OpenSim.Region.Framework.Scenes
2124 linkPart.CreateSelected = true; 2861 linkPart.CreateSelected = true;
2125 2862
2126 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2863 // 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); 2864 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2128 2865
2129 // If the added SOP is physical, also tell the physics engine about the link relationship. 2866 // 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) 2867 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2134,6 +2871,7 @@ namespace OpenSim.Region.Framework.Scenes
2134 } 2871 }
2135 2872
2136 linkPart.LinkNum = linkNum++; 2873 linkPart.LinkNum = linkNum++;
2874 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2137 2875
2138 // Get a list of the SOP's in the old group in order of their linknum's. 2876 // Get a list of the SOP's in the old group in order of their linknum's.
2139 SceneObjectPart[] ogParts = objectGroup.Parts; 2877 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2152,7 +2890,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 2890
2153 // Update the physics flags for the newly added SOP 2891 // Update the physics flags for the newly added SOP
2154 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2892 // (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); 2893 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2156 2894
2157 // If the added SOP is physical, also tell the physics engine about the link relationship. 2895 // 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) 2896 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2170,7 +2908,7 @@ namespace OpenSim.Region.Framework.Scenes
2170 objectGroup.IsDeleted = true; 2908 objectGroup.IsDeleted = true;
2171 2909
2172 objectGroup.m_parts.Clear(); 2910 objectGroup.m_parts.Clear();
2173 2911
2174 // Can't do this yet since backup still makes use of the root part without any synchronization 2912 // Can't do this yet since backup still makes use of the root part without any synchronization
2175// objectGroup.m_rootPart = null; 2913// objectGroup.m_rootPart = null;
2176 2914
@@ -2184,6 +2922,9 @@ namespace OpenSim.Region.Framework.Scenes
2184 // unmoved prims! 2922 // unmoved prims!
2185 ResetChildPrimPhysicsPositions(); 2923 ResetChildPrimPhysicsPositions();
2186 2924
2925 if (m_rootPart.PhysActor != null)
2926 m_rootPart.PhysActor.Building = false;
2927
2187 //HasGroupChanged = true; 2928 //HasGroupChanged = true;
2188 //ScheduleGroupForFullUpdate(); 2929 //ScheduleGroupForFullUpdate();
2189 } 2930 }
@@ -2251,7 +2992,10 @@ namespace OpenSim.Region.Framework.Scenes
2251// m_log.DebugFormat( 2992// m_log.DebugFormat(
2252// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2993// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2253// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2994// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2254 2995
2996 if (m_rootPart.PhysActor != null)
2997 m_rootPart.PhysActor.Building = true;
2998
2255 linkPart.ClearUndoState(); 2999 linkPart.ClearUndoState();
2256 3000
2257 Vector3 worldPos = linkPart.GetWorldPosition(); 3001 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2322,6 +3066,14 @@ namespace OpenSim.Region.Framework.Scenes
2322 3066
2323 // When we delete a group, we currently have to force persist to the database if the object id has changed 3067 // 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) 3068 // (since delete works by deleting all rows which have a given object id)
3069
3070 // this is as it seems to be in sl now
3071 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3072 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3073
3074 if (m_rootPart.PhysActor != null)
3075 m_rootPart.PhysActor.Building = false;
3076
2325 objectGroup.HasGroupChangedDueToDelink = true; 3077 objectGroup.HasGroupChangedDueToDelink = true;
2326 3078
2327 return objectGroup; 3079 return objectGroup;
@@ -2333,6 +3085,8 @@ namespace OpenSim.Region.Framework.Scenes
2333 /// <param name="objectGroup"></param> 3085 /// <param name="objectGroup"></param>
2334 public virtual void DetachFromBackup() 3086 public virtual void DetachFromBackup()
2335 { 3087 {
3088 if (m_scene != null)
3089 m_scene.SceneGraph.FireDetachFromBackup(this);
2336 if (m_isBackedUp && Scene != null) 3090 if (m_isBackedUp && Scene != null)
2337 m_scene.EventManager.OnBackup -= ProcessBackup; 3091 m_scene.EventManager.OnBackup -= ProcessBackup;
2338 3092
@@ -2353,7 +3107,8 @@ namespace OpenSim.Region.Framework.Scenes
2353 Vector3 axPos = part.OffsetPosition; 3107 Vector3 axPos = part.OffsetPosition;
2354 axPos *= parentRot; 3108 axPos *= parentRot;
2355 part.OffsetPosition = axPos; 3109 part.OffsetPosition = axPos;
2356 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3110 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3111 part.GroupPosition = newPos;
2357 part.OffsetPosition = Vector3.Zero; 3112 part.OffsetPosition = Vector3.Zero;
2358 3113
2359 // Compution our rotation to be not relative to the old parent 3114 // Compution our rotation to be not relative to the old parent
@@ -2368,7 +3123,7 @@ namespace OpenSim.Region.Framework.Scenes
2368 part.LinkNum = linkNum; 3123 part.LinkNum = linkNum;
2369 3124
2370 // Compute the new position of this SOP relative to the group position 3125 // Compute the new position of this SOP relative to the group position
2371 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3126 part.OffsetPosition = newPos - AbsolutePosition;
2372 3127
2373 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3128 // (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 3129 // It would have the affect of setting the physics engine position multiple
@@ -2378,18 +3133,19 @@ namespace OpenSim.Region.Framework.Scenes
2378 // Rotate the relative position by the rotation of the group 3133 // Rotate the relative position by the rotation of the group
2379 Quaternion rootRotation = m_rootPart.RotationOffset; 3134 Quaternion rootRotation = m_rootPart.RotationOffset;
2380 Vector3 pos = part.OffsetPosition; 3135 Vector3 pos = part.OffsetPosition;
2381 pos *= Quaternion.Inverse(rootRotation); 3136 pos *= Quaternion.Conjugate(rootRotation);
2382 part.OffsetPosition = pos; 3137 part.OffsetPosition = pos;
2383 3138
2384 // Compute the SOP's rotation relative to the rotation of the group. 3139 // Compute the SOP's rotation relative to the rotation of the group.
2385 parentRot = m_rootPart.RotationOffset; 3140 parentRot = m_rootPart.RotationOffset;
2386 oldRot = part.RotationOffset; 3141 oldRot = part.RotationOffset;
2387 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3142 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2388 part.RotationOffset = newRot; 3143 part.RotationOffset = newRot;
2389 3144
2390 // Since this SOP's state has changed, push those changes into the physics engine 3145 // Since this SOP's state has changed, push those changes into the physics engine
2391 // and the simulator. 3146 // and the simulator.
2392 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3147 // done on caller
3148// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2393 } 3149 }
2394 3150
2395 /// <summary> 3151 /// <summary>
@@ -2411,10 +3167,14 @@ namespace OpenSim.Region.Framework.Scenes
2411 { 3167 {
2412 if (!m_rootPart.BlockGrab) 3168 if (!m_rootPart.BlockGrab)
2413 { 3169 {
2414 Vector3 llmoveforce = pos - AbsolutePosition; 3170/* Vector3 llmoveforce = pos - AbsolutePosition;
2415 Vector3 grabforce = llmoveforce; 3171 Vector3 grabforce = llmoveforce;
2416 grabforce = (grabforce / 10) * pa.Mass; 3172 grabforce = (grabforce / 10) * pa.Mass;
2417 pa.AddForce(grabforce, true); 3173 */
3174 // empirically convert distance diference to a impulse
3175 Vector3 grabforce = pos - AbsolutePosition;
3176 grabforce = grabforce * (pa.Mass/ 10.0f);
3177 pa.AddForce(grabforce, false);
2418 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3178 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2419 } 3179 }
2420 } 3180 }
@@ -2610,6 +3370,8 @@ namespace OpenSim.Region.Framework.Scenes
2610 /// <param name="SetVolumeDetect"></param> 3370 /// <param name="SetVolumeDetect"></param>
2611 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3371 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2612 { 3372 {
3373 HasGroupChanged = true;
3374
2613 SceneObjectPart selectionPart = GetPart(localID); 3375 SceneObjectPart selectionPart = GetPart(localID);
2614 3376
2615 if (SetTemporary && Scene != null) 3377 if (SetTemporary && Scene != null)
@@ -2640,8 +3402,22 @@ namespace OpenSim.Region.Framework.Scenes
2640 } 3402 }
2641 } 3403 }
2642 3404
2643 for (int i = 0; i < parts.Length; i++) 3405 if (parts.Length > 1)
2644 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3406 {
3407 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3408
3409 for (int i = 0; i < parts.Length; i++)
3410 {
3411
3412 if (parts[i].UUID != m_rootPart.UUID)
3413 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3414 }
3415
3416 if (m_rootPart.PhysActor != null)
3417 m_rootPart.PhysActor.Building = false;
3418 }
3419 else
3420 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2645 } 3421 }
2646 } 3422 }
2647 3423
@@ -2654,6 +3430,17 @@ namespace OpenSim.Region.Framework.Scenes
2654 } 3430 }
2655 } 3431 }
2656 3432
3433
3434
3435 /// <summary>
3436 /// Gets the number of parts
3437 /// </summary>
3438 /// <returns></returns>
3439 public int GetPartCount()
3440 {
3441 return Parts.Count();
3442 }
3443
2657 /// <summary> 3444 /// <summary>
2658 /// Update the texture entry for this part 3445 /// Update the texture entry for this part
2659 /// </summary> 3446 /// </summary>
@@ -2670,11 +3457,20 @@ namespace OpenSim.Region.Framework.Scenes
2670 3457
2671 public void AdjustChildPrimPermissions() 3458 public void AdjustChildPrimPermissions()
2672 { 3459 {
3460 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits
3461 uint foldedPerms = RootPart.OwnerMask & 3;
3462
2673 ForEachPart(part => 3463 ForEachPart(part =>
2674 { 3464 {
3465 newOwnerMask &= part.BaseMask;
2675 if (part != RootPart) 3466 if (part != RootPart)
2676 part.ClonePermissions(RootPart); 3467 part.ClonePermissions(RootPart);
2677 }); 3468 });
3469
3470 uint lockMask = ~(uint)PermissionMask.Move;
3471 uint lockBit = RootPart.OwnerMask & (uint)PermissionMask.Move;
3472 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
3473 RootPart.ScheduleFullUpdate();
2678 } 3474 }
2679 3475
2680 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 3476 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2682,8 +3478,24 @@ namespace OpenSim.Region.Framework.Scenes
2682 { 3478 {
2683 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3479 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2684 3480
3481 bool god = Scene.Permissions.IsGod(AgentID);
3482
3483 if (field == 1 && god)
3484 {
3485 ForEachPart(part =>
3486 {
3487 part.BaseMask = RootPart.BaseMask;
3488 });
3489 }
3490
2685 AdjustChildPrimPermissions(); 3491 AdjustChildPrimPermissions();
2686 3492
3493 if (field == 1 && god) // Base mask was set. Update all child part inventories
3494 {
3495 foreach (SceneObjectPart part in Parts)
3496 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3497 }
3498
2687 HasGroupChanged = true; 3499 HasGroupChanged = true;
2688 3500
2689 // Send the group's properties to all clients once all parts are updated 3501 // Send the group's properties to all clients once all parts are updated
@@ -2729,8 +3541,6 @@ namespace OpenSim.Region.Framework.Scenes
2729 3541
2730 PhysicsActor pa = m_rootPart.PhysActor; 3542 PhysicsActor pa = m_rootPart.PhysActor;
2731 3543
2732 RootPart.StoreUndoState(true);
2733
2734 if (Scene != null) 3544 if (Scene != null)
2735 { 3545 {
2736 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3546 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2758,7 +3568,6 @@ namespace OpenSim.Region.Framework.Scenes
2758 SceneObjectPart obPart = parts[i]; 3568 SceneObjectPart obPart = parts[i];
2759 if (obPart.UUID != m_rootPart.UUID) 3569 if (obPart.UUID != m_rootPart.UUID)
2760 { 3570 {
2761// obPart.IgnoreUndoUpdate = true;
2762 Vector3 oldSize = new Vector3(obPart.Scale); 3571 Vector3 oldSize = new Vector3(obPart.Scale);
2763 3572
2764 float f = 1.0f; 3573 float f = 1.0f;
@@ -2870,8 +3679,6 @@ namespace OpenSim.Region.Framework.Scenes
2870 z *= a; 3679 z *= a;
2871 } 3680 }
2872 } 3681 }
2873
2874// obPart.IgnoreUndoUpdate = false;
2875 } 3682 }
2876 } 3683 }
2877 } 3684 }
@@ -2881,9 +3688,7 @@ namespace OpenSim.Region.Framework.Scenes
2881 prevScale.Y *= y; 3688 prevScale.Y *= y;
2882 prevScale.Z *= z; 3689 prevScale.Z *= z;
2883 3690
2884// RootPart.IgnoreUndoUpdate = true;
2885 RootPart.Resize(prevScale); 3691 RootPart.Resize(prevScale);
2886// RootPart.IgnoreUndoUpdate = false;
2887 3692
2888 for (int i = 0; i < parts.Length; i++) 3693 for (int i = 0; i < parts.Length; i++)
2889 { 3694 {
@@ -2891,8 +3696,6 @@ namespace OpenSim.Region.Framework.Scenes
2891 3696
2892 if (obPart.UUID != m_rootPart.UUID) 3697 if (obPart.UUID != m_rootPart.UUID)
2893 { 3698 {
2894 obPart.IgnoreUndoUpdate = true;
2895
2896 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3699 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2897 currentpos.X *= x; 3700 currentpos.X *= x;
2898 currentpos.Y *= y; 3701 currentpos.Y *= y;
@@ -2905,16 +3708,12 @@ namespace OpenSim.Region.Framework.Scenes
2905 3708
2906 obPart.Resize(newSize); 3709 obPart.Resize(newSize);
2907 obPart.UpdateOffSet(currentpos); 3710 obPart.UpdateOffSet(currentpos);
2908
2909 obPart.IgnoreUndoUpdate = false;
2910 } 3711 }
2911 3712
2912// obPart.IgnoreUndoUpdate = false; 3713 HasGroupChanged = true;
2913// obPart.StoreUndoState(); 3714 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3715 ScheduleGroupForTerseUpdate();
2914 } 3716 }
2915
2916// m_log.DebugFormat(
2917// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2918 } 3717 }
2919 3718
2920 #endregion 3719 #endregion
@@ -2927,14 +3726,6 @@ namespace OpenSim.Region.Framework.Scenes
2927 /// <param name="pos"></param> 3726 /// <param name="pos"></param>
2928 public void UpdateGroupPosition(Vector3 pos) 3727 public void UpdateGroupPosition(Vector3 pos)
2929 { 3728 {
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)) 3729 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2939 { 3730 {
2940 if (IsAttachment) 3731 if (IsAttachment)
@@ -2967,21 +3758,17 @@ namespace OpenSim.Region.Framework.Scenes
2967 /// </summary> 3758 /// </summary>
2968 /// <param name="pos"></param> 3759 /// <param name="pos"></param>
2969 /// <param name="localID"></param> 3760 /// <param name="localID"></param>
3761 ///
3762
2970 public void UpdateSinglePosition(Vector3 pos, uint localID) 3763 public void UpdateSinglePosition(Vector3 pos, uint localID)
2971 { 3764 {
2972 SceneObjectPart part = GetPart(localID); 3765 SceneObjectPart part = GetPart(localID);
2973 3766
2974// SceneObjectPart[] parts = m_parts.GetArray();
2975// for (int i = 0; i < parts.Length; i++)
2976// parts[i].StoreUndoState();
2977
2978 if (part != null) 3767 if (part != null)
2979 { 3768 {
2980// m_log.DebugFormat( 3769// unlock parts position change
2981// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3770 if (m_rootPart.PhysActor != null)
2982 3771 m_rootPart.PhysActor.Building = true;
2983 part.StoreUndoState(false);
2984 part.IgnoreUndoUpdate = true;
2985 3772
2986 if (part.UUID == m_rootPart.UUID) 3773 if (part.UUID == m_rootPart.UUID)
2987 { 3774 {
@@ -2992,8 +3779,10 @@ namespace OpenSim.Region.Framework.Scenes
2992 part.UpdateOffSet(pos); 3779 part.UpdateOffSet(pos);
2993 } 3780 }
2994 3781
3782 if (m_rootPart.PhysActor != null)
3783 m_rootPart.PhysActor.Building = false;
3784
2995 HasGroupChanged = true; 3785 HasGroupChanged = true;
2996 part.IgnoreUndoUpdate = false;
2997 } 3786 }
2998 } 3787 }
2999 3788
@@ -3003,13 +3792,7 @@ namespace OpenSim.Region.Framework.Scenes
3003 /// <param name="pos"></param> 3792 /// <param name="pos"></param>
3004 public void UpdateRootPosition(Vector3 pos) 3793 public void UpdateRootPosition(Vector3 pos)
3005 { 3794 {
3006// m_log.DebugFormat( 3795 // 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); 3796 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3014 Vector3 oldPos = 3797 Vector3 oldPos =
3015 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3798 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3032,7 +3815,14 @@ namespace OpenSim.Region.Framework.Scenes
3032 AbsolutePosition = newPos; 3815 AbsolutePosition = newPos;
3033 3816
3034 HasGroupChanged = true; 3817 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3818 if (m_rootPart.Undoing)
3819 {
3820 ScheduleGroupForFullUpdate();
3821 }
3822 else
3823 {
3824 ScheduleGroupForTerseUpdate();
3825 }
3036 } 3826 }
3037 3827
3038 #endregion 3828 #endregion
@@ -3045,24 +3835,16 @@ namespace OpenSim.Region.Framework.Scenes
3045 /// <param name="rot"></param> 3835 /// <param name="rot"></param>
3046 public void UpdateGroupRotationR(Quaternion rot) 3836 public void UpdateGroupRotationR(Quaternion rot)
3047 { 3837 {
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); 3838 m_rootPart.UpdateRotation(rot);
3058 3839
3840/* this is done by rootpart RotationOffset set called by UpdateRotation
3059 PhysicsActor actor = m_rootPart.PhysActor; 3841 PhysicsActor actor = m_rootPart.PhysActor;
3060 if (actor != null) 3842 if (actor != null)
3061 { 3843 {
3062 actor.Orientation = m_rootPart.RotationOffset; 3844 actor.Orientation = m_rootPart.RotationOffset;
3063 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3845 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3064 } 3846 }
3065 3847*/
3066 HasGroupChanged = true; 3848 HasGroupChanged = true;
3067 ScheduleGroupForTerseUpdate(); 3849 ScheduleGroupForTerseUpdate();
3068 } 3850 }
@@ -3074,16 +3856,6 @@ namespace OpenSim.Region.Framework.Scenes
3074 /// <param name="rot"></param> 3856 /// <param name="rot"></param>
3075 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3857 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3076 { 3858 {
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); 3859 m_rootPart.UpdateRotation(rot);
3088 3860
3089 PhysicsActor actor = m_rootPart.PhysActor; 3861 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3102,8 +3874,6 @@ namespace OpenSim.Region.Framework.Scenes
3102 3874
3103 HasGroupChanged = true; 3875 HasGroupChanged = true;
3104 ScheduleGroupForTerseUpdate(); 3876 ScheduleGroupForTerseUpdate();
3105
3106 RootPart.IgnoreUndoUpdate = false;
3107 } 3877 }
3108 3878
3109 /// <summary> 3879 /// <summary>
@@ -3116,13 +3886,11 @@ namespace OpenSim.Region.Framework.Scenes
3116 SceneObjectPart part = GetPart(localID); 3886 SceneObjectPart part = GetPart(localID);
3117 3887
3118 SceneObjectPart[] parts = m_parts.GetArray(); 3888 SceneObjectPart[] parts = m_parts.GetArray();
3119 for (int i = 0; i < parts.Length; i++)
3120 parts[i].StoreUndoState();
3121 3889
3122 if (part != null) 3890 if (part != null)
3123 { 3891 {
3124// m_log.DebugFormat( 3892 if (m_rootPart.PhysActor != null)
3125// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3893 m_rootPart.PhysActor.Building = true;
3126 3894
3127 if (part.UUID == m_rootPart.UUID) 3895 if (part.UUID == m_rootPart.UUID)
3128 { 3896 {
@@ -3132,6 +3900,9 @@ namespace OpenSim.Region.Framework.Scenes
3132 { 3900 {
3133 part.UpdateRotation(rot); 3901 part.UpdateRotation(rot);
3134 } 3902 }
3903
3904 if (m_rootPart.PhysActor != null)
3905 m_rootPart.PhysActor.Building = false;
3135 } 3906 }
3136 } 3907 }
3137 3908
@@ -3145,12 +3916,8 @@ namespace OpenSim.Region.Framework.Scenes
3145 SceneObjectPart part = GetPart(localID); 3916 SceneObjectPart part = GetPart(localID);
3146 if (part != null) 3917 if (part != null)
3147 { 3918 {
3148// m_log.DebugFormat( 3919 if (m_rootPart.PhysActor != null)
3149// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3920 m_rootPart.PhysActor.Building = true;
3150// part.Name, part.LocalId, rot);
3151
3152 part.StoreUndoState();
3153 part.IgnoreUndoUpdate = true;
3154 3921
3155 if (part.UUID == m_rootPart.UUID) 3922 if (part.UUID == m_rootPart.UUID)
3156 { 3923 {
@@ -3163,7 +3930,8 @@ namespace OpenSim.Region.Framework.Scenes
3163 part.OffsetPosition = pos; 3930 part.OffsetPosition = pos;
3164 } 3931 }
3165 3932
3166 part.IgnoreUndoUpdate = false; 3933 if (m_rootPart.PhysActor != null)
3934 m_rootPart.PhysActor.Building = false;
3167 } 3935 }
3168 } 3936 }
3169 3937
@@ -3173,15 +3941,12 @@ namespace OpenSim.Region.Framework.Scenes
3173 /// <param name="rot"></param> 3941 /// <param name="rot"></param>
3174 public void UpdateRootRotation(Quaternion rot) 3942 public void UpdateRootRotation(Quaternion rot)
3175 { 3943 {
3176// m_log.DebugFormat( 3944 // 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; 3945 Quaternion axRot = rot;
3181 Quaternion oldParentRot = m_rootPart.RotationOffset; 3946 Quaternion oldParentRot = m_rootPart.RotationOffset;
3182 3947
3183 m_rootPart.StoreUndoState(); 3948 //Don't use UpdateRotation because it schedules an update prematurely
3184 m_rootPart.UpdateRotation(rot); 3949 m_rootPart.RotationOffset = rot;
3185 3950
3186 PhysicsActor pa = m_rootPart.PhysActor; 3951 PhysicsActor pa = m_rootPart.PhysActor;
3187 3952
@@ -3197,35 +3962,145 @@ namespace OpenSim.Region.Framework.Scenes
3197 SceneObjectPart prim = parts[i]; 3962 SceneObjectPart prim = parts[i];
3198 if (prim.UUID != m_rootPart.UUID) 3963 if (prim.UUID != m_rootPart.UUID)
3199 { 3964 {
3200 prim.IgnoreUndoUpdate = true; 3965 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3966 NewRot = Quaternion.Inverse(axRot) * NewRot;
3967 prim.RotationOffset = NewRot;
3968
3201 Vector3 axPos = prim.OffsetPosition; 3969 Vector3 axPos = prim.OffsetPosition;
3970
3202 axPos *= oldParentRot; 3971 axPos *= oldParentRot;
3203 axPos *= Quaternion.Inverse(axRot); 3972 axPos *= Quaternion.Inverse(axRot);
3204 prim.OffsetPosition = axPos; 3973 prim.OffsetPosition = axPos;
3205 Quaternion primsRot = prim.RotationOffset; 3974 }
3206 Quaternion newRot = oldParentRot * primsRot; 3975 }
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 3976
3224 m_rootPart.ScheduleTerseUpdate(); 3977 HasGroupChanged = true;
3978 ScheduleGroupForFullUpdate();
3979 }
3225 3980
3226// m_log.DebugFormat( 3981 private enum updatetype :int
3227// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3982 {
3228// Name, LocalId, rot); 3983 none = 0,
3984 partterse = 1,
3985 partfull = 2,
3986 groupterse = 3,
3987 groupfull = 4
3988 }
3989
3990 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3991 {
3992 // TODO this still as excessive *.Schedule*Update()s
3993
3994 if (part != null && part.ParentGroup != null)
3995 {
3996 ObjectChangeType change = data.change;
3997 bool togroup = ((change & ObjectChangeType.Group) != 0);
3998 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3999
4000 SceneObjectGroup group = part.ParentGroup;
4001 PhysicsActor pha = group.RootPart.PhysActor;
4002
4003 updatetype updateType = updatetype.none;
4004
4005 if (togroup)
4006 {
4007 // related to group
4008 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4009 {
4010 if ((change & ObjectChangeType.Rotation) != 0)
4011 {
4012 group.RootPart.UpdateRotation(data.rotation);
4013 updateType = updatetype.none;
4014 }
4015 if ((change & ObjectChangeType.Position) != 0)
4016 {
4017 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4018 UpdateGroupPosition(data.position);
4019 updateType = updatetype.groupterse;
4020 }
4021 else
4022 // ugly rotation update of all parts
4023 {
4024 group.ResetChildPrimPhysicsPositions();
4025 }
4026
4027 }
4028 if ((change & ObjectChangeType.Scale) != 0)
4029 {
4030 if (pha != null)
4031 pha.Building = true;
4032
4033 group.GroupResize(data.scale);
4034 updateType = updatetype.none;
4035
4036 if (pha != null)
4037 pha.Building = false;
4038 }
4039 }
4040 else
4041 {
4042 // related to single prim in a link-set ( ie group)
4043 if (pha != null)
4044 pha.Building = true;
4045
4046 // root part is special
4047 // parts offset positions or rotations need to change also
4048
4049 if (part == group.RootPart)
4050 {
4051 if ((change & ObjectChangeType.Rotation) != 0)
4052 group.UpdateRootRotation(data.rotation);
4053 if ((change & ObjectChangeType.Position) != 0)
4054 group.UpdateRootPosition(data.position);
4055 if ((change & ObjectChangeType.Scale) != 0)
4056 part.Resize(data.scale);
4057 }
4058 else
4059 {
4060 if ((change & ObjectChangeType.Position) != 0)
4061 {
4062 part.OffsetPosition = data.position;
4063 updateType = updatetype.partterse;
4064 }
4065 if ((change & ObjectChangeType.Rotation) != 0)
4066 {
4067 part.UpdateRotation(data.rotation);
4068 updateType = updatetype.none;
4069 }
4070 if ((change & ObjectChangeType.Scale) != 0)
4071 {
4072 part.Resize(data.scale);
4073 updateType = updatetype.none;
4074 }
4075 }
4076
4077 if (pha != null)
4078 pha.Building = false;
4079 }
4080
4081 if (updateType != updatetype.none)
4082 {
4083 group.HasGroupChanged = true;
4084
4085 switch (updateType)
4086 {
4087 case updatetype.partterse:
4088 part.ScheduleTerseUpdate();
4089 break;
4090 case updatetype.partfull:
4091 part.ScheduleFullUpdate();
4092 break;
4093 case updatetype.groupterse:
4094 group.ScheduleGroupForTerseUpdate();
4095 break;
4096 case updatetype.groupfull:
4097 group.ScheduleGroupForFullUpdate();
4098 break;
4099 default:
4100 break;
4101 }
4102 }
4103 }
3229 } 4104 }
3230 4105
3231 #endregion 4106 #endregion
@@ -3324,10 +4199,11 @@ namespace OpenSim.Region.Framework.Scenes
3324 scriptPosTarget target = m_targets[idx]; 4199 scriptPosTarget target = m_targets[idx];
3325 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4200 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3326 { 4201 {
4202 at_target = true;
4203
3327 // trigger at_target 4204 // trigger at_target
3328 if (m_scriptListens_atTarget) 4205 if (m_scriptListens_atTarget)
3329 { 4206 {
3330 at_target = true;
3331 scriptPosTarget att = new scriptPosTarget(); 4207 scriptPosTarget att = new scriptPosTarget();
3332 att.targetPos = target.targetPos; 4208 att.targetPos = target.targetPos;
3333 att.tolerance = target.tolerance; 4209 att.tolerance = target.tolerance;
@@ -3445,11 +4321,50 @@ namespace OpenSim.Region.Framework.Scenes
3445 } 4321 }
3446 } 4322 }
3447 } 4323 }
3448 4324
4325 public Vector3 GetGeometricCenter()
4326 {
4327 // this is not real geometric center but a average of positions relative to root prim acording to
4328 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4329 // ignoring tortured prims details since sl also seems to ignore
4330 // so no real use in doing it on physics
4331
4332 Vector3 gc = Vector3.Zero;
4333
4334 int nparts = m_parts.Count;
4335 if (nparts <= 1)
4336 return gc;
4337
4338 SceneObjectPart[] parts = m_parts.GetArray();
4339 nparts = parts.Length; // just in case it changed
4340 if (nparts <= 1)
4341 return gc;
4342
4343 Quaternion parentRot = RootPart.RotationOffset;
4344 Vector3 pPos;
4345
4346 // average all parts positions
4347 for (int i = 0; i < nparts; i++)
4348 {
4349 // do it directly
4350 // gc += parts[i].GetWorldPosition();
4351 if (parts[i] != RootPart)
4352 {
4353 pPos = parts[i].OffsetPosition;
4354 gc += pPos;
4355 }
4356
4357 }
4358 gc /= nparts;
4359
4360 // relative to root:
4361// gc -= AbsolutePosition;
4362 return gc;
4363 }
4364
3449 public float GetMass() 4365 public float GetMass()
3450 { 4366 {
3451 float retmass = 0f; 4367 float retmass = 0f;
3452
3453 SceneObjectPart[] parts = m_parts.GetArray(); 4368 SceneObjectPart[] parts = m_parts.GetArray();
3454 for (int i = 0; i < parts.Length; i++) 4369 for (int i = 0; i < parts.Length; i++)
3455 retmass += parts[i].GetMass(); 4370 retmass += parts[i].GetMass();
@@ -3457,6 +4372,39 @@ namespace OpenSim.Region.Framework.Scenes
3457 return retmass; 4372 return retmass;
3458 } 4373 }
3459 4374
4375 // center of mass of full object
4376 public Vector3 GetCenterOfMass()
4377 {
4378 PhysicsActor pa = RootPart.PhysActor;
4379
4380 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4381 {
4382 // physics knows better about center of mass of physical prims
4383 Vector3 tmp = pa.CenterOfMass;
4384 return tmp;
4385 }
4386
4387 Vector3 Ptot = Vector3.Zero;
4388 float totmass = 0f;
4389 float m;
4390
4391 SceneObjectPart[] parts = m_parts.GetArray();
4392 for (int i = 0; i < parts.Length; i++)
4393 {
4394 m = parts[i].GetMass();
4395 Ptot += parts[i].GetPartCenterOfMass() * m;
4396 totmass += m;
4397 }
4398
4399 if (totmass == 0)
4400 totmass = 0;
4401 else
4402 totmass = 1 / totmass;
4403 Ptot *= totmass;
4404
4405 return Ptot;
4406 }
4407
3460 /// <summary> 4408 /// <summary>
3461 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4409 /// 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. 4410 /// the physics engine can use it.
@@ -3636,6 +4584,14 @@ namespace OpenSim.Region.Framework.Scenes
3636 FromItemID = uuid; 4584 FromItemID = uuid;
3637 } 4585 }
3638 4586
4587 public void ResetOwnerChangeFlag()
4588 {
4589 ForEachPart(delegate(SceneObjectPart part)
4590 {
4591 part.ResetOwnerChangeFlag();
4592 });
4593 }
4594
3639 #endregion 4595 #endregion
3640 } 4596 }
3641} 4597}