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 7b5fdcb..c465138 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="pos"></param> 3813 /// <param name="pos"></param>
3032 public void UpdateRootPosition(Vector3 pos) 3814 public void UpdateRootPosition(Vector3 pos)
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 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3817 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3042 Vector3 oldPos = 3818 Vector3 oldPos =
3043 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3819 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3060,7 +3836,14 @@ namespace OpenSim.Region.Framework.Scenes
3060 AbsolutePosition = newPos; 3836 AbsolutePosition = newPos;
3061 3837
3062 HasGroupChanged = true; 3838 HasGroupChanged = true;
3063 ScheduleGroupForTerseUpdate(); 3839 if (m_rootPart.Undoing)
3840 {
3841 ScheduleGroupForFullUpdate();
3842 }
3843 else
3844 {
3845 ScheduleGroupForTerseUpdate();
3846 }
3064 } 3847 }
3065 3848
3066 #endregion 3849 #endregion
@@ -3073,24 +3856,16 @@ namespace OpenSim.Region.Framework.Scenes
3073 /// <param name="rot"></param> 3856 /// <param name="rot"></param>
3074 public void UpdateGroupRotationR(Quaternion rot) 3857 public void UpdateGroupRotationR(Quaternion rot)
3075 { 3858 {
3076// m_log.DebugFormat(
3077// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3078
3079// SceneObjectPart[] parts = m_parts.GetArray();
3080// for (int i = 0; i < parts.Length; i++)
3081// parts[i].StoreUndoState();
3082
3083 m_rootPart.StoreUndoState(true);
3084
3085 m_rootPart.UpdateRotation(rot); 3859 m_rootPart.UpdateRotation(rot);
3086 3860
3861/* this is done by rootpart RotationOffset set called by UpdateRotation
3087 PhysicsActor actor = m_rootPart.PhysActor; 3862 PhysicsActor actor = m_rootPart.PhysActor;
3088 if (actor != null) 3863 if (actor != null)
3089 { 3864 {
3090 actor.Orientation = m_rootPart.RotationOffset; 3865 actor.Orientation = m_rootPart.RotationOffset;
3091 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3866 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3092 } 3867 }
3093 3868*/
3094 HasGroupChanged = true; 3869 HasGroupChanged = true;
3095 ScheduleGroupForTerseUpdate(); 3870 ScheduleGroupForTerseUpdate();
3096 } 3871 }
@@ -3102,16 +3877,6 @@ namespace OpenSim.Region.Framework.Scenes
3102 /// <param name="rot"></param> 3877 /// <param name="rot"></param>
3103 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3878 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3104 { 3879 {
3105// m_log.DebugFormat(
3106// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3107
3108// SceneObjectPart[] parts = m_parts.GetArray();
3109// for (int i = 0; i < parts.Length; i++)
3110// parts[i].StoreUndoState();
3111
3112 RootPart.StoreUndoState(true);
3113 RootPart.IgnoreUndoUpdate = true;
3114
3115 m_rootPart.UpdateRotation(rot); 3880 m_rootPart.UpdateRotation(rot);
3116 3881
3117 PhysicsActor actor = m_rootPart.PhysActor; 3882 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3130,8 +3895,6 @@ namespace OpenSim.Region.Framework.Scenes
3130 3895
3131 HasGroupChanged = true; 3896 HasGroupChanged = true;
3132 ScheduleGroupForTerseUpdate(); 3897 ScheduleGroupForTerseUpdate();
3133
3134 RootPart.IgnoreUndoUpdate = false;
3135 } 3898 }
3136 3899
3137 /// <summary> 3900 /// <summary>
@@ -3144,13 +3907,11 @@ namespace OpenSim.Region.Framework.Scenes
3144 SceneObjectPart part = GetPart(localID); 3907 SceneObjectPart part = GetPart(localID);
3145 3908
3146 SceneObjectPart[] parts = m_parts.GetArray(); 3909 SceneObjectPart[] parts = m_parts.GetArray();
3147 for (int i = 0; i < parts.Length; i++)
3148 parts[i].StoreUndoState();
3149 3910
3150 if (part != null) 3911 if (part != null)
3151 { 3912 {
3152// m_log.DebugFormat( 3913 if (m_rootPart.PhysActor != null)
3153// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3914 m_rootPart.PhysActor.Building = true;
3154 3915
3155 if (part.UUID == m_rootPart.UUID) 3916 if (part.UUID == m_rootPart.UUID)
3156 { 3917 {
@@ -3160,6 +3921,9 @@ namespace OpenSim.Region.Framework.Scenes
3160 { 3921 {
3161 part.UpdateRotation(rot); 3922 part.UpdateRotation(rot);
3162 } 3923 }
3924
3925 if (m_rootPart.PhysActor != null)
3926 m_rootPart.PhysActor.Building = false;
3163 } 3927 }
3164 } 3928 }
3165 3929
@@ -3173,12 +3937,8 @@ namespace OpenSim.Region.Framework.Scenes
3173 SceneObjectPart part = GetPart(localID); 3937 SceneObjectPart part = GetPart(localID);
3174 if (part != null) 3938 if (part != null)
3175 { 3939 {
3176// m_log.DebugFormat( 3940 if (m_rootPart.PhysActor != null)
3177// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3941 m_rootPart.PhysActor.Building = true;
3178// part.Name, part.LocalId, rot);
3179
3180 part.StoreUndoState();
3181 part.IgnoreUndoUpdate = true;
3182 3942
3183 if (part.UUID == m_rootPart.UUID) 3943 if (part.UUID == m_rootPart.UUID)
3184 { 3944 {
@@ -3191,7 +3951,8 @@ namespace OpenSim.Region.Framework.Scenes
3191 part.OffsetPosition = pos; 3951 part.OffsetPosition = pos;
3192 } 3952 }
3193 3953
3194 part.IgnoreUndoUpdate = false; 3954 if (m_rootPart.PhysActor != null)
3955 m_rootPart.PhysActor.Building = false;
3195 } 3956 }
3196 } 3957 }
3197 3958
@@ -3201,15 +3962,12 @@ namespace OpenSim.Region.Framework.Scenes
3201 /// <param name="rot"></param> 3962 /// <param name="rot"></param>
3202 public void UpdateRootRotation(Quaternion rot) 3963 public void UpdateRootRotation(Quaternion rot)
3203 { 3964 {
3204// m_log.DebugFormat( 3965 // needs to be called with phys building true
3205// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3206// Name, LocalId, rot);
3207
3208 Quaternion axRot = rot; 3966 Quaternion axRot = rot;
3209 Quaternion oldParentRot = m_rootPart.RotationOffset; 3967 Quaternion oldParentRot = m_rootPart.RotationOffset;
3210 3968
3211 m_rootPart.StoreUndoState(); 3969 //Don't use UpdateRotation because it schedules an update prematurely
3212 m_rootPart.UpdateRotation(rot); 3970 m_rootPart.RotationOffset = rot;
3213 3971
3214 PhysicsActor pa = m_rootPart.PhysActor; 3972 PhysicsActor pa = m_rootPart.PhysActor;
3215 3973
@@ -3225,35 +3983,145 @@ namespace OpenSim.Region.Framework.Scenes
3225 SceneObjectPart prim = parts[i]; 3983 SceneObjectPart prim = parts[i];
3226 if (prim.UUID != m_rootPart.UUID) 3984 if (prim.UUID != m_rootPart.UUID)
3227 { 3985 {
3228 prim.IgnoreUndoUpdate = true; 3986 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3987 NewRot = Quaternion.Inverse(axRot) * NewRot;
3988 prim.RotationOffset = NewRot;
3989
3229 Vector3 axPos = prim.OffsetPosition; 3990 Vector3 axPos = prim.OffsetPosition;
3991
3230 axPos *= oldParentRot; 3992 axPos *= oldParentRot;
3231 axPos *= Quaternion.Inverse(axRot); 3993 axPos *= Quaternion.Inverse(axRot);
3232 prim.OffsetPosition = axPos; 3994 prim.OffsetPosition = axPos;
3233 Quaternion primsRot = prim.RotationOffset; 3995 }
3234 Quaternion newRot = oldParentRot * primsRot; 3996 }
3235 newRot = Quaternion.Inverse(axRot) * newRot;
3236 prim.RotationOffset = newRot;
3237 prim.ScheduleTerseUpdate();
3238 prim.IgnoreUndoUpdate = false;
3239 }
3240 }
3241
3242// for (int i = 0; i < parts.Length; i++)
3243// {
3244// SceneObjectPart childpart = parts[i];
3245// if (childpart != m_rootPart)
3246// {
3247//// childpart.IgnoreUndoUpdate = false;
3248//// childpart.StoreUndoState();
3249// }
3250// }
3251 3997
3252 m_rootPart.ScheduleTerseUpdate(); 3998 HasGroupChanged = true;
3999 ScheduleGroupForFullUpdate();
4000 }
3253 4001
3254// m_log.DebugFormat( 4002 private enum updatetype :int
3255// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4003 {
3256// Name, LocalId, rot); 4004 none = 0,
4005 partterse = 1,
4006 partfull = 2,
4007 groupterse = 3,
4008 groupfull = 4
4009 }
4010
4011 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4012 {
4013 // TODO this still as excessive *.Schedule*Update()s
4014
4015 if (part != null && part.ParentGroup != null)
4016 {
4017 ObjectChangeType change = data.change;
4018 bool togroup = ((change & ObjectChangeType.Group) != 0);
4019 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4020
4021 SceneObjectGroup group = part.ParentGroup;
4022 PhysicsActor pha = group.RootPart.PhysActor;
4023
4024 updatetype updateType = updatetype.none;
4025
4026 if (togroup)
4027 {
4028 // related to group
4029 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4030 {
4031 if ((change & ObjectChangeType.Rotation) != 0)
4032 {
4033 group.RootPart.UpdateRotation(data.rotation);
4034 updateType = updatetype.none;
4035 }
4036 if ((change & ObjectChangeType.Position) != 0)
4037 {
4038 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4039 UpdateGroupPosition(data.position);
4040 updateType = updatetype.groupterse;
4041 }
4042 else
4043 // ugly rotation update of all parts
4044 {
4045 group.ResetChildPrimPhysicsPositions();
4046 }
4047
4048 }
4049 if ((change & ObjectChangeType.Scale) != 0)
4050 {
4051 if (pha != null)
4052 pha.Building = true;
4053
4054 group.GroupResize(data.scale);
4055 updateType = updatetype.none;
4056
4057 if (pha != null)
4058 pha.Building = false;
4059 }
4060 }
4061 else
4062 {
4063 // related to single prim in a link-set ( ie group)
4064 if (pha != null)
4065 pha.Building = true;
4066
4067 // root part is special
4068 // parts offset positions or rotations need to change also
4069
4070 if (part == group.RootPart)
4071 {
4072 if ((change & ObjectChangeType.Rotation) != 0)
4073 group.UpdateRootRotation(data.rotation);
4074 if ((change & ObjectChangeType.Position) != 0)
4075 group.UpdateRootPosition(data.position);
4076 if ((change & ObjectChangeType.Scale) != 0)
4077 part.Resize(data.scale);
4078 }
4079 else
4080 {
4081 if ((change & ObjectChangeType.Position) != 0)
4082 {
4083 part.OffsetPosition = data.position;
4084 updateType = updatetype.partterse;
4085 }
4086 if ((change & ObjectChangeType.Rotation) != 0)
4087 {
4088 part.UpdateRotation(data.rotation);
4089 updateType = updatetype.none;
4090 }
4091 if ((change & ObjectChangeType.Scale) != 0)
4092 {
4093 part.Resize(data.scale);
4094 updateType = updatetype.none;
4095 }
4096 }
4097
4098 if (pha != null)
4099 pha.Building = false;
4100 }
4101
4102 if (updateType != updatetype.none)
4103 {
4104 group.HasGroupChanged = true;
4105
4106 switch (updateType)
4107 {
4108 case updatetype.partterse:
4109 part.ScheduleTerseUpdate();
4110 break;
4111 case updatetype.partfull:
4112 part.ScheduleFullUpdate();
4113 break;
4114 case updatetype.groupterse:
4115 group.ScheduleGroupForTerseUpdate();
4116 break;
4117 case updatetype.groupfull:
4118 group.ScheduleGroupForFullUpdate();
4119 break;
4120 default:
4121 break;
4122 }
4123 }
4124 }
3257 } 4125 }
3258 4126
3259 #endregion 4127 #endregion
@@ -3294,6 +4162,8 @@ namespace OpenSim.Region.Framework.Scenes
3294 waypoint.handle = handle; 4162 waypoint.handle = handle;
3295 lock (m_rotTargets) 4163 lock (m_rotTargets)
3296 { 4164 {
4165 if (m_rotTargets.Count >= 8)
4166 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3297 m_rotTargets.Add(handle, waypoint); 4167 m_rotTargets.Add(handle, waypoint);
3298 } 4168 }
3299 m_scene.AddGroupTarget(this); 4169 m_scene.AddGroupTarget(this);
@@ -3319,6 +4189,8 @@ namespace OpenSim.Region.Framework.Scenes
3319 waypoint.handle = handle; 4189 waypoint.handle = handle;
3320 lock (m_targets) 4190 lock (m_targets)
3321 { 4191 {
4192 if (m_targets.Count >= 8)
4193 m_targets.Remove(m_targets.ElementAt(0).Key);
3322 m_targets.Add(handle, waypoint); 4194 m_targets.Add(handle, waypoint);
3323 } 4195 }
3324 m_scene.AddGroupTarget(this); 4196 m_scene.AddGroupTarget(this);
@@ -3352,10 +4224,11 @@ namespace OpenSim.Region.Framework.Scenes
3352 scriptPosTarget target = m_targets[idx]; 4224 scriptPosTarget target = m_targets[idx];
3353 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4225 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3354 { 4226 {
4227 at_target = true;
4228
3355 // trigger at_target 4229 // trigger at_target
3356 if (m_scriptListens_atTarget) 4230 if (m_scriptListens_atTarget)
3357 { 4231 {
3358 at_target = true;
3359 scriptPosTarget att = new scriptPosTarget(); 4232 scriptPosTarget att = new scriptPosTarget();
3360 att.targetPos = target.targetPos; 4233 att.targetPos = target.targetPos;
3361 att.tolerance = target.tolerance; 4234 att.tolerance = target.tolerance;
@@ -3473,11 +4346,50 @@ namespace OpenSim.Region.Framework.Scenes
3473 } 4346 }
3474 } 4347 }
3475 } 4348 }
3476 4349
4350 public Vector3 GetGeometricCenter()
4351 {
4352 // this is not real geometric center but a average of positions relative to root prim acording to
4353 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4354 // ignoring tortured prims details since sl also seems to ignore
4355 // so no real use in doing it on physics
4356
4357 Vector3 gc = Vector3.Zero;
4358
4359 int nparts = m_parts.Count;
4360 if (nparts <= 1)
4361 return gc;
4362
4363 SceneObjectPart[] parts = m_parts.GetArray();
4364 nparts = parts.Length; // just in case it changed
4365 if (nparts <= 1)
4366 return gc;
4367
4368 Quaternion parentRot = RootPart.RotationOffset;
4369 Vector3 pPos;
4370
4371 // average all parts positions
4372 for (int i = 0; i < nparts; i++)
4373 {
4374 // do it directly
4375 // gc += parts[i].GetWorldPosition();
4376 if (parts[i] != RootPart)
4377 {
4378 pPos = parts[i].OffsetPosition;
4379 gc += pPos;
4380 }
4381
4382 }
4383 gc /= nparts;
4384
4385 // relative to root:
4386// gc -= AbsolutePosition;
4387 return gc;
4388 }
4389
3477 public float GetMass() 4390 public float GetMass()
3478 { 4391 {
3479 float retmass = 0f; 4392 float retmass = 0f;
3480
3481 SceneObjectPart[] parts = m_parts.GetArray(); 4393 SceneObjectPart[] parts = m_parts.GetArray();
3482 for (int i = 0; i < parts.Length; i++) 4394 for (int i = 0; i < parts.Length; i++)
3483 retmass += parts[i].GetMass(); 4395 retmass += parts[i].GetMass();
@@ -3485,6 +4397,39 @@ namespace OpenSim.Region.Framework.Scenes
3485 return retmass; 4397 return retmass;
3486 } 4398 }
3487 4399
4400 // center of mass of full object
4401 public Vector3 GetCenterOfMass()
4402 {
4403 PhysicsActor pa = RootPart.PhysActor;
4404
4405 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4406 {
4407 // physics knows better about center of mass of physical prims
4408 Vector3 tmp = pa.CenterOfMass;
4409 return tmp;
4410 }
4411
4412 Vector3 Ptot = Vector3.Zero;
4413 float totmass = 0f;
4414 float m;
4415
4416 SceneObjectPart[] parts = m_parts.GetArray();
4417 for (int i = 0; i < parts.Length; i++)
4418 {
4419 m = parts[i].GetMass();
4420 Ptot += parts[i].GetPartCenterOfMass() * m;
4421 totmass += m;
4422 }
4423
4424 if (totmass == 0)
4425 totmass = 0;
4426 else
4427 totmass = 1 / totmass;
4428 Ptot *= totmass;
4429
4430 return Ptot;
4431 }
4432
3488 /// <summary> 4433 /// <summary>
3489 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4434 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3490 /// the physics engine can use it. 4435 /// the physics engine can use it.
@@ -3664,6 +4609,14 @@ namespace OpenSim.Region.Framework.Scenes
3664 FromItemID = uuid; 4609 FromItemID = uuid;
3665 } 4610 }
3666 4611
4612 public void ResetOwnerChangeFlag()
4613 {
4614 ForEachPart(delegate(SceneObjectPart part)
4615 {
4616 part.ResetOwnerChangeFlag();
4617 });
4618 }
4619
3667 #endregion 4620 #endregion
3668 } 4621 }
3669} 4622}