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, 1182 insertions, 234 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index da80e4f..155e450 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;
@@ -44,6 +45,7 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
44 45
45namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
46{ 47{
48
47 [Flags] 49 [Flags]
48 public enum scriptEvents 50 public enum scriptEvents
49 { 51 {
@@ -78,14 +80,14 @@ namespace OpenSim.Region.Framework.Scenes
78 object_rez = 4194304 80 object_rez = 4194304
79 } 81 }
80 82
81 struct scriptPosTarget 83 public struct scriptPosTarget
82 { 84 {
83 public Vector3 targetPos; 85 public Vector3 targetPos;
84 public float tolerance; 86 public float tolerance;
85 public uint handle; 87 public uint handle;
86 } 88 }
87 89
88 struct scriptRotTarget 90 public struct scriptRotTarget
89 { 91 {
90 public Quaternion targetRot; 92 public Quaternion targetRot;
91 public float tolerance; 93 public float tolerance;
@@ -116,8 +118,12 @@ namespace OpenSim.Region.Framework.Scenes
116 /// since the group's last persistent backup 118 /// since the group's last persistent backup
117 /// </summary> 119 /// </summary>
118 private bool m_hasGroupChanged = false; 120 private bool m_hasGroupChanged = false;
119 private long timeFirstChanged; 121 private long timeFirstChanged = 0;
120 private long timeLastChanged; 122 private long timeLastChanged = 0;
123 private long m_maxPersistTime = 0;
124 private long m_minPersistTime = 0;
125// private Random m_rand;
126 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
121 127
122 /// <summary> 128 /// <summary>
123 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 129 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -134,9 +140,44 @@ namespace OpenSim.Region.Framework.Scenes
134 { 140 {
135 if (value) 141 if (value)
136 { 142 {
143
144 if (m_isBackedUp)
145 {
146 m_scene.SceneGraph.FireChangeBackup(this);
147 }
137 timeLastChanged = DateTime.Now.Ticks; 148 timeLastChanged = DateTime.Now.Ticks;
138 if (!m_hasGroupChanged) 149 if (!m_hasGroupChanged)
139 timeFirstChanged = DateTime.Now.Ticks; 150 timeFirstChanged = DateTime.Now.Ticks;
151 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
152 {
153/*
154 if (m_rand == null)
155 {
156 byte[] val = new byte[16];
157 m_rootPart.UUID.ToBytes(val, 0);
158 m_rand = new Random(BitConverter.ToInt32(val, 0));
159 }
160 */
161 if (m_scene.GetRootAgentCount() == 0)
162 {
163 //If the region is empty, this change has been made by an automated process
164 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
165
166// float factor = 1.5f + (float)(m_rand.NextDouble());
167 float factor = 2.0f;
168 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
169 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
170 }
171 else
172 {
173 //If the region is not empty, we want to obey the minimum and maximum persist times
174 //but add a random factor so we stagger the object persistance a little
175// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
176// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
177 m_maxPersistTime = m_scene.m_persistAfter;
178 m_minPersistTime = m_scene.m_dontPersistBefore;
179 }
180 }
140 } 181 }
141 m_hasGroupChanged = value; 182 m_hasGroupChanged = value;
142 183
@@ -151,7 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
151 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 192 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
152 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 193 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
153 /// </summary> 194 /// </summary>
154 public bool HasGroupChangedDueToDelink { get; private set; } 195 public bool HasGroupChangedDueToDelink { get; set; }
155 196
156 private bool isTimeToPersist() 197 private bool isTimeToPersist()
157 { 198 {
@@ -161,8 +202,19 @@ namespace OpenSim.Region.Framework.Scenes
161 return false; 202 return false;
162 if (m_scene.ShuttingDown) 203 if (m_scene.ShuttingDown)
163 return true; 204 return true;
205
206 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
207 {
208 m_maxPersistTime = m_scene.m_persistAfter;
209 m_minPersistTime = m_scene.m_dontPersistBefore;
210 }
211
164 long currentTime = DateTime.Now.Ticks; 212 long currentTime = DateTime.Now.Ticks;
165 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 213
214 if (timeLastChanged == 0) timeLastChanged = currentTime;
215 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
216
217 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
166 return true; 218 return true;
167 return false; 219 return false;
168 } 220 }
@@ -265,26 +317,38 @@ namespace OpenSim.Region.Framework.Scenes
265 get { return RootPart.VolumeDetectActive; } 317 get { return RootPart.VolumeDetectActive; }
266 } 318 }
267 319
268 private Vector3 lastPhysGroupPos;
269 private Quaternion lastPhysGroupRot;
270
271 private bool m_isBackedUp; 320 private bool m_isBackedUp;
272 321
322 public bool IsBackedUp
323 {
324 get { return m_isBackedUp; }
325 }
326
273 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 327 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
274 328
275 protected ulong m_regionHandle; 329 protected ulong m_regionHandle;
276 protected SceneObjectPart m_rootPart; 330 protected SceneObjectPart m_rootPart;
277 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); 331 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
278 332
279 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); 333 private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>();
280 private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); 334 private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>();
335
336 public SortedDictionary<uint, scriptPosTarget> AtTargets
337 {
338 get { return m_targets; }
339 }
340
341 public SortedDictionary<uint, scriptRotTarget> RotTargets
342 {
343 get { return m_rotTargets; }
344 }
281 345
282 private bool m_scriptListens_atTarget; 346 private bool m_scriptListens_atTarget;
283 private bool m_scriptListens_notAtTarget; 347 private bool m_scriptListens_notAtTarget;
284
285 private bool m_scriptListens_atRotTarget; 348 private bool m_scriptListens_atRotTarget;
286 private bool m_scriptListens_notAtRotTarget; 349 private bool m_scriptListens_notAtRotTarget;
287 350
351 public bool m_dupeInProgress = false;
288 internal Dictionary<UUID, string> m_savedScriptState; 352 internal Dictionary<UUID, string> m_savedScriptState;
289 353
290 #region Properties 354 #region Properties
@@ -321,6 +385,16 @@ namespace OpenSim.Region.Framework.Scenes
321 get { return m_parts.Count; } 385 get { return m_parts.Count; }
322 } 386 }
323 387
388// protected Quaternion m_rotation = Quaternion.Identity;
389//
390// public virtual Quaternion Rotation
391// {
392// get { return m_rotation; }
393// set {
394// m_rotation = value;
395// }
396// }
397
324 public Quaternion GroupRotation 398 public Quaternion GroupRotation
325 { 399 {
326 get { return m_rootPart.RotationOffset; } 400 get { return m_rootPart.RotationOffset; }
@@ -427,7 +501,15 @@ namespace OpenSim.Region.Framework.Scenes
427 { 501 {
428 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 502 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
429 } 503 }
430 504
505
506
507 private struct avtocrossInfo
508 {
509 public ScenePresence av;
510 public uint ParentID;
511 }
512
431 /// <summary> 513 /// <summary>
432 /// The absolute position of this scene object in the scene 514 /// The absolute position of this scene object in the scene
433 /// </summary> 515 /// </summary>
@@ -455,13 +537,129 @@ namespace OpenSim.Region.Framework.Scenes
455 || Scene.TestBorderCross(val, Cardinals.S)) 537 || Scene.TestBorderCross(val, Cardinals.S))
456 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 538 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
457 { 539 {
540 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
541 uint x = 0;
542 uint y = 0;
543 string version = String.Empty;
544 Vector3 newpos = Vector3.Zero;
545 OpenSim.Services.Interfaces.GridRegion destination = null;
546
458 if (m_rootPart.KeyframeMotion != null) 547 if (m_rootPart.KeyframeMotion != null)
459 m_rootPart.KeyframeMotion.StartCrossingCheck(); 548 m_rootPart.KeyframeMotion.StartCrossingCheck();
460 549
461 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 550 bool canCross = true;
551 foreach (ScenePresence av in m_linkedAvatars)
552 {
553 // We need to cross these agents. First, let's find
554 // out if any of them can't cross for some reason.
555 // We have to deny the crossing entirely if any
556 // of them are banned. Alternatively, we could
557 // unsit banned agents....
558
559
560 // We set the avatar position as being the object
561 // position to get the region to send to
562 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
563 {
564 canCross = false;
565 break;
566 }
567
568 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
569 }
570
571 if (canCross)
572 {
573 // We unparent the SP quietly so that it won't
574 // be made to stand up
575
576 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
577
578 foreach (ScenePresence av in m_linkedAvatars)
579 {
580 avtocrossInfo avinfo = new avtocrossInfo();
581 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
582 if (parentPart != null)
583 av.ParentUUID = parentPart.UUID;
584
585 avinfo.av = av;
586 avinfo.ParentID = av.ParentID;
587 avsToCross.Add(avinfo);
588
589 av.ParentID = 0;
590 }
591
592 // m_linkedAvatars.Clear();
593 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
594
595 // Normalize
596 if (val.X >= Constants.RegionSize)
597 val.X -= Constants.RegionSize;
598 if (val.Y >= Constants.RegionSize)
599 val.Y -= Constants.RegionSize;
600 if (val.X < 0)
601 val.X += Constants.RegionSize;
602 if (val.Y < 0)
603 val.Y += Constants.RegionSize;
604
605 // If it's deleted, crossing was successful
606 if (IsDeleted)
607 {
608 // foreach (ScenePresence av in m_linkedAvatars)
609 foreach (avtocrossInfo avinfo in avsToCross)
610 {
611 ScenePresence av = avinfo.av;
612 if (!av.IsInTransit) // just in case...
613 {
614 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
615
616 av.IsInTransit = true;
617
618 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
619 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
620 }
621 else
622 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
623 }
624 avsToCross.Clear();
625 return;
626 }
627 else // cross failed, put avas back ??
628 {
629 foreach (avtocrossInfo avinfo in avsToCross)
630 {
631 ScenePresence av = avinfo.av;
632 av.ParentUUID = UUID.Zero;
633 av.ParentID = avinfo.ParentID;
634// m_linkedAvatars.Add(av);
635 }
636 }
637 avsToCross.Clear();
638
639 }
640 else
641 {
642 if (m_rootPart.KeyframeMotion != null)
643 m_rootPart.KeyframeMotion.CrossingFailure();
644
645 if (RootPart.PhysActor != null)
646 {
647 RootPart.PhysActor.CrossingFailure();
648 }
649 }
650 Vector3 oldp = AbsolutePosition;
651 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
652 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
653 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
462 } 654 }
463 } 655 }
464 656
657/* don't see the need but worse don't see where is restored to false if things stay in
658 foreach (SceneObjectPart part in m_parts.GetArray())
659 {
660 part.IgnoreUndoUpdate = true;
661 }
662 */
465 if (RootPart.GetStatusSandbox()) 663 if (RootPart.GetStatusSandbox())
466 { 664 {
467 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 665 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -479,9 +677,38 @@ namespace OpenSim.Region.Framework.Scenes
479 // Restuff the new GroupPosition into each SOP of the linkset. 677 // Restuff the new GroupPosition into each SOP of the linkset.
480 // This has the affect of resetting and tainting the physics actors. 678 // This has the affect of resetting and tainting the physics actors.
481 SceneObjectPart[] parts = m_parts.GetArray(); 679 SceneObjectPart[] parts = m_parts.GetArray();
482 for (int i = 0; i < parts.Length; i++) 680 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
483 parts[i].GroupPosition = val; 681 if (m_dupeInProgress)
682 triggerScriptEvent = false;
683 foreach (SceneObjectPart part in parts)
684 {
685 part.GroupPosition = val;
686 if (triggerScriptEvent)
687 part.TriggerScriptChangedEvent(Changed.POSITION);
688 }
484 689
690/*
691 This seems not needed and should not be needed:
692 sp absolute position depends on sit part absolute position fixed above.
693 sp ParentPosition is not used anywhere.
694 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
695 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
696
697 if (!m_dupeInProgress)
698 {
699 foreach (ScenePresence av in m_linkedAvatars)
700 {
701 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
702 if (p != null && m_parts.TryGetValue(p.UUID, out p))
703 {
704 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
705 av.AbsolutePosition += offset;
706// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
707 av.SendAvatarDataToAllAgents();
708 }
709 }
710 }
711*/
485 //if (m_rootPart.PhysActor != null) 712 //if (m_rootPart.PhysActor != null)
486 //{ 713 //{
487 //m_rootPart.PhysActor.Position = 714 //m_rootPart.PhysActor.Position =
@@ -495,6 +722,40 @@ namespace OpenSim.Region.Framework.Scenes
495 } 722 }
496 } 723 }
497 724
725 public override Vector3 Velocity
726 {
727 get { return RootPart.Velocity; }
728 set { RootPart.Velocity = value; }
729 }
730
731 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
732 {
733 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
734 ScenePresence agent = icon.EndInvoke(iar);
735
736 //// If the cross was successful, this agent is a child agent
737 if (agent.IsChildAgent)
738 {
739 if (agent.ParentUUID != UUID.Zero)
740 {
741 agent.ParentPart = null;
742// agent.ParentPosition = Vector3.Zero;
743// agent.ParentUUID = UUID.Zero;
744 }
745 }
746
747 agent.ParentUUID = UUID.Zero;
748
749// agent.Reset();
750// else // Not successful
751// agent.RestoreInCurrentScene();
752
753 // In any case
754 agent.IsInTransit = false;
755
756 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
757 }
758
498 public override uint LocalId 759 public override uint LocalId
499 { 760 {
500 get { return m_rootPart.LocalId; } 761 get { return m_rootPart.LocalId; }
@@ -565,6 +826,11 @@ namespace OpenSim.Region.Framework.Scenes
565 m_isSelected = value; 826 m_isSelected = value;
566 // Tell physics engine that group is selected 827 // Tell physics engine that group is selected
567 828
829 // this is not right
830 // but ode engines should only really need to know about root part
831 // so they can put entire object simulation on hold and not colliding
832 // keep as was for now
833
568 PhysicsActor pa = m_rootPart.PhysActor; 834 PhysicsActor pa = m_rootPart.PhysActor;
569 if (pa != null) 835 if (pa != null)
570 { 836 {
@@ -586,6 +852,40 @@ namespace OpenSim.Region.Framework.Scenes
586 } 852 }
587 } 853 }
588 854
855 public void PartSelectChanged(bool partSelect)
856 {
857 // any part selected makes group selected
858 if (m_isSelected == partSelect)
859 return;
860
861 if (partSelect)
862 {
863 IsSelected = partSelect;
864// if (!IsAttachment)
865// ScheduleGroupForFullUpdate();
866 }
867 else
868 {
869 // bad bad bad 2 heavy for large linksets
870 // since viewer does send lot of (un)selects
871 // this needs to be replaced by a specific list or count ?
872 // but that will require extra code in several places
873
874 SceneObjectPart[] parts = m_parts.GetArray();
875 for (int i = 0; i < parts.Length; i++)
876 {
877 SceneObjectPart part = parts[i];
878 if (part.IsSelected)
879 return;
880 }
881 IsSelected = partSelect;
882 if (!IsAttachment)
883 {
884 ScheduleGroupForFullUpdate();
885 }
886 }
887 }
888
589 private SceneObjectPart m_PlaySoundMasterPrim = null; 889 private SceneObjectPart m_PlaySoundMasterPrim = null;
590 public SceneObjectPart PlaySoundMasterPrim 890 public SceneObjectPart PlaySoundMasterPrim
591 { 891 {
@@ -680,6 +980,7 @@ namespace OpenSim.Region.Framework.Scenes
680 /// </summary> 980 /// </summary>
681 public SceneObjectGroup() 981 public SceneObjectGroup()
682 { 982 {
983
683 } 984 }
684 985
685 /// <summary> 986 /// <summary>
@@ -697,8 +998,8 @@ namespace OpenSim.Region.Framework.Scenes
697 /// Constructor. This object is added to the scene later via AttachToScene() 998 /// Constructor. This object is added to the scene later via AttachToScene()
698 /// </summary> 999 /// </summary>
699 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 1000 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
700 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 1001 {
701 { 1002 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
702 } 1003 }
703 1004
704 /// <summary> 1005 /// <summary>
@@ -733,6 +1034,9 @@ namespace OpenSim.Region.Framework.Scenes
733 /// </summary> 1034 /// </summary>
734 public virtual void AttachToBackup() 1035 public virtual void AttachToBackup()
735 { 1036 {
1037 if (IsAttachment) return;
1038 m_scene.SceneGraph.FireAttachToBackup(this);
1039
736 if (InSceneBackup) 1040 if (InSceneBackup)
737 { 1041 {
738 //m_log.DebugFormat( 1042 //m_log.DebugFormat(
@@ -775,6 +1079,13 @@ namespace OpenSim.Region.Framework.Scenes
775 1079
776 ApplyPhysics(); 1080 ApplyPhysics();
777 1081
1082 if (RootPart.PhysActor != null)
1083 RootPart.Force = RootPart.Force;
1084 if (RootPart.PhysActor != null)
1085 RootPart.Torque = RootPart.Torque;
1086 if (RootPart.PhysActor != null)
1087 RootPart.Buoyancy = RootPart.Buoyancy;
1088
778 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1089 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
779 // for the same object with very different properties. The caller must schedule the update. 1090 // for the same object with very different properties. The caller must schedule the update.
780 //ScheduleGroupForFullUpdate(); 1091 //ScheduleGroupForFullUpdate();
@@ -790,6 +1101,10 @@ namespace OpenSim.Region.Framework.Scenes
790 EntityIntersection result = new EntityIntersection(); 1101 EntityIntersection result = new EntityIntersection();
791 1102
792 SceneObjectPart[] parts = m_parts.GetArray(); 1103 SceneObjectPart[] parts = m_parts.GetArray();
1104
1105 // Find closest hit here
1106 float idist = float.MaxValue;
1107
793 for (int i = 0; i < parts.Length; i++) 1108 for (int i = 0; i < parts.Length; i++)
794 { 1109 {
795 SceneObjectPart part = parts[i]; 1110 SceneObjectPart part = parts[i];
@@ -804,11 +1119,6 @@ namespace OpenSim.Region.Framework.Scenes
804 1119
805 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1120 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
806 1121
807 // This may need to be updated to the maximum draw distance possible..
808 // We might (and probably will) be checking for prim creation from other sims
809 // when the camera crosses the border.
810 float idist = Constants.RegionSize;
811
812 if (inter.HitTF) 1122 if (inter.HitTF)
813 { 1123 {
814 // We need to find the closest prim to return to the testcaller along the ray 1124 // We need to find the closest prim to return to the testcaller along the ray
@@ -819,10 +1129,11 @@ namespace OpenSim.Region.Framework.Scenes
819 result.obj = part; 1129 result.obj = part;
820 result.normal = inter.normal; 1130 result.normal = inter.normal;
821 result.distance = inter.distance; 1131 result.distance = inter.distance;
1132
1133 idist = inter.distance;
822 } 1134 }
823 } 1135 }
824 } 1136 }
825
826 return result; 1137 return result;
827 } 1138 }
828 1139
@@ -834,25 +1145,27 @@ namespace OpenSim.Region.Framework.Scenes
834 /// <returns></returns> 1145 /// <returns></returns>
835 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1146 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
836 { 1147 {
837 maxX = -256f; 1148 maxX = float.MinValue;
838 maxY = -256f; 1149 maxY = float.MinValue;
839 maxZ = -256f; 1150 maxZ = float.MinValue;
840 minX = 256f; 1151 minX = float.MaxValue;
841 minY = 256f; 1152 minY = float.MaxValue;
842 minZ = 8192f; 1153 minZ = float.MaxValue;
843 1154
844 SceneObjectPart[] parts = m_parts.GetArray(); 1155 SceneObjectPart[] parts = m_parts.GetArray();
845 for (int i = 0; i < parts.Length; i++) 1156 foreach (SceneObjectPart part in parts)
846 { 1157 {
847 SceneObjectPart part = parts[i];
848
849 Vector3 worldPos = part.GetWorldPosition(); 1158 Vector3 worldPos = part.GetWorldPosition();
850 Vector3 offset = worldPos - AbsolutePosition; 1159 Vector3 offset = worldPos - AbsolutePosition;
851 Quaternion worldRot; 1160 Quaternion worldRot;
852 if (part.ParentID == 0) 1161 if (part.ParentID == 0)
1162 {
853 worldRot = part.RotationOffset; 1163 worldRot = part.RotationOffset;
1164 }
854 else 1165 else
1166 {
855 worldRot = part.GetWorldRotation(); 1167 worldRot = part.GetWorldRotation();
1168 }
856 1169
857 Vector3 frontTopLeft; 1170 Vector3 frontTopLeft;
858 Vector3 frontTopRight; 1171 Vector3 frontTopRight;
@@ -864,6 +1177,8 @@ namespace OpenSim.Region.Framework.Scenes
864 Vector3 backBottomLeft; 1177 Vector3 backBottomLeft;
865 Vector3 backBottomRight; 1178 Vector3 backBottomRight;
866 1179
1180 // Vector3[] corners = new Vector3[8];
1181
867 Vector3 orig = Vector3.Zero; 1182 Vector3 orig = Vector3.Zero;
868 1183
869 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1184 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -898,6 +1213,38 @@ namespace OpenSim.Region.Framework.Scenes
898 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1213 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
899 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1214 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
900 1215
1216
1217
1218 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1219 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1220 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1221 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1222 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1223 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1224 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1225 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1226
1227 //for (int i = 0; i < 8; i++)
1228 //{
1229 // corners[i] = corners[i] * worldRot;
1230 // corners[i] += offset;
1231
1232 // if (corners[i].X > maxX)
1233 // maxX = corners[i].X;
1234 // if (corners[i].X < minX)
1235 // minX = corners[i].X;
1236
1237 // if (corners[i].Y > maxY)
1238 // maxY = corners[i].Y;
1239 // if (corners[i].Y < minY)
1240 // minY = corners[i].Y;
1241
1242 // if (corners[i].Z > maxZ)
1243 // maxZ = corners[i].Y;
1244 // if (corners[i].Z < minZ)
1245 // minZ = corners[i].Z;
1246 //}
1247
901 frontTopLeft = frontTopLeft * worldRot; 1248 frontTopLeft = frontTopLeft * worldRot;
902 frontTopRight = frontTopRight * worldRot; 1249 frontTopRight = frontTopRight * worldRot;
903 frontBottomLeft = frontBottomLeft * worldRot; 1250 frontBottomLeft = frontBottomLeft * worldRot;
@@ -919,6 +1266,15 @@ namespace OpenSim.Region.Framework.Scenes
919 backTopLeft += offset; 1266 backTopLeft += offset;
920 backTopRight += offset; 1267 backTopRight += offset;
921 1268
1269 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1270 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1271 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1272 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1273 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1274 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1275 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1276 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1277
922 if (frontTopRight.X > maxX) 1278 if (frontTopRight.X > maxX)
923 maxX = frontTopRight.X; 1279 maxX = frontTopRight.X;
924 if (frontTopLeft.X > maxX) 1280 if (frontTopLeft.X > maxX)
@@ -1062,17 +1418,118 @@ namespace OpenSim.Region.Framework.Scenes
1062 1418
1063 #endregion 1419 #endregion
1064 1420
1421 public void GetResourcesCosts(SceneObjectPart apart,
1422 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1423 {
1424 // this information may need to be cached
1425
1426 float cost;
1427 float tmpcost;
1428
1429 bool ComplexCost = false;
1430
1431 SceneObjectPart p;
1432 SceneObjectPart[] parts;
1433
1434 lock (m_parts)
1435 {
1436 parts = m_parts.GetArray();
1437 }
1438
1439 int nparts = parts.Length;
1440
1441
1442 for (int i = 0; i < nparts; i++)
1443 {
1444 p = parts[i];
1445
1446 if (p.UsesComplexCost)
1447 {
1448 ComplexCost = true;
1449 break;
1450 }
1451 }
1452
1453 if (ComplexCost)
1454 {
1455 linksetResCost = 0;
1456 linksetPhysCost = 0;
1457 partCost = 0;
1458 partPhysCost = 0;
1459
1460 for (int i = 0; i < nparts; i++)
1461 {
1462 p = parts[i];
1463
1464 cost = p.StreamingCost;
1465 tmpcost = p.SimulationCost;
1466 if (tmpcost > cost)
1467 cost = tmpcost;
1468 tmpcost = p.PhysicsCost;
1469 if (tmpcost > cost)
1470 cost = tmpcost;
1471
1472 linksetPhysCost += tmpcost;
1473 linksetResCost += cost;
1474
1475 if (p == apart)
1476 {
1477 partCost = cost;
1478 partPhysCost = tmpcost;
1479 }
1480 }
1481 }
1482 else
1483 {
1484 partPhysCost = 1.0f;
1485 partCost = 1.0f;
1486 linksetResCost = (float)nparts;
1487 linksetPhysCost = linksetResCost;
1488 }
1489 }
1490
1491 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1492 {
1493 SceneObjectPart p;
1494 SceneObjectPart[] parts;
1495
1496 lock (m_parts)
1497 {
1498 parts = m_parts.GetArray();
1499 }
1500
1501 int nparts = parts.Length;
1502
1503 PhysCost = 0;
1504 StreamCost = 0;
1505 SimulCost = 0;
1506
1507 for (int i = 0; i < nparts; i++)
1508 {
1509 p = parts[i];
1510
1511 StreamCost += p.StreamingCost;
1512 SimulCost += p.SimulationCost;
1513 PhysCost += p.PhysicsCost;
1514 }
1515 }
1516
1065 public void SaveScriptedState(XmlTextWriter writer) 1517 public void SaveScriptedState(XmlTextWriter writer)
1066 { 1518 {
1519 SaveScriptedState(writer, false);
1520 }
1521
1522 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1523 {
1067 XmlDocument doc = new XmlDocument(); 1524 XmlDocument doc = new XmlDocument();
1068 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1525 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1069 1526
1070 SceneObjectPart[] parts = m_parts.GetArray(); 1527 SceneObjectPart[] parts = m_parts.GetArray();
1071 for (int i = 0; i < parts.Length; i++) 1528 for (int i = 0; i < parts.Length; i++)
1072 { 1529 {
1073 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1530 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1074 foreach (KeyValuePair<UUID, string> kvp in pstates) 1531 foreach (KeyValuePair<UUID, string> kvp in pstates)
1075 states.Add(kvp.Key, kvp.Value); 1532 states[kvp.Key] = kvp.Value;
1076 } 1533 }
1077 1534
1078 if (states.Count > 0) 1535 if (states.Count > 0)
@@ -1092,6 +1549,169 @@ namespace OpenSim.Region.Framework.Scenes
1092 } 1549 }
1093 1550
1094 /// <summary> 1551 /// <summary>
1552 /// Add the avatar to this linkset (avatar is sat).
1553 /// </summary>
1554 /// <param name="agentID"></param>
1555 public void AddAvatar(UUID agentID)
1556 {
1557 ScenePresence presence;
1558 if (m_scene.TryGetScenePresence(agentID, out presence))
1559 {
1560 if (!m_linkedAvatars.Contains(presence))
1561 {
1562 m_linkedAvatars.Add(presence);
1563 }
1564 }
1565 }
1566
1567 /// <summary>
1568 /// Delete the avatar from this linkset (avatar is unsat).
1569 /// </summary>
1570 /// <param name="agentID"></param>
1571 public void DeleteAvatar(UUID agentID)
1572 {
1573 ScenePresence presence;
1574 if (m_scene.TryGetScenePresence(agentID, out presence))
1575 {
1576 if (m_linkedAvatars.Contains(presence))
1577 {
1578 m_linkedAvatars.Remove(presence);
1579 }
1580 }
1581 }
1582
1583 /// <summary>
1584 /// Returns the list of linked presences (avatars sat on this group)
1585 /// </summary>
1586 /// <param name="agentID"></param>
1587 public List<ScenePresence> GetLinkedAvatars()
1588 {
1589 return m_linkedAvatars;
1590 }
1591
1592 /// <summary>
1593 /// Attach this scene object to the given avatar.
1594 /// </summary>
1595 /// <param name="agentID"></param>
1596 /// <param name="attachmentpoint"></param>
1597 /// <param name="AttachOffset"></param>
1598 private void AttachToAgent(
1599 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1600 {
1601 if (avatar != null)
1602 {
1603 // don't attach attachments to child agents
1604 if (avatar.IsChildAgent) return;
1605
1606 // Remove from database and parcel prim count
1607 m_scene.DeleteFromStorage(so.UUID);
1608 m_scene.EventManager.TriggerParcelPrimCountTainted();
1609
1610 so.AttachedAvatar = avatar.UUID;
1611
1612 if (so.RootPart.PhysActor != null)
1613 {
1614 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1615 so.RootPart.PhysActor = null;
1616 }
1617
1618 so.AbsolutePosition = attachOffset;
1619 so.RootPart.AttachedPos = attachOffset;
1620 so.IsAttachment = true;
1621 so.RootPart.SetParentLocalId(avatar.LocalId);
1622 so.AttachmentPoint = attachmentpoint;
1623
1624 avatar.AddAttachment(this);
1625
1626 if (!silent)
1627 {
1628 // Killing it here will cause the client to deselect it
1629 // It then reappears on the avatar, deselected
1630 // through the full update below
1631 //
1632 if (IsSelected)
1633 {
1634 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1635 }
1636
1637 IsSelected = false; // fudge....
1638 ScheduleGroupForFullUpdate();
1639 }
1640 }
1641 else
1642 {
1643 m_log.WarnFormat(
1644 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1645 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1646 }
1647 }
1648
1649 public byte GetAttachmentPoint()
1650 {
1651 return m_rootPart.Shape.State;
1652 }
1653
1654 public void DetachToGround()
1655 {
1656 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1657 if (avatar == null)
1658 return;
1659
1660 avatar.RemoveAttachment(this);
1661
1662 Vector3 detachedpos = new Vector3(127f,127f,127f);
1663 if (avatar == null)
1664 return;
1665
1666 detachedpos = avatar.AbsolutePosition;
1667 FromItemID = UUID.Zero;
1668
1669 AbsolutePosition = detachedpos;
1670 AttachedAvatar = UUID.Zero;
1671
1672 //SceneObjectPart[] parts = m_parts.GetArray();
1673 //for (int i = 0; i < parts.Length; i++)
1674 // parts[i].AttachedAvatar = UUID.Zero;
1675
1676 m_rootPart.SetParentLocalId(0);
1677 AttachmentPoint = (byte)0;
1678 // must check if buildind should be true or false here
1679 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1680 HasGroupChanged = true;
1681 RootPart.Rezzed = DateTime.Now;
1682 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1683 AttachToBackup();
1684 m_scene.EventManager.TriggerParcelPrimCountTainted();
1685 m_rootPart.ScheduleFullUpdate();
1686 m_rootPart.ClearUndoState();
1687 }
1688
1689 public void DetachToInventoryPrep()
1690 {
1691 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1692 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1693 if (avatar != null)
1694 {
1695 //detachedpos = avatar.AbsolutePosition;
1696 avatar.RemoveAttachment(this);
1697 }
1698
1699 AttachedAvatar = UUID.Zero;
1700
1701 /*SceneObjectPart[] parts = m_parts.GetArray();
1702 for (int i = 0; i < parts.Length; i++)
1703 parts[i].AttachedAvatar = UUID.Zero;*/
1704
1705 m_rootPart.SetParentLocalId(0);
1706 //m_rootPart.SetAttachmentPoint((byte)0);
1707 IsAttachment = false;
1708 AbsolutePosition = m_rootPart.AttachedPos;
1709 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1710 //AttachToBackup();
1711 //m_rootPart.ScheduleFullUpdate();
1712 }
1713
1714 /// <summary>
1095 /// 1715 ///
1096 /// </summary> 1716 /// </summary>
1097 /// <param name="part"></param> 1717 /// <param name="part"></param>
@@ -1131,7 +1751,10 @@ namespace OpenSim.Region.Framework.Scenes
1131 public void AddPart(SceneObjectPart part) 1751 public void AddPart(SceneObjectPart part)
1132 { 1752 {
1133 part.SetParent(this); 1753 part.SetParent(this);
1134 part.LinkNum = m_parts.Add(part.UUID, part); 1754 m_parts.Add(part.UUID, part);
1755
1756 part.LinkNum = m_parts.Count;
1757
1135 if (part.LinkNum == 2) 1758 if (part.LinkNum == 2)
1136 RootPart.LinkNum = 1; 1759 RootPart.LinkNum = 1;
1137 } 1760 }
@@ -1157,6 +1780,14 @@ namespace OpenSim.Region.Framework.Scenes
1157 parts[i].UUID = UUID.Random(); 1780 parts[i].UUID = UUID.Random();
1158 } 1781 }
1159 1782
1783 // helper provided for parts.
1784 public int GetSceneMaxUndo()
1785 {
1786 if (m_scene != null)
1787 return m_scene.MaxUndoCount;
1788 return 5;
1789 }
1790
1160 // justincc: I don't believe this hack is needed any longer, especially since the physics 1791 // justincc: I don't believe this hack is needed any longer, especially since the physics
1161 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1792 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1162 // this method was preventing proper reload of scene objects. 1793 // this method was preventing proper reload of scene objects.
@@ -1214,7 +1845,7 @@ namespace OpenSim.Region.Framework.Scenes
1214// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1845// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1215// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1846// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1216 1847
1217 part.StoreUndoState(); 1848// part.StoreUndoState();
1218 part.OnGrab(offsetPos, remoteClient); 1849 part.OnGrab(offsetPos, remoteClient);
1219 } 1850 }
1220 1851
@@ -1234,6 +1865,11 @@ namespace OpenSim.Region.Framework.Scenes
1234 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1865 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1235 public void DeleteGroupFromScene(bool silent) 1866 public void DeleteGroupFromScene(bool silent)
1236 { 1867 {
1868 // We need to keep track of this state in case this group is still queued for backup.
1869 IsDeleted = true;
1870
1871 DetachFromBackup();
1872
1237 SceneObjectPart[] parts = m_parts.GetArray(); 1873 SceneObjectPart[] parts = m_parts.GetArray();
1238 for (int i = 0; i < parts.Length; i++) 1874 for (int i = 0; i < parts.Length; i++)
1239 { 1875 {
@@ -1257,6 +1893,7 @@ namespace OpenSim.Region.Framework.Scenes
1257 } 1893 }
1258 }); 1894 });
1259 } 1895 }
1896
1260 } 1897 }
1261 1898
1262 public void AddScriptLPS(int count) 1899 public void AddScriptLPS(int count)
@@ -1326,28 +1963,43 @@ namespace OpenSim.Region.Framework.Scenes
1326 /// </summary> 1963 /// </summary>
1327 public void ApplyPhysics() 1964 public void ApplyPhysics()
1328 { 1965 {
1329 // Apply physics to the root prim
1330 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1331
1332 // Apply physics to child prims
1333 SceneObjectPart[] parts = m_parts.GetArray(); 1966 SceneObjectPart[] parts = m_parts.GetArray();
1334 if (parts.Length > 1) 1967 if (parts.Length > 1)
1335 { 1968 {
1969 ResetChildPrimPhysicsPositions();
1970
1971 // Apply physics to the root prim
1972 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1973
1974
1336 for (int i = 0; i < parts.Length; i++) 1975 for (int i = 0; i < parts.Length; i++)
1337 { 1976 {
1338 SceneObjectPart part = parts[i]; 1977 SceneObjectPart part = parts[i];
1339 if (part.LocalId != m_rootPart.LocalId) 1978 if (part.LocalId != m_rootPart.LocalId)
1340 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1979 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1341 } 1980 }
1342
1343 // Hack to get the physics scene geometries in the right spot 1981 // Hack to get the physics scene geometries in the right spot
1344 ResetChildPrimPhysicsPositions(); 1982// ResetChildPrimPhysicsPositions();
1983 if (m_rootPart.PhysActor != null)
1984 {
1985 m_rootPart.PhysActor.Building = false;
1986 }
1987 }
1988 else
1989 {
1990 // Apply physics to the root prim
1991 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1345 } 1992 }
1346 } 1993 }
1347 1994
1348 public void SetOwnerId(UUID userId) 1995 public void SetOwnerId(UUID userId)
1349 { 1996 {
1350 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1997 ForEachPart(delegate(SceneObjectPart part)
1998 {
1999
2000 part.OwnerID = userId;
2001
2002 });
1351 } 2003 }
1352 2004
1353 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2005 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1379,11 +2031,17 @@ namespace OpenSim.Region.Framework.Scenes
1379 return; 2031 return;
1380 } 2032 }
1381 2033
2034 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2035 return;
2036
1382 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2037 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1383 // any exception propogate upwards. 2038 // any exception propogate upwards.
1384 try 2039 try
1385 { 2040 {
1386 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2041 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2042 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2043 m_scene.LoadingPrims) // Land may not be valid yet
2044
1387 { 2045 {
1388 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2046 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1389 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2047 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1410,6 +2068,7 @@ namespace OpenSim.Region.Framework.Scenes
1410 } 2068 }
1411 } 2069 }
1412 } 2070 }
2071
1413 } 2072 }
1414 2073
1415 if (m_scene.UseBackup && HasGroupChanged) 2074 if (m_scene.UseBackup && HasGroupChanged)
@@ -1417,10 +2076,30 @@ namespace OpenSim.Region.Framework.Scenes
1417 // don't backup while it's selected or you're asking for changes mid stream. 2076 // don't backup while it's selected or you're asking for changes mid stream.
1418 if (isTimeToPersist() || forcedBackup) 2077 if (isTimeToPersist() || forcedBackup)
1419 { 2078 {
2079 if (m_rootPart.PhysActor != null &&
2080 (!m_rootPart.PhysActor.IsPhysical))
2081 {
2082 // Possible ghost prim
2083 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2084 {
2085 foreach (SceneObjectPart part in m_parts.GetArray())
2086 {
2087 // Re-set physics actor positions and
2088 // orientations
2089 part.GroupPosition = m_rootPart.GroupPosition;
2090 }
2091 }
2092 }
1420// m_log.DebugFormat( 2093// m_log.DebugFormat(
1421// "[SCENE]: Storing {0}, {1} in {2}", 2094// "[SCENE]: Storing {0}, {1} in {2}",
1422// Name, UUID, m_scene.RegionInfo.RegionName); 2095// Name, UUID, m_scene.RegionInfo.RegionName);
1423 2096
2097 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2098 {
2099 RootPart.Shape.State = 0;
2100 ScheduleGroupForFullUpdate();
2101 }
2102
1424 SceneObjectGroup backup_group = Copy(false); 2103 SceneObjectGroup backup_group = Copy(false);
1425 backup_group.RootPart.Velocity = RootPart.Velocity; 2104 backup_group.RootPart.Velocity = RootPart.Velocity;
1426 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2105 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1430,6 +2109,16 @@ namespace OpenSim.Region.Framework.Scenes
1430 HasGroupChangedDueToDelink = false; 2109 HasGroupChangedDueToDelink = false;
1431 2110
1432 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2111 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2112/*
2113 backup_group.ForEachPart(delegate(SceneObjectPart part)
2114 {
2115 if (part.KeyframeMotion != null)
2116 {
2117 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2118// part.KeyframeMotion.UpdateSceneObject(this);
2119 }
2120 });
2121*/
1433 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2122 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1434 2123
1435 backup_group.ForEachPart(delegate(SceneObjectPart part) 2124 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1486,10 +2175,14 @@ namespace OpenSim.Region.Framework.Scenes
1486 /// <returns></returns> 2175 /// <returns></returns>
1487 public SceneObjectGroup Copy(bool userExposed) 2176 public SceneObjectGroup Copy(bool userExposed)
1488 { 2177 {
2178 m_dupeInProgress = true;
1489 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2179 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1490 dupe.m_isBackedUp = false; 2180 dupe.m_isBackedUp = false;
1491 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2181 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1492 2182
2183 // new group as no sitting avatars
2184 dupe.m_linkedAvatars = new List<ScenePresence>();
2185
1493 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2186 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1494 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2187 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1495 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2188 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1500,7 +2193,7 @@ namespace OpenSim.Region.Framework.Scenes
1500 // This is only necessary when userExposed is false! 2193 // This is only necessary when userExposed is false!
1501 2194
1502 bool previousAttachmentStatus = dupe.IsAttachment; 2195 bool previousAttachmentStatus = dupe.IsAttachment;
1503 2196
1504 if (!userExposed) 2197 if (!userExposed)
1505 dupe.IsAttachment = true; 2198 dupe.IsAttachment = true;
1506 2199
@@ -1513,16 +2206,17 @@ namespace OpenSim.Region.Framework.Scenes
1513 2206
1514 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2207 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1515 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2208 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2209
1516 2210
1517 if (userExposed) 2211 if (userExposed)
1518 dupe.m_rootPart.TrimPermissions(); 2212 dupe.m_rootPart.TrimPermissions();
1519 2213
1520 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2214 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1521 2215
1522 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2216 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1523 { 2217 {
1524 return p1.LinkNum.CompareTo(p2.LinkNum); 2218 return p1.LinkNum.CompareTo(p2.LinkNum);
1525 } 2219 }
1526 ); 2220 );
1527 2221
1528 foreach (SceneObjectPart part in partList) 2222 foreach (SceneObjectPart part in partList)
@@ -1532,43 +2226,56 @@ namespace OpenSim.Region.Framework.Scenes
1532 { 2226 {
1533 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2227 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1534 newPart.LinkNum = part.LinkNum; 2228 newPart.LinkNum = part.LinkNum;
1535 } 2229 if (userExposed)
2230 newPart.ParentID = dupe.m_rootPart.LocalId;
2231 }
1536 else 2232 else
1537 { 2233 {
1538 newPart = dupe.m_rootPart; 2234 newPart = dupe.m_rootPart;
1539 } 2235 }
2236/*
2237 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2238 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1540 2239
1541 // Need to duplicate the physics actor as well 2240 // Need to duplicate the physics actor as well
1542 PhysicsActor originalPartPa = part.PhysActor; 2241 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1543 if (originalPartPa != null && userExposed)
1544 { 2242 {
1545 PrimitiveBaseShape pbs = newPart.Shape; 2243 PrimitiveBaseShape pbs = newPart.Shape;
1546
1547 newPart.PhysActor 2244 newPart.PhysActor
1548 = m_scene.PhysicsScene.AddPrimShape( 2245 = m_scene.PhysicsScene.AddPrimShape(
1549 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2246 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1550 pbs, 2247 pbs,
1551 newPart.AbsolutePosition, 2248 newPart.AbsolutePosition,
1552 newPart.Scale, 2249 newPart.Scale,
1553 newPart.RotationOffset, 2250 newPart.GetWorldRotation(),
1554 originalPartPa.IsPhysical, 2251 isphys,
2252 isphan,
1555 newPart.LocalId); 2253 newPart.LocalId);
1556 2254
1557 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2255 newPart.DoPhysicsPropertyUpdate(isphys, true);
1558 } 2256 */
2257 if (userExposed)
2258 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2259// }
2260 // copy keyframemotion
1559 if (part.KeyframeMotion != null) 2261 if (part.KeyframeMotion != null)
1560 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2262 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1561 } 2263 }
1562 2264
1563 if (userExposed) 2265 if (userExposed)
1564 { 2266 {
1565 dupe.UpdateParentIDs(); 2267// done above dupe.UpdateParentIDs();
2268
2269 if (dupe.m_rootPart.PhysActor != null)
2270 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2271
1566 dupe.HasGroupChanged = true; 2272 dupe.HasGroupChanged = true;
1567 dupe.AttachToBackup(); 2273 dupe.AttachToBackup();
1568 2274
1569 ScheduleGroupForFullUpdate(); 2275 ScheduleGroupForFullUpdate();
1570 } 2276 }
1571 2277
2278 m_dupeInProgress = false;
1572 return dupe; 2279 return dupe;
1573 } 2280 }
1574 2281
@@ -1580,7 +2287,14 @@ namespace OpenSim.Region.Framework.Scenes
1580 /// <param name="cGroupID"></param> 2287 /// <param name="cGroupID"></param>
1581 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2288 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1582 { 2289 {
1583 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2290 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2291 // give newpart a new local ID lettng old part keep same
2292 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2293 newpart.LocalId = m_scene.AllocateLocalId();
2294
2295 SetRootPart(newpart);
2296 if (userExposed)
2297 RootPart.Velocity = Vector3.Zero; // In case source is moving
1584 } 2298 }
1585 2299
1586 public void ScriptSetPhysicsStatus(bool usePhysics) 2300 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1638,27 +2352,14 @@ namespace OpenSim.Region.Framework.Scenes
1638 2352
1639 if (pa != null) 2353 if (pa != null)
1640 { 2354 {
1641 pa.AddForce(impulse, true); 2355 // false to be applied as a impulse
1642 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2356 pa.AddForce(impulse, false);
1643 }
1644 }
1645 }
1646
1647 public void applyAngularImpulse(Vector3 impulse)
1648 {
1649 PhysicsActor pa = RootPart.PhysActor;
1650
1651 if (pa != null)
1652 {
1653 if (!IsAttachment)
1654 {
1655 pa.AddAngularForce(impulse, true);
1656 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2357 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1657 } 2358 }
1658 } 2359 }
1659 } 2360 }
1660 2361
1661 public void setAngularImpulse(Vector3 impulse) 2362 public void ApplyAngularImpulse(Vector3 impulse)
1662 { 2363 {
1663 PhysicsActor pa = RootPart.PhysActor; 2364 PhysicsActor pa = RootPart.PhysActor;
1664 2365
@@ -1666,7 +2367,8 @@ namespace OpenSim.Region.Framework.Scenes
1666 { 2367 {
1667 if (!IsAttachment) 2368 if (!IsAttachment)
1668 { 2369 {
1669 pa.Torque = impulse; 2370 // false to be applied as a impulse
2371 pa.AddAngularForce(impulse, false);
1670 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2372 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1671 } 2373 }
1672 } 2374 }
@@ -1674,20 +2376,10 @@ namespace OpenSim.Region.Framework.Scenes
1674 2376
1675 public Vector3 GetTorque() 2377 public Vector3 GetTorque()
1676 { 2378 {
1677 PhysicsActor pa = RootPart.PhysActor; 2379 return RootPart.Torque;
1678
1679 if (pa != null)
1680 {
1681 if (!IsAttachment)
1682 {
1683 Vector3 torque = pa.Torque;
1684 return torque;
1685 }
1686 }
1687
1688 return Vector3.Zero;
1689 } 2380 }
1690 2381
2382 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1691 public void moveToTarget(Vector3 target, float tau) 2383 public void moveToTarget(Vector3 target, float tau)
1692 { 2384 {
1693 if (IsAttachment) 2385 if (IsAttachment)
@@ -1717,8 +2409,50 @@ namespace OpenSim.Region.Framework.Scenes
1717 2409
1718 if (pa != null) 2410 if (pa != null)
1719 pa.PIDActive = false; 2411 pa.PIDActive = false;
2412
2413 RootPart.ScheduleTerseUpdate(); // send a stop information
2414 }
2415
2416 public void rotLookAt(Quaternion target, float strength, float damping)
2417 {
2418 SceneObjectPart rootpart = m_rootPart;
2419 if (rootpart != null)
2420 {
2421 if (IsAttachment)
2422 {
2423 /*
2424 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2425 if (avatar != null)
2426 {
2427 Rotate the Av?
2428 } */
2429 }
2430 else
2431 {
2432 if (rootpart.PhysActor != null)
2433 { // APID must be implemented in your physics system for this to function.
2434 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2435 rootpart.PhysActor.APIDStrength = strength;
2436 rootpart.PhysActor.APIDDamping = damping;
2437 rootpart.PhysActor.APIDActive = true;
2438 }
2439 }
2440 }
1720 } 2441 }
2442
2443 public void stopLookAt()
2444 {
2445 SceneObjectPart rootpart = m_rootPart;
2446 if (rootpart != null)
2447 {
2448 if (rootpart.PhysActor != null)
2449 { // APID must be implemented in your physics system for this to function.
2450 rootpart.PhysActor.APIDActive = false;
2451 }
2452 }
1721 2453
2454 }
2455
1722 /// <summary> 2456 /// <summary>
1723 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2457 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1724 /// </summary> 2458 /// </summary>
@@ -1735,7 +2469,7 @@ namespace OpenSim.Region.Framework.Scenes
1735 { 2469 {
1736 pa.PIDHoverHeight = height; 2470 pa.PIDHoverHeight = height;
1737 pa.PIDHoverType = hoverType; 2471 pa.PIDHoverType = hoverType;
1738 pa.PIDTau = tau; 2472 pa.PIDHoverTau = tau;
1739 pa.PIDHoverActive = true; 2473 pa.PIDHoverActive = true;
1740 } 2474 }
1741 else 2475 else
@@ -1775,7 +2509,12 @@ namespace OpenSim.Region.Framework.Scenes
1775 /// <param name="cGroupID"></param> 2509 /// <param name="cGroupID"></param>
1776 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2510 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1777 { 2511 {
1778 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2512 // give new ID to the new part, letting old keep original
2513 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2514 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2515 newPart.LocalId = m_scene.AllocateLocalId();
2516 newPart.SetParent(this);
2517
1779 AddPart(newPart); 2518 AddPart(newPart);
1780 2519
1781 SetPartAsNonRoot(newPart); 2520 SetPartAsNonRoot(newPart);
@@ -1825,6 +2564,7 @@ namespace OpenSim.Region.Framework.Scenes
1825 2564
1826 #endregion 2565 #endregion
1827 2566
2567
1828 public override void Update() 2568 public override void Update()
1829 { 2569 {
1830 // Check that the group was not deleted before the scheduled update 2570 // Check that the group was not deleted before the scheduled update
@@ -1843,19 +2583,8 @@ namespace OpenSim.Region.Framework.Scenes
1843 // check to see if the physical position or rotation warrant an update. 2583 // check to see if the physical position or rotation warrant an update.
1844 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2584 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1845 { 2585 {
1846 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2586 // rootpart SendScheduledUpdates will check if a update is needed
1847 2587 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1848 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
1849 {
1850 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1851 lastPhysGroupPos = AbsolutePosition;
1852 }
1853
1854 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
1855 {
1856 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1857 lastPhysGroupRot = GroupRotation;
1858 }
1859 } 2588 }
1860 2589
1861 SceneObjectPart[] parts = m_parts.GetArray(); 2590 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1914,11 +2643,11 @@ namespace OpenSim.Region.Framework.Scenes
1914 /// Immediately send a full update for this scene object. 2643 /// Immediately send a full update for this scene object.
1915 /// </summary> 2644 /// </summary>
1916 public void SendGroupFullUpdate() 2645 public void SendGroupFullUpdate()
1917 { 2646 {
1918 if (IsDeleted) 2647 if (IsDeleted)
1919 return; 2648 return;
1920 2649
1921// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2650// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1922 2651
1923 RootPart.SendFullUpdateToAllClients(); 2652 RootPart.SendFullUpdateToAllClients();
1924 2653
@@ -2074,6 +2803,11 @@ namespace OpenSim.Region.Framework.Scenes
2074 // 'linkPart' == the root of the group being linked into this group 2803 // 'linkPart' == the root of the group being linked into this group
2075 SceneObjectPart linkPart = objectGroup.m_rootPart; 2804 SceneObjectPart linkPart = objectGroup.m_rootPart;
2076 2805
2806 if (m_rootPart.PhysActor != null)
2807 m_rootPart.PhysActor.Building = true;
2808 if (linkPart.PhysActor != null)
2809 linkPart.PhysActor.Building = true;
2810
2077 // physics flags from group to be applied to linked parts 2811 // physics flags from group to be applied to linked parts
2078 bool grpusephys = UsesPhysics; 2812 bool grpusephys = UsesPhysics;
2079 bool grptemporary = IsTemporary; 2813 bool grptemporary = IsTemporary;
@@ -2099,12 +2833,12 @@ namespace OpenSim.Region.Framework.Scenes
2099 Vector3 axPos = linkPart.OffsetPosition; 2833 Vector3 axPos = linkPart.OffsetPosition;
2100 // Rotate the linking root SOP's position to be relative to the new root prim 2834 // Rotate the linking root SOP's position to be relative to the new root prim
2101 Quaternion parentRot = m_rootPart.RotationOffset; 2835 Quaternion parentRot = m_rootPart.RotationOffset;
2102 axPos *= Quaternion.Inverse(parentRot); 2836 axPos *= Quaternion.Conjugate(parentRot);
2103 linkPart.OffsetPosition = axPos; 2837 linkPart.OffsetPosition = axPos;
2104 2838
2105 // Make the linking root SOP's rotation relative to the new root prim 2839 // Make the linking root SOP's rotation relative to the new root prim
2106 Quaternion oldRot = linkPart.RotationOffset; 2840 Quaternion oldRot = linkPart.RotationOffset;
2107 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2841 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2108 linkPart.RotationOffset = newRot; 2842 linkPart.RotationOffset = newRot;
2109 2843
2110 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2844 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2138,7 +2872,7 @@ namespace OpenSim.Region.Framework.Scenes
2138 linkPart.CreateSelected = true; 2872 linkPart.CreateSelected = true;
2139 2873
2140 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2874 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2141 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2875 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2142 2876
2143 // If the added SOP is physical, also tell the physics engine about the link relationship. 2877 // If the added SOP is physical, also tell the physics engine about the link relationship.
2144 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2878 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2148,6 +2882,7 @@ namespace OpenSim.Region.Framework.Scenes
2148 } 2882 }
2149 2883
2150 linkPart.LinkNum = linkNum++; 2884 linkPart.LinkNum = linkNum++;
2885 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2151 2886
2152 // Get a list of the SOP's in the old group in order of their linknum's. 2887 // Get a list of the SOP's in the old group in order of their linknum's.
2153 SceneObjectPart[] ogParts = objectGroup.Parts; 2888 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2166,7 +2901,7 @@ namespace OpenSim.Region.Framework.Scenes
2166 2901
2167 // Update the physics flags for the newly added SOP 2902 // Update the physics flags for the newly added SOP
2168 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2903 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2169 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2904 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2170 2905
2171 // If the added SOP is physical, also tell the physics engine about the link relationship. 2906 // If the added SOP is physical, also tell the physics engine about the link relationship.
2172 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2907 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2184,7 +2919,7 @@ namespace OpenSim.Region.Framework.Scenes
2184 objectGroup.IsDeleted = true; 2919 objectGroup.IsDeleted = true;
2185 2920
2186 objectGroup.m_parts.Clear(); 2921 objectGroup.m_parts.Clear();
2187 2922
2188 // Can't do this yet since backup still makes use of the root part without any synchronization 2923 // Can't do this yet since backup still makes use of the root part without any synchronization
2189// objectGroup.m_rootPart = null; 2924// objectGroup.m_rootPart = null;
2190 2925
@@ -2198,6 +2933,9 @@ namespace OpenSim.Region.Framework.Scenes
2198 // unmoved prims! 2933 // unmoved prims!
2199 ResetChildPrimPhysicsPositions(); 2934 ResetChildPrimPhysicsPositions();
2200 2935
2936 if (m_rootPart.PhysActor != null)
2937 m_rootPart.PhysActor.Building = false;
2938
2201 //HasGroupChanged = true; 2939 //HasGroupChanged = true;
2202 //ScheduleGroupForFullUpdate(); 2940 //ScheduleGroupForFullUpdate();
2203 } 2941 }
@@ -2265,7 +3003,10 @@ namespace OpenSim.Region.Framework.Scenes
2265// m_log.DebugFormat( 3003// m_log.DebugFormat(
2266// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3004// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2267// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3005// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2268 3006
3007 if (m_rootPart.PhysActor != null)
3008 m_rootPart.PhysActor.Building = true;
3009
2269 linkPart.ClearUndoState(); 3010 linkPart.ClearUndoState();
2270 3011
2271 Vector3 worldPos = linkPart.GetWorldPosition(); 3012 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2336,6 +3077,14 @@ namespace OpenSim.Region.Framework.Scenes
2336 3077
2337 // When we delete a group, we currently have to force persist to the database if the object id has changed 3078 // When we delete a group, we currently have to force persist to the database if the object id has changed
2338 // (since delete works by deleting all rows which have a given object id) 3079 // (since delete works by deleting all rows which have a given object id)
3080
3081 // this is as it seems to be in sl now
3082 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3083 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3084
3085 if (m_rootPart.PhysActor != null)
3086 m_rootPart.PhysActor.Building = false;
3087
2339 objectGroup.HasGroupChangedDueToDelink = true; 3088 objectGroup.HasGroupChangedDueToDelink = true;
2340 3089
2341 return objectGroup; 3090 return objectGroup;
@@ -2347,6 +3096,8 @@ namespace OpenSim.Region.Framework.Scenes
2347 /// <param name="objectGroup"></param> 3096 /// <param name="objectGroup"></param>
2348 public virtual void DetachFromBackup() 3097 public virtual void DetachFromBackup()
2349 { 3098 {
3099 if (m_scene != null)
3100 m_scene.SceneGraph.FireDetachFromBackup(this);
2350 if (m_isBackedUp && Scene != null) 3101 if (m_isBackedUp && Scene != null)
2351 m_scene.EventManager.OnBackup -= ProcessBackup; 3102 m_scene.EventManager.OnBackup -= ProcessBackup;
2352 3103
@@ -2367,7 +3118,8 @@ namespace OpenSim.Region.Framework.Scenes
2367 Vector3 axPos = part.OffsetPosition; 3118 Vector3 axPos = part.OffsetPosition;
2368 axPos *= parentRot; 3119 axPos *= parentRot;
2369 part.OffsetPosition = axPos; 3120 part.OffsetPosition = axPos;
2370 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3121 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3122 part.GroupPosition = newPos;
2371 part.OffsetPosition = Vector3.Zero; 3123 part.OffsetPosition = Vector3.Zero;
2372 3124
2373 // Compution our rotation to be not relative to the old parent 3125 // Compution our rotation to be not relative to the old parent
@@ -2382,7 +3134,7 @@ namespace OpenSim.Region.Framework.Scenes
2382 part.LinkNum = linkNum; 3134 part.LinkNum = linkNum;
2383 3135
2384 // Compute the new position of this SOP relative to the group position 3136 // Compute the new position of this SOP relative to the group position
2385 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3137 part.OffsetPosition = newPos - AbsolutePosition;
2386 3138
2387 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3139 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2388 // It would have the affect of setting the physics engine position multiple 3140 // It would have the affect of setting the physics engine position multiple
@@ -2392,18 +3144,19 @@ namespace OpenSim.Region.Framework.Scenes
2392 // Rotate the relative position by the rotation of the group 3144 // Rotate the relative position by the rotation of the group
2393 Quaternion rootRotation = m_rootPart.RotationOffset; 3145 Quaternion rootRotation = m_rootPart.RotationOffset;
2394 Vector3 pos = part.OffsetPosition; 3146 Vector3 pos = part.OffsetPosition;
2395 pos *= Quaternion.Inverse(rootRotation); 3147 pos *= Quaternion.Conjugate(rootRotation);
2396 part.OffsetPosition = pos; 3148 part.OffsetPosition = pos;
2397 3149
2398 // Compute the SOP's rotation relative to the rotation of the group. 3150 // Compute the SOP's rotation relative to the rotation of the group.
2399 parentRot = m_rootPart.RotationOffset; 3151 parentRot = m_rootPart.RotationOffset;
2400 oldRot = part.RotationOffset; 3152 oldRot = part.RotationOffset;
2401 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3153 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2402 part.RotationOffset = newRot; 3154 part.RotationOffset = newRot;
2403 3155
2404 // Since this SOP's state has changed, push those changes into the physics engine 3156 // Since this SOP's state has changed, push those changes into the physics engine
2405 // and the simulator. 3157 // and the simulator.
2406 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3158 // done on caller
3159// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2407 } 3160 }
2408 3161
2409 /// <summary> 3162 /// <summary>
@@ -2425,10 +3178,14 @@ namespace OpenSim.Region.Framework.Scenes
2425 { 3178 {
2426 if (!m_rootPart.BlockGrab) 3179 if (!m_rootPart.BlockGrab)
2427 { 3180 {
2428 Vector3 llmoveforce = pos - AbsolutePosition; 3181/* Vector3 llmoveforce = pos - AbsolutePosition;
2429 Vector3 grabforce = llmoveforce; 3182 Vector3 grabforce = llmoveforce;
2430 grabforce = (grabforce / 10) * pa.Mass; 3183 grabforce = (grabforce / 10) * pa.Mass;
2431 pa.AddForce(grabforce, true); 3184 */
3185 // empirically convert distance diference to a impulse
3186 Vector3 grabforce = pos - AbsolutePosition;
3187 grabforce = grabforce * (pa.Mass/ 10.0f);
3188 pa.AddForce(grabforce, false);
2432 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3189 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2433 } 3190 }
2434 } 3191 }
@@ -2624,6 +3381,8 @@ namespace OpenSim.Region.Framework.Scenes
2624 /// <param name="SetVolumeDetect"></param> 3381 /// <param name="SetVolumeDetect"></param>
2625 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3382 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2626 { 3383 {
3384 HasGroupChanged = true;
3385
2627 SceneObjectPart selectionPart = GetPart(localID); 3386 SceneObjectPart selectionPart = GetPart(localID);
2628 3387
2629 if (SetTemporary && Scene != null) 3388 if (SetTemporary && Scene != null)
@@ -2654,8 +3413,22 @@ namespace OpenSim.Region.Framework.Scenes
2654 } 3413 }
2655 } 3414 }
2656 3415
2657 for (int i = 0; i < parts.Length; i++) 3416 if (parts.Length > 1)
2658 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3417 {
3418 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3419
3420 for (int i = 0; i < parts.Length; i++)
3421 {
3422
3423 if (parts[i].UUID != m_rootPart.UUID)
3424 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3425 }
3426
3427 if (m_rootPart.PhysActor != null)
3428 m_rootPart.PhysActor.Building = false;
3429 }
3430 else
3431 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2659 } 3432 }
2660 } 3433 }
2661 3434
@@ -2668,6 +3441,17 @@ namespace OpenSim.Region.Framework.Scenes
2668 } 3441 }
2669 } 3442 }
2670 3443
3444
3445
3446 /// <summary>
3447 /// Gets the number of parts
3448 /// </summary>
3449 /// <returns></returns>
3450 public int GetPartCount()
3451 {
3452 return Parts.Count();
3453 }
3454
2671 /// <summary> 3455 /// <summary>
2672 /// Update the texture entry for this part 3456 /// Update the texture entry for this part
2673 /// </summary> 3457 /// </summary>
@@ -2705,8 +3489,24 @@ namespace OpenSim.Region.Framework.Scenes
2705 { 3489 {
2706 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3490 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2707 3491
3492 bool god = Scene.Permissions.IsGod(AgentID);
3493
3494 if (field == 1 && god)
3495 {
3496 ForEachPart(part =>
3497 {
3498 part.BaseMask = RootPart.BaseMask;
3499 });
3500 }
3501
2708 AdjustChildPrimPermissions(); 3502 AdjustChildPrimPermissions();
2709 3503
3504 if (field == 1 && god) // Base mask was set. Update all child part inventories
3505 {
3506 foreach (SceneObjectPart part in Parts)
3507 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3508 }
3509
2710 HasGroupChanged = true; 3510 HasGroupChanged = true;
2711 3511
2712 // Send the group's properties to all clients once all parts are updated 3512 // Send the group's properties to all clients once all parts are updated
@@ -2752,8 +3552,6 @@ namespace OpenSim.Region.Framework.Scenes
2752 3552
2753 PhysicsActor pa = m_rootPart.PhysActor; 3553 PhysicsActor pa = m_rootPart.PhysActor;
2754 3554
2755 RootPart.StoreUndoState(true);
2756
2757 if (Scene != null) 3555 if (Scene != null)
2758 { 3556 {
2759 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3557 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2781,7 +3579,6 @@ namespace OpenSim.Region.Framework.Scenes
2781 SceneObjectPart obPart = parts[i]; 3579 SceneObjectPart obPart = parts[i];
2782 if (obPart.UUID != m_rootPart.UUID) 3580 if (obPart.UUID != m_rootPart.UUID)
2783 { 3581 {
2784// obPart.IgnoreUndoUpdate = true;
2785 Vector3 oldSize = new Vector3(obPart.Scale); 3582 Vector3 oldSize = new Vector3(obPart.Scale);
2786 3583
2787 float f = 1.0f; 3584 float f = 1.0f;
@@ -2893,8 +3690,6 @@ namespace OpenSim.Region.Framework.Scenes
2893 z *= a; 3690 z *= a;
2894 } 3691 }
2895 } 3692 }
2896
2897// obPart.IgnoreUndoUpdate = false;
2898 } 3693 }
2899 } 3694 }
2900 } 3695 }
@@ -2904,9 +3699,7 @@ namespace OpenSim.Region.Framework.Scenes
2904 prevScale.Y *= y; 3699 prevScale.Y *= y;
2905 prevScale.Z *= z; 3700 prevScale.Z *= z;
2906 3701
2907// RootPart.IgnoreUndoUpdate = true;
2908 RootPart.Resize(prevScale); 3702 RootPart.Resize(prevScale);
2909// RootPart.IgnoreUndoUpdate = false;
2910 3703
2911 for (int i = 0; i < parts.Length; i++) 3704 for (int i = 0; i < parts.Length; i++)
2912 { 3705 {
@@ -2914,8 +3707,6 @@ namespace OpenSim.Region.Framework.Scenes
2914 3707
2915 if (obPart.UUID != m_rootPart.UUID) 3708 if (obPart.UUID != m_rootPart.UUID)
2916 { 3709 {
2917 obPart.IgnoreUndoUpdate = true;
2918
2919 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3710 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2920 currentpos.X *= x; 3711 currentpos.X *= x;
2921 currentpos.Y *= y; 3712 currentpos.Y *= y;
@@ -2928,16 +3719,12 @@ namespace OpenSim.Region.Framework.Scenes
2928 3719
2929 obPart.Resize(newSize); 3720 obPart.Resize(newSize);
2930 obPart.UpdateOffSet(currentpos); 3721 obPart.UpdateOffSet(currentpos);
2931
2932 obPart.IgnoreUndoUpdate = false;
2933 } 3722 }
2934 3723
2935// obPart.IgnoreUndoUpdate = false; 3724 HasGroupChanged = true;
2936// obPart.StoreUndoState(); 3725 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3726 ScheduleGroupForTerseUpdate();
2937 } 3727 }
2938
2939// m_log.DebugFormat(
2940// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2941 } 3728 }
2942 3729
2943 #endregion 3730 #endregion
@@ -2950,14 +3737,6 @@ namespace OpenSim.Region.Framework.Scenes
2950 /// <param name="pos"></param> 3737 /// <param name="pos"></param>
2951 public void UpdateGroupPosition(Vector3 pos) 3738 public void UpdateGroupPosition(Vector3 pos)
2952 { 3739 {
2953// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2954
2955 RootPart.StoreUndoState(true);
2956
2957// SceneObjectPart[] parts = m_parts.GetArray();
2958// for (int i = 0; i < parts.Length; i++)
2959// parts[i].StoreUndoState();
2960
2961 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3740 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2962 { 3741 {
2963 if (IsAttachment) 3742 if (IsAttachment)
@@ -2990,21 +3769,17 @@ namespace OpenSim.Region.Framework.Scenes
2990 /// </summary> 3769 /// </summary>
2991 /// <param name="pos"></param> 3770 /// <param name="pos"></param>
2992 /// <param name="localID"></param> 3771 /// <param name="localID"></param>
3772 ///
3773
2993 public void UpdateSinglePosition(Vector3 pos, uint localID) 3774 public void UpdateSinglePosition(Vector3 pos, uint localID)
2994 { 3775 {
2995 SceneObjectPart part = GetPart(localID); 3776 SceneObjectPart part = GetPart(localID);
2996 3777
2997// SceneObjectPart[] parts = m_parts.GetArray();
2998// for (int i = 0; i < parts.Length; i++)
2999// parts[i].StoreUndoState();
3000
3001 if (part != null) 3778 if (part != null)
3002 { 3779 {
3003// m_log.DebugFormat( 3780// unlock parts position change
3004// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3781 if (m_rootPart.PhysActor != null)
3005 3782 m_rootPart.PhysActor.Building = true;
3006 part.StoreUndoState(false);
3007 part.IgnoreUndoUpdate = true;
3008 3783
3009 if (part.UUID == m_rootPart.UUID) 3784 if (part.UUID == m_rootPart.UUID)
3010 { 3785 {
@@ -3015,8 +3790,10 @@ namespace OpenSim.Region.Framework.Scenes
3015 part.UpdateOffSet(pos); 3790 part.UpdateOffSet(pos);
3016 } 3791 }
3017 3792
3793 if (m_rootPart.PhysActor != null)
3794 m_rootPart.PhysActor.Building = false;
3795
3018 HasGroupChanged = true; 3796 HasGroupChanged = true;
3019 part.IgnoreUndoUpdate = false;
3020 } 3797 }
3021 } 3798 }
3022 3799
@@ -3026,13 +3803,7 @@ namespace OpenSim.Region.Framework.Scenes
3026 /// <param name="pos"></param> 3803 /// <param name="pos"></param>
3027 public void UpdateRootPosition(Vector3 pos) 3804 public void UpdateRootPosition(Vector3 pos)
3028 { 3805 {
3029// m_log.DebugFormat( 3806 // needs to be called with phys building true
3030// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3031
3032// SceneObjectPart[] parts = m_parts.GetArray();
3033// for (int i = 0; i < parts.Length; i++)
3034// parts[i].StoreUndoState();
3035
3036 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3807 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3037 Vector3 oldPos = 3808 Vector3 oldPos =
3038 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3809 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3055,7 +3826,14 @@ namespace OpenSim.Region.Framework.Scenes
3055 AbsolutePosition = newPos; 3826 AbsolutePosition = newPos;
3056 3827
3057 HasGroupChanged = true; 3828 HasGroupChanged = true;
3058 ScheduleGroupForTerseUpdate(); 3829 if (m_rootPart.Undoing)
3830 {
3831 ScheduleGroupForFullUpdate();
3832 }
3833 else
3834 {
3835 ScheduleGroupForTerseUpdate();
3836 }
3059 } 3837 }
3060 3838
3061 #endregion 3839 #endregion
@@ -3068,24 +3846,16 @@ namespace OpenSim.Region.Framework.Scenes
3068 /// <param name="rot"></param> 3846 /// <param name="rot"></param>
3069 public void UpdateGroupRotationR(Quaternion rot) 3847 public void UpdateGroupRotationR(Quaternion rot)
3070 { 3848 {
3071// m_log.DebugFormat(
3072// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3073
3074// SceneObjectPart[] parts = m_parts.GetArray();
3075// for (int i = 0; i < parts.Length; i++)
3076// parts[i].StoreUndoState();
3077
3078 m_rootPart.StoreUndoState(true);
3079
3080 m_rootPart.UpdateRotation(rot); 3849 m_rootPart.UpdateRotation(rot);
3081 3850
3851/* this is done by rootpart RotationOffset set called by UpdateRotation
3082 PhysicsActor actor = m_rootPart.PhysActor; 3852 PhysicsActor actor = m_rootPart.PhysActor;
3083 if (actor != null) 3853 if (actor != null)
3084 { 3854 {
3085 actor.Orientation = m_rootPart.RotationOffset; 3855 actor.Orientation = m_rootPart.RotationOffset;
3086 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3856 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3087 } 3857 }
3088 3858*/
3089 HasGroupChanged = true; 3859 HasGroupChanged = true;
3090 ScheduleGroupForTerseUpdate(); 3860 ScheduleGroupForTerseUpdate();
3091 } 3861 }
@@ -3097,16 +3867,6 @@ namespace OpenSim.Region.Framework.Scenes
3097 /// <param name="rot"></param> 3867 /// <param name="rot"></param>
3098 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3868 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3099 { 3869 {
3100// m_log.DebugFormat(
3101// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3102
3103// SceneObjectPart[] parts = m_parts.GetArray();
3104// for (int i = 0; i < parts.Length; i++)
3105// parts[i].StoreUndoState();
3106
3107 RootPart.StoreUndoState(true);
3108 RootPart.IgnoreUndoUpdate = true;
3109
3110 m_rootPart.UpdateRotation(rot); 3870 m_rootPart.UpdateRotation(rot);
3111 3871
3112 PhysicsActor actor = m_rootPart.PhysActor; 3872 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3125,8 +3885,6 @@ namespace OpenSim.Region.Framework.Scenes
3125 3885
3126 HasGroupChanged = true; 3886 HasGroupChanged = true;
3127 ScheduleGroupForTerseUpdate(); 3887 ScheduleGroupForTerseUpdate();
3128
3129 RootPart.IgnoreUndoUpdate = false;
3130 } 3888 }
3131 3889
3132 /// <summary> 3890 /// <summary>
@@ -3139,13 +3897,11 @@ namespace OpenSim.Region.Framework.Scenes
3139 SceneObjectPart part = GetPart(localID); 3897 SceneObjectPart part = GetPart(localID);
3140 3898
3141 SceneObjectPart[] parts = m_parts.GetArray(); 3899 SceneObjectPart[] parts = m_parts.GetArray();
3142 for (int i = 0; i < parts.Length; i++)
3143 parts[i].StoreUndoState();
3144 3900
3145 if (part != null) 3901 if (part != null)
3146 { 3902 {
3147// m_log.DebugFormat( 3903 if (m_rootPart.PhysActor != null)
3148// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3904 m_rootPart.PhysActor.Building = true;
3149 3905
3150 if (part.UUID == m_rootPart.UUID) 3906 if (part.UUID == m_rootPart.UUID)
3151 { 3907 {
@@ -3155,6 +3911,9 @@ namespace OpenSim.Region.Framework.Scenes
3155 { 3911 {
3156 part.UpdateRotation(rot); 3912 part.UpdateRotation(rot);
3157 } 3913 }
3914
3915 if (m_rootPart.PhysActor != null)
3916 m_rootPart.PhysActor.Building = false;
3158 } 3917 }
3159 } 3918 }
3160 3919
@@ -3168,12 +3927,8 @@ namespace OpenSim.Region.Framework.Scenes
3168 SceneObjectPart part = GetPart(localID); 3927 SceneObjectPart part = GetPart(localID);
3169 if (part != null) 3928 if (part != null)
3170 { 3929 {
3171// m_log.DebugFormat( 3930 if (m_rootPart.PhysActor != null)
3172// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3931 m_rootPart.PhysActor.Building = true;
3173// part.Name, part.LocalId, rot);
3174
3175 part.StoreUndoState();
3176 part.IgnoreUndoUpdate = true;
3177 3932
3178 if (part.UUID == m_rootPart.UUID) 3933 if (part.UUID == m_rootPart.UUID)
3179 { 3934 {
@@ -3186,7 +3941,8 @@ namespace OpenSim.Region.Framework.Scenes
3186 part.OffsetPosition = pos; 3941 part.OffsetPosition = pos;
3187 } 3942 }
3188 3943
3189 part.IgnoreUndoUpdate = false; 3944 if (m_rootPart.PhysActor != null)
3945 m_rootPart.PhysActor.Building = false;
3190 } 3946 }
3191 } 3947 }
3192 3948
@@ -3196,15 +3952,12 @@ namespace OpenSim.Region.Framework.Scenes
3196 /// <param name="rot"></param> 3952 /// <param name="rot"></param>
3197 public void UpdateRootRotation(Quaternion rot) 3953 public void UpdateRootRotation(Quaternion rot)
3198 { 3954 {
3199// m_log.DebugFormat( 3955 // needs to be called with phys building true
3200// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3201// Name, LocalId, rot);
3202
3203 Quaternion axRot = rot; 3956 Quaternion axRot = rot;
3204 Quaternion oldParentRot = m_rootPart.RotationOffset; 3957 Quaternion oldParentRot = m_rootPart.RotationOffset;
3205 3958
3206 m_rootPart.StoreUndoState(); 3959 //Don't use UpdateRotation because it schedules an update prematurely
3207 m_rootPart.UpdateRotation(rot); 3960 m_rootPart.RotationOffset = rot;
3208 3961
3209 PhysicsActor pa = m_rootPart.PhysActor; 3962 PhysicsActor pa = m_rootPart.PhysActor;
3210 3963
@@ -3220,35 +3973,145 @@ namespace OpenSim.Region.Framework.Scenes
3220 SceneObjectPart prim = parts[i]; 3973 SceneObjectPart prim = parts[i];
3221 if (prim.UUID != m_rootPart.UUID) 3974 if (prim.UUID != m_rootPart.UUID)
3222 { 3975 {
3223 prim.IgnoreUndoUpdate = true; 3976 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3977 NewRot = Quaternion.Inverse(axRot) * NewRot;
3978 prim.RotationOffset = NewRot;
3979
3224 Vector3 axPos = prim.OffsetPosition; 3980 Vector3 axPos = prim.OffsetPosition;
3981
3225 axPos *= oldParentRot; 3982 axPos *= oldParentRot;
3226 axPos *= Quaternion.Inverse(axRot); 3983 axPos *= Quaternion.Inverse(axRot);
3227 prim.OffsetPosition = axPos; 3984 prim.OffsetPosition = axPos;
3228 Quaternion primsRot = prim.RotationOffset; 3985 }
3229 Quaternion newRot = oldParentRot * primsRot; 3986 }
3230 newRot = Quaternion.Inverse(axRot) * newRot;
3231 prim.RotationOffset = newRot;
3232 prim.ScheduleTerseUpdate();
3233 prim.IgnoreUndoUpdate = false;
3234 }
3235 }
3236
3237// for (int i = 0; i < parts.Length; i++)
3238// {
3239// SceneObjectPart childpart = parts[i];
3240// if (childpart != m_rootPart)
3241// {
3242//// childpart.IgnoreUndoUpdate = false;
3243//// childpart.StoreUndoState();
3244// }
3245// }
3246 3987
3247 m_rootPart.ScheduleTerseUpdate(); 3988 HasGroupChanged = true;
3989 ScheduleGroupForFullUpdate();
3990 }
3248 3991
3249// m_log.DebugFormat( 3992 private enum updatetype :int
3250// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3993 {
3251// Name, LocalId, rot); 3994 none = 0,
3995 partterse = 1,
3996 partfull = 2,
3997 groupterse = 3,
3998 groupfull = 4
3999 }
4000
4001 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4002 {
4003 // TODO this still as excessive *.Schedule*Update()s
4004
4005 if (part != null && part.ParentGroup != null)
4006 {
4007 ObjectChangeType change = data.change;
4008 bool togroup = ((change & ObjectChangeType.Group) != 0);
4009 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4010
4011 SceneObjectGroup group = part.ParentGroup;
4012 PhysicsActor pha = group.RootPart.PhysActor;
4013
4014 updatetype updateType = updatetype.none;
4015
4016 if (togroup)
4017 {
4018 // related to group
4019 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4020 {
4021 if ((change & ObjectChangeType.Rotation) != 0)
4022 {
4023 group.RootPart.UpdateRotation(data.rotation);
4024 updateType = updatetype.none;
4025 }
4026 if ((change & ObjectChangeType.Position) != 0)
4027 {
4028 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4029 UpdateGroupPosition(data.position);
4030 updateType = updatetype.groupterse;
4031 }
4032 else
4033 // ugly rotation update of all parts
4034 {
4035 group.ResetChildPrimPhysicsPositions();
4036 }
4037
4038 }
4039 if ((change & ObjectChangeType.Scale) != 0)
4040 {
4041 if (pha != null)
4042 pha.Building = true;
4043
4044 group.GroupResize(data.scale);
4045 updateType = updatetype.none;
4046
4047 if (pha != null)
4048 pha.Building = false;
4049 }
4050 }
4051 else
4052 {
4053 // related to single prim in a link-set ( ie group)
4054 if (pha != null)
4055 pha.Building = true;
4056
4057 // root part is special
4058 // parts offset positions or rotations need to change also
4059
4060 if (part == group.RootPart)
4061 {
4062 if ((change & ObjectChangeType.Rotation) != 0)
4063 group.UpdateRootRotation(data.rotation);
4064 if ((change & ObjectChangeType.Position) != 0)
4065 group.UpdateRootPosition(data.position);
4066 if ((change & ObjectChangeType.Scale) != 0)
4067 part.Resize(data.scale);
4068 }
4069 else
4070 {
4071 if ((change & ObjectChangeType.Position) != 0)
4072 {
4073 part.OffsetPosition = data.position;
4074 updateType = updatetype.partterse;
4075 }
4076 if ((change & ObjectChangeType.Rotation) != 0)
4077 {
4078 part.UpdateRotation(data.rotation);
4079 updateType = updatetype.none;
4080 }
4081 if ((change & ObjectChangeType.Scale) != 0)
4082 {
4083 part.Resize(data.scale);
4084 updateType = updatetype.none;
4085 }
4086 }
4087
4088 if (pha != null)
4089 pha.Building = false;
4090 }
4091
4092 if (updateType != updatetype.none)
4093 {
4094 group.HasGroupChanged = true;
4095
4096 switch (updateType)
4097 {
4098 case updatetype.partterse:
4099 part.ScheduleTerseUpdate();
4100 break;
4101 case updatetype.partfull:
4102 part.ScheduleFullUpdate();
4103 break;
4104 case updatetype.groupterse:
4105 group.ScheduleGroupForTerseUpdate();
4106 break;
4107 case updatetype.groupfull:
4108 group.ScheduleGroupForFullUpdate();
4109 break;
4110 default:
4111 break;
4112 }
4113 }
4114 }
3252 } 4115 }
3253 4116
3254 #endregion 4117 #endregion
@@ -3289,6 +4152,8 @@ namespace OpenSim.Region.Framework.Scenes
3289 waypoint.handle = handle; 4152 waypoint.handle = handle;
3290 lock (m_rotTargets) 4153 lock (m_rotTargets)
3291 { 4154 {
4155 if (m_rotTargets.Count >= 8)
4156 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3292 m_rotTargets.Add(handle, waypoint); 4157 m_rotTargets.Add(handle, waypoint);
3293 } 4158 }
3294 m_scene.AddGroupTarget(this); 4159 m_scene.AddGroupTarget(this);
@@ -3314,6 +4179,8 @@ namespace OpenSim.Region.Framework.Scenes
3314 waypoint.handle = handle; 4179 waypoint.handle = handle;
3315 lock (m_targets) 4180 lock (m_targets)
3316 { 4181 {
4182 if (m_targets.Count >= 8)
4183 m_targets.Remove(m_targets.ElementAt(0).Key);
3317 m_targets.Add(handle, waypoint); 4184 m_targets.Add(handle, waypoint);
3318 } 4185 }
3319 m_scene.AddGroupTarget(this); 4186 m_scene.AddGroupTarget(this);
@@ -3347,10 +4214,11 @@ namespace OpenSim.Region.Framework.Scenes
3347 scriptPosTarget target = m_targets[idx]; 4214 scriptPosTarget target = m_targets[idx];
3348 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4215 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3349 { 4216 {
4217 at_target = true;
4218
3350 // trigger at_target 4219 // trigger at_target
3351 if (m_scriptListens_atTarget) 4220 if (m_scriptListens_atTarget)
3352 { 4221 {
3353 at_target = true;
3354 scriptPosTarget att = new scriptPosTarget(); 4222 scriptPosTarget att = new scriptPosTarget();
3355 att.targetPos = target.targetPos; 4223 att.targetPos = target.targetPos;
3356 att.tolerance = target.tolerance; 4224 att.tolerance = target.tolerance;
@@ -3468,11 +4336,50 @@ namespace OpenSim.Region.Framework.Scenes
3468 } 4336 }
3469 } 4337 }
3470 } 4338 }
3471 4339
4340 public Vector3 GetGeometricCenter()
4341 {
4342 // this is not real geometric center but a average of positions relative to root prim acording to
4343 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4344 // ignoring tortured prims details since sl also seems to ignore
4345 // so no real use in doing it on physics
4346
4347 Vector3 gc = Vector3.Zero;
4348
4349 int nparts = m_parts.Count;
4350 if (nparts <= 1)
4351 return gc;
4352
4353 SceneObjectPart[] parts = m_parts.GetArray();
4354 nparts = parts.Length; // just in case it changed
4355 if (nparts <= 1)
4356 return gc;
4357
4358 Quaternion parentRot = RootPart.RotationOffset;
4359 Vector3 pPos;
4360
4361 // average all parts positions
4362 for (int i = 0; i < nparts; i++)
4363 {
4364 // do it directly
4365 // gc += parts[i].GetWorldPosition();
4366 if (parts[i] != RootPart)
4367 {
4368 pPos = parts[i].OffsetPosition;
4369 gc += pPos;
4370 }
4371
4372 }
4373 gc /= nparts;
4374
4375 // relative to root:
4376// gc -= AbsolutePosition;
4377 return gc;
4378 }
4379
3472 public float GetMass() 4380 public float GetMass()
3473 { 4381 {
3474 float retmass = 0f; 4382 float retmass = 0f;
3475
3476 SceneObjectPart[] parts = m_parts.GetArray(); 4383 SceneObjectPart[] parts = m_parts.GetArray();
3477 for (int i = 0; i < parts.Length; i++) 4384 for (int i = 0; i < parts.Length; i++)
3478 retmass += parts[i].GetMass(); 4385 retmass += parts[i].GetMass();
@@ -3480,6 +4387,39 @@ namespace OpenSim.Region.Framework.Scenes
3480 return retmass; 4387 return retmass;
3481 } 4388 }
3482 4389
4390 // center of mass of full object
4391 public Vector3 GetCenterOfMass()
4392 {
4393 PhysicsActor pa = RootPart.PhysActor;
4394
4395 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4396 {
4397 // physics knows better about center of mass of physical prims
4398 Vector3 tmp = pa.CenterOfMass;
4399 return tmp;
4400 }
4401
4402 Vector3 Ptot = Vector3.Zero;
4403 float totmass = 0f;
4404 float m;
4405
4406 SceneObjectPart[] parts = m_parts.GetArray();
4407 for (int i = 0; i < parts.Length; i++)
4408 {
4409 m = parts[i].GetMass();
4410 Ptot += parts[i].GetPartCenterOfMass() * m;
4411 totmass += m;
4412 }
4413
4414 if (totmass == 0)
4415 totmass = 0;
4416 else
4417 totmass = 1 / totmass;
4418 Ptot *= totmass;
4419
4420 return Ptot;
4421 }
4422
3483 /// <summary> 4423 /// <summary>
3484 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4424 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3485 /// the physics engine can use it. 4425 /// the physics engine can use it.
@@ -3659,6 +4599,14 @@ namespace OpenSim.Region.Framework.Scenes
3659 FromItemID = uuid; 4599 FromItemID = uuid;
3660 } 4600 }
3661 4601
4602 public void ResetOwnerChangeFlag()
4603 {
4604 ForEachPart(delegate(SceneObjectPart part)
4605 {
4606 part.ResetOwnerChangeFlag();
4607 });
4608 }
4609
3662 #endregion 4610 #endregion
3663 } 4611 }
3664} 4612}