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.cs1422
1 files changed, 1188 insertions, 234 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 4b4e4ba..6deb870 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,169 @@ 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
1671 avatar.RemoveAttachment(this);
1672
1673 Vector3 detachedpos = new Vector3(127f,127f,127f);
1674 if (avatar == null)
1675 return;
1676
1677 detachedpos = avatar.AbsolutePosition;
1678 FromItemID = UUID.Zero;
1679
1680 AbsolutePosition = detachedpos;
1681 AttachedAvatar = UUID.Zero;
1682
1683 //SceneObjectPart[] parts = m_parts.GetArray();
1684 //for (int i = 0; i < parts.Length; i++)
1685 // parts[i].AttachedAvatar = UUID.Zero;
1686
1687 m_rootPart.SetParentLocalId(0);
1688 AttachmentPoint = (byte)0;
1689 // must check if buildind should be true or false here
1690 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1691 HasGroupChanged = true;
1692 RootPart.Rezzed = DateTime.Now;
1693 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1694 AttachToBackup();
1695 m_scene.EventManager.TriggerParcelPrimCountTainted();
1696 m_rootPart.ScheduleFullUpdate();
1697 m_rootPart.ClearUndoState();
1698 }
1699
1700 public void DetachToInventoryPrep()
1701 {
1702 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1703 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1704 if (avatar != null)
1705 {
1706 //detachedpos = avatar.AbsolutePosition;
1707 avatar.RemoveAttachment(this);
1708 }
1709
1710 AttachedAvatar = UUID.Zero;
1711
1712 /*SceneObjectPart[] parts = m_parts.GetArray();
1713 for (int i = 0; i < parts.Length; i++)
1714 parts[i].AttachedAvatar = UUID.Zero;*/
1715
1716 m_rootPart.SetParentLocalId(0);
1717 //m_rootPart.SetAttachmentPoint((byte)0);
1718 IsAttachment = false;
1719 AbsolutePosition = m_rootPart.AttachedPos;
1720 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1721 //AttachToBackup();
1722 //m_rootPart.ScheduleFullUpdate();
1723 }
1724
1725 /// <summary>
1100 /// 1726 ///
1101 /// </summary> 1727 /// </summary>
1102 /// <param name="part"></param> 1728 /// <param name="part"></param>
@@ -1136,7 +1762,10 @@ namespace OpenSim.Region.Framework.Scenes
1136 public void AddPart(SceneObjectPart part) 1762 public void AddPart(SceneObjectPart part)
1137 { 1763 {
1138 part.SetParent(this); 1764 part.SetParent(this);
1139 part.LinkNum = m_parts.Add(part.UUID, part); 1765 m_parts.Add(part.UUID, part);
1766
1767 part.LinkNum = m_parts.Count;
1768
1140 if (part.LinkNum == 2) 1769 if (part.LinkNum == 2)
1141 RootPart.LinkNum = 1; 1770 RootPart.LinkNum = 1;
1142 } 1771 }
@@ -1162,6 +1791,14 @@ namespace OpenSim.Region.Framework.Scenes
1162 parts[i].UUID = UUID.Random(); 1791 parts[i].UUID = UUID.Random();
1163 } 1792 }
1164 1793
1794 // helper provided for parts.
1795 public int GetSceneMaxUndo()
1796 {
1797 if (m_scene != null)
1798 return m_scene.MaxUndoCount;
1799 return 5;
1800 }
1801
1165 // justincc: I don't believe this hack is needed any longer, especially since the physics 1802 // 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 1803 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1167 // this method was preventing proper reload of scene objects. 1804 // this method was preventing proper reload of scene objects.
@@ -1219,7 +1856,7 @@ namespace OpenSim.Region.Framework.Scenes
1219// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1856// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1220// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1857// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1221 1858
1222 part.StoreUndoState(); 1859// part.StoreUndoState();
1223 part.OnGrab(offsetPos, remoteClient); 1860 part.OnGrab(offsetPos, remoteClient);
1224 } 1861 }
1225 1862
@@ -1239,6 +1876,11 @@ namespace OpenSim.Region.Framework.Scenes
1239 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1876 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1240 public void DeleteGroupFromScene(bool silent) 1877 public void DeleteGroupFromScene(bool silent)
1241 { 1878 {
1879 // We need to keep track of this state in case this group is still queued for backup.
1880 IsDeleted = true;
1881
1882 DetachFromBackup();
1883
1242 SceneObjectPart[] parts = m_parts.GetArray(); 1884 SceneObjectPart[] parts = m_parts.GetArray();
1243 for (int i = 0; i < parts.Length; i++) 1885 for (int i = 0; i < parts.Length; i++)
1244 { 1886 {
@@ -1262,6 +1904,7 @@ namespace OpenSim.Region.Framework.Scenes
1262 } 1904 }
1263 }); 1905 });
1264 } 1906 }
1907
1265 } 1908 }
1266 1909
1267 public void AddScriptLPS(int count) 1910 public void AddScriptLPS(int count)
@@ -1331,28 +1974,43 @@ namespace OpenSim.Region.Framework.Scenes
1331 /// </summary> 1974 /// </summary>
1332 public void ApplyPhysics() 1975 public void ApplyPhysics()
1333 { 1976 {
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(); 1977 SceneObjectPart[] parts = m_parts.GetArray();
1339 if (parts.Length > 1) 1978 if (parts.Length > 1)
1340 { 1979 {
1980 ResetChildPrimPhysicsPositions();
1981
1982 // Apply physics to the root prim
1983 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1984
1985
1341 for (int i = 0; i < parts.Length; i++) 1986 for (int i = 0; i < parts.Length; i++)
1342 { 1987 {
1343 SceneObjectPart part = parts[i]; 1988 SceneObjectPart part = parts[i];
1344 if (part.LocalId != m_rootPart.LocalId) 1989 if (part.LocalId != m_rootPart.LocalId)
1345 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1990 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1346 } 1991 }
1347
1348 // Hack to get the physics scene geometries in the right spot 1992 // Hack to get the physics scene geometries in the right spot
1349 ResetChildPrimPhysicsPositions(); 1993// ResetChildPrimPhysicsPositions();
1994 if (m_rootPart.PhysActor != null)
1995 {
1996 m_rootPart.PhysActor.Building = false;
1997 }
1998 }
1999 else
2000 {
2001 // Apply physics to the root prim
2002 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1350 } 2003 }
1351 } 2004 }
1352 2005
1353 public void SetOwnerId(UUID userId) 2006 public void SetOwnerId(UUID userId)
1354 { 2007 {
1355 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2008 ForEachPart(delegate(SceneObjectPart part)
2009 {
2010
2011 part.OwnerID = userId;
2012
2013 });
1356 } 2014 }
1357 2015
1358 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2016 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1384,11 +2042,17 @@ namespace OpenSim.Region.Framework.Scenes
1384 return; 2042 return;
1385 } 2043 }
1386 2044
2045 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2046 return;
2047
1387 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2048 // 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. 2049 // any exception propogate upwards.
1389 try 2050 try
1390 { 2051 {
1391 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2052 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2053 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2054 m_scene.LoadingPrims) // Land may not be valid yet
2055
1392 { 2056 {
1393 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2057 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1394 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2058 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1415,6 +2079,7 @@ namespace OpenSim.Region.Framework.Scenes
1415 } 2079 }
1416 } 2080 }
1417 } 2081 }
2082
1418 } 2083 }
1419 2084
1420 if (m_scene.UseBackup && HasGroupChanged) 2085 if (m_scene.UseBackup && HasGroupChanged)
@@ -1422,10 +2087,30 @@ namespace OpenSim.Region.Framework.Scenes
1422 // don't backup while it's selected or you're asking for changes mid stream. 2087 // don't backup while it's selected or you're asking for changes mid stream.
1423 if (isTimeToPersist() || forcedBackup) 2088 if (isTimeToPersist() || forcedBackup)
1424 { 2089 {
2090 if (m_rootPart.PhysActor != null &&
2091 (!m_rootPart.PhysActor.IsPhysical))
2092 {
2093 // Possible ghost prim
2094 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2095 {
2096 foreach (SceneObjectPart part in m_parts.GetArray())
2097 {
2098 // Re-set physics actor positions and
2099 // orientations
2100 part.GroupPosition = m_rootPart.GroupPosition;
2101 }
2102 }
2103 }
1425// m_log.DebugFormat( 2104// m_log.DebugFormat(
1426// "[SCENE]: Storing {0}, {1} in {2}", 2105// "[SCENE]: Storing {0}, {1} in {2}",
1427// Name, UUID, m_scene.RegionInfo.RegionName); 2106// Name, UUID, m_scene.RegionInfo.RegionName);
1428 2107
2108 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2109 {
2110 RootPart.Shape.State = 0;
2111 ScheduleGroupForFullUpdate();
2112 }
2113
1429 SceneObjectGroup backup_group = Copy(false); 2114 SceneObjectGroup backup_group = Copy(false);
1430 backup_group.RootPart.Velocity = RootPart.Velocity; 2115 backup_group.RootPart.Velocity = RootPart.Velocity;
1431 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2116 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1435,6 +2120,16 @@ namespace OpenSim.Region.Framework.Scenes
1435 HasGroupChangedDueToDelink = false; 2120 HasGroupChangedDueToDelink = false;
1436 2121
1437 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2122 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2123/*
2124 backup_group.ForEachPart(delegate(SceneObjectPart part)
2125 {
2126 if (part.KeyframeMotion != null)
2127 {
2128 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2129// part.KeyframeMotion.UpdateSceneObject(this);
2130 }
2131 });
2132*/
1438 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2133 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1439 2134
1440 backup_group.ForEachPart(delegate(SceneObjectPart part) 2135 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1491,10 +2186,14 @@ namespace OpenSim.Region.Framework.Scenes
1491 /// <returns></returns> 2186 /// <returns></returns>
1492 public SceneObjectGroup Copy(bool userExposed) 2187 public SceneObjectGroup Copy(bool userExposed)
1493 { 2188 {
2189 m_dupeInProgress = true;
1494 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2190 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1495 dupe.m_isBackedUp = false; 2191 dupe.m_isBackedUp = false;
1496 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2192 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1497 2193
2194 // new group as no sitting avatars
2195 dupe.m_linkedAvatars = new List<ScenePresence>();
2196
1498 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2197 // 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! 2198 // 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! 2199 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1505,7 +2204,7 @@ namespace OpenSim.Region.Framework.Scenes
1505 // This is only necessary when userExposed is false! 2204 // This is only necessary when userExposed is false!
1506 2205
1507 bool previousAttachmentStatus = dupe.IsAttachment; 2206 bool previousAttachmentStatus = dupe.IsAttachment;
1508 2207
1509 if (!userExposed) 2208 if (!userExposed)
1510 dupe.IsAttachment = true; 2209 dupe.IsAttachment = true;
1511 2210
@@ -1518,16 +2217,17 @@ namespace OpenSim.Region.Framework.Scenes
1518 2217
1519 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2218 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1520 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2219 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2220
1521 2221
1522 if (userExposed) 2222 if (userExposed)
1523 dupe.m_rootPart.TrimPermissions(); 2223 dupe.m_rootPart.TrimPermissions();
1524 2224
1525 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2225 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1526 2226
1527 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2227 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1528 { 2228 {
1529 return p1.LinkNum.CompareTo(p2.LinkNum); 2229 return p1.LinkNum.CompareTo(p2.LinkNum);
1530 } 2230 }
1531 ); 2231 );
1532 2232
1533 foreach (SceneObjectPart part in partList) 2233 foreach (SceneObjectPart part in partList)
@@ -1537,43 +2237,56 @@ namespace OpenSim.Region.Framework.Scenes
1537 { 2237 {
1538 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2238 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1539 newPart.LinkNum = part.LinkNum; 2239 newPart.LinkNum = part.LinkNum;
1540 } 2240 if (userExposed)
2241 newPart.ParentID = dupe.m_rootPart.LocalId;
2242 }
1541 else 2243 else
1542 { 2244 {
1543 newPart = dupe.m_rootPart; 2245 newPart = dupe.m_rootPart;
1544 } 2246 }
2247/*
2248 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2249 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1545 2250
1546 // Need to duplicate the physics actor as well 2251 // Need to duplicate the physics actor as well
1547 PhysicsActor originalPartPa = part.PhysActor; 2252 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1548 if (originalPartPa != null && userExposed)
1549 { 2253 {
1550 PrimitiveBaseShape pbs = newPart.Shape; 2254 PrimitiveBaseShape pbs = newPart.Shape;
1551
1552 newPart.PhysActor 2255 newPart.PhysActor
1553 = m_scene.PhysicsScene.AddPrimShape( 2256 = m_scene.PhysicsScene.AddPrimShape(
1554 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2257 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1555 pbs, 2258 pbs,
1556 newPart.AbsolutePosition, 2259 newPart.AbsolutePosition,
1557 newPart.Scale, 2260 newPart.Scale,
1558 newPart.RotationOffset, 2261 newPart.GetWorldRotation(),
1559 originalPartPa.IsPhysical, 2262 isphys,
2263 isphan,
1560 newPart.LocalId); 2264 newPart.LocalId);
1561 2265
1562 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2266 newPart.DoPhysicsPropertyUpdate(isphys, true);
1563 } 2267 */
2268 if (userExposed)
2269 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2270// }
2271 // copy keyframemotion
1564 if (part.KeyframeMotion != null) 2272 if (part.KeyframeMotion != null)
1565 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2273 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1566 } 2274 }
1567 2275
1568 if (userExposed) 2276 if (userExposed)
1569 { 2277 {
1570 dupe.UpdateParentIDs(); 2278// done above dupe.UpdateParentIDs();
2279
2280 if (dupe.m_rootPart.PhysActor != null)
2281 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2282
1571 dupe.HasGroupChanged = true; 2283 dupe.HasGroupChanged = true;
1572 dupe.AttachToBackup(); 2284 dupe.AttachToBackup();
1573 2285
1574 ScheduleGroupForFullUpdate(); 2286 ScheduleGroupForFullUpdate();
1575 } 2287 }
1576 2288
2289 m_dupeInProgress = false;
1577 return dupe; 2290 return dupe;
1578 } 2291 }
1579 2292
@@ -1585,7 +2298,14 @@ namespace OpenSim.Region.Framework.Scenes
1585 /// <param name="cGroupID"></param> 2298 /// <param name="cGroupID"></param>
1586 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2299 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1587 { 2300 {
1588 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2301 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2302 // give newpart a new local ID lettng old part keep same
2303 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2304 newpart.LocalId = m_scene.AllocateLocalId();
2305
2306 SetRootPart(newpart);
2307 if (userExposed)
2308 RootPart.Velocity = Vector3.Zero; // In case source is moving
1589 } 2309 }
1590 2310
1591 public void ScriptSetPhysicsStatus(bool usePhysics) 2311 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1643,27 +2363,14 @@ namespace OpenSim.Region.Framework.Scenes
1643 2363
1644 if (pa != null) 2364 if (pa != null)
1645 { 2365 {
1646 pa.AddForce(impulse, true); 2366 // false to be applied as a impulse
1647 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2367 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); 2368 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1662 } 2369 }
1663 } 2370 }
1664 } 2371 }
1665 2372
1666 public void setAngularImpulse(Vector3 impulse) 2373 public void ApplyAngularImpulse(Vector3 impulse)
1667 { 2374 {
1668 PhysicsActor pa = RootPart.PhysActor; 2375 PhysicsActor pa = RootPart.PhysActor;
1669 2376
@@ -1671,7 +2378,8 @@ namespace OpenSim.Region.Framework.Scenes
1671 { 2378 {
1672 if (!IsAttachment) 2379 if (!IsAttachment)
1673 { 2380 {
1674 pa.Torque = impulse; 2381 // false to be applied as a impulse
2382 pa.AddAngularForce(impulse, false);
1675 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2383 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1676 } 2384 }
1677 } 2385 }
@@ -1679,20 +2387,10 @@ namespace OpenSim.Region.Framework.Scenes
1679 2387
1680 public Vector3 GetTorque() 2388 public Vector3 GetTorque()
1681 { 2389 {
1682 PhysicsActor pa = RootPart.PhysActor; 2390 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 } 2391 }
1695 2392
2393 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1696 public void moveToTarget(Vector3 target, float tau) 2394 public void moveToTarget(Vector3 target, float tau)
1697 { 2395 {
1698 if (IsAttachment) 2396 if (IsAttachment)
@@ -1722,8 +2420,50 @@ namespace OpenSim.Region.Framework.Scenes
1722 2420
1723 if (pa != null) 2421 if (pa != null)
1724 pa.PIDActive = false; 2422 pa.PIDActive = false;
2423
2424 RootPart.ScheduleTerseUpdate(); // send a stop information
2425 }
2426
2427 public void rotLookAt(Quaternion target, float strength, float damping)
2428 {
2429 SceneObjectPart rootpart = m_rootPart;
2430 if (rootpart != null)
2431 {
2432 if (IsAttachment)
2433 {
2434 /*
2435 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2436 if (avatar != null)
2437 {
2438 Rotate the Av?
2439 } */
2440 }
2441 else
2442 {
2443 if (rootpart.PhysActor != null)
2444 { // APID must be implemented in your physics system for this to function.
2445 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2446 rootpart.PhysActor.APIDStrength = strength;
2447 rootpart.PhysActor.APIDDamping = damping;
2448 rootpart.PhysActor.APIDActive = true;
2449 }
2450 }
2451 }
1725 } 2452 }
2453
2454 public void stopLookAt()
2455 {
2456 SceneObjectPart rootpart = m_rootPart;
2457 if (rootpart != null)
2458 {
2459 if (rootpart.PhysActor != null)
2460 { // APID must be implemented in your physics system for this to function.
2461 rootpart.PhysActor.APIDActive = false;
2462 }
2463 }
1726 2464
2465 }
2466
1727 /// <summary> 2467 /// <summary>
1728 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2468 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1729 /// </summary> 2469 /// </summary>
@@ -1740,7 +2480,7 @@ namespace OpenSim.Region.Framework.Scenes
1740 { 2480 {
1741 pa.PIDHoverHeight = height; 2481 pa.PIDHoverHeight = height;
1742 pa.PIDHoverType = hoverType; 2482 pa.PIDHoverType = hoverType;
1743 pa.PIDTau = tau; 2483 pa.PIDHoverTau = tau;
1744 pa.PIDHoverActive = true; 2484 pa.PIDHoverActive = true;
1745 } 2485 }
1746 else 2486 else
@@ -1780,7 +2520,12 @@ namespace OpenSim.Region.Framework.Scenes
1780 /// <param name="cGroupID"></param> 2520 /// <param name="cGroupID"></param>
1781 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2521 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1782 { 2522 {
1783 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2523 // give new ID to the new part, letting old keep original
2524 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2525 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2526 newPart.LocalId = m_scene.AllocateLocalId();
2527 newPart.SetParent(this);
2528
1784 AddPart(newPart); 2529 AddPart(newPart);
1785 2530
1786 SetPartAsNonRoot(newPart); 2531 SetPartAsNonRoot(newPart);
@@ -1830,6 +2575,7 @@ namespace OpenSim.Region.Framework.Scenes
1830 2575
1831 #endregion 2576 #endregion
1832 2577
2578
1833 public override void Update() 2579 public override void Update()
1834 { 2580 {
1835 // Check that the group was not deleted before the scheduled update 2581 // Check that the group was not deleted before the scheduled update
@@ -1848,19 +2594,8 @@ namespace OpenSim.Region.Framework.Scenes
1848 // check to see if the physical position or rotation warrant an update. 2594 // check to see if the physical position or rotation warrant an update.
1849 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2595 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1850 { 2596 {
1851 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2597 // rootpart SendScheduledUpdates will check if a update is needed
1852 2598 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 } 2599 }
1865 2600
1866 SceneObjectPart[] parts = m_parts.GetArray(); 2601 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1919,11 +2654,11 @@ namespace OpenSim.Region.Framework.Scenes
1919 /// Immediately send a full update for this scene object. 2654 /// Immediately send a full update for this scene object.
1920 /// </summary> 2655 /// </summary>
1921 public void SendGroupFullUpdate() 2656 public void SendGroupFullUpdate()
1922 { 2657 {
1923 if (IsDeleted) 2658 if (IsDeleted)
1924 return; 2659 return;
1925 2660
1926// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2661// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1927 2662
1928 RootPart.SendFullUpdateToAllClients(); 2663 RootPart.SendFullUpdateToAllClients();
1929 2664
@@ -2079,6 +2814,11 @@ namespace OpenSim.Region.Framework.Scenes
2079 // 'linkPart' == the root of the group being linked into this group 2814 // 'linkPart' == the root of the group being linked into this group
2080 SceneObjectPart linkPart = objectGroup.m_rootPart; 2815 SceneObjectPart linkPart = objectGroup.m_rootPart;
2081 2816
2817 if (m_rootPart.PhysActor != null)
2818 m_rootPart.PhysActor.Building = true;
2819 if (linkPart.PhysActor != null)
2820 linkPart.PhysActor.Building = true;
2821
2082 // physics flags from group to be applied to linked parts 2822 // physics flags from group to be applied to linked parts
2083 bool grpusephys = UsesPhysics; 2823 bool grpusephys = UsesPhysics;
2084 bool grptemporary = IsTemporary; 2824 bool grptemporary = IsTemporary;
@@ -2104,12 +2844,12 @@ namespace OpenSim.Region.Framework.Scenes
2104 Vector3 axPos = linkPart.OffsetPosition; 2844 Vector3 axPos = linkPart.OffsetPosition;
2105 // Rotate the linking root SOP's position to be relative to the new root prim 2845 // Rotate the linking root SOP's position to be relative to the new root prim
2106 Quaternion parentRot = m_rootPart.RotationOffset; 2846 Quaternion parentRot = m_rootPart.RotationOffset;
2107 axPos *= Quaternion.Inverse(parentRot); 2847 axPos *= Quaternion.Conjugate(parentRot);
2108 linkPart.OffsetPosition = axPos; 2848 linkPart.OffsetPosition = axPos;
2109 2849
2110 // Make the linking root SOP's rotation relative to the new root prim 2850 // Make the linking root SOP's rotation relative to the new root prim
2111 Quaternion oldRot = linkPart.RotationOffset; 2851 Quaternion oldRot = linkPart.RotationOffset;
2112 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2852 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2113 linkPart.RotationOffset = newRot; 2853 linkPart.RotationOffset = newRot;
2114 2854
2115 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2855 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2143,7 +2883,7 @@ namespace OpenSim.Region.Framework.Scenes
2143 linkPart.CreateSelected = true; 2883 linkPart.CreateSelected = true;
2144 2884
2145 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2885 // 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); 2886 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2147 2887
2148 // If the added SOP is physical, also tell the physics engine about the link relationship. 2888 // 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) 2889 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2153,6 +2893,7 @@ namespace OpenSim.Region.Framework.Scenes
2153 } 2893 }
2154 2894
2155 linkPart.LinkNum = linkNum++; 2895 linkPart.LinkNum = linkNum++;
2896 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2156 2897
2157 // Get a list of the SOP's in the old group in order of their linknum's. 2898 // Get a list of the SOP's in the old group in order of their linknum's.
2158 SceneObjectPart[] ogParts = objectGroup.Parts; 2899 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2171,7 +2912,7 @@ namespace OpenSim.Region.Framework.Scenes
2171 2912
2172 // Update the physics flags for the newly added SOP 2913 // Update the physics flags for the newly added SOP
2173 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2914 // (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); 2915 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2175 2916
2176 // If the added SOP is physical, also tell the physics engine about the link relationship. 2917 // 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) 2918 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2189,7 +2930,7 @@ namespace OpenSim.Region.Framework.Scenes
2189 objectGroup.IsDeleted = true; 2930 objectGroup.IsDeleted = true;
2190 2931
2191 objectGroup.m_parts.Clear(); 2932 objectGroup.m_parts.Clear();
2192 2933
2193 // Can't do this yet since backup still makes use of the root part without any synchronization 2934 // Can't do this yet since backup still makes use of the root part without any synchronization
2194// objectGroup.m_rootPart = null; 2935// objectGroup.m_rootPart = null;
2195 2936
@@ -2203,6 +2944,9 @@ namespace OpenSim.Region.Framework.Scenes
2203 // unmoved prims! 2944 // unmoved prims!
2204 ResetChildPrimPhysicsPositions(); 2945 ResetChildPrimPhysicsPositions();
2205 2946
2947 if (m_rootPart.PhysActor != null)
2948 m_rootPart.PhysActor.Building = false;
2949
2206 //HasGroupChanged = true; 2950 //HasGroupChanged = true;
2207 //ScheduleGroupForFullUpdate(); 2951 //ScheduleGroupForFullUpdate();
2208 } 2952 }
@@ -2270,7 +3014,10 @@ namespace OpenSim.Region.Framework.Scenes
2270// m_log.DebugFormat( 3014// m_log.DebugFormat(
2271// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3015// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2272// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3016// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2273 3017
3018 if (m_rootPart.PhysActor != null)
3019 m_rootPart.PhysActor.Building = true;
3020
2274 linkPart.ClearUndoState(); 3021 linkPart.ClearUndoState();
2275 3022
2276 Vector3 worldPos = linkPart.GetWorldPosition(); 3023 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2341,6 +3088,14 @@ namespace OpenSim.Region.Framework.Scenes
2341 3088
2342 // When we delete a group, we currently have to force persist to the database if the object id has changed 3089 // 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) 3090 // (since delete works by deleting all rows which have a given object id)
3091
3092 // this is as it seems to be in sl now
3093 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3094 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3095
3096 if (m_rootPart.PhysActor != null)
3097 m_rootPart.PhysActor.Building = false;
3098
2344 objectGroup.HasGroupChangedDueToDelink = true; 3099 objectGroup.HasGroupChangedDueToDelink = true;
2345 3100
2346 return objectGroup; 3101 return objectGroup;
@@ -2352,6 +3107,8 @@ namespace OpenSim.Region.Framework.Scenes
2352 /// <param name="objectGroup"></param> 3107 /// <param name="objectGroup"></param>
2353 public virtual void DetachFromBackup() 3108 public virtual void DetachFromBackup()
2354 { 3109 {
3110 if (m_scene != null)
3111 m_scene.SceneGraph.FireDetachFromBackup(this);
2355 if (m_isBackedUp && Scene != null) 3112 if (m_isBackedUp && Scene != null)
2356 m_scene.EventManager.OnBackup -= ProcessBackup; 3113 m_scene.EventManager.OnBackup -= ProcessBackup;
2357 3114
@@ -2372,7 +3129,8 @@ namespace OpenSim.Region.Framework.Scenes
2372 Vector3 axPos = part.OffsetPosition; 3129 Vector3 axPos = part.OffsetPosition;
2373 axPos *= parentRot; 3130 axPos *= parentRot;
2374 part.OffsetPosition = axPos; 3131 part.OffsetPosition = axPos;
2375 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3132 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3133 part.GroupPosition = newPos;
2376 part.OffsetPosition = Vector3.Zero; 3134 part.OffsetPosition = Vector3.Zero;
2377 3135
2378 // Compution our rotation to be not relative to the old parent 3136 // Compution our rotation to be not relative to the old parent
@@ -2387,7 +3145,7 @@ namespace OpenSim.Region.Framework.Scenes
2387 part.LinkNum = linkNum; 3145 part.LinkNum = linkNum;
2388 3146
2389 // Compute the new position of this SOP relative to the group position 3147 // Compute the new position of this SOP relative to the group position
2390 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3148 part.OffsetPosition = newPos - AbsolutePosition;
2391 3149
2392 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3150 // (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 3151 // It would have the affect of setting the physics engine position multiple
@@ -2397,18 +3155,19 @@ namespace OpenSim.Region.Framework.Scenes
2397 // Rotate the relative position by the rotation of the group 3155 // Rotate the relative position by the rotation of the group
2398 Quaternion rootRotation = m_rootPart.RotationOffset; 3156 Quaternion rootRotation = m_rootPart.RotationOffset;
2399 Vector3 pos = part.OffsetPosition; 3157 Vector3 pos = part.OffsetPosition;
2400 pos *= Quaternion.Inverse(rootRotation); 3158 pos *= Quaternion.Conjugate(rootRotation);
2401 part.OffsetPosition = pos; 3159 part.OffsetPosition = pos;
2402 3160
2403 // Compute the SOP's rotation relative to the rotation of the group. 3161 // Compute the SOP's rotation relative to the rotation of the group.
2404 parentRot = m_rootPart.RotationOffset; 3162 parentRot = m_rootPart.RotationOffset;
2405 oldRot = part.RotationOffset; 3163 oldRot = part.RotationOffset;
2406 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3164 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2407 part.RotationOffset = newRot; 3165 part.RotationOffset = newRot;
2408 3166
2409 // Since this SOP's state has changed, push those changes into the physics engine 3167 // Since this SOP's state has changed, push those changes into the physics engine
2410 // and the simulator. 3168 // and the simulator.
2411 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3169 // done on caller
3170// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2412 } 3171 }
2413 3172
2414 /// <summary> 3173 /// <summary>
@@ -2430,10 +3189,14 @@ namespace OpenSim.Region.Framework.Scenes
2430 { 3189 {
2431 if (!m_rootPart.BlockGrab) 3190 if (!m_rootPart.BlockGrab)
2432 { 3191 {
2433 Vector3 llmoveforce = pos - AbsolutePosition; 3192/* Vector3 llmoveforce = pos - AbsolutePosition;
2434 Vector3 grabforce = llmoveforce; 3193 Vector3 grabforce = llmoveforce;
2435 grabforce = (grabforce / 10) * pa.Mass; 3194 grabforce = (grabforce / 10) * pa.Mass;
2436 pa.AddForce(grabforce, true); 3195 */
3196 // empirically convert distance diference to a impulse
3197 Vector3 grabforce = pos - AbsolutePosition;
3198 grabforce = grabforce * (pa.Mass/ 10.0f);
3199 pa.AddForce(grabforce, false);
2437 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3200 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2438 } 3201 }
2439 } 3202 }
@@ -2629,6 +3392,8 @@ namespace OpenSim.Region.Framework.Scenes
2629 /// <param name="SetVolumeDetect"></param> 3392 /// <param name="SetVolumeDetect"></param>
2630 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3393 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2631 { 3394 {
3395 HasGroupChanged = true;
3396
2632 SceneObjectPart selectionPart = GetPart(localID); 3397 SceneObjectPart selectionPart = GetPart(localID);
2633 3398
2634 if (SetTemporary && Scene != null) 3399 if (SetTemporary && Scene != null)
@@ -2659,8 +3424,22 @@ namespace OpenSim.Region.Framework.Scenes
2659 } 3424 }
2660 } 3425 }
2661 3426
2662 for (int i = 0; i < parts.Length; i++) 3427 if (parts.Length > 1)
2663 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3428 {
3429 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3430
3431 for (int i = 0; i < parts.Length; i++)
3432 {
3433
3434 if (parts[i].UUID != m_rootPart.UUID)
3435 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3436 }
3437
3438 if (m_rootPart.PhysActor != null)
3439 m_rootPart.PhysActor.Building = false;
3440 }
3441 else
3442 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2664 } 3443 }
2665 } 3444 }
2666 3445
@@ -2673,6 +3452,17 @@ namespace OpenSim.Region.Framework.Scenes
2673 } 3452 }
2674 } 3453 }
2675 3454
3455
3456
3457 /// <summary>
3458 /// Gets the number of parts
3459 /// </summary>
3460 /// <returns></returns>
3461 public int GetPartCount()
3462 {
3463 return Parts.Count();
3464 }
3465
2676 /// <summary> 3466 /// <summary>
2677 /// Update the texture entry for this part 3467 /// Update the texture entry for this part
2678 /// </summary> 3468 /// </summary>
@@ -2710,8 +3500,24 @@ namespace OpenSim.Region.Framework.Scenes
2710 { 3500 {
2711 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3501 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2712 3502
3503 bool god = Scene.Permissions.IsGod(AgentID);
3504
3505 if (field == 1 && god)
3506 {
3507 ForEachPart(part =>
3508 {
3509 part.BaseMask = RootPart.BaseMask;
3510 });
3511 }
3512
2713 AdjustChildPrimPermissions(); 3513 AdjustChildPrimPermissions();
2714 3514
3515 if (field == 1 && god) // Base mask was set. Update all child part inventories
3516 {
3517 foreach (SceneObjectPart part in Parts)
3518 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3519 }
3520
2715 HasGroupChanged = true; 3521 HasGroupChanged = true;
2716 3522
2717 // Send the group's properties to all clients once all parts are updated 3523 // Send the group's properties to all clients once all parts are updated
@@ -2757,8 +3563,6 @@ namespace OpenSim.Region.Framework.Scenes
2757 3563
2758 PhysicsActor pa = m_rootPart.PhysActor; 3564 PhysicsActor pa = m_rootPart.PhysActor;
2759 3565
2760 RootPart.StoreUndoState(true);
2761
2762 if (Scene != null) 3566 if (Scene != null)
2763 { 3567 {
2764 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3568 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2786,7 +3590,6 @@ namespace OpenSim.Region.Framework.Scenes
2786 SceneObjectPart obPart = parts[i]; 3590 SceneObjectPart obPart = parts[i];
2787 if (obPart.UUID != m_rootPart.UUID) 3591 if (obPart.UUID != m_rootPart.UUID)
2788 { 3592 {
2789// obPart.IgnoreUndoUpdate = true;
2790 Vector3 oldSize = new Vector3(obPart.Scale); 3593 Vector3 oldSize = new Vector3(obPart.Scale);
2791 3594
2792 float f = 1.0f; 3595 float f = 1.0f;
@@ -2898,8 +3701,6 @@ namespace OpenSim.Region.Framework.Scenes
2898 z *= a; 3701 z *= a;
2899 } 3702 }
2900 } 3703 }
2901
2902// obPart.IgnoreUndoUpdate = false;
2903 } 3704 }
2904 } 3705 }
2905 } 3706 }
@@ -2909,9 +3710,7 @@ namespace OpenSim.Region.Framework.Scenes
2909 prevScale.Y *= y; 3710 prevScale.Y *= y;
2910 prevScale.Z *= z; 3711 prevScale.Z *= z;
2911 3712
2912// RootPart.IgnoreUndoUpdate = true;
2913 RootPart.Resize(prevScale); 3713 RootPart.Resize(prevScale);
2914// RootPart.IgnoreUndoUpdate = false;
2915 3714
2916 for (int i = 0; i < parts.Length; i++) 3715 for (int i = 0; i < parts.Length; i++)
2917 { 3716 {
@@ -2919,8 +3718,6 @@ namespace OpenSim.Region.Framework.Scenes
2919 3718
2920 if (obPart.UUID != m_rootPart.UUID) 3719 if (obPart.UUID != m_rootPart.UUID)
2921 { 3720 {
2922 obPart.IgnoreUndoUpdate = true;
2923
2924 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3721 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2925 currentpos.X *= x; 3722 currentpos.X *= x;
2926 currentpos.Y *= y; 3723 currentpos.Y *= y;
@@ -2933,16 +3730,12 @@ namespace OpenSim.Region.Framework.Scenes
2933 3730
2934 obPart.Resize(newSize); 3731 obPart.Resize(newSize);
2935 obPart.UpdateOffSet(currentpos); 3732 obPart.UpdateOffSet(currentpos);
2936
2937 obPart.IgnoreUndoUpdate = false;
2938 } 3733 }
2939 3734
2940// obPart.IgnoreUndoUpdate = false; 3735 HasGroupChanged = true;
2941// obPart.StoreUndoState(); 3736 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3737 ScheduleGroupForTerseUpdate();
2942 } 3738 }
2943
2944// m_log.DebugFormat(
2945// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2946 } 3739 }
2947 3740
2948 #endregion 3741 #endregion
@@ -2955,14 +3748,6 @@ namespace OpenSim.Region.Framework.Scenes
2955 /// <param name="pos"></param> 3748 /// <param name="pos"></param>
2956 public void UpdateGroupPosition(Vector3 pos) 3749 public void UpdateGroupPosition(Vector3 pos)
2957 { 3750 {
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)) 3751 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2967 { 3752 {
2968 if (IsAttachment) 3753 if (IsAttachment)
@@ -2995,21 +3780,17 @@ namespace OpenSim.Region.Framework.Scenes
2995 /// </summary> 3780 /// </summary>
2996 /// <param name="pos"></param> 3781 /// <param name="pos"></param>
2997 /// <param name="localID"></param> 3782 /// <param name="localID"></param>
3783 ///
3784
2998 public void UpdateSinglePosition(Vector3 pos, uint localID) 3785 public void UpdateSinglePosition(Vector3 pos, uint localID)
2999 { 3786 {
3000 SceneObjectPart part = GetPart(localID); 3787 SceneObjectPart part = GetPart(localID);
3001 3788
3002// SceneObjectPart[] parts = m_parts.GetArray();
3003// for (int i = 0; i < parts.Length; i++)
3004// parts[i].StoreUndoState();
3005
3006 if (part != null) 3789 if (part != null)
3007 { 3790 {
3008// m_log.DebugFormat( 3791// unlock parts position change
3009// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3792 if (m_rootPart.PhysActor != null)
3010 3793 m_rootPart.PhysActor.Building = true;
3011 part.StoreUndoState(false);
3012 part.IgnoreUndoUpdate = true;
3013 3794
3014 if (part.UUID == m_rootPart.UUID) 3795 if (part.UUID == m_rootPart.UUID)
3015 { 3796 {
@@ -3020,8 +3801,10 @@ namespace OpenSim.Region.Framework.Scenes
3020 part.UpdateOffSet(pos); 3801 part.UpdateOffSet(pos);
3021 } 3802 }
3022 3803
3804 if (m_rootPart.PhysActor != null)
3805 m_rootPart.PhysActor.Building = false;
3806
3023 HasGroupChanged = true; 3807 HasGroupChanged = true;
3024 part.IgnoreUndoUpdate = false;
3025 } 3808 }
3026 } 3809 }
3027 3810
@@ -3031,13 +3814,7 @@ namespace OpenSim.Region.Framework.Scenes
3031 /// <param name="newPos"></param> 3814 /// <param name="newPos"></param>
3032 public void UpdateRootPosition(Vector3 newPos) 3815 public void UpdateRootPosition(Vector3 newPos)
3033 { 3816 {
3034// m_log.DebugFormat( 3817 // 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; 3818 Vector3 oldPos;
3042 3819
3043 // FIXME: This improves the situation where editing just the root prim of an attached object would send 3820 // FIXME: This improves the situation where editing just the root prim of an attached object would send
@@ -3063,7 +3840,14 @@ namespace OpenSim.Region.Framework.Scenes
3063 AbsolutePosition = newPos; 3840 AbsolutePosition = newPos;
3064 3841
3065 HasGroupChanged = true; 3842 HasGroupChanged = true;
3066 ScheduleGroupForTerseUpdate(); 3843 if (m_rootPart.Undoing)
3844 {
3845 ScheduleGroupForFullUpdate();
3846 }
3847 else
3848 {
3849 ScheduleGroupForTerseUpdate();
3850 }
3067 } 3851 }
3068 3852
3069 #endregion 3853 #endregion
@@ -3076,24 +3860,16 @@ namespace OpenSim.Region.Framework.Scenes
3076 /// <param name="rot"></param> 3860 /// <param name="rot"></param>
3077 public void UpdateGroupRotationR(Quaternion rot) 3861 public void UpdateGroupRotationR(Quaternion rot)
3078 { 3862 {
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); 3863 m_rootPart.UpdateRotation(rot);
3089 3864
3865/* this is done by rootpart RotationOffset set called by UpdateRotation
3090 PhysicsActor actor = m_rootPart.PhysActor; 3866 PhysicsActor actor = m_rootPart.PhysActor;
3091 if (actor != null) 3867 if (actor != null)
3092 { 3868 {
3093 actor.Orientation = m_rootPart.RotationOffset; 3869 actor.Orientation = m_rootPart.RotationOffset;
3094 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3870 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3095 } 3871 }
3096 3872*/
3097 HasGroupChanged = true; 3873 HasGroupChanged = true;
3098 ScheduleGroupForTerseUpdate(); 3874 ScheduleGroupForTerseUpdate();
3099 } 3875 }
@@ -3105,16 +3881,6 @@ namespace OpenSim.Region.Framework.Scenes
3105 /// <param name="rot"></param> 3881 /// <param name="rot"></param>
3106 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3882 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3107 { 3883 {
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); 3884 m_rootPart.UpdateRotation(rot);
3119 3885
3120 PhysicsActor actor = m_rootPart.PhysActor; 3886 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3133,8 +3899,6 @@ namespace OpenSim.Region.Framework.Scenes
3133 3899
3134 HasGroupChanged = true; 3900 HasGroupChanged = true;
3135 ScheduleGroupForTerseUpdate(); 3901 ScheduleGroupForTerseUpdate();
3136
3137 RootPart.IgnoreUndoUpdate = false;
3138 } 3902 }
3139 3903
3140 /// <summary> 3904 /// <summary>
@@ -3147,13 +3911,11 @@ namespace OpenSim.Region.Framework.Scenes
3147 SceneObjectPart part = GetPart(localID); 3911 SceneObjectPart part = GetPart(localID);
3148 3912
3149 SceneObjectPart[] parts = m_parts.GetArray(); 3913 SceneObjectPart[] parts = m_parts.GetArray();
3150 for (int i = 0; i < parts.Length; i++)
3151 parts[i].StoreUndoState();
3152 3914
3153 if (part != null) 3915 if (part != null)
3154 { 3916 {
3155// m_log.DebugFormat( 3917 if (m_rootPart.PhysActor != null)
3156// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3918 m_rootPart.PhysActor.Building = true;
3157 3919
3158 if (part.UUID == m_rootPart.UUID) 3920 if (part.UUID == m_rootPart.UUID)
3159 { 3921 {
@@ -3163,6 +3925,9 @@ namespace OpenSim.Region.Framework.Scenes
3163 { 3925 {
3164 part.UpdateRotation(rot); 3926 part.UpdateRotation(rot);
3165 } 3927 }
3928
3929 if (m_rootPart.PhysActor != null)
3930 m_rootPart.PhysActor.Building = false;
3166 } 3931 }
3167 } 3932 }
3168 3933
@@ -3176,12 +3941,8 @@ namespace OpenSim.Region.Framework.Scenes
3176 SceneObjectPart part = GetPart(localID); 3941 SceneObjectPart part = GetPart(localID);
3177 if (part != null) 3942 if (part != null)
3178 { 3943 {
3179// m_log.DebugFormat( 3944 if (m_rootPart.PhysActor != null)
3180// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3945 m_rootPart.PhysActor.Building = true;
3181// part.Name, part.LocalId, rot);
3182
3183 part.StoreUndoState();
3184 part.IgnoreUndoUpdate = true;
3185 3946
3186 if (part.UUID == m_rootPart.UUID) 3947 if (part.UUID == m_rootPart.UUID)
3187 { 3948 {
@@ -3194,7 +3955,8 @@ namespace OpenSim.Region.Framework.Scenes
3194 part.OffsetPosition = pos; 3955 part.OffsetPosition = pos;
3195 } 3956 }
3196 3957
3197 part.IgnoreUndoUpdate = false; 3958 if (m_rootPart.PhysActor != null)
3959 m_rootPart.PhysActor.Building = false;
3198 } 3960 }
3199 } 3961 }
3200 3962
@@ -3204,15 +3966,12 @@ namespace OpenSim.Region.Framework.Scenes
3204 /// <param name="rot"></param> 3966 /// <param name="rot"></param>
3205 public void UpdateRootRotation(Quaternion rot) 3967 public void UpdateRootRotation(Quaternion rot)
3206 { 3968 {
3207// m_log.DebugFormat( 3969 // 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; 3970 Quaternion axRot = rot;
3212 Quaternion oldParentRot = m_rootPart.RotationOffset; 3971 Quaternion oldParentRot = m_rootPart.RotationOffset;
3213 3972
3214 m_rootPart.StoreUndoState(); 3973 //Don't use UpdateRotation because it schedules an update prematurely
3215 m_rootPart.UpdateRotation(rot); 3974 m_rootPart.RotationOffset = rot;
3216 3975
3217 PhysicsActor pa = m_rootPart.PhysActor; 3976 PhysicsActor pa = m_rootPart.PhysActor;
3218 3977
@@ -3228,35 +3987,145 @@ namespace OpenSim.Region.Framework.Scenes
3228 SceneObjectPart prim = parts[i]; 3987 SceneObjectPart prim = parts[i];
3229 if (prim.UUID != m_rootPart.UUID) 3988 if (prim.UUID != m_rootPart.UUID)
3230 { 3989 {
3231 prim.IgnoreUndoUpdate = true; 3990 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3991 NewRot = Quaternion.Inverse(axRot) * NewRot;
3992 prim.RotationOffset = NewRot;
3993
3232 Vector3 axPos = prim.OffsetPosition; 3994 Vector3 axPos = prim.OffsetPosition;
3995
3233 axPos *= oldParentRot; 3996 axPos *= oldParentRot;
3234 axPos *= Quaternion.Inverse(axRot); 3997 axPos *= Quaternion.Inverse(axRot);
3235 prim.OffsetPosition = axPos; 3998 prim.OffsetPosition = axPos;
3236 Quaternion primsRot = prim.RotationOffset; 3999 }
3237 Quaternion newRot = oldParentRot * primsRot; 4000 }
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 4001
3255 m_rootPart.ScheduleTerseUpdate(); 4002 HasGroupChanged = true;
4003 ScheduleGroupForFullUpdate();
4004 }
3256 4005
3257// m_log.DebugFormat( 4006 private enum updatetype :int
3258// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4007 {
3259// Name, LocalId, rot); 4008 none = 0,
4009 partterse = 1,
4010 partfull = 2,
4011 groupterse = 3,
4012 groupfull = 4
4013 }
4014
4015 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4016 {
4017 // TODO this still as excessive *.Schedule*Update()s
4018
4019 if (part != null && part.ParentGroup != null)
4020 {
4021 ObjectChangeType change = data.change;
4022 bool togroup = ((change & ObjectChangeType.Group) != 0);
4023 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4024
4025 SceneObjectGroup group = part.ParentGroup;
4026 PhysicsActor pha = group.RootPart.PhysActor;
4027
4028 updatetype updateType = updatetype.none;
4029
4030 if (togroup)
4031 {
4032 // related to group
4033 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4034 {
4035 if ((change & ObjectChangeType.Rotation) != 0)
4036 {
4037 group.RootPart.UpdateRotation(data.rotation);
4038 updateType = updatetype.none;
4039 }
4040 if ((change & ObjectChangeType.Position) != 0)
4041 {
4042 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4043 UpdateGroupPosition(data.position);
4044 updateType = updatetype.groupterse;
4045 }
4046 else
4047 // ugly rotation update of all parts
4048 {
4049 group.ResetChildPrimPhysicsPositions();
4050 }
4051
4052 }
4053 if ((change & ObjectChangeType.Scale) != 0)
4054 {
4055 if (pha != null)
4056 pha.Building = true;
4057
4058 group.GroupResize(data.scale);
4059 updateType = updatetype.none;
4060
4061 if (pha != null)
4062 pha.Building = false;
4063 }
4064 }
4065 else
4066 {
4067 // related to single prim in a link-set ( ie group)
4068 if (pha != null)
4069 pha.Building = true;
4070
4071 // root part is special
4072 // parts offset positions or rotations need to change also
4073
4074 if (part == group.RootPart)
4075 {
4076 if ((change & ObjectChangeType.Rotation) != 0)
4077 group.UpdateRootRotation(data.rotation);
4078 if ((change & ObjectChangeType.Position) != 0)
4079 group.UpdateRootPosition(data.position);
4080 if ((change & ObjectChangeType.Scale) != 0)
4081 part.Resize(data.scale);
4082 }
4083 else
4084 {
4085 if ((change & ObjectChangeType.Position) != 0)
4086 {
4087 part.OffsetPosition = data.position;
4088 updateType = updatetype.partterse;
4089 }
4090 if ((change & ObjectChangeType.Rotation) != 0)
4091 {
4092 part.UpdateRotation(data.rotation);
4093 updateType = updatetype.none;
4094 }
4095 if ((change & ObjectChangeType.Scale) != 0)
4096 {
4097 part.Resize(data.scale);
4098 updateType = updatetype.none;
4099 }
4100 }
4101
4102 if (pha != null)
4103 pha.Building = false;
4104 }
4105
4106 if (updateType != updatetype.none)
4107 {
4108 group.HasGroupChanged = true;
4109
4110 switch (updateType)
4111 {
4112 case updatetype.partterse:
4113 part.ScheduleTerseUpdate();
4114 break;
4115 case updatetype.partfull:
4116 part.ScheduleFullUpdate();
4117 break;
4118 case updatetype.groupterse:
4119 group.ScheduleGroupForTerseUpdate();
4120 break;
4121 case updatetype.groupfull:
4122 group.ScheduleGroupForFullUpdate();
4123 break;
4124 default:
4125 break;
4126 }
4127 }
4128 }
3260 } 4129 }
3261 4130
3262 #endregion 4131 #endregion
@@ -3297,6 +4166,8 @@ namespace OpenSim.Region.Framework.Scenes
3297 waypoint.handle = handle; 4166 waypoint.handle = handle;
3298 lock (m_rotTargets) 4167 lock (m_rotTargets)
3299 { 4168 {
4169 if (m_rotTargets.Count >= 8)
4170 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3300 m_rotTargets.Add(handle, waypoint); 4171 m_rotTargets.Add(handle, waypoint);
3301 } 4172 }
3302 m_scene.AddGroupTarget(this); 4173 m_scene.AddGroupTarget(this);
@@ -3322,6 +4193,8 @@ namespace OpenSim.Region.Framework.Scenes
3322 waypoint.handle = handle; 4193 waypoint.handle = handle;
3323 lock (m_targets) 4194 lock (m_targets)
3324 { 4195 {
4196 if (m_targets.Count >= 8)
4197 m_targets.Remove(m_targets.ElementAt(0).Key);
3325 m_targets.Add(handle, waypoint); 4198 m_targets.Add(handle, waypoint);
3326 } 4199 }
3327 m_scene.AddGroupTarget(this); 4200 m_scene.AddGroupTarget(this);
@@ -3355,10 +4228,11 @@ namespace OpenSim.Region.Framework.Scenes
3355 scriptPosTarget target = m_targets[idx]; 4228 scriptPosTarget target = m_targets[idx];
3356 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4229 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3357 { 4230 {
4231 at_target = true;
4232
3358 // trigger at_target 4233 // trigger at_target
3359 if (m_scriptListens_atTarget) 4234 if (m_scriptListens_atTarget)
3360 { 4235 {
3361 at_target = true;
3362 scriptPosTarget att = new scriptPosTarget(); 4236 scriptPosTarget att = new scriptPosTarget();
3363 att.targetPos = target.targetPos; 4237 att.targetPos = target.targetPos;
3364 att.tolerance = target.tolerance; 4238 att.tolerance = target.tolerance;
@@ -3476,11 +4350,50 @@ namespace OpenSim.Region.Framework.Scenes
3476 } 4350 }
3477 } 4351 }
3478 } 4352 }
3479 4353
4354 public Vector3 GetGeometricCenter()
4355 {
4356 // this is not real geometric center but a average of positions relative to root prim acording to
4357 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4358 // ignoring tortured prims details since sl also seems to ignore
4359 // so no real use in doing it on physics
4360
4361 Vector3 gc = Vector3.Zero;
4362
4363 int nparts = m_parts.Count;
4364 if (nparts <= 1)
4365 return gc;
4366
4367 SceneObjectPart[] parts = m_parts.GetArray();
4368 nparts = parts.Length; // just in case it changed
4369 if (nparts <= 1)
4370 return gc;
4371
4372 Quaternion parentRot = RootPart.RotationOffset;
4373 Vector3 pPos;
4374
4375 // average all parts positions
4376 for (int i = 0; i < nparts; i++)
4377 {
4378 // do it directly
4379 // gc += parts[i].GetWorldPosition();
4380 if (parts[i] != RootPart)
4381 {
4382 pPos = parts[i].OffsetPosition;
4383 gc += pPos;
4384 }
4385
4386 }
4387 gc /= nparts;
4388
4389 // relative to root:
4390// gc -= AbsolutePosition;
4391 return gc;
4392 }
4393
3480 public float GetMass() 4394 public float GetMass()
3481 { 4395 {
3482 float retmass = 0f; 4396 float retmass = 0f;
3483
3484 SceneObjectPart[] parts = m_parts.GetArray(); 4397 SceneObjectPart[] parts = m_parts.GetArray();
3485 for (int i = 0; i < parts.Length; i++) 4398 for (int i = 0; i < parts.Length; i++)
3486 retmass += parts[i].GetMass(); 4399 retmass += parts[i].GetMass();
@@ -3488,6 +4401,39 @@ namespace OpenSim.Region.Framework.Scenes
3488 return retmass; 4401 return retmass;
3489 } 4402 }
3490 4403
4404 // center of mass of full object
4405 public Vector3 GetCenterOfMass()
4406 {
4407 PhysicsActor pa = RootPart.PhysActor;
4408
4409 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4410 {
4411 // physics knows better about center of mass of physical prims
4412 Vector3 tmp = pa.CenterOfMass;
4413 return tmp;
4414 }
4415
4416 Vector3 Ptot = Vector3.Zero;
4417 float totmass = 0f;
4418 float m;
4419
4420 SceneObjectPart[] parts = m_parts.GetArray();
4421 for (int i = 0; i < parts.Length; i++)
4422 {
4423 m = parts[i].GetMass();
4424 Ptot += parts[i].GetPartCenterOfMass() * m;
4425 totmass += m;
4426 }
4427
4428 if (totmass == 0)
4429 totmass = 0;
4430 else
4431 totmass = 1 / totmass;
4432 Ptot *= totmass;
4433
4434 return Ptot;
4435 }
4436
3491 /// <summary> 4437 /// <summary>
3492 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4438 /// 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. 4439 /// the physics engine can use it.
@@ -3667,6 +4613,14 @@ namespace OpenSim.Region.Framework.Scenes
3667 FromItemID = uuid; 4613 FromItemID = uuid;
3668 } 4614 }
3669 4615
4616 public void ResetOwnerChangeFlag()
4617 {
4618 ForEachPart(delegate(SceneObjectPart part)
4619 {
4620 part.ResetOwnerChangeFlag();
4621 });
4622 }
4623
3670 #endregion 4624 #endregion
3671 } 4625 }
3672} 4626}