aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs1395
1 files changed, 1181 insertions, 214 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 35e7c45..1fc8d3d 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,12 +24,13 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.ComponentModel; 29using System.ComponentModel;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing; 31using System.Drawing;
32using System.IO; 32using System.IO;
33using System.Diagnostics;
33using System.Linq; 34using System.Linq;
34using System.Threading; 35using System.Threading;
35using System.Xml; 36using System.Xml;
@@ -43,6 +44,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
43 44
44namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
45{ 46{
47
46 [Flags] 48 [Flags]
47 public enum scriptEvents 49 public enum scriptEvents
48 { 50 {
@@ -115,8 +117,12 @@ namespace OpenSim.Region.Framework.Scenes
115 /// since the group's last persistent backup 117 /// since the group's last persistent backup
116 /// </summary> 118 /// </summary>
117 private bool m_hasGroupChanged = false; 119 private bool m_hasGroupChanged = false;
118 private long timeFirstChanged; 120 private long timeFirstChanged = 0;
119 private long timeLastChanged; 121 private long timeLastChanged = 0;
122 private long m_maxPersistTime = 0;
123 private long m_minPersistTime = 0;
124// private Random m_rand;
125 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
120 126
121 /// <summary> 127 /// <summary>
122 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 128 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -133,9 +139,44 @@ namespace OpenSim.Region.Framework.Scenes
133 { 139 {
134 if (value) 140 if (value)
135 { 141 {
142
143 if (m_isBackedUp)
144 {
145 m_scene.SceneGraph.FireChangeBackup(this);
146 }
136 timeLastChanged = DateTime.Now.Ticks; 147 timeLastChanged = DateTime.Now.Ticks;
137 if (!m_hasGroupChanged) 148 if (!m_hasGroupChanged)
138 timeFirstChanged = DateTime.Now.Ticks; 149 timeFirstChanged = DateTime.Now.Ticks;
150 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
151 {
152/*
153 if (m_rand == null)
154 {
155 byte[] val = new byte[16];
156 m_rootPart.UUID.ToBytes(val, 0);
157 m_rand = new Random(BitConverter.ToInt32(val, 0));
158 }
159 */
160 if (m_scene.GetRootAgentCount() == 0)
161 {
162 //If the region is empty, this change has been made by an automated process
163 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
164
165// float factor = 1.5f + (float)(m_rand.NextDouble());
166 float factor = 2.0f;
167 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
168 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
169 }
170 else
171 {
172 //If the region is not empty, we want to obey the minimum and maximum persist times
173 //but add a random factor so we stagger the object persistance a little
174// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
175// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
176 m_maxPersistTime = m_scene.m_persistAfter;
177 m_minPersistTime = m_scene.m_dontPersistBefore;
178 }
179 }
139 } 180 }
140 m_hasGroupChanged = value; 181 m_hasGroupChanged = value;
141 182
@@ -150,7 +191,7 @@ namespace OpenSim.Region.Framework.Scenes
150 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 191 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
151 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 192 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
152 /// </summary> 193 /// </summary>
153 public bool HasGroupChangedDueToDelink { get; private set; } 194 public bool HasGroupChangedDueToDelink { get; set; }
154 195
155 private bool isTimeToPersist() 196 private bool isTimeToPersist()
156 { 197 {
@@ -160,8 +201,19 @@ namespace OpenSim.Region.Framework.Scenes
160 return false; 201 return false;
161 if (m_scene.ShuttingDown) 202 if (m_scene.ShuttingDown)
162 return true; 203 return true;
204
205 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
206 {
207 m_maxPersistTime = m_scene.m_persistAfter;
208 m_minPersistTime = m_scene.m_dontPersistBefore;
209 }
210
163 long currentTime = DateTime.Now.Ticks; 211 long currentTime = DateTime.Now.Ticks;
164 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 212
213 if (timeLastChanged == 0) timeLastChanged = currentTime;
214 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
215
216 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
165 return true; 217 return true;
166 return false; 218 return false;
167 } 219 }
@@ -269,6 +321,11 @@ namespace OpenSim.Region.Framework.Scenes
269 321
270 private bool m_isBackedUp; 322 private bool m_isBackedUp;
271 323
324 public bool IsBackedUp
325 {
326 get { return m_isBackedUp; }
327 }
328
272 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 329 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
273 330
274 protected ulong m_regionHandle; 331 protected ulong m_regionHandle;
@@ -280,10 +337,10 @@ namespace OpenSim.Region.Framework.Scenes
280 337
281 private bool m_scriptListens_atTarget; 338 private bool m_scriptListens_atTarget;
282 private bool m_scriptListens_notAtTarget; 339 private bool m_scriptListens_notAtTarget;
283
284 private bool m_scriptListens_atRotTarget; 340 private bool m_scriptListens_atRotTarget;
285 private bool m_scriptListens_notAtRotTarget; 341 private bool m_scriptListens_notAtRotTarget;
286 342
343 public bool m_dupeInProgress = false;
287 internal Dictionary<UUID, string> m_savedScriptState; 344 internal Dictionary<UUID, string> m_savedScriptState;
288 345
289 #region Properties 346 #region Properties
@@ -320,6 +377,16 @@ namespace OpenSim.Region.Framework.Scenes
320 get { return m_parts.Count; } 377 get { return m_parts.Count; }
321 } 378 }
322 379
380// protected Quaternion m_rotation = Quaternion.Identity;
381//
382// public virtual Quaternion Rotation
383// {
384// get { return m_rotation; }
385// set {
386// m_rotation = value;
387// }
388// }
389
323 public Quaternion GroupRotation 390 public Quaternion GroupRotation
324 { 391 {
325 get { return m_rootPart.RotationOffset; } 392 get { return m_rootPart.RotationOffset; }
@@ -426,7 +493,15 @@ namespace OpenSim.Region.Framework.Scenes
426 { 493 {
427 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 494 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
428 } 495 }
429 496
497
498
499 private struct avtocrossInfo
500 {
501 public ScenePresence av;
502 public uint ParentID;
503 }
504
430 /// <summary> 505 /// <summary>
431 /// The absolute position of this scene object in the scene 506 /// The absolute position of this scene object in the scene
432 /// </summary> 507 /// </summary>
@@ -454,10 +529,129 @@ namespace OpenSim.Region.Framework.Scenes
454 || Scene.TestBorderCross(val, Cardinals.S)) 529 || Scene.TestBorderCross(val, Cardinals.S))
455 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 530 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
456 { 531 {
457 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 532 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
533 uint x = 0;
534 uint y = 0;
535 string version = String.Empty;
536 Vector3 newpos = Vector3.Zero;
537 OpenSim.Services.Interfaces.GridRegion destination = null;
538
539 if (m_rootPart.KeyframeMotion != null)
540 m_rootPart.KeyframeMotion.StartCrossingCheck();
541
542 bool canCross = true;
543 foreach (ScenePresence av in m_linkedAvatars)
544 {
545 // We need to cross these agents. First, let's find
546 // out if any of them can't cross for some reason.
547 // We have to deny the crossing entirely if any
548 // of them are banned. Alternatively, we could
549 // unsit banned agents....
550
551
552 // We set the avatar position as being the object
553 // position to get the region to send to
554 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
555 {
556 canCross = false;
557 break;
558 }
559
560 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
561 }
562
563 if (canCross)
564 {
565 // We unparent the SP quietly so that it won't
566 // be made to stand up
567
568 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
569
570 foreach (ScenePresence av in m_linkedAvatars)
571 {
572 avtocrossInfo avinfo = new avtocrossInfo();
573 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
574 if (parentPart != null)
575 av.ParentUUID = parentPart.UUID;
576
577 avinfo.av = av;
578 avinfo.ParentID = av.ParentID;
579 avsToCross.Add(avinfo);
580
581 av.ParentID = 0;
582 }
583
584 // m_linkedAvatars.Clear();
585 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
586
587 // Normalize
588 if (val.X >= Constants.RegionSize)
589 val.X -= Constants.RegionSize;
590 if (val.Y >= Constants.RegionSize)
591 val.Y -= Constants.RegionSize;
592 if (val.X < 0)
593 val.X += Constants.RegionSize;
594 if (val.Y < 0)
595 val.Y += Constants.RegionSize;
596
597 // If it's deleted, crossing was successful
598 if (IsDeleted)
599 {
600 // foreach (ScenePresence av in m_linkedAvatars)
601 foreach (avtocrossInfo avinfo in avsToCross)
602 {
603 ScenePresence av = avinfo.av;
604 if (!av.IsInTransit) // just in case...
605 {
606 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
607
608 av.IsInTransit = true;
609
610 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
611 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
612 }
613 else
614 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
615 }
616 avsToCross.Clear();
617 return;
618 }
619 else // cross failed, put avas back ??
620 {
621 foreach (avtocrossInfo avinfo in avsToCross)
622 {
623 ScenePresence av = avinfo.av;
624 av.ParentUUID = UUID.Zero;
625 av.ParentID = avinfo.ParentID;
626// m_linkedAvatars.Add(av);
627 }
628 }
629 avsToCross.Clear();
630
631 }
632 else
633 {
634 if (m_rootPart.KeyframeMotion != null)
635 m_rootPart.KeyframeMotion.CrossingFailure();
636
637 if (RootPart.PhysActor != null)
638 {
639 RootPart.PhysActor.CrossingFailure();
640 }
641 }
642 Vector3 oldp = AbsolutePosition;
643 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
644 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
645 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
458 } 646 }
459 } 647 }
460 648
649/* don't see the need but worse don't see where is restored to false if things stay in
650 foreach (SceneObjectPart part in m_parts.GetArray())
651 {
652 part.IgnoreUndoUpdate = true;
653 }
654 */
461 if (RootPart.GetStatusSandbox()) 655 if (RootPart.GetStatusSandbox())
462 { 656 {
463 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 657 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -475,9 +669,38 @@ namespace OpenSim.Region.Framework.Scenes
475 // Restuff the new GroupPosition into each SOP of the linkset. 669 // Restuff the new GroupPosition into each SOP of the linkset.
476 // This has the affect of resetting and tainting the physics actors. 670 // This has the affect of resetting and tainting the physics actors.
477 SceneObjectPart[] parts = m_parts.GetArray(); 671 SceneObjectPart[] parts = m_parts.GetArray();
478 for (int i = 0; i < parts.Length; i++) 672 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
479 parts[i].GroupPosition = val; 673 if (m_dupeInProgress)
674 triggerScriptEvent = false;
675 foreach (SceneObjectPart part in parts)
676 {
677 part.GroupPosition = val;
678 if (triggerScriptEvent)
679 part.TriggerScriptChangedEvent(Changed.POSITION);
680 }
480 681
682/*
683 This seems not needed and should not be needed:
684 sp absolute position depends on sit part absolute position fixed above.
685 sp ParentPosition is not used anywhere.
686 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
687 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
688
689 if (!m_dupeInProgress)
690 {
691 foreach (ScenePresence av in m_linkedAvatars)
692 {
693 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
694 if (p != null && m_parts.TryGetValue(p.UUID, out p))
695 {
696 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
697 av.AbsolutePosition += offset;
698// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
699 av.SendAvatarDataToAllAgents();
700 }
701 }
702 }
703*/
481 //if (m_rootPart.PhysActor != null) 704 //if (m_rootPart.PhysActor != null)
482 //{ 705 //{
483 //m_rootPart.PhysActor.Position = 706 //m_rootPart.PhysActor.Position =
@@ -491,6 +714,40 @@ namespace OpenSim.Region.Framework.Scenes
491 } 714 }
492 } 715 }
493 716
717 public override Vector3 Velocity
718 {
719 get { return RootPart.Velocity; }
720 set { RootPart.Velocity = value; }
721 }
722
723 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
724 {
725 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
726 ScenePresence agent = icon.EndInvoke(iar);
727
728 //// If the cross was successful, this agent is a child agent
729 if (agent.IsChildAgent)
730 {
731 if (agent.ParentUUID != UUID.Zero)
732 {
733 agent.ParentPart = null;
734// agent.ParentPosition = Vector3.Zero;
735// agent.ParentUUID = UUID.Zero;
736 }
737 }
738
739 agent.ParentUUID = UUID.Zero;
740
741// agent.Reset();
742// else // Not successful
743// agent.RestoreInCurrentScene();
744
745 // In any case
746 agent.IsInTransit = false;
747
748 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
749 }
750
494 public override uint LocalId 751 public override uint LocalId
495 { 752 {
496 get { return m_rootPart.LocalId; } 753 get { return m_rootPart.LocalId; }
@@ -561,6 +818,11 @@ namespace OpenSim.Region.Framework.Scenes
561 m_isSelected = value; 818 m_isSelected = value;
562 // Tell physics engine that group is selected 819 // Tell physics engine that group is selected
563 820
821 // this is not right
822 // but ode engines should only really need to know about root part
823 // so they can put entire object simulation on hold and not colliding
824 // keep as was for now
825
564 PhysicsActor pa = m_rootPart.PhysActor; 826 PhysicsActor pa = m_rootPart.PhysActor;
565 if (pa != null) 827 if (pa != null)
566 { 828 {
@@ -577,6 +839,42 @@ namespace OpenSim.Region.Framework.Scenes
577 childPa.Selected = value; 839 childPa.Selected = value;
578 } 840 }
579 } 841 }
842 if (RootPart.KeyframeMotion != null)
843 RootPart.KeyframeMotion.Selected = value;
844 }
845 }
846
847 public void PartSelectChanged(bool partSelect)
848 {
849 // any part selected makes group selected
850 if (m_isSelected == partSelect)
851 return;
852
853 if (partSelect)
854 {
855 IsSelected = partSelect;
856// if (!IsAttachment)
857// ScheduleGroupForFullUpdate();
858 }
859 else
860 {
861 // bad bad bad 2 heavy for large linksets
862 // since viewer does send lot of (un)selects
863 // this needs to be replaced by a specific list or count ?
864 // but that will require extra code in several places
865
866 SceneObjectPart[] parts = m_parts.GetArray();
867 for (int i = 0; i < parts.Length; i++)
868 {
869 SceneObjectPart part = parts[i];
870 if (part.IsSelected)
871 return;
872 }
873 IsSelected = partSelect;
874 if (!IsAttachment)
875 {
876 ScheduleGroupForFullUpdate();
877 }
580 } 878 }
581 } 879 }
582 880
@@ -662,6 +960,7 @@ namespace OpenSim.Region.Framework.Scenes
662 /// </summary> 960 /// </summary>
663 public SceneObjectGroup() 961 public SceneObjectGroup()
664 { 962 {
963
665 } 964 }
666 965
667 /// <summary> 966 /// <summary>
@@ -679,8 +978,8 @@ namespace OpenSim.Region.Framework.Scenes
679 /// Constructor. This object is added to the scene later via AttachToScene() 978 /// Constructor. This object is added to the scene later via AttachToScene()
680 /// </summary> 979 /// </summary>
681 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 980 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
682 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 981 {
683 { 982 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
684 } 983 }
685 984
686 /// <summary> 985 /// <summary>
@@ -715,6 +1014,9 @@ namespace OpenSim.Region.Framework.Scenes
715 /// </summary> 1014 /// </summary>
716 public virtual void AttachToBackup() 1015 public virtual void AttachToBackup()
717 { 1016 {
1017 if (IsAttachment) return;
1018 m_scene.SceneGraph.FireAttachToBackup(this);
1019
718 if (InSceneBackup) 1020 if (InSceneBackup)
719 { 1021 {
720 //m_log.DebugFormat( 1022 //m_log.DebugFormat(
@@ -757,6 +1059,13 @@ namespace OpenSim.Region.Framework.Scenes
757 1059
758 ApplyPhysics(); 1060 ApplyPhysics();
759 1061
1062 if (RootPart.PhysActor != null)
1063 RootPart.Force = RootPart.Force;
1064 if (RootPart.PhysActor != null)
1065 RootPart.Torque = RootPart.Torque;
1066 if (RootPart.PhysActor != null)
1067 RootPart.Buoyancy = RootPart.Buoyancy;
1068
760 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1069 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
761 // for the same object with very different properties. The caller must schedule the update. 1070 // for the same object with very different properties. The caller must schedule the update.
762 //ScheduleGroupForFullUpdate(); 1071 //ScheduleGroupForFullUpdate();
@@ -772,6 +1081,10 @@ namespace OpenSim.Region.Framework.Scenes
772 EntityIntersection result = new EntityIntersection(); 1081 EntityIntersection result = new EntityIntersection();
773 1082
774 SceneObjectPart[] parts = m_parts.GetArray(); 1083 SceneObjectPart[] parts = m_parts.GetArray();
1084
1085 // Find closest hit here
1086 float idist = float.MaxValue;
1087
775 for (int i = 0; i < parts.Length; i++) 1088 for (int i = 0; i < parts.Length; i++)
776 { 1089 {
777 SceneObjectPart part = parts[i]; 1090 SceneObjectPart part = parts[i];
@@ -786,11 +1099,6 @@ namespace OpenSim.Region.Framework.Scenes
786 1099
787 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1100 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
788 1101
789 // This may need to be updated to the maximum draw distance possible..
790 // We might (and probably will) be checking for prim creation from other sims
791 // when the camera crosses the border.
792 float idist = Constants.RegionSize;
793
794 if (inter.HitTF) 1102 if (inter.HitTF)
795 { 1103 {
796 // We need to find the closest prim to return to the testcaller along the ray 1104 // We need to find the closest prim to return to the testcaller along the ray
@@ -801,10 +1109,11 @@ namespace OpenSim.Region.Framework.Scenes
801 result.obj = part; 1109 result.obj = part;
802 result.normal = inter.normal; 1110 result.normal = inter.normal;
803 result.distance = inter.distance; 1111 result.distance = inter.distance;
1112
1113 idist = inter.distance;
804 } 1114 }
805 } 1115 }
806 } 1116 }
807
808 return result; 1117 return result;
809 } 1118 }
810 1119
@@ -816,25 +1125,27 @@ namespace OpenSim.Region.Framework.Scenes
816 /// <returns></returns> 1125 /// <returns></returns>
817 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1126 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
818 { 1127 {
819 maxX = -256f; 1128 maxX = float.MinValue;
820 maxY = -256f; 1129 maxY = float.MinValue;
821 maxZ = -256f; 1130 maxZ = float.MinValue;
822 minX = 256f; 1131 minX = float.MaxValue;
823 minY = 256f; 1132 minY = float.MaxValue;
824 minZ = 8192f; 1133 minZ = float.MaxValue;
825 1134
826 SceneObjectPart[] parts = m_parts.GetArray(); 1135 SceneObjectPart[] parts = m_parts.GetArray();
827 for (int i = 0; i < parts.Length; i++) 1136 foreach (SceneObjectPart part in parts)
828 { 1137 {
829 SceneObjectPart part = parts[i];
830
831 Vector3 worldPos = part.GetWorldPosition(); 1138 Vector3 worldPos = part.GetWorldPosition();
832 Vector3 offset = worldPos - AbsolutePosition; 1139 Vector3 offset = worldPos - AbsolutePosition;
833 Quaternion worldRot; 1140 Quaternion worldRot;
834 if (part.ParentID == 0) 1141 if (part.ParentID == 0)
1142 {
835 worldRot = part.RotationOffset; 1143 worldRot = part.RotationOffset;
1144 }
836 else 1145 else
1146 {
837 worldRot = part.GetWorldRotation(); 1147 worldRot = part.GetWorldRotation();
1148 }
838 1149
839 Vector3 frontTopLeft; 1150 Vector3 frontTopLeft;
840 Vector3 frontTopRight; 1151 Vector3 frontTopRight;
@@ -846,6 +1157,8 @@ namespace OpenSim.Region.Framework.Scenes
846 Vector3 backBottomLeft; 1157 Vector3 backBottomLeft;
847 Vector3 backBottomRight; 1158 Vector3 backBottomRight;
848 1159
1160 // Vector3[] corners = new Vector3[8];
1161
849 Vector3 orig = Vector3.Zero; 1162 Vector3 orig = Vector3.Zero;
850 1163
851 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1164 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -880,6 +1193,38 @@ namespace OpenSim.Region.Framework.Scenes
880 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1193 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
881 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1194 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
882 1195
1196
1197
1198 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1199 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1200 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1201 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1202 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1203 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1204 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1205 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1206
1207 //for (int i = 0; i < 8; i++)
1208 //{
1209 // corners[i] = corners[i] * worldRot;
1210 // corners[i] += offset;
1211
1212 // if (corners[i].X > maxX)
1213 // maxX = corners[i].X;
1214 // if (corners[i].X < minX)
1215 // minX = corners[i].X;
1216
1217 // if (corners[i].Y > maxY)
1218 // maxY = corners[i].Y;
1219 // if (corners[i].Y < minY)
1220 // minY = corners[i].Y;
1221
1222 // if (corners[i].Z > maxZ)
1223 // maxZ = corners[i].Y;
1224 // if (corners[i].Z < minZ)
1225 // minZ = corners[i].Z;
1226 //}
1227
883 frontTopLeft = frontTopLeft * worldRot; 1228 frontTopLeft = frontTopLeft * worldRot;
884 frontTopRight = frontTopRight * worldRot; 1229 frontTopRight = frontTopRight * worldRot;
885 frontBottomLeft = frontBottomLeft * worldRot; 1230 frontBottomLeft = frontBottomLeft * worldRot;
@@ -901,6 +1246,15 @@ namespace OpenSim.Region.Framework.Scenes
901 backTopLeft += offset; 1246 backTopLeft += offset;
902 backTopRight += offset; 1247 backTopRight += offset;
903 1248
1249 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1250 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1251 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1252 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1253 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1254 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1255 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1256 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1257
904 if (frontTopRight.X > maxX) 1258 if (frontTopRight.X > maxX)
905 maxX = frontTopRight.X; 1259 maxX = frontTopRight.X;
906 if (frontTopLeft.X > maxX) 1260 if (frontTopLeft.X > maxX)
@@ -1044,17 +1398,118 @@ namespace OpenSim.Region.Framework.Scenes
1044 1398
1045 #endregion 1399 #endregion
1046 1400
1401 public void GetResourcesCosts(SceneObjectPart apart,
1402 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1403 {
1404 // this information may need to be cached
1405
1406 float cost;
1407 float tmpcost;
1408
1409 bool ComplexCost = false;
1410
1411 SceneObjectPart p;
1412 SceneObjectPart[] parts;
1413
1414 lock (m_parts)
1415 {
1416 parts = m_parts.GetArray();
1417 }
1418
1419 int nparts = parts.Length;
1420
1421
1422 for (int i = 0; i < nparts; i++)
1423 {
1424 p = parts[i];
1425
1426 if (p.UsesComplexCost)
1427 {
1428 ComplexCost = true;
1429 break;
1430 }
1431 }
1432
1433 if (ComplexCost)
1434 {
1435 linksetResCost = 0;
1436 linksetPhysCost = 0;
1437 partCost = 0;
1438 partPhysCost = 0;
1439
1440 for (int i = 0; i < nparts; i++)
1441 {
1442 p = parts[i];
1443
1444 cost = p.StreamingCost;
1445 tmpcost = p.SimulationCost;
1446 if (tmpcost > cost)
1447 cost = tmpcost;
1448 tmpcost = p.PhysicsCost;
1449 if (tmpcost > cost)
1450 cost = tmpcost;
1451
1452 linksetPhysCost += tmpcost;
1453 linksetResCost += cost;
1454
1455 if (p == apart)
1456 {
1457 partCost = cost;
1458 partPhysCost = tmpcost;
1459 }
1460 }
1461 }
1462 else
1463 {
1464 partPhysCost = 1.0f;
1465 partCost = 1.0f;
1466 linksetResCost = (float)nparts;
1467 linksetPhysCost = linksetResCost;
1468 }
1469 }
1470
1471 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1472 {
1473 SceneObjectPart p;
1474 SceneObjectPart[] parts;
1475
1476 lock (m_parts)
1477 {
1478 parts = m_parts.GetArray();
1479 }
1480
1481 int nparts = parts.Length;
1482
1483 PhysCost = 0;
1484 StreamCost = 0;
1485 SimulCost = 0;
1486
1487 for (int i = 0; i < nparts; i++)
1488 {
1489 p = parts[i];
1490
1491 StreamCost += p.StreamingCost;
1492 SimulCost += p.SimulationCost;
1493 PhysCost += p.PhysicsCost;
1494 }
1495 }
1496
1047 public void SaveScriptedState(XmlTextWriter writer) 1497 public void SaveScriptedState(XmlTextWriter writer)
1048 { 1498 {
1499 SaveScriptedState(writer, false);
1500 }
1501
1502 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1503 {
1049 XmlDocument doc = new XmlDocument(); 1504 XmlDocument doc = new XmlDocument();
1050 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1505 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1051 1506
1052 SceneObjectPart[] parts = m_parts.GetArray(); 1507 SceneObjectPart[] parts = m_parts.GetArray();
1053 for (int i = 0; i < parts.Length; i++) 1508 for (int i = 0; i < parts.Length; i++)
1054 { 1509 {
1055 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1510 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1056 foreach (KeyValuePair<UUID, string> kvp in pstates) 1511 foreach (KeyValuePair<UUID, string> kvp in pstates)
1057 states.Add(kvp.Key, kvp.Value); 1512 states[kvp.Key] = kvp.Value;
1058 } 1513 }
1059 1514
1060 if (states.Count > 0) 1515 if (states.Count > 0)
@@ -1074,6 +1529,169 @@ namespace OpenSim.Region.Framework.Scenes
1074 } 1529 }
1075 1530
1076 /// <summary> 1531 /// <summary>
1532 /// Add the avatar to this linkset (avatar is sat).
1533 /// </summary>
1534 /// <param name="agentID"></param>
1535 public void AddAvatar(UUID agentID)
1536 {
1537 ScenePresence presence;
1538 if (m_scene.TryGetScenePresence(agentID, out presence))
1539 {
1540 if (!m_linkedAvatars.Contains(presence))
1541 {
1542 m_linkedAvatars.Add(presence);
1543 }
1544 }
1545 }
1546
1547 /// <summary>
1548 /// Delete the avatar from this linkset (avatar is unsat).
1549 /// </summary>
1550 /// <param name="agentID"></param>
1551 public void DeleteAvatar(UUID agentID)
1552 {
1553 ScenePresence presence;
1554 if (m_scene.TryGetScenePresence(agentID, out presence))
1555 {
1556 if (m_linkedAvatars.Contains(presence))
1557 {
1558 m_linkedAvatars.Remove(presence);
1559 }
1560 }
1561 }
1562
1563 /// <summary>
1564 /// Returns the list of linked presences (avatars sat on this group)
1565 /// </summary>
1566 /// <param name="agentID"></param>
1567 public List<ScenePresence> GetLinkedAvatars()
1568 {
1569 return m_linkedAvatars;
1570 }
1571
1572 /// <summary>
1573 /// Attach this scene object to the given avatar.
1574 /// </summary>
1575 /// <param name="agentID"></param>
1576 /// <param name="attachmentpoint"></param>
1577 /// <param name="AttachOffset"></param>
1578 private void AttachToAgent(
1579 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1580 {
1581 if (avatar != null)
1582 {
1583 // don't attach attachments to child agents
1584 if (avatar.IsChildAgent) return;
1585
1586 // Remove from database and parcel prim count
1587 m_scene.DeleteFromStorage(so.UUID);
1588 m_scene.EventManager.TriggerParcelPrimCountTainted();
1589
1590 so.AttachedAvatar = avatar.UUID;
1591
1592 if (so.RootPart.PhysActor != null)
1593 {
1594 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1595 so.RootPart.PhysActor = null;
1596 }
1597
1598 so.AbsolutePosition = attachOffset;
1599 so.RootPart.AttachedPos = attachOffset;
1600 so.IsAttachment = true;
1601 so.RootPart.SetParentLocalId(avatar.LocalId);
1602 so.AttachmentPoint = attachmentpoint;
1603
1604 avatar.AddAttachment(this);
1605
1606 if (!silent)
1607 {
1608 // Killing it here will cause the client to deselect it
1609 // It then reappears on the avatar, deselected
1610 // through the full update below
1611 //
1612 if (IsSelected)
1613 {
1614 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1615 }
1616
1617 IsSelected = false; // fudge....
1618 ScheduleGroupForFullUpdate();
1619 }
1620 }
1621 else
1622 {
1623 m_log.WarnFormat(
1624 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1625 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1626 }
1627 }
1628
1629 public byte GetAttachmentPoint()
1630 {
1631 return m_rootPart.Shape.State;
1632 }
1633
1634 public void DetachToGround()
1635 {
1636 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1637 if (avatar == null)
1638 return;
1639
1640 avatar.RemoveAttachment(this);
1641
1642 Vector3 detachedpos = new Vector3(127f,127f,127f);
1643 if (avatar == null)
1644 return;
1645
1646 detachedpos = avatar.AbsolutePosition;
1647 FromItemID = UUID.Zero;
1648
1649 AbsolutePosition = detachedpos;
1650 AttachedAvatar = UUID.Zero;
1651
1652 //SceneObjectPart[] parts = m_parts.GetArray();
1653 //for (int i = 0; i < parts.Length; i++)
1654 // parts[i].AttachedAvatar = UUID.Zero;
1655
1656 m_rootPart.SetParentLocalId(0);
1657 AttachmentPoint = (byte)0;
1658 // must check if buildind should be true or false here
1659 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1660 HasGroupChanged = true;
1661 RootPart.Rezzed = DateTime.Now;
1662 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1663 AttachToBackup();
1664 m_scene.EventManager.TriggerParcelPrimCountTainted();
1665 m_rootPart.ScheduleFullUpdate();
1666 m_rootPart.ClearUndoState();
1667 }
1668
1669 public void DetachToInventoryPrep()
1670 {
1671 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1672 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1673 if (avatar != null)
1674 {
1675 //detachedpos = avatar.AbsolutePosition;
1676 avatar.RemoveAttachment(this);
1677 }
1678
1679 AttachedAvatar = UUID.Zero;
1680
1681 /*SceneObjectPart[] parts = m_parts.GetArray();
1682 for (int i = 0; i < parts.Length; i++)
1683 parts[i].AttachedAvatar = UUID.Zero;*/
1684
1685 m_rootPart.SetParentLocalId(0);
1686 //m_rootPart.SetAttachmentPoint((byte)0);
1687 IsAttachment = false;
1688 AbsolutePosition = m_rootPart.AttachedPos;
1689 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1690 //AttachToBackup();
1691 //m_rootPart.ScheduleFullUpdate();
1692 }
1693
1694 /// <summary>
1077 /// 1695 ///
1078 /// </summary> 1696 /// </summary>
1079 /// <param name="part"></param> 1697 /// <param name="part"></param>
@@ -1113,7 +1731,10 @@ namespace OpenSim.Region.Framework.Scenes
1113 public void AddPart(SceneObjectPart part) 1731 public void AddPart(SceneObjectPart part)
1114 { 1732 {
1115 part.SetParent(this); 1733 part.SetParent(this);
1116 part.LinkNum = m_parts.Add(part.UUID, part); 1734 m_parts.Add(part.UUID, part);
1735
1736 part.LinkNum = m_parts.Count;
1737
1117 if (part.LinkNum == 2) 1738 if (part.LinkNum == 2)
1118 RootPart.LinkNum = 1; 1739 RootPart.LinkNum = 1;
1119 } 1740 }
@@ -1139,6 +1760,14 @@ namespace OpenSim.Region.Framework.Scenes
1139 parts[i].UUID = UUID.Random(); 1760 parts[i].UUID = UUID.Random();
1140 } 1761 }
1141 1762
1763 // helper provided for parts.
1764 public int GetSceneMaxUndo()
1765 {
1766 if (m_scene != null)
1767 return m_scene.MaxUndoCount;
1768 return 5;
1769 }
1770
1142 // justincc: I don't believe this hack is needed any longer, especially since the physics 1771 // justincc: I don't believe this hack is needed any longer, especially since the physics
1143 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1772 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1144 // this method was preventing proper reload of scene objects. 1773 // this method was preventing proper reload of scene objects.
@@ -1196,7 +1825,7 @@ namespace OpenSim.Region.Framework.Scenes
1196// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1825// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1197// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1826// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1198 1827
1199 part.StoreUndoState(); 1828// part.StoreUndoState();
1200 part.OnGrab(offsetPos, remoteClient); 1829 part.OnGrab(offsetPos, remoteClient);
1201 } 1830 }
1202 1831
@@ -1216,6 +1845,11 @@ namespace OpenSim.Region.Framework.Scenes
1216 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1845 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1217 public void DeleteGroupFromScene(bool silent) 1846 public void DeleteGroupFromScene(bool silent)
1218 { 1847 {
1848 // We need to keep track of this state in case this group is still queued for backup.
1849 IsDeleted = true;
1850
1851 DetachFromBackup();
1852
1219 SceneObjectPart[] parts = m_parts.GetArray(); 1853 SceneObjectPart[] parts = m_parts.GetArray();
1220 for (int i = 0; i < parts.Length; i++) 1854 for (int i = 0; i < parts.Length; i++)
1221 { 1855 {
@@ -1239,6 +1873,7 @@ namespace OpenSim.Region.Framework.Scenes
1239 } 1873 }
1240 }); 1874 });
1241 } 1875 }
1876
1242 } 1877 }
1243 1878
1244 public void AddScriptLPS(int count) 1879 public void AddScriptLPS(int count)
@@ -1308,28 +1943,43 @@ namespace OpenSim.Region.Framework.Scenes
1308 /// </summary> 1943 /// </summary>
1309 public void ApplyPhysics() 1944 public void ApplyPhysics()
1310 { 1945 {
1311 // Apply physics to the root prim
1312 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1313
1314 // Apply physics to child prims
1315 SceneObjectPart[] parts = m_parts.GetArray(); 1946 SceneObjectPart[] parts = m_parts.GetArray();
1316 if (parts.Length > 1) 1947 if (parts.Length > 1)
1317 { 1948 {
1949 ResetChildPrimPhysicsPositions();
1950
1951 // Apply physics to the root prim
1952 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1953
1954
1318 for (int i = 0; i < parts.Length; i++) 1955 for (int i = 0; i < parts.Length; i++)
1319 { 1956 {
1320 SceneObjectPart part = parts[i]; 1957 SceneObjectPart part = parts[i];
1321 if (part.LocalId != m_rootPart.LocalId) 1958 if (part.LocalId != m_rootPart.LocalId)
1322 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1959 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1323 } 1960 }
1324
1325 // Hack to get the physics scene geometries in the right spot 1961 // Hack to get the physics scene geometries in the right spot
1326 ResetChildPrimPhysicsPositions(); 1962// ResetChildPrimPhysicsPositions();
1963 if (m_rootPart.PhysActor != null)
1964 {
1965 m_rootPart.PhysActor.Building = false;
1966 }
1967 }
1968 else
1969 {
1970 // Apply physics to the root prim
1971 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1327 } 1972 }
1328 } 1973 }
1329 1974
1330 public void SetOwnerId(UUID userId) 1975 public void SetOwnerId(UUID userId)
1331 { 1976 {
1332 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1977 ForEachPart(delegate(SceneObjectPart part)
1978 {
1979
1980 part.OwnerID = userId;
1981
1982 });
1333 } 1983 }
1334 1984
1335 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1985 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1361,11 +2011,17 @@ namespace OpenSim.Region.Framework.Scenes
1361 return; 2011 return;
1362 } 2012 }
1363 2013
2014 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2015 return;
2016
1364 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2017 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1365 // any exception propogate upwards. 2018 // any exception propogate upwards.
1366 try 2019 try
1367 { 2020 {
1368 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2021 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2022 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2023 m_scene.LoadingPrims) // Land may not be valid yet
2024
1369 { 2025 {
1370 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2026 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1371 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2027 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1392,6 +2048,7 @@ namespace OpenSim.Region.Framework.Scenes
1392 } 2048 }
1393 } 2049 }
1394 } 2050 }
2051
1395 } 2052 }
1396 2053
1397 if (m_scene.UseBackup && HasGroupChanged) 2054 if (m_scene.UseBackup && HasGroupChanged)
@@ -1399,10 +2056,30 @@ namespace OpenSim.Region.Framework.Scenes
1399 // don't backup while it's selected or you're asking for changes mid stream. 2056 // don't backup while it's selected or you're asking for changes mid stream.
1400 if (isTimeToPersist() || forcedBackup) 2057 if (isTimeToPersist() || forcedBackup)
1401 { 2058 {
2059 if (m_rootPart.PhysActor != null &&
2060 (!m_rootPart.PhysActor.IsPhysical))
2061 {
2062 // Possible ghost prim
2063 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2064 {
2065 foreach (SceneObjectPart part in m_parts.GetArray())
2066 {
2067 // Re-set physics actor positions and
2068 // orientations
2069 part.GroupPosition = m_rootPart.GroupPosition;
2070 }
2071 }
2072 }
1402// m_log.DebugFormat( 2073// m_log.DebugFormat(
1403// "[SCENE]: Storing {0}, {1} in {2}", 2074// "[SCENE]: Storing {0}, {1} in {2}",
1404// Name, UUID, m_scene.RegionInfo.RegionName); 2075// Name, UUID, m_scene.RegionInfo.RegionName);
1405 2076
2077 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2078 {
2079 RootPart.Shape.State = 0;
2080 ScheduleGroupForFullUpdate();
2081 }
2082
1406 SceneObjectGroup backup_group = Copy(false); 2083 SceneObjectGroup backup_group = Copy(false);
1407 backup_group.RootPart.Velocity = RootPart.Velocity; 2084 backup_group.RootPart.Velocity = RootPart.Velocity;
1408 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2085 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1412,6 +2089,16 @@ namespace OpenSim.Region.Framework.Scenes
1412 HasGroupChangedDueToDelink = false; 2089 HasGroupChangedDueToDelink = false;
1413 2090
1414 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2091 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2092/*
2093 backup_group.ForEachPart(delegate(SceneObjectPart part)
2094 {
2095 if (part.KeyframeMotion != null)
2096 {
2097 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2098// part.KeyframeMotion.UpdateSceneObject(this);
2099 }
2100 });
2101*/
1415 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2102 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1416 2103
1417 backup_group.ForEachPart(delegate(SceneObjectPart part) 2104 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1468,10 +2155,14 @@ namespace OpenSim.Region.Framework.Scenes
1468 /// <returns></returns> 2155 /// <returns></returns>
1469 public SceneObjectGroup Copy(bool userExposed) 2156 public SceneObjectGroup Copy(bool userExposed)
1470 { 2157 {
2158 m_dupeInProgress = true;
1471 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2159 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1472 dupe.m_isBackedUp = false; 2160 dupe.m_isBackedUp = false;
1473 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2161 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1474 2162
2163 // new group as no sitting avatars
2164 dupe.m_linkedAvatars = new List<ScenePresence>();
2165
1475 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2166 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1476 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2167 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1477 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2168 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1482,7 +2173,7 @@ namespace OpenSim.Region.Framework.Scenes
1482 // This is only necessary when userExposed is false! 2173 // This is only necessary when userExposed is false!
1483 2174
1484 bool previousAttachmentStatus = dupe.IsAttachment; 2175 bool previousAttachmentStatus = dupe.IsAttachment;
1485 2176
1486 if (!userExposed) 2177 if (!userExposed)
1487 dupe.IsAttachment = true; 2178 dupe.IsAttachment = true;
1488 2179
@@ -1495,16 +2186,17 @@ namespace OpenSim.Region.Framework.Scenes
1495 2186
1496 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2187 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1497 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2188 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2189
1498 2190
1499 if (userExposed) 2191 if (userExposed)
1500 dupe.m_rootPart.TrimPermissions(); 2192 dupe.m_rootPart.TrimPermissions();
1501 2193
1502 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2194 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1503 2195
1504 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2196 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1505 { 2197 {
1506 return p1.LinkNum.CompareTo(p2.LinkNum); 2198 return p1.LinkNum.CompareTo(p2.LinkNum);
1507 } 2199 }
1508 ); 2200 );
1509 2201
1510 foreach (SceneObjectPart part in partList) 2202 foreach (SceneObjectPart part in partList)
@@ -1514,41 +2206,56 @@ namespace OpenSim.Region.Framework.Scenes
1514 { 2206 {
1515 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2207 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1516 newPart.LinkNum = part.LinkNum; 2208 newPart.LinkNum = part.LinkNum;
1517 } 2209 if (userExposed)
2210 newPart.ParentID = dupe.m_rootPart.LocalId;
2211 }
1518 else 2212 else
1519 { 2213 {
1520 newPart = dupe.m_rootPart; 2214 newPart = dupe.m_rootPart;
1521 } 2215 }
2216/*
2217 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2218 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1522 2219
1523 // Need to duplicate the physics actor as well 2220 // Need to duplicate the physics actor as well
1524 PhysicsActor originalPartPa = part.PhysActor; 2221 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1525 if (originalPartPa != null && userExposed)
1526 { 2222 {
1527 PrimitiveBaseShape pbs = newPart.Shape; 2223 PrimitiveBaseShape pbs = newPart.Shape;
1528
1529 newPart.PhysActor 2224 newPart.PhysActor
1530 = m_scene.PhysicsScene.AddPrimShape( 2225 = m_scene.PhysicsScene.AddPrimShape(
1531 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2226 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1532 pbs, 2227 pbs,
1533 newPart.AbsolutePosition, 2228 newPart.AbsolutePosition,
1534 newPart.Scale, 2229 newPart.Scale,
1535 newPart.RotationOffset, 2230 newPart.GetWorldRotation(),
1536 originalPartPa.IsPhysical, 2231 isphys,
2232 isphan,
1537 newPart.LocalId); 2233 newPart.LocalId);
1538 2234
1539 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2235 newPart.DoPhysicsPropertyUpdate(isphys, true);
1540 } 2236 */
2237 if (userExposed)
2238 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2239// }
2240 // copy keyframemotion
2241 if (part.KeyframeMotion != null)
2242 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1541 } 2243 }
1542 2244
1543 if (userExposed) 2245 if (userExposed)
1544 { 2246 {
1545 dupe.UpdateParentIDs(); 2247// done above dupe.UpdateParentIDs();
2248
2249 if (dupe.m_rootPart.PhysActor != null)
2250 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2251
1546 dupe.HasGroupChanged = true; 2252 dupe.HasGroupChanged = true;
1547 dupe.AttachToBackup(); 2253 dupe.AttachToBackup();
1548 2254
1549 ScheduleGroupForFullUpdate(); 2255 ScheduleGroupForFullUpdate();
1550 } 2256 }
1551 2257
2258 m_dupeInProgress = false;
1552 return dupe; 2259 return dupe;
1553 } 2260 }
1554 2261
@@ -1560,11 +2267,24 @@ namespace OpenSim.Region.Framework.Scenes
1560 /// <param name="cGroupID"></param> 2267 /// <param name="cGroupID"></param>
1561 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2268 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1562 { 2269 {
1563 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2270 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2271 // give newpart a new local ID lettng old part keep same
2272 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2273 newpart.LocalId = m_scene.AllocateLocalId();
2274
2275 SetRootPart(newpart);
2276 if (userExposed)
2277 RootPart.Velocity = Vector3.Zero; // In case source is moving
1564 } 2278 }
1565 2279
1566 public void ScriptSetPhysicsStatus(bool usePhysics) 2280 public void ScriptSetPhysicsStatus(bool usePhysics)
1567 { 2281 {
2282 if (usePhysics)
2283 {
2284 if (RootPart.KeyframeMotion != null)
2285 RootPart.KeyframeMotion.Stop();
2286 RootPart.KeyframeMotion = null;
2287 }
1568 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2288 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1569 } 2289 }
1570 2290
@@ -1612,27 +2332,14 @@ namespace OpenSim.Region.Framework.Scenes
1612 2332
1613 if (pa != null) 2333 if (pa != null)
1614 { 2334 {
1615 pa.AddForce(impulse, true); 2335 // false to be applied as a impulse
1616 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2336 pa.AddForce(impulse, false);
1617 }
1618 }
1619 }
1620
1621 public void applyAngularImpulse(Vector3 impulse)
1622 {
1623 PhysicsActor pa = RootPart.PhysActor;
1624
1625 if (pa != null)
1626 {
1627 if (!IsAttachment)
1628 {
1629 pa.AddAngularForce(impulse, true);
1630 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2337 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1631 } 2338 }
1632 } 2339 }
1633 } 2340 }
1634 2341
1635 public void setAngularImpulse(Vector3 impulse) 2342 public void ApplyAngularImpulse(Vector3 impulse)
1636 { 2343 {
1637 PhysicsActor pa = RootPart.PhysActor; 2344 PhysicsActor pa = RootPart.PhysActor;
1638 2345
@@ -1640,7 +2347,8 @@ namespace OpenSim.Region.Framework.Scenes
1640 { 2347 {
1641 if (!IsAttachment) 2348 if (!IsAttachment)
1642 { 2349 {
1643 pa.Torque = impulse; 2350 // false to be applied as a impulse
2351 pa.AddAngularForce(impulse, false);
1644 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2352 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1645 } 2353 }
1646 } 2354 }
@@ -1648,20 +2356,10 @@ namespace OpenSim.Region.Framework.Scenes
1648 2356
1649 public Vector3 GetTorque() 2357 public Vector3 GetTorque()
1650 { 2358 {
1651 PhysicsActor pa = RootPart.PhysActor; 2359 return RootPart.Torque;
1652
1653 if (pa != null)
1654 {
1655 if (!IsAttachment)
1656 {
1657 Vector3 torque = pa.Torque;
1658 return torque;
1659 }
1660 }
1661
1662 return Vector3.Zero;
1663 } 2360 }
1664 2361
2362 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1665 public void moveToTarget(Vector3 target, float tau) 2363 public void moveToTarget(Vector3 target, float tau)
1666 { 2364 {
1667 if (IsAttachment) 2365 if (IsAttachment)
@@ -1693,6 +2391,46 @@ namespace OpenSim.Region.Framework.Scenes
1693 pa.PIDActive = false; 2391 pa.PIDActive = false;
1694 } 2392 }
1695 2393
2394 public void rotLookAt(Quaternion target, float strength, float damping)
2395 {
2396 SceneObjectPart rootpart = m_rootPart;
2397 if (rootpart != null)
2398 {
2399 if (IsAttachment)
2400 {
2401 /*
2402 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2403 if (avatar != null)
2404 {
2405 Rotate the Av?
2406 } */
2407 }
2408 else
2409 {
2410 if (rootpart.PhysActor != null)
2411 { // APID must be implemented in your physics system for this to function.
2412 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2413 rootpart.PhysActor.APIDStrength = strength;
2414 rootpart.PhysActor.APIDDamping = damping;
2415 rootpart.PhysActor.APIDActive = true;
2416 }
2417 }
2418 }
2419 }
2420
2421 public void stopLookAt()
2422 {
2423 SceneObjectPart rootpart = m_rootPart;
2424 if (rootpart != null)
2425 {
2426 if (rootpart.PhysActor != null)
2427 { // APID must be implemented in your physics system for this to function.
2428 rootpart.PhysActor.APIDActive = false;
2429 }
2430 }
2431
2432 }
2433
1696 /// <summary> 2434 /// <summary>
1697 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2435 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1698 /// </summary> 2436 /// </summary>
@@ -1709,7 +2447,7 @@ namespace OpenSim.Region.Framework.Scenes
1709 { 2447 {
1710 pa.PIDHoverHeight = height; 2448 pa.PIDHoverHeight = height;
1711 pa.PIDHoverType = hoverType; 2449 pa.PIDHoverType = hoverType;
1712 pa.PIDTau = tau; 2450 pa.PIDHoverTau = tau;
1713 pa.PIDHoverActive = true; 2451 pa.PIDHoverActive = true;
1714 } 2452 }
1715 else 2453 else
@@ -1749,7 +2487,12 @@ namespace OpenSim.Region.Framework.Scenes
1749 /// <param name="cGroupID"></param> 2487 /// <param name="cGroupID"></param>
1750 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2488 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1751 { 2489 {
1752 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2490 // give new ID to the new part, letting old keep original
2491 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2492 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2493 newPart.LocalId = m_scene.AllocateLocalId();
2494 newPart.SetParent(this);
2495
1753 AddPart(newPart); 2496 AddPart(newPart);
1754 2497
1755 SetPartAsNonRoot(newPart); 2498 SetPartAsNonRoot(newPart);
@@ -1888,11 +2631,11 @@ namespace OpenSim.Region.Framework.Scenes
1888 /// Immediately send a full update for this scene object. 2631 /// Immediately send a full update for this scene object.
1889 /// </summary> 2632 /// </summary>
1890 public void SendGroupFullUpdate() 2633 public void SendGroupFullUpdate()
1891 { 2634 {
1892 if (IsDeleted) 2635 if (IsDeleted)
1893 return; 2636 return;
1894 2637
1895// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2638// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1896 2639
1897 RootPart.SendFullUpdateToAllClients(); 2640 RootPart.SendFullUpdateToAllClients();
1898 2641
@@ -2048,6 +2791,11 @@ namespace OpenSim.Region.Framework.Scenes
2048 // 'linkPart' == the root of the group being linked into this group 2791 // 'linkPart' == the root of the group being linked into this group
2049 SceneObjectPart linkPart = objectGroup.m_rootPart; 2792 SceneObjectPart linkPart = objectGroup.m_rootPart;
2050 2793
2794 if (m_rootPart.PhysActor != null)
2795 m_rootPart.PhysActor.Building = true;
2796 if (linkPart.PhysActor != null)
2797 linkPart.PhysActor.Building = true;
2798
2051 // physics flags from group to be applied to linked parts 2799 // physics flags from group to be applied to linked parts
2052 bool grpusephys = UsesPhysics; 2800 bool grpusephys = UsesPhysics;
2053 bool grptemporary = IsTemporary; 2801 bool grptemporary = IsTemporary;
@@ -2073,12 +2821,12 @@ namespace OpenSim.Region.Framework.Scenes
2073 Vector3 axPos = linkPart.OffsetPosition; 2821 Vector3 axPos = linkPart.OffsetPosition;
2074 // Rotate the linking root SOP's position to be relative to the new root prim 2822 // Rotate the linking root SOP's position to be relative to the new root prim
2075 Quaternion parentRot = m_rootPart.RotationOffset; 2823 Quaternion parentRot = m_rootPart.RotationOffset;
2076 axPos *= Quaternion.Inverse(parentRot); 2824 axPos *= Quaternion.Conjugate(parentRot);
2077 linkPart.OffsetPosition = axPos; 2825 linkPart.OffsetPosition = axPos;
2078 2826
2079 // Make the linking root SOP's rotation relative to the new root prim 2827 // Make the linking root SOP's rotation relative to the new root prim
2080 Quaternion oldRot = linkPart.RotationOffset; 2828 Quaternion oldRot = linkPart.RotationOffset;
2081 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2829 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2082 linkPart.RotationOffset = newRot; 2830 linkPart.RotationOffset = newRot;
2083 2831
2084 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2832 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2112,7 +2860,7 @@ namespace OpenSim.Region.Framework.Scenes
2112 linkPart.CreateSelected = true; 2860 linkPart.CreateSelected = true;
2113 2861
2114 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2862 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2115 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2863 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2116 2864
2117 // If the added SOP is physical, also tell the physics engine about the link relationship. 2865 // If the added SOP is physical, also tell the physics engine about the link relationship.
2118 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2866 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2122,6 +2870,7 @@ namespace OpenSim.Region.Framework.Scenes
2122 } 2870 }
2123 2871
2124 linkPart.LinkNum = linkNum++; 2872 linkPart.LinkNum = linkNum++;
2873 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2125 2874
2126 // Get a list of the SOP's in the old group in order of their linknum's. 2875 // Get a list of the SOP's in the old group in order of their linknum's.
2127 SceneObjectPart[] ogParts = objectGroup.Parts; 2876 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2140,7 +2889,7 @@ namespace OpenSim.Region.Framework.Scenes
2140 2889
2141 // Update the physics flags for the newly added SOP 2890 // Update the physics flags for the newly added SOP
2142 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2891 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2143 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2892 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2144 2893
2145 // If the added SOP is physical, also tell the physics engine about the link relationship. 2894 // If the added SOP is physical, also tell the physics engine about the link relationship.
2146 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2895 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2158,7 +2907,7 @@ namespace OpenSim.Region.Framework.Scenes
2158 objectGroup.IsDeleted = true; 2907 objectGroup.IsDeleted = true;
2159 2908
2160 objectGroup.m_parts.Clear(); 2909 objectGroup.m_parts.Clear();
2161 2910
2162 // Can't do this yet since backup still makes use of the root part without any synchronization 2911 // Can't do this yet since backup still makes use of the root part without any synchronization
2163// objectGroup.m_rootPart = null; 2912// objectGroup.m_rootPart = null;
2164 2913
@@ -2172,6 +2921,9 @@ namespace OpenSim.Region.Framework.Scenes
2172 // unmoved prims! 2921 // unmoved prims!
2173 ResetChildPrimPhysicsPositions(); 2922 ResetChildPrimPhysicsPositions();
2174 2923
2924 if (m_rootPart.PhysActor != null)
2925 m_rootPart.PhysActor.Building = false;
2926
2175 //HasGroupChanged = true; 2927 //HasGroupChanged = true;
2176 //ScheduleGroupForFullUpdate(); 2928 //ScheduleGroupForFullUpdate();
2177 } 2929 }
@@ -2239,7 +2991,10 @@ namespace OpenSim.Region.Framework.Scenes
2239// m_log.DebugFormat( 2991// m_log.DebugFormat(
2240// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2992// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2241// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2993// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2242 2994
2995 if (m_rootPart.PhysActor != null)
2996 m_rootPart.PhysActor.Building = true;
2997
2243 linkPart.ClearUndoState(); 2998 linkPart.ClearUndoState();
2244 2999
2245 Vector3 worldPos = linkPart.GetWorldPosition(); 3000 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2310,6 +3065,14 @@ namespace OpenSim.Region.Framework.Scenes
2310 3065
2311 // When we delete a group, we currently have to force persist to the database if the object id has changed 3066 // When we delete a group, we currently have to force persist to the database if the object id has changed
2312 // (since delete works by deleting all rows which have a given object id) 3067 // (since delete works by deleting all rows which have a given object id)
3068
3069 // this is as it seems to be in sl now
3070 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3071 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3072
3073 if (m_rootPart.PhysActor != null)
3074 m_rootPart.PhysActor.Building = false;
3075
2313 objectGroup.HasGroupChangedDueToDelink = true; 3076 objectGroup.HasGroupChangedDueToDelink = true;
2314 3077
2315 return objectGroup; 3078 return objectGroup;
@@ -2321,6 +3084,8 @@ namespace OpenSim.Region.Framework.Scenes
2321 /// <param name="objectGroup"></param> 3084 /// <param name="objectGroup"></param>
2322 public virtual void DetachFromBackup() 3085 public virtual void DetachFromBackup()
2323 { 3086 {
3087 if (m_scene != null)
3088 m_scene.SceneGraph.FireDetachFromBackup(this);
2324 if (m_isBackedUp && Scene != null) 3089 if (m_isBackedUp && Scene != null)
2325 m_scene.EventManager.OnBackup -= ProcessBackup; 3090 m_scene.EventManager.OnBackup -= ProcessBackup;
2326 3091
@@ -2341,7 +3106,8 @@ namespace OpenSim.Region.Framework.Scenes
2341 Vector3 axPos = part.OffsetPosition; 3106 Vector3 axPos = part.OffsetPosition;
2342 axPos *= parentRot; 3107 axPos *= parentRot;
2343 part.OffsetPosition = axPos; 3108 part.OffsetPosition = axPos;
2344 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3109 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3110 part.GroupPosition = newPos;
2345 part.OffsetPosition = Vector3.Zero; 3111 part.OffsetPosition = Vector3.Zero;
2346 3112
2347 // Compution our rotation to be not relative to the old parent 3113 // Compution our rotation to be not relative to the old parent
@@ -2356,7 +3122,7 @@ namespace OpenSim.Region.Framework.Scenes
2356 part.LinkNum = linkNum; 3122 part.LinkNum = linkNum;
2357 3123
2358 // Compute the new position of this SOP relative to the group position 3124 // Compute the new position of this SOP relative to the group position
2359 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3125 part.OffsetPosition = newPos - AbsolutePosition;
2360 3126
2361 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3127 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2362 // It would have the affect of setting the physics engine position multiple 3128 // It would have the affect of setting the physics engine position multiple
@@ -2366,18 +3132,19 @@ namespace OpenSim.Region.Framework.Scenes
2366 // Rotate the relative position by the rotation of the group 3132 // Rotate the relative position by the rotation of the group
2367 Quaternion rootRotation = m_rootPart.RotationOffset; 3133 Quaternion rootRotation = m_rootPart.RotationOffset;
2368 Vector3 pos = part.OffsetPosition; 3134 Vector3 pos = part.OffsetPosition;
2369 pos *= Quaternion.Inverse(rootRotation); 3135 pos *= Quaternion.Conjugate(rootRotation);
2370 part.OffsetPosition = pos; 3136 part.OffsetPosition = pos;
2371 3137
2372 // Compute the SOP's rotation relative to the rotation of the group. 3138 // Compute the SOP's rotation relative to the rotation of the group.
2373 parentRot = m_rootPart.RotationOffset; 3139 parentRot = m_rootPart.RotationOffset;
2374 oldRot = part.RotationOffset; 3140 oldRot = part.RotationOffset;
2375 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3141 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2376 part.RotationOffset = newRot; 3142 part.RotationOffset = newRot;
2377 3143
2378 // Since this SOP's state has changed, push those changes into the physics engine 3144 // Since this SOP's state has changed, push those changes into the physics engine
2379 // and the simulator. 3145 // and the simulator.
2380 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3146 // done on caller
3147// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2381 } 3148 }
2382 3149
2383 /// <summary> 3150 /// <summary>
@@ -2399,10 +3166,14 @@ namespace OpenSim.Region.Framework.Scenes
2399 { 3166 {
2400 if (!m_rootPart.BlockGrab) 3167 if (!m_rootPart.BlockGrab)
2401 { 3168 {
2402 Vector3 llmoveforce = pos - AbsolutePosition; 3169/* Vector3 llmoveforce = pos - AbsolutePosition;
2403 Vector3 grabforce = llmoveforce; 3170 Vector3 grabforce = llmoveforce;
2404 grabforce = (grabforce / 10) * pa.Mass; 3171 grabforce = (grabforce / 10) * pa.Mass;
2405 pa.AddForce(grabforce, true); 3172 */
3173 // empirically convert distance diference to a impulse
3174 Vector3 grabforce = pos - AbsolutePosition;
3175 grabforce = grabforce * (pa.Mass/ 10.0f);
3176 pa.AddForce(grabforce, false);
2406 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3177 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2407 } 3178 }
2408 } 3179 }
@@ -2598,6 +3369,8 @@ namespace OpenSim.Region.Framework.Scenes
2598 /// <param name="SetVolumeDetect"></param> 3369 /// <param name="SetVolumeDetect"></param>
2599 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3370 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2600 { 3371 {
3372 HasGroupChanged = true;
3373
2601 SceneObjectPart selectionPart = GetPart(localID); 3374 SceneObjectPart selectionPart = GetPart(localID);
2602 3375
2603 if (SetTemporary && Scene != null) 3376 if (SetTemporary && Scene != null)
@@ -2628,8 +3401,22 @@ namespace OpenSim.Region.Framework.Scenes
2628 } 3401 }
2629 } 3402 }
2630 3403
2631 for (int i = 0; i < parts.Length; i++) 3404 if (parts.Length > 1)
2632 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3405 {
3406 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3407
3408 for (int i = 0; i < parts.Length; i++)
3409 {
3410
3411 if (parts[i].UUID != m_rootPart.UUID)
3412 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3413 }
3414
3415 if (m_rootPart.PhysActor != null)
3416 m_rootPart.PhysActor.Building = false;
3417 }
3418 else
3419 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2633 } 3420 }
2634 } 3421 }
2635 3422
@@ -2642,6 +3429,17 @@ namespace OpenSim.Region.Framework.Scenes
2642 } 3429 }
2643 } 3430 }
2644 3431
3432
3433
3434 /// <summary>
3435 /// Gets the number of parts
3436 /// </summary>
3437 /// <returns></returns>
3438 public int GetPartCount()
3439 {
3440 return Parts.Count();
3441 }
3442
2645 /// <summary> 3443 /// <summary>
2646 /// Update the texture entry for this part 3444 /// Update the texture entry for this part
2647 /// </summary> 3445 /// </summary>
@@ -2658,11 +3456,20 @@ namespace OpenSim.Region.Framework.Scenes
2658 3456
2659 public void AdjustChildPrimPermissions() 3457 public void AdjustChildPrimPermissions()
2660 { 3458 {
3459 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits
3460 uint foldedPerms = RootPart.OwnerMask & 3;
3461
2661 ForEachPart(part => 3462 ForEachPart(part =>
2662 { 3463 {
3464 newOwnerMask &= part.BaseMask;
2663 if (part != RootPart) 3465 if (part != RootPart)
2664 part.ClonePermissions(RootPart); 3466 part.ClonePermissions(RootPart);
2665 }); 3467 });
3468
3469 uint lockMask = ~(uint)PermissionMask.Move;
3470 uint lockBit = RootPart.OwnerMask & (uint)PermissionMask.Move;
3471 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
3472 RootPart.ScheduleFullUpdate();
2666 } 3473 }
2667 3474
2668 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 3475 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2670,8 +3477,24 @@ namespace OpenSim.Region.Framework.Scenes
2670 { 3477 {
2671 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3478 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2672 3479
3480 bool god = Scene.Permissions.IsGod(AgentID);
3481
3482 if (field == 1 && god)
3483 {
3484 ForEachPart(part =>
3485 {
3486 part.BaseMask = RootPart.BaseMask;
3487 });
3488 }
3489
2673 AdjustChildPrimPermissions(); 3490 AdjustChildPrimPermissions();
2674 3491
3492 if (field == 1 && god) // Base mask was set. Update all child part inventories
3493 {
3494 foreach (SceneObjectPart part in Parts)
3495 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3496 }
3497
2675 HasGroupChanged = true; 3498 HasGroupChanged = true;
2676 3499
2677 // Send the group's properties to all clients once all parts are updated 3500 // Send the group's properties to all clients once all parts are updated
@@ -2717,8 +3540,6 @@ namespace OpenSim.Region.Framework.Scenes
2717 3540
2718 PhysicsActor pa = m_rootPart.PhysActor; 3541 PhysicsActor pa = m_rootPart.PhysActor;
2719 3542
2720 RootPart.StoreUndoState(true);
2721
2722 if (Scene != null) 3543 if (Scene != null)
2723 { 3544 {
2724 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3545 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2746,7 +3567,6 @@ namespace OpenSim.Region.Framework.Scenes
2746 SceneObjectPart obPart = parts[i]; 3567 SceneObjectPart obPart = parts[i];
2747 if (obPart.UUID != m_rootPart.UUID) 3568 if (obPart.UUID != m_rootPart.UUID)
2748 { 3569 {
2749// obPart.IgnoreUndoUpdate = true;
2750 Vector3 oldSize = new Vector3(obPart.Scale); 3570 Vector3 oldSize = new Vector3(obPart.Scale);
2751 3571
2752 float f = 1.0f; 3572 float f = 1.0f;
@@ -2858,8 +3678,6 @@ namespace OpenSim.Region.Framework.Scenes
2858 z *= a; 3678 z *= a;
2859 } 3679 }
2860 } 3680 }
2861
2862// obPart.IgnoreUndoUpdate = false;
2863 } 3681 }
2864 } 3682 }
2865 } 3683 }
@@ -2869,9 +3687,7 @@ namespace OpenSim.Region.Framework.Scenes
2869 prevScale.Y *= y; 3687 prevScale.Y *= y;
2870 prevScale.Z *= z; 3688 prevScale.Z *= z;
2871 3689
2872// RootPart.IgnoreUndoUpdate = true;
2873 RootPart.Resize(prevScale); 3690 RootPart.Resize(prevScale);
2874// RootPart.IgnoreUndoUpdate = false;
2875 3691
2876 for (int i = 0; i < parts.Length; i++) 3692 for (int i = 0; i < parts.Length; i++)
2877 { 3693 {
@@ -2879,8 +3695,6 @@ namespace OpenSim.Region.Framework.Scenes
2879 3695
2880 if (obPart.UUID != m_rootPart.UUID) 3696 if (obPart.UUID != m_rootPart.UUID)
2881 { 3697 {
2882 obPart.IgnoreUndoUpdate = true;
2883
2884 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3698 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2885 currentpos.X *= x; 3699 currentpos.X *= x;
2886 currentpos.Y *= y; 3700 currentpos.Y *= y;
@@ -2893,16 +3707,12 @@ namespace OpenSim.Region.Framework.Scenes
2893 3707
2894 obPart.Resize(newSize); 3708 obPart.Resize(newSize);
2895 obPart.UpdateOffSet(currentpos); 3709 obPart.UpdateOffSet(currentpos);
2896
2897 obPart.IgnoreUndoUpdate = false;
2898 } 3710 }
2899 3711
2900// obPart.IgnoreUndoUpdate = false; 3712 HasGroupChanged = true;
2901// obPart.StoreUndoState(); 3713 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3714 ScheduleGroupForTerseUpdate();
2902 } 3715 }
2903
2904// m_log.DebugFormat(
2905// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2906 } 3716 }
2907 3717
2908 #endregion 3718 #endregion
@@ -2915,14 +3725,6 @@ namespace OpenSim.Region.Framework.Scenes
2915 /// <param name="pos"></param> 3725 /// <param name="pos"></param>
2916 public void UpdateGroupPosition(Vector3 pos) 3726 public void UpdateGroupPosition(Vector3 pos)
2917 { 3727 {
2918// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2919
2920 RootPart.StoreUndoState(true);
2921
2922// SceneObjectPart[] parts = m_parts.GetArray();
2923// for (int i = 0; i < parts.Length; i++)
2924// parts[i].StoreUndoState();
2925
2926 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3728 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2927 { 3729 {
2928 if (IsAttachment) 3730 if (IsAttachment)
@@ -2955,21 +3757,17 @@ namespace OpenSim.Region.Framework.Scenes
2955 /// </summary> 3757 /// </summary>
2956 /// <param name="pos"></param> 3758 /// <param name="pos"></param>
2957 /// <param name="localID"></param> 3759 /// <param name="localID"></param>
3760 ///
3761
2958 public void UpdateSinglePosition(Vector3 pos, uint localID) 3762 public void UpdateSinglePosition(Vector3 pos, uint localID)
2959 { 3763 {
2960 SceneObjectPart part = GetPart(localID); 3764 SceneObjectPart part = GetPart(localID);
2961 3765
2962// SceneObjectPart[] parts = m_parts.GetArray();
2963// for (int i = 0; i < parts.Length; i++)
2964// parts[i].StoreUndoState();
2965
2966 if (part != null) 3766 if (part != null)
2967 { 3767 {
2968// m_log.DebugFormat( 3768// unlock parts position change
2969// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3769 if (m_rootPart.PhysActor != null)
2970 3770 m_rootPart.PhysActor.Building = true;
2971 part.StoreUndoState(false);
2972 part.IgnoreUndoUpdate = true;
2973 3771
2974 if (part.UUID == m_rootPart.UUID) 3772 if (part.UUID == m_rootPart.UUID)
2975 { 3773 {
@@ -2980,8 +3778,10 @@ namespace OpenSim.Region.Framework.Scenes
2980 part.UpdateOffSet(pos); 3778 part.UpdateOffSet(pos);
2981 } 3779 }
2982 3780
3781 if (m_rootPart.PhysActor != null)
3782 m_rootPart.PhysActor.Building = false;
3783
2983 HasGroupChanged = true; 3784 HasGroupChanged = true;
2984 part.IgnoreUndoUpdate = false;
2985 } 3785 }
2986 } 3786 }
2987 3787
@@ -2991,13 +3791,7 @@ namespace OpenSim.Region.Framework.Scenes
2991 /// <param name="pos"></param> 3791 /// <param name="pos"></param>
2992 public void UpdateRootPosition(Vector3 pos) 3792 public void UpdateRootPosition(Vector3 pos)
2993 { 3793 {
2994// m_log.DebugFormat( 3794 // needs to be called with phys building true
2995// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2996
2997// SceneObjectPart[] parts = m_parts.GetArray();
2998// for (int i = 0; i < parts.Length; i++)
2999// parts[i].StoreUndoState();
3000
3001 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3795 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3002 Vector3 oldPos = 3796 Vector3 oldPos =
3003 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3797 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3020,7 +3814,14 @@ namespace OpenSim.Region.Framework.Scenes
3020 AbsolutePosition = newPos; 3814 AbsolutePosition = newPos;
3021 3815
3022 HasGroupChanged = true; 3816 HasGroupChanged = true;
3023 ScheduleGroupForTerseUpdate(); 3817 if (m_rootPart.Undoing)
3818 {
3819 ScheduleGroupForFullUpdate();
3820 }
3821 else
3822 {
3823 ScheduleGroupForTerseUpdate();
3824 }
3024 } 3825 }
3025 3826
3026 #endregion 3827 #endregion
@@ -3033,24 +3834,16 @@ namespace OpenSim.Region.Framework.Scenes
3033 /// <param name="rot"></param> 3834 /// <param name="rot"></param>
3034 public void UpdateGroupRotationR(Quaternion rot) 3835 public void UpdateGroupRotationR(Quaternion rot)
3035 { 3836 {
3036// m_log.DebugFormat(
3037// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3038
3039// SceneObjectPart[] parts = m_parts.GetArray();
3040// for (int i = 0; i < parts.Length; i++)
3041// parts[i].StoreUndoState();
3042
3043 m_rootPart.StoreUndoState(true);
3044
3045 m_rootPart.UpdateRotation(rot); 3837 m_rootPart.UpdateRotation(rot);
3046 3838
3839/* this is done by rootpart RotationOffset set called by UpdateRotation
3047 PhysicsActor actor = m_rootPart.PhysActor; 3840 PhysicsActor actor = m_rootPart.PhysActor;
3048 if (actor != null) 3841 if (actor != null)
3049 { 3842 {
3050 actor.Orientation = m_rootPart.RotationOffset; 3843 actor.Orientation = m_rootPart.RotationOffset;
3051 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3844 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3052 } 3845 }
3053 3846*/
3054 HasGroupChanged = true; 3847 HasGroupChanged = true;
3055 ScheduleGroupForTerseUpdate(); 3848 ScheduleGroupForTerseUpdate();
3056 } 3849 }
@@ -3062,16 +3855,6 @@ namespace OpenSim.Region.Framework.Scenes
3062 /// <param name="rot"></param> 3855 /// <param name="rot"></param>
3063 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3856 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3064 { 3857 {
3065// m_log.DebugFormat(
3066// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3067
3068// SceneObjectPart[] parts = m_parts.GetArray();
3069// for (int i = 0; i < parts.Length; i++)
3070// parts[i].StoreUndoState();
3071
3072 RootPart.StoreUndoState(true);
3073 RootPart.IgnoreUndoUpdate = true;
3074
3075 m_rootPart.UpdateRotation(rot); 3858 m_rootPart.UpdateRotation(rot);
3076 3859
3077 PhysicsActor actor = m_rootPart.PhysActor; 3860 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3090,8 +3873,6 @@ namespace OpenSim.Region.Framework.Scenes
3090 3873
3091 HasGroupChanged = true; 3874 HasGroupChanged = true;
3092 ScheduleGroupForTerseUpdate(); 3875 ScheduleGroupForTerseUpdate();
3093
3094 RootPart.IgnoreUndoUpdate = false;
3095 } 3876 }
3096 3877
3097 /// <summary> 3878 /// <summary>
@@ -3104,13 +3885,11 @@ namespace OpenSim.Region.Framework.Scenes
3104 SceneObjectPart part = GetPart(localID); 3885 SceneObjectPart part = GetPart(localID);
3105 3886
3106 SceneObjectPart[] parts = m_parts.GetArray(); 3887 SceneObjectPart[] parts = m_parts.GetArray();
3107 for (int i = 0; i < parts.Length; i++)
3108 parts[i].StoreUndoState();
3109 3888
3110 if (part != null) 3889 if (part != null)
3111 { 3890 {
3112// m_log.DebugFormat( 3891 if (m_rootPart.PhysActor != null)
3113// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3892 m_rootPart.PhysActor.Building = true;
3114 3893
3115 if (part.UUID == m_rootPart.UUID) 3894 if (part.UUID == m_rootPart.UUID)
3116 { 3895 {
@@ -3120,6 +3899,9 @@ namespace OpenSim.Region.Framework.Scenes
3120 { 3899 {
3121 part.UpdateRotation(rot); 3900 part.UpdateRotation(rot);
3122 } 3901 }
3902
3903 if (m_rootPart.PhysActor != null)
3904 m_rootPart.PhysActor.Building = false;
3123 } 3905 }
3124 } 3906 }
3125 3907
@@ -3133,12 +3915,8 @@ namespace OpenSim.Region.Framework.Scenes
3133 SceneObjectPart part = GetPart(localID); 3915 SceneObjectPart part = GetPart(localID);
3134 if (part != null) 3916 if (part != null)
3135 { 3917 {
3136// m_log.DebugFormat( 3918 if (m_rootPart.PhysActor != null)
3137// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3919 m_rootPart.PhysActor.Building = true;
3138// part.Name, part.LocalId, rot);
3139
3140 part.StoreUndoState();
3141 part.IgnoreUndoUpdate = true;
3142 3920
3143 if (part.UUID == m_rootPart.UUID) 3921 if (part.UUID == m_rootPart.UUID)
3144 { 3922 {
@@ -3151,7 +3929,8 @@ namespace OpenSim.Region.Framework.Scenes
3151 part.OffsetPosition = pos; 3929 part.OffsetPosition = pos;
3152 } 3930 }
3153 3931
3154 part.IgnoreUndoUpdate = false; 3932 if (m_rootPart.PhysActor != null)
3933 m_rootPart.PhysActor.Building = false;
3155 } 3934 }
3156 } 3935 }
3157 3936
@@ -3161,15 +3940,12 @@ namespace OpenSim.Region.Framework.Scenes
3161 /// <param name="rot"></param> 3940 /// <param name="rot"></param>
3162 public void UpdateRootRotation(Quaternion rot) 3941 public void UpdateRootRotation(Quaternion rot)
3163 { 3942 {
3164// m_log.DebugFormat( 3943 // needs to be called with phys building true
3165// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3166// Name, LocalId, rot);
3167
3168 Quaternion axRot = rot; 3944 Quaternion axRot = rot;
3169 Quaternion oldParentRot = m_rootPart.RotationOffset; 3945 Quaternion oldParentRot = m_rootPart.RotationOffset;
3170 3946
3171 m_rootPart.StoreUndoState(); 3947 //Don't use UpdateRotation because it schedules an update prematurely
3172 m_rootPart.UpdateRotation(rot); 3948 m_rootPart.RotationOffset = rot;
3173 3949
3174 PhysicsActor pa = m_rootPart.PhysActor; 3950 PhysicsActor pa = m_rootPart.PhysActor;
3175 3951
@@ -3185,35 +3961,145 @@ namespace OpenSim.Region.Framework.Scenes
3185 SceneObjectPart prim = parts[i]; 3961 SceneObjectPart prim = parts[i];
3186 if (prim.UUID != m_rootPart.UUID) 3962 if (prim.UUID != m_rootPart.UUID)
3187 { 3963 {
3188 prim.IgnoreUndoUpdate = true; 3964 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3965 NewRot = Quaternion.Inverse(axRot) * NewRot;
3966 prim.RotationOffset = NewRot;
3967
3189 Vector3 axPos = prim.OffsetPosition; 3968 Vector3 axPos = prim.OffsetPosition;
3969
3190 axPos *= oldParentRot; 3970 axPos *= oldParentRot;
3191 axPos *= Quaternion.Inverse(axRot); 3971 axPos *= Quaternion.Inverse(axRot);
3192 prim.OffsetPosition = axPos; 3972 prim.OffsetPosition = axPos;
3193 Quaternion primsRot = prim.RotationOffset; 3973 }
3194 Quaternion newRot = oldParentRot * primsRot; 3974 }
3195 newRot = Quaternion.Inverse(axRot) * newRot;
3196 prim.RotationOffset = newRot;
3197 prim.ScheduleTerseUpdate();
3198 prim.IgnoreUndoUpdate = false;
3199 }
3200 }
3201
3202// for (int i = 0; i < parts.Length; i++)
3203// {
3204// SceneObjectPart childpart = parts[i];
3205// if (childpart != m_rootPart)
3206// {
3207//// childpart.IgnoreUndoUpdate = false;
3208//// childpart.StoreUndoState();
3209// }
3210// }
3211 3975
3212 m_rootPart.ScheduleTerseUpdate(); 3976 HasGroupChanged = true;
3977 ScheduleGroupForFullUpdate();
3978 }
3213 3979
3214// m_log.DebugFormat( 3980 private enum updatetype :int
3215// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3981 {
3216// Name, LocalId, rot); 3982 none = 0,
3983 partterse = 1,
3984 partfull = 2,
3985 groupterse = 3,
3986 groupfull = 4
3987 }
3988
3989 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3990 {
3991 // TODO this still as excessive *.Schedule*Update()s
3992
3993 if (part != null && part.ParentGroup != null)
3994 {
3995 ObjectChangeType change = data.change;
3996 bool togroup = ((change & ObjectChangeType.Group) != 0);
3997 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3998
3999 SceneObjectGroup group = part.ParentGroup;
4000 PhysicsActor pha = group.RootPart.PhysActor;
4001
4002 updatetype updateType = updatetype.none;
4003
4004 if (togroup)
4005 {
4006 // related to group
4007 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4008 {
4009 if ((change & ObjectChangeType.Rotation) != 0)
4010 {
4011 group.RootPart.UpdateRotation(data.rotation);
4012 updateType = updatetype.none;
4013 }
4014 if ((change & ObjectChangeType.Position) != 0)
4015 {
4016 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4017 UpdateGroupPosition(data.position);
4018 updateType = updatetype.groupterse;
4019 }
4020 else
4021 // ugly rotation update of all parts
4022 {
4023 group.ResetChildPrimPhysicsPositions();
4024 }
4025
4026 }
4027 if ((change & ObjectChangeType.Scale) != 0)
4028 {
4029 if (pha != null)
4030 pha.Building = true;
4031
4032 group.GroupResize(data.scale);
4033 updateType = updatetype.none;
4034
4035 if (pha != null)
4036 pha.Building = false;
4037 }
4038 }
4039 else
4040 {
4041 // related to single prim in a link-set ( ie group)
4042 if (pha != null)
4043 pha.Building = true;
4044
4045 // root part is special
4046 // parts offset positions or rotations need to change also
4047
4048 if (part == group.RootPart)
4049 {
4050 if ((change & ObjectChangeType.Rotation) != 0)
4051 group.UpdateRootRotation(data.rotation);
4052 if ((change & ObjectChangeType.Position) != 0)
4053 group.UpdateRootPosition(data.position);
4054 if ((change & ObjectChangeType.Scale) != 0)
4055 part.Resize(data.scale);
4056 }
4057 else
4058 {
4059 if ((change & ObjectChangeType.Position) != 0)
4060 {
4061 part.OffsetPosition = data.position;
4062 updateType = updatetype.partterse;
4063 }
4064 if ((change & ObjectChangeType.Rotation) != 0)
4065 {
4066 part.UpdateRotation(data.rotation);
4067 updateType = updatetype.none;
4068 }
4069 if ((change & ObjectChangeType.Scale) != 0)
4070 {
4071 part.Resize(data.scale);
4072 updateType = updatetype.none;
4073 }
4074 }
4075
4076 if (pha != null)
4077 pha.Building = false;
4078 }
4079
4080 if (updateType != updatetype.none)
4081 {
4082 group.HasGroupChanged = true;
4083
4084 switch (updateType)
4085 {
4086 case updatetype.partterse:
4087 part.ScheduleTerseUpdate();
4088 break;
4089 case updatetype.partfull:
4090 part.ScheduleFullUpdate();
4091 break;
4092 case updatetype.groupterse:
4093 group.ScheduleGroupForTerseUpdate();
4094 break;
4095 case updatetype.groupfull:
4096 group.ScheduleGroupForFullUpdate();
4097 break;
4098 default:
4099 break;
4100 }
4101 }
4102 }
3217 } 4103 }
3218 4104
3219 #endregion 4105 #endregion
@@ -3312,10 +4198,11 @@ namespace OpenSim.Region.Framework.Scenes
3312 scriptPosTarget target = m_targets[idx]; 4198 scriptPosTarget target = m_targets[idx];
3313 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4199 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3314 { 4200 {
4201 at_target = true;
4202
3315 // trigger at_target 4203 // trigger at_target
3316 if (m_scriptListens_atTarget) 4204 if (m_scriptListens_atTarget)
3317 { 4205 {
3318 at_target = true;
3319 scriptPosTarget att = new scriptPosTarget(); 4206 scriptPosTarget att = new scriptPosTarget();
3320 att.targetPos = target.targetPos; 4207 att.targetPos = target.targetPos;
3321 att.tolerance = target.tolerance; 4208 att.tolerance = target.tolerance;
@@ -3433,11 +4320,50 @@ namespace OpenSim.Region.Framework.Scenes
3433 } 4320 }
3434 } 4321 }
3435 } 4322 }
3436 4323
4324 public Vector3 GetGeometricCenter()
4325 {
4326 // this is not real geometric center but a average of positions relative to root prim acording to
4327 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4328 // ignoring tortured prims details since sl also seems to ignore
4329 // so no real use in doing it on physics
4330
4331 Vector3 gc = Vector3.Zero;
4332
4333 int nparts = m_parts.Count;
4334 if (nparts <= 1)
4335 return gc;
4336
4337 SceneObjectPart[] parts = m_parts.GetArray();
4338 nparts = parts.Length; // just in case it changed
4339 if (nparts <= 1)
4340 return gc;
4341
4342 Quaternion parentRot = RootPart.RotationOffset;
4343 Vector3 pPos;
4344
4345 // average all parts positions
4346 for (int i = 0; i < nparts; i++)
4347 {
4348 // do it directly
4349 // gc += parts[i].GetWorldPosition();
4350 if (parts[i] != RootPart)
4351 {
4352 pPos = parts[i].OffsetPosition;
4353 gc += pPos;
4354 }
4355
4356 }
4357 gc /= nparts;
4358
4359 // relative to root:
4360// gc -= AbsolutePosition;
4361 return gc;
4362 }
4363
3437 public float GetMass() 4364 public float GetMass()
3438 { 4365 {
3439 float retmass = 0f; 4366 float retmass = 0f;
3440
3441 SceneObjectPart[] parts = m_parts.GetArray(); 4367 SceneObjectPart[] parts = m_parts.GetArray();
3442 for (int i = 0; i < parts.Length; i++) 4368 for (int i = 0; i < parts.Length; i++)
3443 retmass += parts[i].GetMass(); 4369 retmass += parts[i].GetMass();
@@ -3445,6 +4371,39 @@ namespace OpenSim.Region.Framework.Scenes
3445 return retmass; 4371 return retmass;
3446 } 4372 }
3447 4373
4374 // center of mass of full object
4375 public Vector3 GetCenterOfMass()
4376 {
4377 PhysicsActor pa = RootPart.PhysActor;
4378
4379 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4380 {
4381 // physics knows better about center of mass of physical prims
4382 Vector3 tmp = pa.CenterOfMass;
4383 return tmp;
4384 }
4385
4386 Vector3 Ptot = Vector3.Zero;
4387 float totmass = 0f;
4388 float m;
4389
4390 SceneObjectPart[] parts = m_parts.GetArray();
4391 for (int i = 0; i < parts.Length; i++)
4392 {
4393 m = parts[i].GetMass();
4394 Ptot += parts[i].GetPartCenterOfMass() * m;
4395 totmass += m;
4396 }
4397
4398 if (totmass == 0)
4399 totmass = 0;
4400 else
4401 totmass = 1 / totmass;
4402 Ptot *= totmass;
4403
4404 return Ptot;
4405 }
4406
3448 /// <summary> 4407 /// <summary>
3449 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4408 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3450 /// the physics engine can use it. 4409 /// the physics engine can use it.
@@ -3613,6 +4572,14 @@ namespace OpenSim.Region.Framework.Scenes
3613 FromItemID = uuid; 4572 FromItemID = uuid;
3614 } 4573 }
3615 4574
4575 public void ResetOwnerChangeFlag()
4576 {
4577 ForEachPart(delegate(SceneObjectPart part)
4578 {
4579 part.ResetOwnerChangeFlag();
4580 });
4581 }
4582
3616 #endregion 4583 #endregion
3617 } 4584 }
3618} 4585}