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.cs1424
1 files changed, 1190 insertions, 234 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 4b4e4ba..997a1be 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 }
@@ -220,6 +272,11 @@ namespace OpenSim.Region.Framework.Scenes
220 { 272 {
221 AttachmentPoint = 0; 273 AttachmentPoint = 0;
222 274
275 // Don't zap trees
276 if (RootPart.Shape.PCode == (byte)PCode.Tree ||
277 RootPart.Shape.PCode == (byte)PCode.NewTree)
278 return;
279
223 // Even though we don't use child part state parameters for attachments any more, we still need to set 280 // Even though we don't use child part state parameters for attachments any more, we still need to set
224 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if 281 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
225 // we store them correctly, scene objects that we receive from elsewhere might not. 282 // we store them correctly, scene objects that we receive from elsewhere might not.
@@ -265,26 +322,38 @@ namespace OpenSim.Region.Framework.Scenes
265 get { return RootPart.VolumeDetectActive; } 322 get { return RootPart.VolumeDetectActive; }
266 } 323 }
267 324
268 private Vector3 lastPhysGroupPos;
269 private Quaternion lastPhysGroupRot;
270
271 private bool m_isBackedUp; 325 private bool m_isBackedUp;
272 326
327 public bool IsBackedUp
328 {
329 get { return m_isBackedUp; }
330 }
331
273 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 332 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
274 333
275 protected ulong m_regionHandle; 334 protected ulong m_regionHandle;
276 protected SceneObjectPart m_rootPart; 335 protected SceneObjectPart m_rootPart;
277 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); 336 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
278 337
279 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); 338 private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>();
280 private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); 339 private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>();
340
341 public SortedDictionary<uint, scriptPosTarget> AtTargets
342 {
343 get { return m_targets; }
344 }
345
346 public SortedDictionary<uint, scriptRotTarget> RotTargets
347 {
348 get { return m_rotTargets; }
349 }
281 350
282 private bool m_scriptListens_atTarget; 351 private bool m_scriptListens_atTarget;
283 private bool m_scriptListens_notAtTarget; 352 private bool m_scriptListens_notAtTarget;
284
285 private bool m_scriptListens_atRotTarget; 353 private bool m_scriptListens_atRotTarget;
286 private bool m_scriptListens_notAtRotTarget; 354 private bool m_scriptListens_notAtRotTarget;
287 355
356 public bool m_dupeInProgress = false;
288 internal Dictionary<UUID, string> m_savedScriptState; 357 internal Dictionary<UUID, string> m_savedScriptState;
289 358
290 #region Properties 359 #region Properties
@@ -321,6 +390,16 @@ namespace OpenSim.Region.Framework.Scenes
321 get { return m_parts.Count; } 390 get { return m_parts.Count; }
322 } 391 }
323 392
393// protected Quaternion m_rotation = Quaternion.Identity;
394//
395// public virtual Quaternion Rotation
396// {
397// get { return m_rotation; }
398// set {
399// m_rotation = value;
400// }
401// }
402
324 public Quaternion GroupRotation 403 public Quaternion GroupRotation
325 { 404 {
326 get { return m_rootPart.RotationOffset; } 405 get { return m_rootPart.RotationOffset; }
@@ -427,7 +506,15 @@ namespace OpenSim.Region.Framework.Scenes
427 { 506 {
428 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 507 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
429 } 508 }
430 509
510
511
512 private struct avtocrossInfo
513 {
514 public ScenePresence av;
515 public uint ParentID;
516 }
517
431 /// <summary> 518 /// <summary>
432 /// The absolute position of this scene object in the scene 519 /// The absolute position of this scene object in the scene
433 /// </summary> 520 /// </summary>
@@ -455,13 +542,130 @@ namespace OpenSim.Region.Framework.Scenes
455 || Scene.TestBorderCross(val, Cardinals.S)) 542 || Scene.TestBorderCross(val, Cardinals.S))
456 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 543 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
457 { 544 {
545 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
546 uint x = 0;
547 uint y = 0;
548 string version = String.Empty;
549 Vector3 newpos = Vector3.Zero;
550 OpenSim.Services.Interfaces.GridRegion destination = null;
551
458 if (m_rootPart.KeyframeMotion != null) 552 if (m_rootPart.KeyframeMotion != null)
459 m_rootPart.KeyframeMotion.StartCrossingCheck(); 553 m_rootPart.KeyframeMotion.StartCrossingCheck();
460 554
461 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 555 bool canCross = true;
556 foreach (ScenePresence av in m_linkedAvatars)
557 {
558 // We need to cross these agents. First, let's find
559 // out if any of them can't cross for some reason.
560 // We have to deny the crossing entirely if any
561 // of them are banned. Alternatively, we could
562 // unsit banned agents....
563
564
565 // We set the avatar position as being the object
566 // position to get the region to send to
567 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
568 {
569 canCross = false;
570 break;
571 }
572
573 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
574 }
575
576 if (canCross)
577 {
578 // We unparent the SP quietly so that it won't
579 // be made to stand up
580
581 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
582
583 foreach (ScenePresence av in m_linkedAvatars)
584 {
585 avtocrossInfo avinfo = new avtocrossInfo();
586 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
587 if (parentPart != null)
588 av.ParentUUID = parentPart.UUID;
589
590 avinfo.av = av;
591 avinfo.ParentID = av.ParentID;
592 avsToCross.Add(avinfo);
593
594 av.PrevSitOffset = av.OffsetPosition;
595 av.ParentID = 0;
596 }
597
598 // m_linkedAvatars.Clear();
599 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
600
601 // Normalize
602 if (val.X >= Constants.RegionSize)
603 val.X -= Constants.RegionSize;
604 if (val.Y >= Constants.RegionSize)
605 val.Y -= Constants.RegionSize;
606 if (val.X < 0)
607 val.X += Constants.RegionSize;
608 if (val.Y < 0)
609 val.Y += Constants.RegionSize;
610
611 // If it's deleted, crossing was successful
612 if (IsDeleted)
613 {
614 // foreach (ScenePresence av in m_linkedAvatars)
615 foreach (avtocrossInfo avinfo in avsToCross)
616 {
617 ScenePresence av = avinfo.av;
618 if (!av.IsInTransit) // just in case...
619 {
620 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
621
622 av.IsInTransit = true;
623
624 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
625 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
626 }
627 else
628 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
629 }
630 avsToCross.Clear();
631 return;
632 }
633 else // cross failed, put avas back ??
634 {
635 foreach (avtocrossInfo avinfo in avsToCross)
636 {
637 ScenePresence av = avinfo.av;
638 av.ParentUUID = UUID.Zero;
639 av.ParentID = avinfo.ParentID;
640// m_linkedAvatars.Add(av);
641 }
642 }
643 avsToCross.Clear();
644
645 }
646 else
647 {
648 if (m_rootPart.KeyframeMotion != null)
649 m_rootPart.KeyframeMotion.CrossingFailure();
650
651 if (RootPart.PhysActor != null)
652 {
653 RootPart.PhysActor.CrossingFailure();
654 }
655 }
656 Vector3 oldp = AbsolutePosition;
657 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
658 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
659 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
462 } 660 }
463 } 661 }
464 662
663/* don't see the need but worse don't see where is restored to false if things stay in
664 foreach (SceneObjectPart part in m_parts.GetArray())
665 {
666 part.IgnoreUndoUpdate = true;
667 }
668 */
465 if (RootPart.GetStatusSandbox()) 669 if (RootPart.GetStatusSandbox())
466 { 670 {
467 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 671 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -479,9 +683,38 @@ namespace OpenSim.Region.Framework.Scenes
479 // Restuff the new GroupPosition into each SOP of the linkset. 683 // Restuff the new GroupPosition into each SOP of the linkset.
480 // This has the affect of resetting and tainting the physics actors. 684 // This has the affect of resetting and tainting the physics actors.
481 SceneObjectPart[] parts = m_parts.GetArray(); 685 SceneObjectPart[] parts = m_parts.GetArray();
482 for (int i = 0; i < parts.Length; i++) 686 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
483 parts[i].GroupPosition = val; 687 if (m_dupeInProgress)
688 triggerScriptEvent = false;
689 foreach (SceneObjectPart part in parts)
690 {
691 part.GroupPosition = val;
692 if (triggerScriptEvent)
693 part.TriggerScriptChangedEvent(Changed.POSITION);
694 }
484 695
696/*
697 This seems not needed and should not be needed:
698 sp absolute position depends on sit part absolute position fixed above.
699 sp ParentPosition is not used anywhere.
700 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
701 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
702
703 if (!m_dupeInProgress)
704 {
705 foreach (ScenePresence av in m_linkedAvatars)
706 {
707 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
708 if (p != null && m_parts.TryGetValue(p.UUID, out p))
709 {
710 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
711 av.AbsolutePosition += offset;
712// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
713 av.SendAvatarDataToAllAgents();
714 }
715 }
716 }
717*/
485 //if (m_rootPart.PhysActor != null) 718 //if (m_rootPart.PhysActor != null)
486 //{ 719 //{
487 //m_rootPart.PhysActor.Position = 720 //m_rootPart.PhysActor.Position =
@@ -495,6 +728,40 @@ namespace OpenSim.Region.Framework.Scenes
495 } 728 }
496 } 729 }
497 730
731 public override Vector3 Velocity
732 {
733 get { return RootPart.Velocity; }
734 set { RootPart.Velocity = value; }
735 }
736
737 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
738 {
739 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
740 ScenePresence agent = icon.EndInvoke(iar);
741
742 //// If the cross was successful, this agent is a child agent
743 if (agent.IsChildAgent)
744 {
745 if (agent.ParentUUID != UUID.Zero)
746 {
747 agent.ParentPart = null;
748// agent.ParentPosition = Vector3.Zero;
749// agent.ParentUUID = UUID.Zero;
750 }
751 }
752
753 agent.ParentUUID = UUID.Zero;
754
755// agent.Reset();
756// else // Not successful
757// agent.RestoreInCurrentScene();
758
759 // In any case
760 agent.IsInTransit = false;
761
762 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
763 }
764
498 public override uint LocalId 765 public override uint LocalId
499 { 766 {
500 get { return m_rootPart.LocalId; } 767 get { return m_rootPart.LocalId; }
@@ -565,6 +832,11 @@ namespace OpenSim.Region.Framework.Scenes
565 m_isSelected = value; 832 m_isSelected = value;
566 // Tell physics engine that group is selected 833 // Tell physics engine that group is selected
567 834
835 // this is not right
836 // but ode engines should only really need to know about root part
837 // so they can put entire object simulation on hold and not colliding
838 // keep as was for now
839
568 PhysicsActor pa = m_rootPart.PhysActor; 840 PhysicsActor pa = m_rootPart.PhysActor;
569 if (pa != null) 841 if (pa != null)
570 { 842 {
@@ -586,6 +858,40 @@ namespace OpenSim.Region.Framework.Scenes
586 } 858 }
587 } 859 }
588 860
861 public void PartSelectChanged(bool partSelect)
862 {
863 // any part selected makes group selected
864 if (m_isSelected == partSelect)
865 return;
866
867 if (partSelect)
868 {
869 IsSelected = partSelect;
870// if (!IsAttachment)
871// ScheduleGroupForFullUpdate();
872 }
873 else
874 {
875 // bad bad bad 2 heavy for large linksets
876 // since viewer does send lot of (un)selects
877 // this needs to be replaced by a specific list or count ?
878 // but that will require extra code in several places
879
880 SceneObjectPart[] parts = m_parts.GetArray();
881 for (int i = 0; i < parts.Length; i++)
882 {
883 SceneObjectPart part = parts[i];
884 if (part.IsSelected)
885 return;
886 }
887 IsSelected = partSelect;
888 if (!IsAttachment)
889 {
890 ScheduleGroupForFullUpdate();
891 }
892 }
893 }
894
589 private SceneObjectPart m_PlaySoundMasterPrim = null; 895 private SceneObjectPart m_PlaySoundMasterPrim = null;
590 public SceneObjectPart PlaySoundMasterPrim 896 public SceneObjectPart PlaySoundMasterPrim
591 { 897 {
@@ -680,6 +986,7 @@ namespace OpenSim.Region.Framework.Scenes
680 /// </summary> 986 /// </summary>
681 public SceneObjectGroup() 987 public SceneObjectGroup()
682 { 988 {
989
683 } 990 }
684 991
685 /// <summary> 992 /// <summary>
@@ -697,8 +1004,8 @@ namespace OpenSim.Region.Framework.Scenes
697 /// Constructor. This object is added to the scene later via AttachToScene() 1004 /// Constructor. This object is added to the scene later via AttachToScene()
698 /// </summary> 1005 /// </summary>
699 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 1006 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
700 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 1007 {
701 { 1008 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
702 } 1009 }
703 1010
704 /// <summary> 1011 /// <summary>
@@ -733,6 +1040,9 @@ namespace OpenSim.Region.Framework.Scenes
733 /// </summary> 1040 /// </summary>
734 public virtual void AttachToBackup() 1041 public virtual void AttachToBackup()
735 { 1042 {
1043 if (IsAttachment) return;
1044 m_scene.SceneGraph.FireAttachToBackup(this);
1045
736 if (InSceneBackup) 1046 if (InSceneBackup)
737 { 1047 {
738 //m_log.DebugFormat( 1048 //m_log.DebugFormat(
@@ -780,6 +1090,13 @@ namespace OpenSim.Region.Framework.Scenes
780 1090
781 ApplyPhysics(); 1091 ApplyPhysics();
782 1092
1093 if (RootPart.PhysActor != null)
1094 RootPart.Force = RootPart.Force;
1095 if (RootPart.PhysActor != null)
1096 RootPart.Torque = RootPart.Torque;
1097 if (RootPart.PhysActor != null)
1098 RootPart.Buoyancy = RootPart.Buoyancy;
1099
783 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1100 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
784 // for the same object with very different properties. The caller must schedule the update. 1101 // for the same object with very different properties. The caller must schedule the update.
785 //ScheduleGroupForFullUpdate(); 1102 //ScheduleGroupForFullUpdate();
@@ -795,6 +1112,10 @@ namespace OpenSim.Region.Framework.Scenes
795 EntityIntersection result = new EntityIntersection(); 1112 EntityIntersection result = new EntityIntersection();
796 1113
797 SceneObjectPart[] parts = m_parts.GetArray(); 1114 SceneObjectPart[] parts = m_parts.GetArray();
1115
1116 // Find closest hit here
1117 float idist = float.MaxValue;
1118
798 for (int i = 0; i < parts.Length; i++) 1119 for (int i = 0; i < parts.Length; i++)
799 { 1120 {
800 SceneObjectPart part = parts[i]; 1121 SceneObjectPart part = parts[i];
@@ -809,11 +1130,6 @@ namespace OpenSim.Region.Framework.Scenes
809 1130
810 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1131 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
811 1132
812 // This may need to be updated to the maximum draw distance possible..
813 // We might (and probably will) be checking for prim creation from other sims
814 // when the camera crosses the border.
815 float idist = Constants.RegionSize;
816
817 if (inter.HitTF) 1133 if (inter.HitTF)
818 { 1134 {
819 // We need to find the closest prim to return to the testcaller along the ray 1135 // We need to find the closest prim to return to the testcaller along the ray
@@ -824,10 +1140,11 @@ namespace OpenSim.Region.Framework.Scenes
824 result.obj = part; 1140 result.obj = part;
825 result.normal = inter.normal; 1141 result.normal = inter.normal;
826 result.distance = inter.distance; 1142 result.distance = inter.distance;
1143
1144 idist = inter.distance;
827 } 1145 }
828 } 1146 }
829 } 1147 }
830
831 return result; 1148 return result;
832 } 1149 }
833 1150
@@ -839,25 +1156,27 @@ namespace OpenSim.Region.Framework.Scenes
839 /// <returns></returns> 1156 /// <returns></returns>
840 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1157 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
841 { 1158 {
842 maxX = -256f; 1159 maxX = float.MinValue;
843 maxY = -256f; 1160 maxY = float.MinValue;
844 maxZ = -256f; 1161 maxZ = float.MinValue;
845 minX = 256f; 1162 minX = float.MaxValue;
846 minY = 256f; 1163 minY = float.MaxValue;
847 minZ = 8192f; 1164 minZ = float.MaxValue;
848 1165
849 SceneObjectPart[] parts = m_parts.GetArray(); 1166 SceneObjectPart[] parts = m_parts.GetArray();
850 for (int i = 0; i < parts.Length; i++) 1167 foreach (SceneObjectPart part in parts)
851 { 1168 {
852 SceneObjectPart part = parts[i];
853
854 Vector3 worldPos = part.GetWorldPosition(); 1169 Vector3 worldPos = part.GetWorldPosition();
855 Vector3 offset = worldPos - AbsolutePosition; 1170 Vector3 offset = worldPos - AbsolutePosition;
856 Quaternion worldRot; 1171 Quaternion worldRot;
857 if (part.ParentID == 0) 1172 if (part.ParentID == 0)
1173 {
858 worldRot = part.RotationOffset; 1174 worldRot = part.RotationOffset;
1175 }
859 else 1176 else
1177 {
860 worldRot = part.GetWorldRotation(); 1178 worldRot = part.GetWorldRotation();
1179 }
861 1180
862 Vector3 frontTopLeft; 1181 Vector3 frontTopLeft;
863 Vector3 frontTopRight; 1182 Vector3 frontTopRight;
@@ -869,6 +1188,8 @@ namespace OpenSim.Region.Framework.Scenes
869 Vector3 backBottomLeft; 1188 Vector3 backBottomLeft;
870 Vector3 backBottomRight; 1189 Vector3 backBottomRight;
871 1190
1191 // Vector3[] corners = new Vector3[8];
1192
872 Vector3 orig = Vector3.Zero; 1193 Vector3 orig = Vector3.Zero;
873 1194
874 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1195 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -903,6 +1224,38 @@ namespace OpenSim.Region.Framework.Scenes
903 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1224 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
904 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1225 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
905 1226
1227
1228
1229 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1230 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1231 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1232 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1233 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1234 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1235 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1236 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1237
1238 //for (int i = 0; i < 8; i++)
1239 //{
1240 // corners[i] = corners[i] * worldRot;
1241 // corners[i] += offset;
1242
1243 // if (corners[i].X > maxX)
1244 // maxX = corners[i].X;
1245 // if (corners[i].X < minX)
1246 // minX = corners[i].X;
1247
1248 // if (corners[i].Y > maxY)
1249 // maxY = corners[i].Y;
1250 // if (corners[i].Y < minY)
1251 // minY = corners[i].Y;
1252
1253 // if (corners[i].Z > maxZ)
1254 // maxZ = corners[i].Y;
1255 // if (corners[i].Z < minZ)
1256 // minZ = corners[i].Z;
1257 //}
1258
906 frontTopLeft = frontTopLeft * worldRot; 1259 frontTopLeft = frontTopLeft * worldRot;
907 frontTopRight = frontTopRight * worldRot; 1260 frontTopRight = frontTopRight * worldRot;
908 frontBottomLeft = frontBottomLeft * worldRot; 1261 frontBottomLeft = frontBottomLeft * worldRot;
@@ -924,6 +1277,15 @@ namespace OpenSim.Region.Framework.Scenes
924 backTopLeft += offset; 1277 backTopLeft += offset;
925 backTopRight += offset; 1278 backTopRight += offset;
926 1279
1280 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1281 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1282 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1283 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1284 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1285 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1286 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1287 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1288
927 if (frontTopRight.X > maxX) 1289 if (frontTopRight.X > maxX)
928 maxX = frontTopRight.X; 1290 maxX = frontTopRight.X;
929 if (frontTopLeft.X > maxX) 1291 if (frontTopLeft.X > maxX)
@@ -1067,17 +1429,118 @@ namespace OpenSim.Region.Framework.Scenes
1067 1429
1068 #endregion 1430 #endregion
1069 1431
1432 public void GetResourcesCosts(SceneObjectPart apart,
1433 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1434 {
1435 // this information may need to be cached
1436
1437 float cost;
1438 float tmpcost;
1439
1440 bool ComplexCost = false;
1441
1442 SceneObjectPart p;
1443 SceneObjectPart[] parts;
1444
1445 lock (m_parts)
1446 {
1447 parts = m_parts.GetArray();
1448 }
1449
1450 int nparts = parts.Length;
1451
1452
1453 for (int i = 0; i < nparts; i++)
1454 {
1455 p = parts[i];
1456
1457 if (p.UsesComplexCost)
1458 {
1459 ComplexCost = true;
1460 break;
1461 }
1462 }
1463
1464 if (ComplexCost)
1465 {
1466 linksetResCost = 0;
1467 linksetPhysCost = 0;
1468 partCost = 0;
1469 partPhysCost = 0;
1470
1471 for (int i = 0; i < nparts; i++)
1472 {
1473 p = parts[i];
1474
1475 cost = p.StreamingCost;
1476 tmpcost = p.SimulationCost;
1477 if (tmpcost > cost)
1478 cost = tmpcost;
1479 tmpcost = p.PhysicsCost;
1480 if (tmpcost > cost)
1481 cost = tmpcost;
1482
1483 linksetPhysCost += tmpcost;
1484 linksetResCost += cost;
1485
1486 if (p == apart)
1487 {
1488 partCost = cost;
1489 partPhysCost = tmpcost;
1490 }
1491 }
1492 }
1493 else
1494 {
1495 partPhysCost = 1.0f;
1496 partCost = 1.0f;
1497 linksetResCost = (float)nparts;
1498 linksetPhysCost = linksetResCost;
1499 }
1500 }
1501
1502 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1503 {
1504 SceneObjectPart p;
1505 SceneObjectPart[] parts;
1506
1507 lock (m_parts)
1508 {
1509 parts = m_parts.GetArray();
1510 }
1511
1512 int nparts = parts.Length;
1513
1514 PhysCost = 0;
1515 StreamCost = 0;
1516 SimulCost = 0;
1517
1518 for (int i = 0; i < nparts; i++)
1519 {
1520 p = parts[i];
1521
1522 StreamCost += p.StreamingCost;
1523 SimulCost += p.SimulationCost;
1524 PhysCost += p.PhysicsCost;
1525 }
1526 }
1527
1070 public void SaveScriptedState(XmlTextWriter writer) 1528 public void SaveScriptedState(XmlTextWriter writer)
1071 { 1529 {
1530 SaveScriptedState(writer, false);
1531 }
1532
1533 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1534 {
1072 XmlDocument doc = new XmlDocument(); 1535 XmlDocument doc = new XmlDocument();
1073 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1536 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1074 1537
1075 SceneObjectPart[] parts = m_parts.GetArray(); 1538 SceneObjectPart[] parts = m_parts.GetArray();
1076 for (int i = 0; i < parts.Length; i++) 1539 for (int i = 0; i < parts.Length; i++)
1077 { 1540 {
1078 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1541 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1079 foreach (KeyValuePair<UUID, string> kvp in pstates) 1542 foreach (KeyValuePair<UUID, string> kvp in pstates)
1080 states.Add(kvp.Key, kvp.Value); 1543 states[kvp.Key] = kvp.Value;
1081 } 1544 }
1082 1545
1083 if (states.Count > 0) 1546 if (states.Count > 0)
@@ -1097,6 +1560,170 @@ namespace OpenSim.Region.Framework.Scenes
1097 } 1560 }
1098 1561
1099 /// <summary> 1562 /// <summary>
1563 /// Add the avatar to this linkset (avatar is sat).
1564 /// </summary>
1565 /// <param name="agentID"></param>
1566 public void AddAvatar(UUID agentID)
1567 {
1568 ScenePresence presence;
1569 if (m_scene.TryGetScenePresence(agentID, out presence))
1570 {
1571 if (!m_linkedAvatars.Contains(presence))
1572 {
1573 m_linkedAvatars.Add(presence);
1574 }
1575 }
1576 }
1577
1578 /// <summary>
1579 /// Delete the avatar from this linkset (avatar is unsat).
1580 /// </summary>
1581 /// <param name="agentID"></param>
1582 public void DeleteAvatar(UUID agentID)
1583 {
1584 ScenePresence presence;
1585 if (m_scene.TryGetScenePresence(agentID, out presence))
1586 {
1587 if (m_linkedAvatars.Contains(presence))
1588 {
1589 m_linkedAvatars.Remove(presence);
1590 }
1591 }
1592 }
1593
1594 /// <summary>
1595 /// Returns the list of linked presences (avatars sat on this group)
1596 /// </summary>
1597 /// <param name="agentID"></param>
1598 public List<ScenePresence> GetLinkedAvatars()
1599 {
1600 return m_linkedAvatars;
1601 }
1602
1603 /// <summary>
1604 /// Attach this scene object to the given avatar.
1605 /// </summary>
1606 /// <param name="agentID"></param>
1607 /// <param name="attachmentpoint"></param>
1608 /// <param name="AttachOffset"></param>
1609 private void AttachToAgent(
1610 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1611 {
1612 if (avatar != null)
1613 {
1614 // don't attach attachments to child agents
1615 if (avatar.IsChildAgent) return;
1616
1617 // Remove from database and parcel prim count
1618 m_scene.DeleteFromStorage(so.UUID);
1619 m_scene.EventManager.TriggerParcelPrimCountTainted();
1620
1621 so.AttachedAvatar = avatar.UUID;
1622
1623 if (so.RootPart.PhysActor != null)
1624 {
1625 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1626 so.RootPart.PhysActor = null;
1627 }
1628
1629 so.AbsolutePosition = attachOffset;
1630 so.RootPart.AttachedPos = attachOffset;
1631 so.IsAttachment = true;
1632 so.RootPart.SetParentLocalId(avatar.LocalId);
1633 so.AttachmentPoint = attachmentpoint;
1634
1635 avatar.AddAttachment(this);
1636
1637 if (!silent)
1638 {
1639 // Killing it here will cause the client to deselect it
1640 // It then reappears on the avatar, deselected
1641 // through the full update below
1642 //
1643 if (IsSelected)
1644 {
1645 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1646 }
1647
1648 IsSelected = false; // fudge....
1649 ScheduleGroupForFullUpdate();
1650 }
1651 }
1652 else
1653 {
1654 m_log.WarnFormat(
1655 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1656 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1657 }
1658 }
1659
1660 public byte GetAttachmentPoint()
1661 {
1662 return m_rootPart.Shape.State;
1663 }
1664
1665 public void DetachToGround()
1666 {
1667 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1668 if (avatar == null)
1669 return;
1670 m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State;
1671 m_rootPart.AttachedPos = m_rootPart.OffsetPosition;
1672 avatar.RemoveAttachment(this);
1673
1674 Vector3 detachedpos = new Vector3(127f,127f,127f);
1675 if (avatar == null)
1676 return;
1677
1678 detachedpos = avatar.AbsolutePosition;
1679 FromItemID = UUID.Zero;
1680
1681 AbsolutePosition = detachedpos;
1682 AttachedAvatar = UUID.Zero;
1683
1684 //SceneObjectPart[] parts = m_parts.GetArray();
1685 //for (int i = 0; i < parts.Length; i++)
1686 // parts[i].AttachedAvatar = UUID.Zero;
1687
1688 m_rootPart.SetParentLocalId(0);
1689 AttachmentPoint = (byte)0;
1690 // must check if buildind should be true or false here
1691 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1692 HasGroupChanged = true;
1693 RootPart.Rezzed = DateTime.Now;
1694 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1695 AttachToBackup();
1696 m_scene.EventManager.TriggerParcelPrimCountTainted();
1697 m_rootPart.ScheduleFullUpdate();
1698 m_rootPart.ClearUndoState();
1699 }
1700
1701 public void DetachToInventoryPrep()
1702 {
1703 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1704 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1705 if (avatar != null)
1706 {
1707 //detachedpos = avatar.AbsolutePosition;
1708 avatar.RemoveAttachment(this);
1709 }
1710
1711 AttachedAvatar = UUID.Zero;
1712
1713 /*SceneObjectPart[] parts = m_parts.GetArray();
1714 for (int i = 0; i < parts.Length; i++)
1715 parts[i].AttachedAvatar = UUID.Zero;*/
1716
1717 m_rootPart.SetParentLocalId(0);
1718 //m_rootPart.SetAttachmentPoint((byte)0);
1719 IsAttachment = false;
1720 AbsolutePosition = m_rootPart.AttachedPos;
1721 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1722 //AttachToBackup();
1723 //m_rootPart.ScheduleFullUpdate();
1724 }
1725
1726 /// <summary>
1100 /// 1727 ///
1101 /// </summary> 1728 /// </summary>
1102 /// <param name="part"></param> 1729 /// <param name="part"></param>
@@ -1136,7 +1763,10 @@ namespace OpenSim.Region.Framework.Scenes
1136 public void AddPart(SceneObjectPart part) 1763 public void AddPart(SceneObjectPart part)
1137 { 1764 {
1138 part.SetParent(this); 1765 part.SetParent(this);
1139 part.LinkNum = m_parts.Add(part.UUID, part); 1766 m_parts.Add(part.UUID, part);
1767
1768 part.LinkNum = m_parts.Count;
1769
1140 if (part.LinkNum == 2) 1770 if (part.LinkNum == 2)
1141 RootPart.LinkNum = 1; 1771 RootPart.LinkNum = 1;
1142 } 1772 }
@@ -1162,6 +1792,14 @@ namespace OpenSim.Region.Framework.Scenes
1162 parts[i].UUID = UUID.Random(); 1792 parts[i].UUID = UUID.Random();
1163 } 1793 }
1164 1794
1795 // helper provided for parts.
1796 public int GetSceneMaxUndo()
1797 {
1798 if (m_scene != null)
1799 return m_scene.MaxUndoCount;
1800 return 5;
1801 }
1802
1165 // justincc: I don't believe this hack is needed any longer, especially since the physics 1803 // justincc: I don't believe this hack is needed any longer, especially since the physics
1166 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1804 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1167 // this method was preventing proper reload of scene objects. 1805 // this method was preventing proper reload of scene objects.
@@ -1219,7 +1857,7 @@ namespace OpenSim.Region.Framework.Scenes
1219// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1857// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1220// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1858// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1221 1859
1222 part.StoreUndoState(); 1860// part.StoreUndoState();
1223 part.OnGrab(offsetPos, remoteClient); 1861 part.OnGrab(offsetPos, remoteClient);
1224 } 1862 }
1225 1863
@@ -1239,6 +1877,11 @@ namespace OpenSim.Region.Framework.Scenes
1239 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1877 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1240 public void DeleteGroupFromScene(bool silent) 1878 public void DeleteGroupFromScene(bool silent)
1241 { 1879 {
1880 // We need to keep track of this state in case this group is still queued for backup.
1881 IsDeleted = true;
1882
1883 DetachFromBackup();
1884
1242 SceneObjectPart[] parts = m_parts.GetArray(); 1885 SceneObjectPart[] parts = m_parts.GetArray();
1243 for (int i = 0; i < parts.Length; i++) 1886 for (int i = 0; i < parts.Length; i++)
1244 { 1887 {
@@ -1262,6 +1905,7 @@ namespace OpenSim.Region.Framework.Scenes
1262 } 1905 }
1263 }); 1906 });
1264 } 1907 }
1908
1265 } 1909 }
1266 1910
1267 public void AddScriptLPS(int count) 1911 public void AddScriptLPS(int count)
@@ -1331,28 +1975,43 @@ namespace OpenSim.Region.Framework.Scenes
1331 /// </summary> 1975 /// </summary>
1332 public void ApplyPhysics() 1976 public void ApplyPhysics()
1333 { 1977 {
1334 // Apply physics to the root prim
1335 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1336
1337 // Apply physics to child prims
1338 SceneObjectPart[] parts = m_parts.GetArray(); 1978 SceneObjectPart[] parts = m_parts.GetArray();
1339 if (parts.Length > 1) 1979 if (parts.Length > 1)
1340 { 1980 {
1981 ResetChildPrimPhysicsPositions();
1982
1983 // Apply physics to the root prim
1984 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1985
1986
1341 for (int i = 0; i < parts.Length; i++) 1987 for (int i = 0; i < parts.Length; i++)
1342 { 1988 {
1343 SceneObjectPart part = parts[i]; 1989 SceneObjectPart part = parts[i];
1344 if (part.LocalId != m_rootPart.LocalId) 1990 if (part.LocalId != m_rootPart.LocalId)
1345 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1991 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1346 } 1992 }
1347
1348 // Hack to get the physics scene geometries in the right spot 1993 // Hack to get the physics scene geometries in the right spot
1349 ResetChildPrimPhysicsPositions(); 1994// ResetChildPrimPhysicsPositions();
1995 if (m_rootPart.PhysActor != null)
1996 {
1997 m_rootPart.PhysActor.Building = false;
1998 }
1999 }
2000 else
2001 {
2002 // Apply physics to the root prim
2003 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1350 } 2004 }
1351 } 2005 }
1352 2006
1353 public void SetOwnerId(UUID userId) 2007 public void SetOwnerId(UUID userId)
1354 { 2008 {
1355 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2009 ForEachPart(delegate(SceneObjectPart part)
2010 {
2011
2012 part.OwnerID = userId;
2013
2014 });
1356 } 2015 }
1357 2016
1358 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2017 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1384,11 +2043,17 @@ namespace OpenSim.Region.Framework.Scenes
1384 return; 2043 return;
1385 } 2044 }
1386 2045
2046 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2047 return;
2048
1387 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2049 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1388 // any exception propogate upwards. 2050 // any exception propogate upwards.
1389 try 2051 try
1390 { 2052 {
1391 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2053 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2054 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2055 m_scene.LoadingPrims) // Land may not be valid yet
2056
1392 { 2057 {
1393 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2058 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1394 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2059 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1415,6 +2080,7 @@ namespace OpenSim.Region.Framework.Scenes
1415 } 2080 }
1416 } 2081 }
1417 } 2082 }
2083
1418 } 2084 }
1419 2085
1420 if (m_scene.UseBackup && HasGroupChanged) 2086 if (m_scene.UseBackup && HasGroupChanged)
@@ -1422,10 +2088,31 @@ namespace OpenSim.Region.Framework.Scenes
1422 // don't backup while it's selected or you're asking for changes mid stream. 2088 // don't backup while it's selected or you're asking for changes mid stream.
1423 if (isTimeToPersist() || forcedBackup) 2089 if (isTimeToPersist() || forcedBackup)
1424 { 2090 {
2091 if (m_rootPart.PhysActor != null &&
2092 (!m_rootPart.PhysActor.IsPhysical))
2093 {
2094 // Possible ghost prim
2095 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2096 {
2097 foreach (SceneObjectPart part in m_parts.GetArray())
2098 {
2099 // Re-set physics actor positions and
2100 // orientations
2101 part.GroupPosition = m_rootPart.GroupPosition;
2102 }
2103 }
2104 }
1425// m_log.DebugFormat( 2105// m_log.DebugFormat(
1426// "[SCENE]: Storing {0}, {1} in {2}", 2106// "[SCENE]: Storing {0}, {1} in {2}",
1427// Name, UUID, m_scene.RegionInfo.RegionName); 2107// Name, UUID, m_scene.RegionInfo.RegionName);
1428 2108
2109 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2110 {
2111 RootPart.Shape.LastAttachPoint = RootPart.Shape.State;
2112 RootPart.Shape.State = 0;
2113 ScheduleGroupForFullUpdate();
2114 }
2115
1429 SceneObjectGroup backup_group = Copy(false); 2116 SceneObjectGroup backup_group = Copy(false);
1430 backup_group.RootPart.Velocity = RootPart.Velocity; 2117 backup_group.RootPart.Velocity = RootPart.Velocity;
1431 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2118 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1435,6 +2122,16 @@ namespace OpenSim.Region.Framework.Scenes
1435 HasGroupChangedDueToDelink = false; 2122 HasGroupChangedDueToDelink = false;
1436 2123
1437 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2124 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2125/*
2126 backup_group.ForEachPart(delegate(SceneObjectPart part)
2127 {
2128 if (part.KeyframeMotion != null)
2129 {
2130 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2131// part.KeyframeMotion.UpdateSceneObject(this);
2132 }
2133 });
2134*/
1438 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2135 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1439 2136
1440 backup_group.ForEachPart(delegate(SceneObjectPart part) 2137 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1491,10 +2188,14 @@ namespace OpenSim.Region.Framework.Scenes
1491 /// <returns></returns> 2188 /// <returns></returns>
1492 public SceneObjectGroup Copy(bool userExposed) 2189 public SceneObjectGroup Copy(bool userExposed)
1493 { 2190 {
2191 m_dupeInProgress = true;
1494 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2192 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1495 dupe.m_isBackedUp = false; 2193 dupe.m_isBackedUp = false;
1496 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2194 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1497 2195
2196 // new group as no sitting avatars
2197 dupe.m_linkedAvatars = new List<ScenePresence>();
2198
1498 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2199 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1499 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2200 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1500 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2201 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1505,7 +2206,7 @@ namespace OpenSim.Region.Framework.Scenes
1505 // This is only necessary when userExposed is false! 2206 // This is only necessary when userExposed is false!
1506 2207
1507 bool previousAttachmentStatus = dupe.IsAttachment; 2208 bool previousAttachmentStatus = dupe.IsAttachment;
1508 2209
1509 if (!userExposed) 2210 if (!userExposed)
1510 dupe.IsAttachment = true; 2211 dupe.IsAttachment = true;
1511 2212
@@ -1518,16 +2219,17 @@ namespace OpenSim.Region.Framework.Scenes
1518 2219
1519 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2220 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1520 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2221 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2222
1521 2223
1522 if (userExposed) 2224 if (userExposed)
1523 dupe.m_rootPart.TrimPermissions(); 2225 dupe.m_rootPart.TrimPermissions();
1524 2226
1525 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2227 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1526 2228
1527 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2229 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1528 { 2230 {
1529 return p1.LinkNum.CompareTo(p2.LinkNum); 2231 return p1.LinkNum.CompareTo(p2.LinkNum);
1530 } 2232 }
1531 ); 2233 );
1532 2234
1533 foreach (SceneObjectPart part in partList) 2235 foreach (SceneObjectPart part in partList)
@@ -1537,43 +2239,56 @@ namespace OpenSim.Region.Framework.Scenes
1537 { 2239 {
1538 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2240 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1539 newPart.LinkNum = part.LinkNum; 2241 newPart.LinkNum = part.LinkNum;
1540 } 2242 if (userExposed)
2243 newPart.ParentID = dupe.m_rootPart.LocalId;
2244 }
1541 else 2245 else
1542 { 2246 {
1543 newPart = dupe.m_rootPart; 2247 newPart = dupe.m_rootPart;
1544 } 2248 }
2249/*
2250 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2251 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1545 2252
1546 // Need to duplicate the physics actor as well 2253 // Need to duplicate the physics actor as well
1547 PhysicsActor originalPartPa = part.PhysActor; 2254 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1548 if (originalPartPa != null && userExposed)
1549 { 2255 {
1550 PrimitiveBaseShape pbs = newPart.Shape; 2256 PrimitiveBaseShape pbs = newPart.Shape;
1551
1552 newPart.PhysActor 2257 newPart.PhysActor
1553 = m_scene.PhysicsScene.AddPrimShape( 2258 = m_scene.PhysicsScene.AddPrimShape(
1554 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2259 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1555 pbs, 2260 pbs,
1556 newPart.AbsolutePosition, 2261 newPart.AbsolutePosition,
1557 newPart.Scale, 2262 newPart.Scale,
1558 newPart.RotationOffset, 2263 newPart.GetWorldRotation(),
1559 originalPartPa.IsPhysical, 2264 isphys,
2265 isphan,
1560 newPart.LocalId); 2266 newPart.LocalId);
1561 2267
1562 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2268 newPart.DoPhysicsPropertyUpdate(isphys, true);
1563 } 2269 */
2270 if (userExposed)
2271 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2272// }
2273 // copy keyframemotion
1564 if (part.KeyframeMotion != null) 2274 if (part.KeyframeMotion != null)
1565 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2275 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1566 } 2276 }
1567 2277
1568 if (userExposed) 2278 if (userExposed)
1569 { 2279 {
1570 dupe.UpdateParentIDs(); 2280// done above dupe.UpdateParentIDs();
2281
2282 if (dupe.m_rootPart.PhysActor != null)
2283 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2284
1571 dupe.HasGroupChanged = true; 2285 dupe.HasGroupChanged = true;
1572 dupe.AttachToBackup(); 2286 dupe.AttachToBackup();
1573 2287
1574 ScheduleGroupForFullUpdate(); 2288 ScheduleGroupForFullUpdate();
1575 } 2289 }
1576 2290
2291 m_dupeInProgress = false;
1577 return dupe; 2292 return dupe;
1578 } 2293 }
1579 2294
@@ -1585,7 +2300,14 @@ namespace OpenSim.Region.Framework.Scenes
1585 /// <param name="cGroupID"></param> 2300 /// <param name="cGroupID"></param>
1586 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2301 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1587 { 2302 {
1588 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2303 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2304 // give newpart a new local ID lettng old part keep same
2305 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2306 newpart.LocalId = m_scene.AllocateLocalId();
2307
2308 SetRootPart(newpart);
2309 if (userExposed)
2310 RootPart.Velocity = Vector3.Zero; // In case source is moving
1589 } 2311 }
1590 2312
1591 public void ScriptSetPhysicsStatus(bool usePhysics) 2313 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1643,27 +2365,14 @@ namespace OpenSim.Region.Framework.Scenes
1643 2365
1644 if (pa != null) 2366 if (pa != null)
1645 { 2367 {
1646 pa.AddForce(impulse, true); 2368 // false to be applied as a impulse
1647 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2369 pa.AddForce(impulse, false);
1648 }
1649 }
1650 }
1651
1652 public void applyAngularImpulse(Vector3 impulse)
1653 {
1654 PhysicsActor pa = RootPart.PhysActor;
1655
1656 if (pa != null)
1657 {
1658 if (!IsAttachment)
1659 {
1660 pa.AddAngularForce(impulse, true);
1661 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2370 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1662 } 2371 }
1663 } 2372 }
1664 } 2373 }
1665 2374
1666 public void setAngularImpulse(Vector3 impulse) 2375 public void ApplyAngularImpulse(Vector3 impulse)
1667 { 2376 {
1668 PhysicsActor pa = RootPart.PhysActor; 2377 PhysicsActor pa = RootPart.PhysActor;
1669 2378
@@ -1671,7 +2380,8 @@ namespace OpenSim.Region.Framework.Scenes
1671 { 2380 {
1672 if (!IsAttachment) 2381 if (!IsAttachment)
1673 { 2382 {
1674 pa.Torque = impulse; 2383 // false to be applied as a impulse
2384 pa.AddAngularForce(impulse, false);
1675 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2385 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1676 } 2386 }
1677 } 2387 }
@@ -1679,20 +2389,10 @@ namespace OpenSim.Region.Framework.Scenes
1679 2389
1680 public Vector3 GetTorque() 2390 public Vector3 GetTorque()
1681 { 2391 {
1682 PhysicsActor pa = RootPart.PhysActor; 2392 return RootPart.Torque;
1683
1684 if (pa != null)
1685 {
1686 if (!IsAttachment)
1687 {
1688 Vector3 torque = pa.Torque;
1689 return torque;
1690 }
1691 }
1692
1693 return Vector3.Zero;
1694 } 2393 }
1695 2394
2395 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1696 public void moveToTarget(Vector3 target, float tau) 2396 public void moveToTarget(Vector3 target, float tau)
1697 { 2397 {
1698 if (IsAttachment) 2398 if (IsAttachment)
@@ -1722,8 +2422,50 @@ namespace OpenSim.Region.Framework.Scenes
1722 2422
1723 if (pa != null) 2423 if (pa != null)
1724 pa.PIDActive = false; 2424 pa.PIDActive = false;
2425
2426 RootPart.ScheduleTerseUpdate(); // send a stop information
2427 }
2428
2429 public void rotLookAt(Quaternion target, float strength, float damping)
2430 {
2431 SceneObjectPart rootpart = m_rootPart;
2432 if (rootpart != null)
2433 {
2434 if (IsAttachment)
2435 {
2436 /*
2437 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2438 if (avatar != null)
2439 {
2440 Rotate the Av?
2441 } */
2442 }
2443 else
2444 {
2445 if (rootpart.PhysActor != null)
2446 { // APID must be implemented in your physics system for this to function.
2447 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2448 rootpart.PhysActor.APIDStrength = strength;
2449 rootpart.PhysActor.APIDDamping = damping;
2450 rootpart.PhysActor.APIDActive = true;
2451 }
2452 }
2453 }
1725 } 2454 }
2455
2456 public void stopLookAt()
2457 {
2458 SceneObjectPart rootpart = m_rootPart;
2459 if (rootpart != null)
2460 {
2461 if (rootpart.PhysActor != null)
2462 { // APID must be implemented in your physics system for this to function.
2463 rootpart.PhysActor.APIDActive = false;
2464 }
2465 }
1726 2466
2467 }
2468
1727 /// <summary> 2469 /// <summary>
1728 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2470 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1729 /// </summary> 2471 /// </summary>
@@ -1740,7 +2482,7 @@ namespace OpenSim.Region.Framework.Scenes
1740 { 2482 {
1741 pa.PIDHoverHeight = height; 2483 pa.PIDHoverHeight = height;
1742 pa.PIDHoverType = hoverType; 2484 pa.PIDHoverType = hoverType;
1743 pa.PIDTau = tau; 2485 pa.PIDHoverTau = tau;
1744 pa.PIDHoverActive = true; 2486 pa.PIDHoverActive = true;
1745 } 2487 }
1746 else 2488 else
@@ -1780,7 +2522,12 @@ namespace OpenSim.Region.Framework.Scenes
1780 /// <param name="cGroupID"></param> 2522 /// <param name="cGroupID"></param>
1781 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2523 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1782 { 2524 {
1783 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2525 // give new ID to the new part, letting old keep original
2526 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2527 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2528 newPart.LocalId = m_scene.AllocateLocalId();
2529 newPart.SetParent(this);
2530
1784 AddPart(newPart); 2531 AddPart(newPart);
1785 2532
1786 SetPartAsNonRoot(newPart); 2533 SetPartAsNonRoot(newPart);
@@ -1830,6 +2577,7 @@ namespace OpenSim.Region.Framework.Scenes
1830 2577
1831 #endregion 2578 #endregion
1832 2579
2580
1833 public override void Update() 2581 public override void Update()
1834 { 2582 {
1835 // Check that the group was not deleted before the scheduled update 2583 // Check that the group was not deleted before the scheduled update
@@ -1848,19 +2596,8 @@ namespace OpenSim.Region.Framework.Scenes
1848 // check to see if the physical position or rotation warrant an update. 2596 // check to see if the physical position or rotation warrant an update.
1849 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2597 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1850 { 2598 {
1851 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2599 // rootpart SendScheduledUpdates will check if a update is needed
1852 2600 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1853 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
1854 {
1855 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1856 lastPhysGroupPos = AbsolutePosition;
1857 }
1858
1859 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
1860 {
1861 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1862 lastPhysGroupRot = GroupRotation;
1863 }
1864 } 2601 }
1865 2602
1866 SceneObjectPart[] parts = m_parts.GetArray(); 2603 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1919,11 +2656,11 @@ namespace OpenSim.Region.Framework.Scenes
1919 /// Immediately send a full update for this scene object. 2656 /// Immediately send a full update for this scene object.
1920 /// </summary> 2657 /// </summary>
1921 public void SendGroupFullUpdate() 2658 public void SendGroupFullUpdate()
1922 { 2659 {
1923 if (IsDeleted) 2660 if (IsDeleted)
1924 return; 2661 return;
1925 2662
1926// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2663// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1927 2664
1928 RootPart.SendFullUpdateToAllClients(); 2665 RootPart.SendFullUpdateToAllClients();
1929 2666
@@ -2079,6 +2816,11 @@ namespace OpenSim.Region.Framework.Scenes
2079 // 'linkPart' == the root of the group being linked into this group 2816 // 'linkPart' == the root of the group being linked into this group
2080 SceneObjectPart linkPart = objectGroup.m_rootPart; 2817 SceneObjectPart linkPart = objectGroup.m_rootPart;
2081 2818
2819 if (m_rootPart.PhysActor != null)
2820 m_rootPart.PhysActor.Building = true;
2821 if (linkPart.PhysActor != null)
2822 linkPart.PhysActor.Building = true;
2823
2082 // physics flags from group to be applied to linked parts 2824 // physics flags from group to be applied to linked parts
2083 bool grpusephys = UsesPhysics; 2825 bool grpusephys = UsesPhysics;
2084 bool grptemporary = IsTemporary; 2826 bool grptemporary = IsTemporary;
@@ -2104,12 +2846,12 @@ namespace OpenSim.Region.Framework.Scenes
2104 Vector3 axPos = linkPart.OffsetPosition; 2846 Vector3 axPos = linkPart.OffsetPosition;
2105 // Rotate the linking root SOP's position to be relative to the new root prim 2847 // Rotate the linking root SOP's position to be relative to the new root prim
2106 Quaternion parentRot = m_rootPart.RotationOffset; 2848 Quaternion parentRot = m_rootPart.RotationOffset;
2107 axPos *= Quaternion.Inverse(parentRot); 2849 axPos *= Quaternion.Conjugate(parentRot);
2108 linkPart.OffsetPosition = axPos; 2850 linkPart.OffsetPosition = axPos;
2109 2851
2110 // Make the linking root SOP's rotation relative to the new root prim 2852 // Make the linking root SOP's rotation relative to the new root prim
2111 Quaternion oldRot = linkPart.RotationOffset; 2853 Quaternion oldRot = linkPart.RotationOffset;
2112 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2854 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2113 linkPart.RotationOffset = newRot; 2855 linkPart.RotationOffset = newRot;
2114 2856
2115 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2857 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2143,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
2143 linkPart.CreateSelected = true; 2885 linkPart.CreateSelected = true;
2144 2886
2145 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2887 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2146 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2888 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2147 2889
2148 // If the added SOP is physical, also tell the physics engine about the link relationship. 2890 // If the added SOP is physical, also tell the physics engine about the link relationship.
2149 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2891 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2153,6 +2895,7 @@ namespace OpenSim.Region.Framework.Scenes
2153 } 2895 }
2154 2896
2155 linkPart.LinkNum = linkNum++; 2897 linkPart.LinkNum = linkNum++;
2898 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2156 2899
2157 // Get a list of the SOP's in the old group in order of their linknum's. 2900 // Get a list of the SOP's in the old group in order of their linknum's.
2158 SceneObjectPart[] ogParts = objectGroup.Parts; 2901 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2171,7 +2914,7 @@ namespace OpenSim.Region.Framework.Scenes
2171 2914
2172 // Update the physics flags for the newly added SOP 2915 // Update the physics flags for the newly added SOP
2173 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2916 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2174 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2917 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2175 2918
2176 // If the added SOP is physical, also tell the physics engine about the link relationship. 2919 // If the added SOP is physical, also tell the physics engine about the link relationship.
2177 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2920 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2189,7 +2932,7 @@ namespace OpenSim.Region.Framework.Scenes
2189 objectGroup.IsDeleted = true; 2932 objectGroup.IsDeleted = true;
2190 2933
2191 objectGroup.m_parts.Clear(); 2934 objectGroup.m_parts.Clear();
2192 2935
2193 // Can't do this yet since backup still makes use of the root part without any synchronization 2936 // Can't do this yet since backup still makes use of the root part without any synchronization
2194// objectGroup.m_rootPart = null; 2937// objectGroup.m_rootPart = null;
2195 2938
@@ -2203,6 +2946,9 @@ namespace OpenSim.Region.Framework.Scenes
2203 // unmoved prims! 2946 // unmoved prims!
2204 ResetChildPrimPhysicsPositions(); 2947 ResetChildPrimPhysicsPositions();
2205 2948
2949 if (m_rootPart.PhysActor != null)
2950 m_rootPart.PhysActor.Building = false;
2951
2206 //HasGroupChanged = true; 2952 //HasGroupChanged = true;
2207 //ScheduleGroupForFullUpdate(); 2953 //ScheduleGroupForFullUpdate();
2208 } 2954 }
@@ -2270,7 +3016,10 @@ namespace OpenSim.Region.Framework.Scenes
2270// m_log.DebugFormat( 3016// m_log.DebugFormat(
2271// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3017// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2272// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3018// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2273 3019
3020 if (m_rootPart.PhysActor != null)
3021 m_rootPart.PhysActor.Building = true;
3022
2274 linkPart.ClearUndoState(); 3023 linkPart.ClearUndoState();
2275 3024
2276 Vector3 worldPos = linkPart.GetWorldPosition(); 3025 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2341,6 +3090,14 @@ namespace OpenSim.Region.Framework.Scenes
2341 3090
2342 // When we delete a group, we currently have to force persist to the database if the object id has changed 3091 // When we delete a group, we currently have to force persist to the database if the object id has changed
2343 // (since delete works by deleting all rows which have a given object id) 3092 // (since delete works by deleting all rows which have a given object id)
3093
3094 // this is as it seems to be in sl now
3095 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3096 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3097
3098 if (m_rootPart.PhysActor != null)
3099 m_rootPart.PhysActor.Building = false;
3100
2344 objectGroup.HasGroupChangedDueToDelink = true; 3101 objectGroup.HasGroupChangedDueToDelink = true;
2345 3102
2346 return objectGroup; 3103 return objectGroup;
@@ -2352,6 +3109,8 @@ namespace OpenSim.Region.Framework.Scenes
2352 /// <param name="objectGroup"></param> 3109 /// <param name="objectGroup"></param>
2353 public virtual void DetachFromBackup() 3110 public virtual void DetachFromBackup()
2354 { 3111 {
3112 if (m_scene != null)
3113 m_scene.SceneGraph.FireDetachFromBackup(this);
2355 if (m_isBackedUp && Scene != null) 3114 if (m_isBackedUp && Scene != null)
2356 m_scene.EventManager.OnBackup -= ProcessBackup; 3115 m_scene.EventManager.OnBackup -= ProcessBackup;
2357 3116
@@ -2372,7 +3131,8 @@ namespace OpenSim.Region.Framework.Scenes
2372 Vector3 axPos = part.OffsetPosition; 3131 Vector3 axPos = part.OffsetPosition;
2373 axPos *= parentRot; 3132 axPos *= parentRot;
2374 part.OffsetPosition = axPos; 3133 part.OffsetPosition = axPos;
2375 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3134 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3135 part.GroupPosition = newPos;
2376 part.OffsetPosition = Vector3.Zero; 3136 part.OffsetPosition = Vector3.Zero;
2377 3137
2378 // Compution our rotation to be not relative to the old parent 3138 // Compution our rotation to be not relative to the old parent
@@ -2387,7 +3147,7 @@ namespace OpenSim.Region.Framework.Scenes
2387 part.LinkNum = linkNum; 3147 part.LinkNum = linkNum;
2388 3148
2389 // Compute the new position of this SOP relative to the group position 3149 // Compute the new position of this SOP relative to the group position
2390 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3150 part.OffsetPosition = newPos - AbsolutePosition;
2391 3151
2392 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3152 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2393 // It would have the affect of setting the physics engine position multiple 3153 // It would have the affect of setting the physics engine position multiple
@@ -2397,18 +3157,19 @@ namespace OpenSim.Region.Framework.Scenes
2397 // Rotate the relative position by the rotation of the group 3157 // Rotate the relative position by the rotation of the group
2398 Quaternion rootRotation = m_rootPart.RotationOffset; 3158 Quaternion rootRotation = m_rootPart.RotationOffset;
2399 Vector3 pos = part.OffsetPosition; 3159 Vector3 pos = part.OffsetPosition;
2400 pos *= Quaternion.Inverse(rootRotation); 3160 pos *= Quaternion.Conjugate(rootRotation);
2401 part.OffsetPosition = pos; 3161 part.OffsetPosition = pos;
2402 3162
2403 // Compute the SOP's rotation relative to the rotation of the group. 3163 // Compute the SOP's rotation relative to the rotation of the group.
2404 parentRot = m_rootPart.RotationOffset; 3164 parentRot = m_rootPart.RotationOffset;
2405 oldRot = part.RotationOffset; 3165 oldRot = part.RotationOffset;
2406 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3166 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2407 part.RotationOffset = newRot; 3167 part.RotationOffset = newRot;
2408 3168
2409 // Since this SOP's state has changed, push those changes into the physics engine 3169 // Since this SOP's state has changed, push those changes into the physics engine
2410 // and the simulator. 3170 // and the simulator.
2411 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3171 // done on caller
3172// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2412 } 3173 }
2413 3174
2414 /// <summary> 3175 /// <summary>
@@ -2430,10 +3191,14 @@ namespace OpenSim.Region.Framework.Scenes
2430 { 3191 {
2431 if (!m_rootPart.BlockGrab) 3192 if (!m_rootPart.BlockGrab)
2432 { 3193 {
2433 Vector3 llmoveforce = pos - AbsolutePosition; 3194/* Vector3 llmoveforce = pos - AbsolutePosition;
2434 Vector3 grabforce = llmoveforce; 3195 Vector3 grabforce = llmoveforce;
2435 grabforce = (grabforce / 10) * pa.Mass; 3196 grabforce = (grabforce / 10) * pa.Mass;
2436 pa.AddForce(grabforce, true); 3197 */
3198 // empirically convert distance diference to a impulse
3199 Vector3 grabforce = pos - AbsolutePosition;
3200 grabforce = grabforce * (pa.Mass/ 10.0f);
3201 pa.AddForce(grabforce, false);
2437 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3202 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2438 } 3203 }
2439 } 3204 }
@@ -2629,6 +3394,8 @@ namespace OpenSim.Region.Framework.Scenes
2629 /// <param name="SetVolumeDetect"></param> 3394 /// <param name="SetVolumeDetect"></param>
2630 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3395 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2631 { 3396 {
3397 HasGroupChanged = true;
3398
2632 SceneObjectPart selectionPart = GetPart(localID); 3399 SceneObjectPart selectionPart = GetPart(localID);
2633 3400
2634 if (SetTemporary && Scene != null) 3401 if (SetTemporary && Scene != null)
@@ -2659,8 +3426,22 @@ namespace OpenSim.Region.Framework.Scenes
2659 } 3426 }
2660 } 3427 }
2661 3428
2662 for (int i = 0; i < parts.Length; i++) 3429 if (parts.Length > 1)
2663 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3430 {
3431 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3432
3433 for (int i = 0; i < parts.Length; i++)
3434 {
3435
3436 if (parts[i].UUID != m_rootPart.UUID)
3437 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3438 }
3439
3440 if (m_rootPart.PhysActor != null)
3441 m_rootPart.PhysActor.Building = false;
3442 }
3443 else
3444 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2664 } 3445 }
2665 } 3446 }
2666 3447
@@ -2673,6 +3454,17 @@ namespace OpenSim.Region.Framework.Scenes
2673 } 3454 }
2674 } 3455 }
2675 3456
3457
3458
3459 /// <summary>
3460 /// Gets the number of parts
3461 /// </summary>
3462 /// <returns></returns>
3463 public int GetPartCount()
3464 {
3465 return Parts.Count();
3466 }
3467
2676 /// <summary> 3468 /// <summary>
2677 /// Update the texture entry for this part 3469 /// Update the texture entry for this part
2678 /// </summary> 3470 /// </summary>
@@ -2710,8 +3502,24 @@ namespace OpenSim.Region.Framework.Scenes
2710 { 3502 {
2711 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3503 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2712 3504
3505 bool god = Scene.Permissions.IsGod(AgentID);
3506
3507 if (field == 1 && god)
3508 {
3509 ForEachPart(part =>
3510 {
3511 part.BaseMask = RootPart.BaseMask;
3512 });
3513 }
3514
2713 AdjustChildPrimPermissions(); 3515 AdjustChildPrimPermissions();
2714 3516
3517 if (field == 1 && god) // Base mask was set. Update all child part inventories
3518 {
3519 foreach (SceneObjectPart part in Parts)
3520 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3521 }
3522
2715 HasGroupChanged = true; 3523 HasGroupChanged = true;
2716 3524
2717 // Send the group's properties to all clients once all parts are updated 3525 // Send the group's properties to all clients once all parts are updated
@@ -2757,8 +3565,6 @@ namespace OpenSim.Region.Framework.Scenes
2757 3565
2758 PhysicsActor pa = m_rootPart.PhysActor; 3566 PhysicsActor pa = m_rootPart.PhysActor;
2759 3567
2760 RootPart.StoreUndoState(true);
2761
2762 if (Scene != null) 3568 if (Scene != null)
2763 { 3569 {
2764 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3570 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2786,7 +3592,6 @@ namespace OpenSim.Region.Framework.Scenes
2786 SceneObjectPart obPart = parts[i]; 3592 SceneObjectPart obPart = parts[i];
2787 if (obPart.UUID != m_rootPart.UUID) 3593 if (obPart.UUID != m_rootPart.UUID)
2788 { 3594 {
2789// obPart.IgnoreUndoUpdate = true;
2790 Vector3 oldSize = new Vector3(obPart.Scale); 3595 Vector3 oldSize = new Vector3(obPart.Scale);
2791 3596
2792 float f = 1.0f; 3597 float f = 1.0f;
@@ -2898,8 +3703,6 @@ namespace OpenSim.Region.Framework.Scenes
2898 z *= a; 3703 z *= a;
2899 } 3704 }
2900 } 3705 }
2901
2902// obPart.IgnoreUndoUpdate = false;
2903 } 3706 }
2904 } 3707 }
2905 } 3708 }
@@ -2909,9 +3712,7 @@ namespace OpenSim.Region.Framework.Scenes
2909 prevScale.Y *= y; 3712 prevScale.Y *= y;
2910 prevScale.Z *= z; 3713 prevScale.Z *= z;
2911 3714
2912// RootPart.IgnoreUndoUpdate = true;
2913 RootPart.Resize(prevScale); 3715 RootPart.Resize(prevScale);
2914// RootPart.IgnoreUndoUpdate = false;
2915 3716
2916 for (int i = 0; i < parts.Length; i++) 3717 for (int i = 0; i < parts.Length; i++)
2917 { 3718 {
@@ -2919,8 +3720,6 @@ namespace OpenSim.Region.Framework.Scenes
2919 3720
2920 if (obPart.UUID != m_rootPart.UUID) 3721 if (obPart.UUID != m_rootPart.UUID)
2921 { 3722 {
2922 obPart.IgnoreUndoUpdate = true;
2923
2924 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3723 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2925 currentpos.X *= x; 3724 currentpos.X *= x;
2926 currentpos.Y *= y; 3725 currentpos.Y *= y;
@@ -2933,16 +3732,12 @@ namespace OpenSim.Region.Framework.Scenes
2933 3732
2934 obPart.Resize(newSize); 3733 obPart.Resize(newSize);
2935 obPart.UpdateOffSet(currentpos); 3734 obPart.UpdateOffSet(currentpos);
2936
2937 obPart.IgnoreUndoUpdate = false;
2938 } 3735 }
2939 3736
2940// obPart.IgnoreUndoUpdate = false; 3737 HasGroupChanged = true;
2941// obPart.StoreUndoState(); 3738 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3739 ScheduleGroupForTerseUpdate();
2942 } 3740 }
2943
2944// m_log.DebugFormat(
2945// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2946 } 3741 }
2947 3742
2948 #endregion 3743 #endregion
@@ -2955,14 +3750,6 @@ namespace OpenSim.Region.Framework.Scenes
2955 /// <param name="pos"></param> 3750 /// <param name="pos"></param>
2956 public void UpdateGroupPosition(Vector3 pos) 3751 public void UpdateGroupPosition(Vector3 pos)
2957 { 3752 {
2958// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2959
2960 RootPart.StoreUndoState(true);
2961
2962// SceneObjectPart[] parts = m_parts.GetArray();
2963// for (int i = 0; i < parts.Length; i++)
2964// parts[i].StoreUndoState();
2965
2966 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3753 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2967 { 3754 {
2968 if (IsAttachment) 3755 if (IsAttachment)
@@ -2995,21 +3782,17 @@ namespace OpenSim.Region.Framework.Scenes
2995 /// </summary> 3782 /// </summary>
2996 /// <param name="pos"></param> 3783 /// <param name="pos"></param>
2997 /// <param name="localID"></param> 3784 /// <param name="localID"></param>
3785 ///
3786
2998 public void UpdateSinglePosition(Vector3 pos, uint localID) 3787 public void UpdateSinglePosition(Vector3 pos, uint localID)
2999 { 3788 {
3000 SceneObjectPart part = GetPart(localID); 3789 SceneObjectPart part = GetPart(localID);
3001 3790
3002// SceneObjectPart[] parts = m_parts.GetArray();
3003// for (int i = 0; i < parts.Length; i++)
3004// parts[i].StoreUndoState();
3005
3006 if (part != null) 3791 if (part != null)
3007 { 3792 {
3008// m_log.DebugFormat( 3793// unlock parts position change
3009// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3794 if (m_rootPart.PhysActor != null)
3010 3795 m_rootPart.PhysActor.Building = true;
3011 part.StoreUndoState(false);
3012 part.IgnoreUndoUpdate = true;
3013 3796
3014 if (part.UUID == m_rootPart.UUID) 3797 if (part.UUID == m_rootPart.UUID)
3015 { 3798 {
@@ -3020,8 +3803,10 @@ namespace OpenSim.Region.Framework.Scenes
3020 part.UpdateOffSet(pos); 3803 part.UpdateOffSet(pos);
3021 } 3804 }
3022 3805
3806 if (m_rootPart.PhysActor != null)
3807 m_rootPart.PhysActor.Building = false;
3808
3023 HasGroupChanged = true; 3809 HasGroupChanged = true;
3024 part.IgnoreUndoUpdate = false;
3025 } 3810 }
3026 } 3811 }
3027 3812
@@ -3031,13 +3816,7 @@ namespace OpenSim.Region.Framework.Scenes
3031 /// <param name="newPos"></param> 3816 /// <param name="newPos"></param>
3032 public void UpdateRootPosition(Vector3 newPos) 3817 public void UpdateRootPosition(Vector3 newPos)
3033 { 3818 {
3034// m_log.DebugFormat( 3819 // needs to be called with phys building true
3035// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3036
3037// SceneObjectPart[] parts = m_parts.GetArray();
3038// for (int i = 0; i < parts.Length; i++)
3039// parts[i].StoreUndoState();
3040
3041 Vector3 oldPos; 3820 Vector3 oldPos;
3042 3821
3043 // FIXME: This improves the situation where editing just the root prim of an attached object would send 3822 // FIXME: This improves the situation where editing just the root prim of an attached object would send
@@ -3063,7 +3842,14 @@ namespace OpenSim.Region.Framework.Scenes
3063 AbsolutePosition = newPos; 3842 AbsolutePosition = newPos;
3064 3843
3065 HasGroupChanged = true; 3844 HasGroupChanged = true;
3066 ScheduleGroupForTerseUpdate(); 3845 if (m_rootPart.Undoing)
3846 {
3847 ScheduleGroupForFullUpdate();
3848 }
3849 else
3850 {
3851 ScheduleGroupForTerseUpdate();
3852 }
3067 } 3853 }
3068 3854
3069 #endregion 3855 #endregion
@@ -3076,24 +3862,16 @@ namespace OpenSim.Region.Framework.Scenes
3076 /// <param name="rot"></param> 3862 /// <param name="rot"></param>
3077 public void UpdateGroupRotationR(Quaternion rot) 3863 public void UpdateGroupRotationR(Quaternion rot)
3078 { 3864 {
3079// m_log.DebugFormat(
3080// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3081
3082// SceneObjectPart[] parts = m_parts.GetArray();
3083// for (int i = 0; i < parts.Length; i++)
3084// parts[i].StoreUndoState();
3085
3086 m_rootPart.StoreUndoState(true);
3087
3088 m_rootPart.UpdateRotation(rot); 3865 m_rootPart.UpdateRotation(rot);
3089 3866
3867/* this is done by rootpart RotationOffset set called by UpdateRotation
3090 PhysicsActor actor = m_rootPart.PhysActor; 3868 PhysicsActor actor = m_rootPart.PhysActor;
3091 if (actor != null) 3869 if (actor != null)
3092 { 3870 {
3093 actor.Orientation = m_rootPart.RotationOffset; 3871 actor.Orientation = m_rootPart.RotationOffset;
3094 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3872 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3095 } 3873 }
3096 3874*/
3097 HasGroupChanged = true; 3875 HasGroupChanged = true;
3098 ScheduleGroupForTerseUpdate(); 3876 ScheduleGroupForTerseUpdate();
3099 } 3877 }
@@ -3105,16 +3883,6 @@ namespace OpenSim.Region.Framework.Scenes
3105 /// <param name="rot"></param> 3883 /// <param name="rot"></param>
3106 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3884 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3107 { 3885 {
3108// m_log.DebugFormat(
3109// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3110
3111// SceneObjectPart[] parts = m_parts.GetArray();
3112// for (int i = 0; i < parts.Length; i++)
3113// parts[i].StoreUndoState();
3114
3115 RootPart.StoreUndoState(true);
3116 RootPart.IgnoreUndoUpdate = true;
3117
3118 m_rootPart.UpdateRotation(rot); 3886 m_rootPart.UpdateRotation(rot);
3119 3887
3120 PhysicsActor actor = m_rootPart.PhysActor; 3888 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3133,8 +3901,6 @@ namespace OpenSim.Region.Framework.Scenes
3133 3901
3134 HasGroupChanged = true; 3902 HasGroupChanged = true;
3135 ScheduleGroupForTerseUpdate(); 3903 ScheduleGroupForTerseUpdate();
3136
3137 RootPart.IgnoreUndoUpdate = false;
3138 } 3904 }
3139 3905
3140 /// <summary> 3906 /// <summary>
@@ -3147,13 +3913,11 @@ namespace OpenSim.Region.Framework.Scenes
3147 SceneObjectPart part = GetPart(localID); 3913 SceneObjectPart part = GetPart(localID);
3148 3914
3149 SceneObjectPart[] parts = m_parts.GetArray(); 3915 SceneObjectPart[] parts = m_parts.GetArray();
3150 for (int i = 0; i < parts.Length; i++)
3151 parts[i].StoreUndoState();
3152 3916
3153 if (part != null) 3917 if (part != null)
3154 { 3918 {
3155// m_log.DebugFormat( 3919 if (m_rootPart.PhysActor != null)
3156// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3920 m_rootPart.PhysActor.Building = true;
3157 3921
3158 if (part.UUID == m_rootPart.UUID) 3922 if (part.UUID == m_rootPart.UUID)
3159 { 3923 {
@@ -3163,6 +3927,9 @@ namespace OpenSim.Region.Framework.Scenes
3163 { 3927 {
3164 part.UpdateRotation(rot); 3928 part.UpdateRotation(rot);
3165 } 3929 }
3930
3931 if (m_rootPart.PhysActor != null)
3932 m_rootPart.PhysActor.Building = false;
3166 } 3933 }
3167 } 3934 }
3168 3935
@@ -3176,12 +3943,8 @@ namespace OpenSim.Region.Framework.Scenes
3176 SceneObjectPart part = GetPart(localID); 3943 SceneObjectPart part = GetPart(localID);
3177 if (part != null) 3944 if (part != null)
3178 { 3945 {
3179// m_log.DebugFormat( 3946 if (m_rootPart.PhysActor != null)
3180// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3947 m_rootPart.PhysActor.Building = true;
3181// part.Name, part.LocalId, rot);
3182
3183 part.StoreUndoState();
3184 part.IgnoreUndoUpdate = true;
3185 3948
3186 if (part.UUID == m_rootPart.UUID) 3949 if (part.UUID == m_rootPart.UUID)
3187 { 3950 {
@@ -3194,7 +3957,8 @@ namespace OpenSim.Region.Framework.Scenes
3194 part.OffsetPosition = pos; 3957 part.OffsetPosition = pos;
3195 } 3958 }
3196 3959
3197 part.IgnoreUndoUpdate = false; 3960 if (m_rootPart.PhysActor != null)
3961 m_rootPart.PhysActor.Building = false;
3198 } 3962 }
3199 } 3963 }
3200 3964
@@ -3204,15 +3968,12 @@ namespace OpenSim.Region.Framework.Scenes
3204 /// <param name="rot"></param> 3968 /// <param name="rot"></param>
3205 public void UpdateRootRotation(Quaternion rot) 3969 public void UpdateRootRotation(Quaternion rot)
3206 { 3970 {
3207// m_log.DebugFormat( 3971 // needs to be called with phys building true
3208// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3209// Name, LocalId, rot);
3210
3211 Quaternion axRot = rot; 3972 Quaternion axRot = rot;
3212 Quaternion oldParentRot = m_rootPart.RotationOffset; 3973 Quaternion oldParentRot = m_rootPart.RotationOffset;
3213 3974
3214 m_rootPart.StoreUndoState(); 3975 //Don't use UpdateRotation because it schedules an update prematurely
3215 m_rootPart.UpdateRotation(rot); 3976 m_rootPart.RotationOffset = rot;
3216 3977
3217 PhysicsActor pa = m_rootPart.PhysActor; 3978 PhysicsActor pa = m_rootPart.PhysActor;
3218 3979
@@ -3228,35 +3989,145 @@ namespace OpenSim.Region.Framework.Scenes
3228 SceneObjectPart prim = parts[i]; 3989 SceneObjectPart prim = parts[i];
3229 if (prim.UUID != m_rootPart.UUID) 3990 if (prim.UUID != m_rootPart.UUID)
3230 { 3991 {
3231 prim.IgnoreUndoUpdate = true; 3992 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3993 NewRot = Quaternion.Inverse(axRot) * NewRot;
3994 prim.RotationOffset = NewRot;
3995
3232 Vector3 axPos = prim.OffsetPosition; 3996 Vector3 axPos = prim.OffsetPosition;
3997
3233 axPos *= oldParentRot; 3998 axPos *= oldParentRot;
3234 axPos *= Quaternion.Inverse(axRot); 3999 axPos *= Quaternion.Inverse(axRot);
3235 prim.OffsetPosition = axPos; 4000 prim.OffsetPosition = axPos;
3236 Quaternion primsRot = prim.RotationOffset; 4001 }
3237 Quaternion newRot = oldParentRot * primsRot; 4002 }
3238 newRot = Quaternion.Inverse(axRot) * newRot;
3239 prim.RotationOffset = newRot;
3240 prim.ScheduleTerseUpdate();
3241 prim.IgnoreUndoUpdate = false;
3242 }
3243 }
3244
3245// for (int i = 0; i < parts.Length; i++)
3246// {
3247// SceneObjectPart childpart = parts[i];
3248// if (childpart != m_rootPart)
3249// {
3250//// childpart.IgnoreUndoUpdate = false;
3251//// childpart.StoreUndoState();
3252// }
3253// }
3254 4003
3255 m_rootPart.ScheduleTerseUpdate(); 4004 HasGroupChanged = true;
4005 ScheduleGroupForFullUpdate();
4006 }
3256 4007
3257// m_log.DebugFormat( 4008 private enum updatetype :int
3258// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4009 {
3259// Name, LocalId, rot); 4010 none = 0,
4011 partterse = 1,
4012 partfull = 2,
4013 groupterse = 3,
4014 groupfull = 4
4015 }
4016
4017 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4018 {
4019 // TODO this still as excessive *.Schedule*Update()s
4020
4021 if (part != null && part.ParentGroup != null)
4022 {
4023 ObjectChangeType change = data.change;
4024 bool togroup = ((change & ObjectChangeType.Group) != 0);
4025 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4026
4027 SceneObjectGroup group = part.ParentGroup;
4028 PhysicsActor pha = group.RootPart.PhysActor;
4029
4030 updatetype updateType = updatetype.none;
4031
4032 if (togroup)
4033 {
4034 // related to group
4035 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4036 {
4037 if ((change & ObjectChangeType.Rotation) != 0)
4038 {
4039 group.RootPart.UpdateRotation(data.rotation);
4040 updateType = updatetype.none;
4041 }
4042 if ((change & ObjectChangeType.Position) != 0)
4043 {
4044 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4045 UpdateGroupPosition(data.position);
4046 updateType = updatetype.groupterse;
4047 }
4048 else
4049 // ugly rotation update of all parts
4050 {
4051 group.ResetChildPrimPhysicsPositions();
4052 }
4053
4054 }
4055 if ((change & ObjectChangeType.Scale) != 0)
4056 {
4057 if (pha != null)
4058 pha.Building = true;
4059
4060 group.GroupResize(data.scale);
4061 updateType = updatetype.none;
4062
4063 if (pha != null)
4064 pha.Building = false;
4065 }
4066 }
4067 else
4068 {
4069 // related to single prim in a link-set ( ie group)
4070 if (pha != null)
4071 pha.Building = true;
4072
4073 // root part is special
4074 // parts offset positions or rotations need to change also
4075
4076 if (part == group.RootPart)
4077 {
4078 if ((change & ObjectChangeType.Rotation) != 0)
4079 group.UpdateRootRotation(data.rotation);
4080 if ((change & ObjectChangeType.Position) != 0)
4081 group.UpdateRootPosition(data.position);
4082 if ((change & ObjectChangeType.Scale) != 0)
4083 part.Resize(data.scale);
4084 }
4085 else
4086 {
4087 if ((change & ObjectChangeType.Position) != 0)
4088 {
4089 part.OffsetPosition = data.position;
4090 updateType = updatetype.partterse;
4091 }
4092 if ((change & ObjectChangeType.Rotation) != 0)
4093 {
4094 part.UpdateRotation(data.rotation);
4095 updateType = updatetype.none;
4096 }
4097 if ((change & ObjectChangeType.Scale) != 0)
4098 {
4099 part.Resize(data.scale);
4100 updateType = updatetype.none;
4101 }
4102 }
4103
4104 if (pha != null)
4105 pha.Building = false;
4106 }
4107
4108 if (updateType != updatetype.none)
4109 {
4110 group.HasGroupChanged = true;
4111
4112 switch (updateType)
4113 {
4114 case updatetype.partterse:
4115 part.ScheduleTerseUpdate();
4116 break;
4117 case updatetype.partfull:
4118 part.ScheduleFullUpdate();
4119 break;
4120 case updatetype.groupterse:
4121 group.ScheduleGroupForTerseUpdate();
4122 break;
4123 case updatetype.groupfull:
4124 group.ScheduleGroupForFullUpdate();
4125 break;
4126 default:
4127 break;
4128 }
4129 }
4130 }
3260 } 4131 }
3261 4132
3262 #endregion 4133 #endregion
@@ -3297,6 +4168,8 @@ namespace OpenSim.Region.Framework.Scenes
3297 waypoint.handle = handle; 4168 waypoint.handle = handle;
3298 lock (m_rotTargets) 4169 lock (m_rotTargets)
3299 { 4170 {
4171 if (m_rotTargets.Count >= 8)
4172 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3300 m_rotTargets.Add(handle, waypoint); 4173 m_rotTargets.Add(handle, waypoint);
3301 } 4174 }
3302 m_scene.AddGroupTarget(this); 4175 m_scene.AddGroupTarget(this);
@@ -3322,6 +4195,8 @@ namespace OpenSim.Region.Framework.Scenes
3322 waypoint.handle = handle; 4195 waypoint.handle = handle;
3323 lock (m_targets) 4196 lock (m_targets)
3324 { 4197 {
4198 if (m_targets.Count >= 8)
4199 m_targets.Remove(m_targets.ElementAt(0).Key);
3325 m_targets.Add(handle, waypoint); 4200 m_targets.Add(handle, waypoint);
3326 } 4201 }
3327 m_scene.AddGroupTarget(this); 4202 m_scene.AddGroupTarget(this);
@@ -3355,10 +4230,11 @@ namespace OpenSim.Region.Framework.Scenes
3355 scriptPosTarget target = m_targets[idx]; 4230 scriptPosTarget target = m_targets[idx];
3356 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4231 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3357 { 4232 {
4233 at_target = true;
4234
3358 // trigger at_target 4235 // trigger at_target
3359 if (m_scriptListens_atTarget) 4236 if (m_scriptListens_atTarget)
3360 { 4237 {
3361 at_target = true;
3362 scriptPosTarget att = new scriptPosTarget(); 4238 scriptPosTarget att = new scriptPosTarget();
3363 att.targetPos = target.targetPos; 4239 att.targetPos = target.targetPos;
3364 att.tolerance = target.tolerance; 4240 att.tolerance = target.tolerance;
@@ -3476,11 +4352,50 @@ namespace OpenSim.Region.Framework.Scenes
3476 } 4352 }
3477 } 4353 }
3478 } 4354 }
3479 4355
4356 public Vector3 GetGeometricCenter()
4357 {
4358 // this is not real geometric center but a average of positions relative to root prim acording to
4359 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4360 // ignoring tortured prims details since sl also seems to ignore
4361 // so no real use in doing it on physics
4362
4363 Vector3 gc = Vector3.Zero;
4364
4365 int nparts = m_parts.Count;
4366 if (nparts <= 1)
4367 return gc;
4368
4369 SceneObjectPart[] parts = m_parts.GetArray();
4370 nparts = parts.Length; // just in case it changed
4371 if (nparts <= 1)
4372 return gc;
4373
4374 Quaternion parentRot = RootPart.RotationOffset;
4375 Vector3 pPos;
4376
4377 // average all parts positions
4378 for (int i = 0; i < nparts; i++)
4379 {
4380 // do it directly
4381 // gc += parts[i].GetWorldPosition();
4382 if (parts[i] != RootPart)
4383 {
4384 pPos = parts[i].OffsetPosition;
4385 gc += pPos;
4386 }
4387
4388 }
4389 gc /= nparts;
4390
4391 // relative to root:
4392// gc -= AbsolutePosition;
4393 return gc;
4394 }
4395
3480 public float GetMass() 4396 public float GetMass()
3481 { 4397 {
3482 float retmass = 0f; 4398 float retmass = 0f;
3483
3484 SceneObjectPart[] parts = m_parts.GetArray(); 4399 SceneObjectPart[] parts = m_parts.GetArray();
3485 for (int i = 0; i < parts.Length; i++) 4400 for (int i = 0; i < parts.Length; i++)
3486 retmass += parts[i].GetMass(); 4401 retmass += parts[i].GetMass();
@@ -3488,6 +4403,39 @@ namespace OpenSim.Region.Framework.Scenes
3488 return retmass; 4403 return retmass;
3489 } 4404 }
3490 4405
4406 // center of mass of full object
4407 public Vector3 GetCenterOfMass()
4408 {
4409 PhysicsActor pa = RootPart.PhysActor;
4410
4411 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4412 {
4413 // physics knows better about center of mass of physical prims
4414 Vector3 tmp = pa.CenterOfMass;
4415 return tmp;
4416 }
4417
4418 Vector3 Ptot = Vector3.Zero;
4419 float totmass = 0f;
4420 float m;
4421
4422 SceneObjectPart[] parts = m_parts.GetArray();
4423 for (int i = 0; i < parts.Length; i++)
4424 {
4425 m = parts[i].GetMass();
4426 Ptot += parts[i].GetPartCenterOfMass() * m;
4427 totmass += m;
4428 }
4429
4430 if (totmass == 0)
4431 totmass = 0;
4432 else
4433 totmass = 1 / totmass;
4434 Ptot *= totmass;
4435
4436 return Ptot;
4437 }
4438
3491 /// <summary> 4439 /// <summary>
3492 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4440 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3493 /// the physics engine can use it. 4441 /// the physics engine can use it.
@@ -3667,6 +4615,14 @@ namespace OpenSim.Region.Framework.Scenes
3667 FromItemID = uuid; 4615 FromItemID = uuid;
3668 } 4616 }
3669 4617
4618 public void ResetOwnerChangeFlag()
4619 {
4620 ForEachPart(delegate(SceneObjectPart part)
4621 {
4622 part.ResetOwnerChangeFlag();
4623 });
4624 }
4625
3670 #endregion 4626 #endregion
3671 } 4627 }
3672} 4628}