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