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 da80e4f..02a8935 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(
@@ -775,6 +1084,13 @@ namespace OpenSim.Region.Framework.Scenes
775 1084
776 ApplyPhysics(); 1085 ApplyPhysics();
777 1086
1087 if (RootPart.PhysActor != null)
1088 RootPart.Force = RootPart.Force;
1089 if (RootPart.PhysActor != null)
1090 RootPart.Torque = RootPart.Torque;
1091 if (RootPart.PhysActor != null)
1092 RootPart.Buoyancy = RootPart.Buoyancy;
1093
778 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1094 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
779 // for the same object with very different properties. The caller must schedule the update. 1095 // for the same object with very different properties. The caller must schedule the update.
780 //ScheduleGroupForFullUpdate(); 1096 //ScheduleGroupForFullUpdate();
@@ -790,6 +1106,10 @@ namespace OpenSim.Region.Framework.Scenes
790 EntityIntersection result = new EntityIntersection(); 1106 EntityIntersection result = new EntityIntersection();
791 1107
792 SceneObjectPart[] parts = m_parts.GetArray(); 1108 SceneObjectPart[] parts = m_parts.GetArray();
1109
1110 // Find closest hit here
1111 float idist = float.MaxValue;
1112
793 for (int i = 0; i < parts.Length; i++) 1113 for (int i = 0; i < parts.Length; i++)
794 { 1114 {
795 SceneObjectPart part = parts[i]; 1115 SceneObjectPart part = parts[i];
@@ -804,11 +1124,6 @@ namespace OpenSim.Region.Framework.Scenes
804 1124
805 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1125 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
806 1126
807 // This may need to be updated to the maximum draw distance possible..
808 // We might (and probably will) be checking for prim creation from other sims
809 // when the camera crosses the border.
810 float idist = Constants.RegionSize;
811
812 if (inter.HitTF) 1127 if (inter.HitTF)
813 { 1128 {
814 // We need to find the closest prim to return to the testcaller along the ray 1129 // We need to find the closest prim to return to the testcaller along the ray
@@ -819,10 +1134,11 @@ namespace OpenSim.Region.Framework.Scenes
819 result.obj = part; 1134 result.obj = part;
820 result.normal = inter.normal; 1135 result.normal = inter.normal;
821 result.distance = inter.distance; 1136 result.distance = inter.distance;
1137
1138 idist = inter.distance;
822 } 1139 }
823 } 1140 }
824 } 1141 }
825
826 return result; 1142 return result;
827 } 1143 }
828 1144
@@ -834,25 +1150,27 @@ namespace OpenSim.Region.Framework.Scenes
834 /// <returns></returns> 1150 /// <returns></returns>
835 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1151 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
836 { 1152 {
837 maxX = -256f; 1153 maxX = float.MinValue;
838 maxY = -256f; 1154 maxY = float.MinValue;
839 maxZ = -256f; 1155 maxZ = float.MinValue;
840 minX = 256f; 1156 minX = float.MaxValue;
841 minY = 256f; 1157 minY = float.MaxValue;
842 minZ = 8192f; 1158 minZ = float.MaxValue;
843 1159
844 SceneObjectPart[] parts = m_parts.GetArray(); 1160 SceneObjectPart[] parts = m_parts.GetArray();
845 for (int i = 0; i < parts.Length; i++) 1161 foreach (SceneObjectPart part in parts)
846 { 1162 {
847 SceneObjectPart part = parts[i];
848
849 Vector3 worldPos = part.GetWorldPosition(); 1163 Vector3 worldPos = part.GetWorldPosition();
850 Vector3 offset = worldPos - AbsolutePosition; 1164 Vector3 offset = worldPos - AbsolutePosition;
851 Quaternion worldRot; 1165 Quaternion worldRot;
852 if (part.ParentID == 0) 1166 if (part.ParentID == 0)
1167 {
853 worldRot = part.RotationOffset; 1168 worldRot = part.RotationOffset;
1169 }
854 else 1170 else
1171 {
855 worldRot = part.GetWorldRotation(); 1172 worldRot = part.GetWorldRotation();
1173 }
856 1174
857 Vector3 frontTopLeft; 1175 Vector3 frontTopLeft;
858 Vector3 frontTopRight; 1176 Vector3 frontTopRight;
@@ -864,6 +1182,8 @@ namespace OpenSim.Region.Framework.Scenes
864 Vector3 backBottomLeft; 1182 Vector3 backBottomLeft;
865 Vector3 backBottomRight; 1183 Vector3 backBottomRight;
866 1184
1185 // Vector3[] corners = new Vector3[8];
1186
867 Vector3 orig = Vector3.Zero; 1187 Vector3 orig = Vector3.Zero;
868 1188
869 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1189 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -898,6 +1218,38 @@ namespace OpenSim.Region.Framework.Scenes
898 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1218 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
899 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1219 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
900 1220
1221
1222
1223 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1224 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1225 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1226 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1227 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1228 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1229 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1230 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1231
1232 //for (int i = 0; i < 8; i++)
1233 //{
1234 // corners[i] = corners[i] * worldRot;
1235 // corners[i] += offset;
1236
1237 // if (corners[i].X > maxX)
1238 // maxX = corners[i].X;
1239 // if (corners[i].X < minX)
1240 // minX = corners[i].X;
1241
1242 // if (corners[i].Y > maxY)
1243 // maxY = corners[i].Y;
1244 // if (corners[i].Y < minY)
1245 // minY = corners[i].Y;
1246
1247 // if (corners[i].Z > maxZ)
1248 // maxZ = corners[i].Y;
1249 // if (corners[i].Z < minZ)
1250 // minZ = corners[i].Z;
1251 //}
1252
901 frontTopLeft = frontTopLeft * worldRot; 1253 frontTopLeft = frontTopLeft * worldRot;
902 frontTopRight = frontTopRight * worldRot; 1254 frontTopRight = frontTopRight * worldRot;
903 frontBottomLeft = frontBottomLeft * worldRot; 1255 frontBottomLeft = frontBottomLeft * worldRot;
@@ -919,6 +1271,15 @@ namespace OpenSim.Region.Framework.Scenes
919 backTopLeft += offset; 1271 backTopLeft += offset;
920 backTopRight += offset; 1272 backTopRight += offset;
921 1273
1274 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1275 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1276 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1277 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1278 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1279 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1280 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1281 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1282
922 if (frontTopRight.X > maxX) 1283 if (frontTopRight.X > maxX)
923 maxX = frontTopRight.X; 1284 maxX = frontTopRight.X;
924 if (frontTopLeft.X > maxX) 1285 if (frontTopLeft.X > maxX)
@@ -1062,17 +1423,118 @@ namespace OpenSim.Region.Framework.Scenes
1062 1423
1063 #endregion 1424 #endregion
1064 1425
1426 public void GetResourcesCosts(SceneObjectPart apart,
1427 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1428 {
1429 // this information may need to be cached
1430
1431 float cost;
1432 float tmpcost;
1433
1434 bool ComplexCost = false;
1435
1436 SceneObjectPart p;
1437 SceneObjectPart[] parts;
1438
1439 lock (m_parts)
1440 {
1441 parts = m_parts.GetArray();
1442 }
1443
1444 int nparts = parts.Length;
1445
1446
1447 for (int i = 0; i < nparts; i++)
1448 {
1449 p = parts[i];
1450
1451 if (p.UsesComplexCost)
1452 {
1453 ComplexCost = true;
1454 break;
1455 }
1456 }
1457
1458 if (ComplexCost)
1459 {
1460 linksetResCost = 0;
1461 linksetPhysCost = 0;
1462 partCost = 0;
1463 partPhysCost = 0;
1464
1465 for (int i = 0; i < nparts; i++)
1466 {
1467 p = parts[i];
1468
1469 cost = p.StreamingCost;
1470 tmpcost = p.SimulationCost;
1471 if (tmpcost > cost)
1472 cost = tmpcost;
1473 tmpcost = p.PhysicsCost;
1474 if (tmpcost > cost)
1475 cost = tmpcost;
1476
1477 linksetPhysCost += tmpcost;
1478 linksetResCost += cost;
1479
1480 if (p == apart)
1481 {
1482 partCost = cost;
1483 partPhysCost = tmpcost;
1484 }
1485 }
1486 }
1487 else
1488 {
1489 partPhysCost = 1.0f;
1490 partCost = 1.0f;
1491 linksetResCost = (float)nparts;
1492 linksetPhysCost = linksetResCost;
1493 }
1494 }
1495
1496 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1497 {
1498 SceneObjectPart p;
1499 SceneObjectPart[] parts;
1500
1501 lock (m_parts)
1502 {
1503 parts = m_parts.GetArray();
1504 }
1505
1506 int nparts = parts.Length;
1507
1508 PhysCost = 0;
1509 StreamCost = 0;
1510 SimulCost = 0;
1511
1512 for (int i = 0; i < nparts; i++)
1513 {
1514 p = parts[i];
1515
1516 StreamCost += p.StreamingCost;
1517 SimulCost += p.SimulationCost;
1518 PhysCost += p.PhysicsCost;
1519 }
1520 }
1521
1065 public void SaveScriptedState(XmlTextWriter writer) 1522 public void SaveScriptedState(XmlTextWriter writer)
1066 { 1523 {
1524 SaveScriptedState(writer, false);
1525 }
1526
1527 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1528 {
1067 XmlDocument doc = new XmlDocument(); 1529 XmlDocument doc = new XmlDocument();
1068 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1530 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1069 1531
1070 SceneObjectPart[] parts = m_parts.GetArray(); 1532 SceneObjectPart[] parts = m_parts.GetArray();
1071 for (int i = 0; i < parts.Length; i++) 1533 for (int i = 0; i < parts.Length; i++)
1072 { 1534 {
1073 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1535 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1074 foreach (KeyValuePair<UUID, string> kvp in pstates) 1536 foreach (KeyValuePair<UUID, string> kvp in pstates)
1075 states.Add(kvp.Key, kvp.Value); 1537 states[kvp.Key] = kvp.Value;
1076 } 1538 }
1077 1539
1078 if (states.Count > 0) 1540 if (states.Count > 0)
@@ -1092,6 +1554,169 @@ namespace OpenSim.Region.Framework.Scenes
1092 } 1554 }
1093 1555
1094 /// <summary> 1556 /// <summary>
1557 /// Add the avatar to this linkset (avatar is sat).
1558 /// </summary>
1559 /// <param name="agentID"></param>
1560 public void AddAvatar(UUID agentID)
1561 {
1562 ScenePresence presence;
1563 if (m_scene.TryGetScenePresence(agentID, out presence))
1564 {
1565 if (!m_linkedAvatars.Contains(presence))
1566 {
1567 m_linkedAvatars.Add(presence);
1568 }
1569 }
1570 }
1571
1572 /// <summary>
1573 /// Delete the avatar from this linkset (avatar is unsat).
1574 /// </summary>
1575 /// <param name="agentID"></param>
1576 public void DeleteAvatar(UUID agentID)
1577 {
1578 ScenePresence presence;
1579 if (m_scene.TryGetScenePresence(agentID, out presence))
1580 {
1581 if (m_linkedAvatars.Contains(presence))
1582 {
1583 m_linkedAvatars.Remove(presence);
1584 }
1585 }
1586 }
1587
1588 /// <summary>
1589 /// Returns the list of linked presences (avatars sat on this group)
1590 /// </summary>
1591 /// <param name="agentID"></param>
1592 public List<ScenePresence> GetLinkedAvatars()
1593 {
1594 return m_linkedAvatars;
1595 }
1596
1597 /// <summary>
1598 /// Attach this scene object to the given avatar.
1599 /// </summary>
1600 /// <param name="agentID"></param>
1601 /// <param name="attachmentpoint"></param>
1602 /// <param name="AttachOffset"></param>
1603 private void AttachToAgent(
1604 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1605 {
1606 if (avatar != null)
1607 {
1608 // don't attach attachments to child agents
1609 if (avatar.IsChildAgent) return;
1610
1611 // Remove from database and parcel prim count
1612 m_scene.DeleteFromStorage(so.UUID);
1613 m_scene.EventManager.TriggerParcelPrimCountTainted();
1614
1615 so.AttachedAvatar = avatar.UUID;
1616
1617 if (so.RootPart.PhysActor != null)
1618 {
1619 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1620 so.RootPart.PhysActor = null;
1621 }
1622
1623 so.AbsolutePosition = attachOffset;
1624 so.RootPart.AttachedPos = attachOffset;
1625 so.IsAttachment = true;
1626 so.RootPart.SetParentLocalId(avatar.LocalId);
1627 so.AttachmentPoint = attachmentpoint;
1628
1629 avatar.AddAttachment(this);
1630
1631 if (!silent)
1632 {
1633 // Killing it here will cause the client to deselect it
1634 // It then reappears on the avatar, deselected
1635 // through the full update below
1636 //
1637 if (IsSelected)
1638 {
1639 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1640 }
1641
1642 IsSelected = false; // fudge....
1643 ScheduleGroupForFullUpdate();
1644 }
1645 }
1646 else
1647 {
1648 m_log.WarnFormat(
1649 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1650 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1651 }
1652 }
1653
1654 public byte GetAttachmentPoint()
1655 {
1656 return m_rootPart.Shape.State;
1657 }
1658
1659 public void DetachToGround()
1660 {
1661 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1662 if (avatar == null)
1663 return;
1664
1665 avatar.RemoveAttachment(this);
1666
1667 Vector3 detachedpos = new Vector3(127f,127f,127f);
1668 if (avatar == null)
1669 return;
1670
1671 detachedpos = avatar.AbsolutePosition;
1672 FromItemID = UUID.Zero;
1673
1674 AbsolutePosition = detachedpos;
1675 AttachedAvatar = UUID.Zero;
1676
1677 //SceneObjectPart[] parts = m_parts.GetArray();
1678 //for (int i = 0; i < parts.Length; i++)
1679 // parts[i].AttachedAvatar = UUID.Zero;
1680
1681 m_rootPart.SetParentLocalId(0);
1682 AttachmentPoint = (byte)0;
1683 // must check if buildind should be true or false here
1684 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1685 HasGroupChanged = true;
1686 RootPart.Rezzed = DateTime.Now;
1687 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1688 AttachToBackup();
1689 m_scene.EventManager.TriggerParcelPrimCountTainted();
1690 m_rootPart.ScheduleFullUpdate();
1691 m_rootPart.ClearUndoState();
1692 }
1693
1694 public void DetachToInventoryPrep()
1695 {
1696 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1697 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1698 if (avatar != null)
1699 {
1700 //detachedpos = avatar.AbsolutePosition;
1701 avatar.RemoveAttachment(this);
1702 }
1703
1704 AttachedAvatar = UUID.Zero;
1705
1706 /*SceneObjectPart[] parts = m_parts.GetArray();
1707 for (int i = 0; i < parts.Length; i++)
1708 parts[i].AttachedAvatar = UUID.Zero;*/
1709
1710 m_rootPart.SetParentLocalId(0);
1711 //m_rootPart.SetAttachmentPoint((byte)0);
1712 IsAttachment = false;
1713 AbsolutePosition = m_rootPart.AttachedPos;
1714 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1715 //AttachToBackup();
1716 //m_rootPart.ScheduleFullUpdate();
1717 }
1718
1719 /// <summary>
1095 /// 1720 ///
1096 /// </summary> 1721 /// </summary>
1097 /// <param name="part"></param> 1722 /// <param name="part"></param>
@@ -1131,7 +1756,10 @@ namespace OpenSim.Region.Framework.Scenes
1131 public void AddPart(SceneObjectPart part) 1756 public void AddPart(SceneObjectPart part)
1132 { 1757 {
1133 part.SetParent(this); 1758 part.SetParent(this);
1134 part.LinkNum = m_parts.Add(part.UUID, part); 1759 m_parts.Add(part.UUID, part);
1760
1761 part.LinkNum = m_parts.Count;
1762
1135 if (part.LinkNum == 2) 1763 if (part.LinkNum == 2)
1136 RootPart.LinkNum = 1; 1764 RootPart.LinkNum = 1;
1137 } 1765 }
@@ -1157,6 +1785,14 @@ namespace OpenSim.Region.Framework.Scenes
1157 parts[i].UUID = UUID.Random(); 1785 parts[i].UUID = UUID.Random();
1158 } 1786 }
1159 1787
1788 // helper provided for parts.
1789 public int GetSceneMaxUndo()
1790 {
1791 if (m_scene != null)
1792 return m_scene.MaxUndoCount;
1793 return 5;
1794 }
1795
1160 // justincc: I don't believe this hack is needed any longer, especially since the physics 1796 // justincc: I don't believe this hack is needed any longer, especially since the physics
1161 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1797 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1162 // this method was preventing proper reload of scene objects. 1798 // this method was preventing proper reload of scene objects.
@@ -1214,7 +1850,7 @@ namespace OpenSim.Region.Framework.Scenes
1214// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1850// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1215// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1851// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1216 1852
1217 part.StoreUndoState(); 1853// part.StoreUndoState();
1218 part.OnGrab(offsetPos, remoteClient); 1854 part.OnGrab(offsetPos, remoteClient);
1219 } 1855 }
1220 1856
@@ -1234,6 +1870,11 @@ namespace OpenSim.Region.Framework.Scenes
1234 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1870 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1235 public void DeleteGroupFromScene(bool silent) 1871 public void DeleteGroupFromScene(bool silent)
1236 { 1872 {
1873 // We need to keep track of this state in case this group is still queued for backup.
1874 IsDeleted = true;
1875
1876 DetachFromBackup();
1877
1237 SceneObjectPart[] parts = m_parts.GetArray(); 1878 SceneObjectPart[] parts = m_parts.GetArray();
1238 for (int i = 0; i < parts.Length; i++) 1879 for (int i = 0; i < parts.Length; i++)
1239 { 1880 {
@@ -1257,6 +1898,7 @@ namespace OpenSim.Region.Framework.Scenes
1257 } 1898 }
1258 }); 1899 });
1259 } 1900 }
1901
1260 } 1902 }
1261 1903
1262 public void AddScriptLPS(int count) 1904 public void AddScriptLPS(int count)
@@ -1326,28 +1968,43 @@ namespace OpenSim.Region.Framework.Scenes
1326 /// </summary> 1968 /// </summary>
1327 public void ApplyPhysics() 1969 public void ApplyPhysics()
1328 { 1970 {
1329 // Apply physics to the root prim
1330 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1331
1332 // Apply physics to child prims
1333 SceneObjectPart[] parts = m_parts.GetArray(); 1971 SceneObjectPart[] parts = m_parts.GetArray();
1334 if (parts.Length > 1) 1972 if (parts.Length > 1)
1335 { 1973 {
1974 ResetChildPrimPhysicsPositions();
1975
1976 // Apply physics to the root prim
1977 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1978
1979
1336 for (int i = 0; i < parts.Length; i++) 1980 for (int i = 0; i < parts.Length; i++)
1337 { 1981 {
1338 SceneObjectPart part = parts[i]; 1982 SceneObjectPart part = parts[i];
1339 if (part.LocalId != m_rootPart.LocalId) 1983 if (part.LocalId != m_rootPart.LocalId)
1340 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1984 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1341 } 1985 }
1342
1343 // Hack to get the physics scene geometries in the right spot 1986 // Hack to get the physics scene geometries in the right spot
1344 ResetChildPrimPhysicsPositions(); 1987// ResetChildPrimPhysicsPositions();
1988 if (m_rootPart.PhysActor != null)
1989 {
1990 m_rootPart.PhysActor.Building = false;
1991 }
1992 }
1993 else
1994 {
1995 // Apply physics to the root prim
1996 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1345 } 1997 }
1346 } 1998 }
1347 1999
1348 public void SetOwnerId(UUID userId) 2000 public void SetOwnerId(UUID userId)
1349 { 2001 {
1350 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2002 ForEachPart(delegate(SceneObjectPart part)
2003 {
2004
2005 part.OwnerID = userId;
2006
2007 });
1351 } 2008 }
1352 2009
1353 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2010 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1379,11 +2036,17 @@ namespace OpenSim.Region.Framework.Scenes
1379 return; 2036 return;
1380 } 2037 }
1381 2038
2039 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2040 return;
2041
1382 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2042 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1383 // any exception propogate upwards. 2043 // any exception propogate upwards.
1384 try 2044 try
1385 { 2045 {
1386 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2046 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2047 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2048 m_scene.LoadingPrims) // Land may not be valid yet
2049
1387 { 2050 {
1388 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2051 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1389 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2052 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1410,6 +2073,7 @@ namespace OpenSim.Region.Framework.Scenes
1410 } 2073 }
1411 } 2074 }
1412 } 2075 }
2076
1413 } 2077 }
1414 2078
1415 if (m_scene.UseBackup && HasGroupChanged) 2079 if (m_scene.UseBackup && HasGroupChanged)
@@ -1417,10 +2081,30 @@ namespace OpenSim.Region.Framework.Scenes
1417 // don't backup while it's selected or you're asking for changes mid stream. 2081 // don't backup while it's selected or you're asking for changes mid stream.
1418 if (isTimeToPersist() || forcedBackup) 2082 if (isTimeToPersist() || forcedBackup)
1419 { 2083 {
2084 if (m_rootPart.PhysActor != null &&
2085 (!m_rootPart.PhysActor.IsPhysical))
2086 {
2087 // Possible ghost prim
2088 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2089 {
2090 foreach (SceneObjectPart part in m_parts.GetArray())
2091 {
2092 // Re-set physics actor positions and
2093 // orientations
2094 part.GroupPosition = m_rootPart.GroupPosition;
2095 }
2096 }
2097 }
1420// m_log.DebugFormat( 2098// m_log.DebugFormat(
1421// "[SCENE]: Storing {0}, {1} in {2}", 2099// "[SCENE]: Storing {0}, {1} in {2}",
1422// Name, UUID, m_scene.RegionInfo.RegionName); 2100// Name, UUID, m_scene.RegionInfo.RegionName);
1423 2101
2102 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2103 {
2104 RootPart.Shape.State = 0;
2105 ScheduleGroupForFullUpdate();
2106 }
2107
1424 SceneObjectGroup backup_group = Copy(false); 2108 SceneObjectGroup backup_group = Copy(false);
1425 backup_group.RootPart.Velocity = RootPart.Velocity; 2109 backup_group.RootPart.Velocity = RootPart.Velocity;
1426 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2110 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1430,6 +2114,16 @@ namespace OpenSim.Region.Framework.Scenes
1430 HasGroupChangedDueToDelink = false; 2114 HasGroupChangedDueToDelink = false;
1431 2115
1432 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2116 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2117/*
2118 backup_group.ForEachPart(delegate(SceneObjectPart part)
2119 {
2120 if (part.KeyframeMotion != null)
2121 {
2122 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2123// part.KeyframeMotion.UpdateSceneObject(this);
2124 }
2125 });
2126*/
1433 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2127 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1434 2128
1435 backup_group.ForEachPart(delegate(SceneObjectPart part) 2129 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1486,10 +2180,14 @@ namespace OpenSim.Region.Framework.Scenes
1486 /// <returns></returns> 2180 /// <returns></returns>
1487 public SceneObjectGroup Copy(bool userExposed) 2181 public SceneObjectGroup Copy(bool userExposed)
1488 { 2182 {
2183 m_dupeInProgress = true;
1489 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2184 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1490 dupe.m_isBackedUp = false; 2185 dupe.m_isBackedUp = false;
1491 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2186 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1492 2187
2188 // new group as no sitting avatars
2189 dupe.m_linkedAvatars = new List<ScenePresence>();
2190
1493 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2191 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1494 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2192 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1495 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2193 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1500,7 +2198,7 @@ namespace OpenSim.Region.Framework.Scenes
1500 // This is only necessary when userExposed is false! 2198 // This is only necessary when userExposed is false!
1501 2199
1502 bool previousAttachmentStatus = dupe.IsAttachment; 2200 bool previousAttachmentStatus = dupe.IsAttachment;
1503 2201
1504 if (!userExposed) 2202 if (!userExposed)
1505 dupe.IsAttachment = true; 2203 dupe.IsAttachment = true;
1506 2204
@@ -1513,16 +2211,17 @@ namespace OpenSim.Region.Framework.Scenes
1513 2211
1514 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2212 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1515 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2213 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2214
1516 2215
1517 if (userExposed) 2216 if (userExposed)
1518 dupe.m_rootPart.TrimPermissions(); 2217 dupe.m_rootPart.TrimPermissions();
1519 2218
1520 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2219 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1521 2220
1522 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2221 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1523 { 2222 {
1524 return p1.LinkNum.CompareTo(p2.LinkNum); 2223 return p1.LinkNum.CompareTo(p2.LinkNum);
1525 } 2224 }
1526 ); 2225 );
1527 2226
1528 foreach (SceneObjectPart part in partList) 2227 foreach (SceneObjectPart part in partList)
@@ -1532,43 +2231,56 @@ namespace OpenSim.Region.Framework.Scenes
1532 { 2231 {
1533 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2232 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1534 newPart.LinkNum = part.LinkNum; 2233 newPart.LinkNum = part.LinkNum;
1535 } 2234 if (userExposed)
2235 newPart.ParentID = dupe.m_rootPart.LocalId;
2236 }
1536 else 2237 else
1537 { 2238 {
1538 newPart = dupe.m_rootPart; 2239 newPart = dupe.m_rootPart;
1539 } 2240 }
2241/*
2242 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2243 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1540 2244
1541 // Need to duplicate the physics actor as well 2245 // Need to duplicate the physics actor as well
1542 PhysicsActor originalPartPa = part.PhysActor; 2246 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1543 if (originalPartPa != null && userExposed)
1544 { 2247 {
1545 PrimitiveBaseShape pbs = newPart.Shape; 2248 PrimitiveBaseShape pbs = newPart.Shape;
1546
1547 newPart.PhysActor 2249 newPart.PhysActor
1548 = m_scene.PhysicsScene.AddPrimShape( 2250 = m_scene.PhysicsScene.AddPrimShape(
1549 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2251 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1550 pbs, 2252 pbs,
1551 newPart.AbsolutePosition, 2253 newPart.AbsolutePosition,
1552 newPart.Scale, 2254 newPart.Scale,
1553 newPart.RotationOffset, 2255 newPart.GetWorldRotation(),
1554 originalPartPa.IsPhysical, 2256 isphys,
2257 isphan,
1555 newPart.LocalId); 2258 newPart.LocalId);
1556 2259
1557 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2260 newPart.DoPhysicsPropertyUpdate(isphys, true);
1558 } 2261 */
2262 if (userExposed)
2263 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2264// }
2265 // copy keyframemotion
1559 if (part.KeyframeMotion != null) 2266 if (part.KeyframeMotion != null)
1560 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2267 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1561 } 2268 }
1562 2269
1563 if (userExposed) 2270 if (userExposed)
1564 { 2271 {
1565 dupe.UpdateParentIDs(); 2272// done above dupe.UpdateParentIDs();
2273
2274 if (dupe.m_rootPart.PhysActor != null)
2275 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2276
1566 dupe.HasGroupChanged = true; 2277 dupe.HasGroupChanged = true;
1567 dupe.AttachToBackup(); 2278 dupe.AttachToBackup();
1568 2279
1569 ScheduleGroupForFullUpdate(); 2280 ScheduleGroupForFullUpdate();
1570 } 2281 }
1571 2282
2283 m_dupeInProgress = false;
1572 return dupe; 2284 return dupe;
1573 } 2285 }
1574 2286
@@ -1580,7 +2292,14 @@ namespace OpenSim.Region.Framework.Scenes
1580 /// <param name="cGroupID"></param> 2292 /// <param name="cGroupID"></param>
1581 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2293 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1582 { 2294 {
1583 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2295 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2296 // give newpart a new local ID lettng old part keep same
2297 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2298 newpart.LocalId = m_scene.AllocateLocalId();
2299
2300 SetRootPart(newpart);
2301 if (userExposed)
2302 RootPart.Velocity = Vector3.Zero; // In case source is moving
1584 } 2303 }
1585 2304
1586 public void ScriptSetPhysicsStatus(bool usePhysics) 2305 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1638,27 +2357,14 @@ namespace OpenSim.Region.Framework.Scenes
1638 2357
1639 if (pa != null) 2358 if (pa != null)
1640 { 2359 {
1641 pa.AddForce(impulse, true); 2360 // false to be applied as a impulse
1642 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2361 pa.AddForce(impulse, false);
1643 }
1644 }
1645 }
1646
1647 public void applyAngularImpulse(Vector3 impulse)
1648 {
1649 PhysicsActor pa = RootPart.PhysActor;
1650
1651 if (pa != null)
1652 {
1653 if (!IsAttachment)
1654 {
1655 pa.AddAngularForce(impulse, true);
1656 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2362 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1657 } 2363 }
1658 } 2364 }
1659 } 2365 }
1660 2366
1661 public void setAngularImpulse(Vector3 impulse) 2367 public void ApplyAngularImpulse(Vector3 impulse)
1662 { 2368 {
1663 PhysicsActor pa = RootPart.PhysActor; 2369 PhysicsActor pa = RootPart.PhysActor;
1664 2370
@@ -1666,7 +2372,8 @@ namespace OpenSim.Region.Framework.Scenes
1666 { 2372 {
1667 if (!IsAttachment) 2373 if (!IsAttachment)
1668 { 2374 {
1669 pa.Torque = impulse; 2375 // false to be applied as a impulse
2376 pa.AddAngularForce(impulse, false);
1670 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2377 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1671 } 2378 }
1672 } 2379 }
@@ -1674,20 +2381,10 @@ namespace OpenSim.Region.Framework.Scenes
1674 2381
1675 public Vector3 GetTorque() 2382 public Vector3 GetTorque()
1676 { 2383 {
1677 PhysicsActor pa = RootPart.PhysActor; 2384 return RootPart.Torque;
1678
1679 if (pa != null)
1680 {
1681 if (!IsAttachment)
1682 {
1683 Vector3 torque = pa.Torque;
1684 return torque;
1685 }
1686 }
1687
1688 return Vector3.Zero;
1689 } 2385 }
1690 2386
2387 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1691 public void moveToTarget(Vector3 target, float tau) 2388 public void moveToTarget(Vector3 target, float tau)
1692 { 2389 {
1693 if (IsAttachment) 2390 if (IsAttachment)
@@ -1717,8 +2414,50 @@ namespace OpenSim.Region.Framework.Scenes
1717 2414
1718 if (pa != null) 2415 if (pa != null)
1719 pa.PIDActive = false; 2416 pa.PIDActive = false;
2417
2418 RootPart.ScheduleTerseUpdate(); // send a stop information
2419 }
2420
2421 public void rotLookAt(Quaternion target, float strength, float damping)
2422 {
2423 SceneObjectPart rootpart = m_rootPart;
2424 if (rootpart != null)
2425 {
2426 if (IsAttachment)
2427 {
2428 /*
2429 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2430 if (avatar != null)
2431 {
2432 Rotate the Av?
2433 } */
2434 }
2435 else
2436 {
2437 if (rootpart.PhysActor != null)
2438 { // APID must be implemented in your physics system for this to function.
2439 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2440 rootpart.PhysActor.APIDStrength = strength;
2441 rootpart.PhysActor.APIDDamping = damping;
2442 rootpart.PhysActor.APIDActive = true;
2443 }
2444 }
2445 }
1720 } 2446 }
2447
2448 public void stopLookAt()
2449 {
2450 SceneObjectPart rootpart = m_rootPart;
2451 if (rootpart != null)
2452 {
2453 if (rootpart.PhysActor != null)
2454 { // APID must be implemented in your physics system for this to function.
2455 rootpart.PhysActor.APIDActive = false;
2456 }
2457 }
1721 2458
2459 }
2460
1722 /// <summary> 2461 /// <summary>
1723 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2462 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1724 /// </summary> 2463 /// </summary>
@@ -1735,7 +2474,7 @@ namespace OpenSim.Region.Framework.Scenes
1735 { 2474 {
1736 pa.PIDHoverHeight = height; 2475 pa.PIDHoverHeight = height;
1737 pa.PIDHoverType = hoverType; 2476 pa.PIDHoverType = hoverType;
1738 pa.PIDTau = tau; 2477 pa.PIDHoverTau = tau;
1739 pa.PIDHoverActive = true; 2478 pa.PIDHoverActive = true;
1740 } 2479 }
1741 else 2480 else
@@ -1775,7 +2514,12 @@ namespace OpenSim.Region.Framework.Scenes
1775 /// <param name="cGroupID"></param> 2514 /// <param name="cGroupID"></param>
1776 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2515 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1777 { 2516 {
1778 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2517 // give new ID to the new part, letting old keep original
2518 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2519 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2520 newPart.LocalId = m_scene.AllocateLocalId();
2521 newPart.SetParent(this);
2522
1779 AddPart(newPart); 2523 AddPart(newPart);
1780 2524
1781 SetPartAsNonRoot(newPart); 2525 SetPartAsNonRoot(newPart);
@@ -1825,6 +2569,7 @@ namespace OpenSim.Region.Framework.Scenes
1825 2569
1826 #endregion 2570 #endregion
1827 2571
2572
1828 public override void Update() 2573 public override void Update()
1829 { 2574 {
1830 // Check that the group was not deleted before the scheduled update 2575 // Check that the group was not deleted before the scheduled update
@@ -1843,19 +2588,8 @@ namespace OpenSim.Region.Framework.Scenes
1843 // check to see if the physical position or rotation warrant an update. 2588 // check to see if the physical position or rotation warrant an update.
1844 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2589 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1845 { 2590 {
1846 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2591 // rootpart SendScheduledUpdates will check if a update is needed
1847 2592 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1848 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
1849 {
1850 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1851 lastPhysGroupPos = AbsolutePosition;
1852 }
1853
1854 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
1855 {
1856 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1857 lastPhysGroupRot = GroupRotation;
1858 }
1859 } 2593 }
1860 2594
1861 SceneObjectPart[] parts = m_parts.GetArray(); 2595 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1914,11 +2648,11 @@ namespace OpenSim.Region.Framework.Scenes
1914 /// Immediately send a full update for this scene object. 2648 /// Immediately send a full update for this scene object.
1915 /// </summary> 2649 /// </summary>
1916 public void SendGroupFullUpdate() 2650 public void SendGroupFullUpdate()
1917 { 2651 {
1918 if (IsDeleted) 2652 if (IsDeleted)
1919 return; 2653 return;
1920 2654
1921// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2655// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1922 2656
1923 RootPart.SendFullUpdateToAllClients(); 2657 RootPart.SendFullUpdateToAllClients();
1924 2658
@@ -2074,6 +2808,11 @@ namespace OpenSim.Region.Framework.Scenes
2074 // 'linkPart' == the root of the group being linked into this group 2808 // 'linkPart' == the root of the group being linked into this group
2075 SceneObjectPart linkPart = objectGroup.m_rootPart; 2809 SceneObjectPart linkPart = objectGroup.m_rootPart;
2076 2810
2811 if (m_rootPart.PhysActor != null)
2812 m_rootPart.PhysActor.Building = true;
2813 if (linkPart.PhysActor != null)
2814 linkPart.PhysActor.Building = true;
2815
2077 // physics flags from group to be applied to linked parts 2816 // physics flags from group to be applied to linked parts
2078 bool grpusephys = UsesPhysics; 2817 bool grpusephys = UsesPhysics;
2079 bool grptemporary = IsTemporary; 2818 bool grptemporary = IsTemporary;
@@ -2099,12 +2838,12 @@ namespace OpenSim.Region.Framework.Scenes
2099 Vector3 axPos = linkPart.OffsetPosition; 2838 Vector3 axPos = linkPart.OffsetPosition;
2100 // Rotate the linking root SOP's position to be relative to the new root prim 2839 // Rotate the linking root SOP's position to be relative to the new root prim
2101 Quaternion parentRot = m_rootPart.RotationOffset; 2840 Quaternion parentRot = m_rootPart.RotationOffset;
2102 axPos *= Quaternion.Inverse(parentRot); 2841 axPos *= Quaternion.Conjugate(parentRot);
2103 linkPart.OffsetPosition = axPos; 2842 linkPart.OffsetPosition = axPos;
2104 2843
2105 // Make the linking root SOP's rotation relative to the new root prim 2844 // Make the linking root SOP's rotation relative to the new root prim
2106 Quaternion oldRot = linkPart.RotationOffset; 2845 Quaternion oldRot = linkPart.RotationOffset;
2107 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2846 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2108 linkPart.RotationOffset = newRot; 2847 linkPart.RotationOffset = newRot;
2109 2848
2110 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2849 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2138,7 +2877,7 @@ namespace OpenSim.Region.Framework.Scenes
2138 linkPart.CreateSelected = true; 2877 linkPart.CreateSelected = true;
2139 2878
2140 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2879 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2141 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2880 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2142 2881
2143 // If the added SOP is physical, also tell the physics engine about the link relationship. 2882 // If the added SOP is physical, also tell the physics engine about the link relationship.
2144 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2883 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2148,6 +2887,7 @@ namespace OpenSim.Region.Framework.Scenes
2148 } 2887 }
2149 2888
2150 linkPart.LinkNum = linkNum++; 2889 linkPart.LinkNum = linkNum++;
2890 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2151 2891
2152 // Get a list of the SOP's in the old group in order of their linknum's. 2892 // Get a list of the SOP's in the old group in order of their linknum's.
2153 SceneObjectPart[] ogParts = objectGroup.Parts; 2893 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2166,7 +2906,7 @@ namespace OpenSim.Region.Framework.Scenes
2166 2906
2167 // Update the physics flags for the newly added SOP 2907 // Update the physics flags for the newly added SOP
2168 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2908 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2169 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2909 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2170 2910
2171 // If the added SOP is physical, also tell the physics engine about the link relationship. 2911 // If the added SOP is physical, also tell the physics engine about the link relationship.
2172 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2912 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2184,7 +2924,7 @@ namespace OpenSim.Region.Framework.Scenes
2184 objectGroup.IsDeleted = true; 2924 objectGroup.IsDeleted = true;
2185 2925
2186 objectGroup.m_parts.Clear(); 2926 objectGroup.m_parts.Clear();
2187 2927
2188 // Can't do this yet since backup still makes use of the root part without any synchronization 2928 // Can't do this yet since backup still makes use of the root part without any synchronization
2189// objectGroup.m_rootPart = null; 2929// objectGroup.m_rootPart = null;
2190 2930
@@ -2198,6 +2938,9 @@ namespace OpenSim.Region.Framework.Scenes
2198 // unmoved prims! 2938 // unmoved prims!
2199 ResetChildPrimPhysicsPositions(); 2939 ResetChildPrimPhysicsPositions();
2200 2940
2941 if (m_rootPart.PhysActor != null)
2942 m_rootPart.PhysActor.Building = false;
2943
2201 //HasGroupChanged = true; 2944 //HasGroupChanged = true;
2202 //ScheduleGroupForFullUpdate(); 2945 //ScheduleGroupForFullUpdate();
2203 } 2946 }
@@ -2265,7 +3008,10 @@ namespace OpenSim.Region.Framework.Scenes
2265// m_log.DebugFormat( 3008// m_log.DebugFormat(
2266// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3009// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2267// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3010// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2268 3011
3012 if (m_rootPart.PhysActor != null)
3013 m_rootPart.PhysActor.Building = true;
3014
2269 linkPart.ClearUndoState(); 3015 linkPart.ClearUndoState();
2270 3016
2271 Vector3 worldPos = linkPart.GetWorldPosition(); 3017 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2336,6 +3082,14 @@ namespace OpenSim.Region.Framework.Scenes
2336 3082
2337 // When we delete a group, we currently have to force persist to the database if the object id has changed 3083 // When we delete a group, we currently have to force persist to the database if the object id has changed
2338 // (since delete works by deleting all rows which have a given object id) 3084 // (since delete works by deleting all rows which have a given object id)
3085
3086 // this is as it seems to be in sl now
3087 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3088 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3089
3090 if (m_rootPart.PhysActor != null)
3091 m_rootPart.PhysActor.Building = false;
3092
2339 objectGroup.HasGroupChangedDueToDelink = true; 3093 objectGroup.HasGroupChangedDueToDelink = true;
2340 3094
2341 return objectGroup; 3095 return objectGroup;
@@ -2347,6 +3101,8 @@ namespace OpenSim.Region.Framework.Scenes
2347 /// <param name="objectGroup"></param> 3101 /// <param name="objectGroup"></param>
2348 public virtual void DetachFromBackup() 3102 public virtual void DetachFromBackup()
2349 { 3103 {
3104 if (m_scene != null)
3105 m_scene.SceneGraph.FireDetachFromBackup(this);
2350 if (m_isBackedUp && Scene != null) 3106 if (m_isBackedUp && Scene != null)
2351 m_scene.EventManager.OnBackup -= ProcessBackup; 3107 m_scene.EventManager.OnBackup -= ProcessBackup;
2352 3108
@@ -2367,7 +3123,8 @@ namespace OpenSim.Region.Framework.Scenes
2367 Vector3 axPos = part.OffsetPosition; 3123 Vector3 axPos = part.OffsetPosition;
2368 axPos *= parentRot; 3124 axPos *= parentRot;
2369 part.OffsetPosition = axPos; 3125 part.OffsetPosition = axPos;
2370 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3126 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3127 part.GroupPosition = newPos;
2371 part.OffsetPosition = Vector3.Zero; 3128 part.OffsetPosition = Vector3.Zero;
2372 3129
2373 // Compution our rotation to be not relative to the old parent 3130 // Compution our rotation to be not relative to the old parent
@@ -2382,7 +3139,7 @@ namespace OpenSim.Region.Framework.Scenes
2382 part.LinkNum = linkNum; 3139 part.LinkNum = linkNum;
2383 3140
2384 // Compute the new position of this SOP relative to the group position 3141 // Compute the new position of this SOP relative to the group position
2385 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3142 part.OffsetPosition = newPos - AbsolutePosition;
2386 3143
2387 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3144 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2388 // It would have the affect of setting the physics engine position multiple 3145 // It would have the affect of setting the physics engine position multiple
@@ -2392,18 +3149,19 @@ namespace OpenSim.Region.Framework.Scenes
2392 // Rotate the relative position by the rotation of the group 3149 // Rotate the relative position by the rotation of the group
2393 Quaternion rootRotation = m_rootPart.RotationOffset; 3150 Quaternion rootRotation = m_rootPart.RotationOffset;
2394 Vector3 pos = part.OffsetPosition; 3151 Vector3 pos = part.OffsetPosition;
2395 pos *= Quaternion.Inverse(rootRotation); 3152 pos *= Quaternion.Conjugate(rootRotation);
2396 part.OffsetPosition = pos; 3153 part.OffsetPosition = pos;
2397 3154
2398 // Compute the SOP's rotation relative to the rotation of the group. 3155 // Compute the SOP's rotation relative to the rotation of the group.
2399 parentRot = m_rootPart.RotationOffset; 3156 parentRot = m_rootPart.RotationOffset;
2400 oldRot = part.RotationOffset; 3157 oldRot = part.RotationOffset;
2401 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3158 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2402 part.RotationOffset = newRot; 3159 part.RotationOffset = newRot;
2403 3160
2404 // Since this SOP's state has changed, push those changes into the physics engine 3161 // Since this SOP's state has changed, push those changes into the physics engine
2405 // and the simulator. 3162 // and the simulator.
2406 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3163 // done on caller
3164// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2407 } 3165 }
2408 3166
2409 /// <summary> 3167 /// <summary>
@@ -2425,10 +3183,14 @@ namespace OpenSim.Region.Framework.Scenes
2425 { 3183 {
2426 if (!m_rootPart.BlockGrab) 3184 if (!m_rootPart.BlockGrab)
2427 { 3185 {
2428 Vector3 llmoveforce = pos - AbsolutePosition; 3186/* Vector3 llmoveforce = pos - AbsolutePosition;
2429 Vector3 grabforce = llmoveforce; 3187 Vector3 grabforce = llmoveforce;
2430 grabforce = (grabforce / 10) * pa.Mass; 3188 grabforce = (grabforce / 10) * pa.Mass;
2431 pa.AddForce(grabforce, true); 3189 */
3190 // empirically convert distance diference to a impulse
3191 Vector3 grabforce = pos - AbsolutePosition;
3192 grabforce = grabforce * (pa.Mass/ 10.0f);
3193 pa.AddForce(grabforce, false);
2432 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3194 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2433 } 3195 }
2434 } 3196 }
@@ -2624,6 +3386,8 @@ namespace OpenSim.Region.Framework.Scenes
2624 /// <param name="SetVolumeDetect"></param> 3386 /// <param name="SetVolumeDetect"></param>
2625 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3387 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2626 { 3388 {
3389 HasGroupChanged = true;
3390
2627 SceneObjectPart selectionPart = GetPart(localID); 3391 SceneObjectPart selectionPart = GetPart(localID);
2628 3392
2629 if (SetTemporary && Scene != null) 3393 if (SetTemporary && Scene != null)
@@ -2654,8 +3418,22 @@ namespace OpenSim.Region.Framework.Scenes
2654 } 3418 }
2655 } 3419 }
2656 3420
2657 for (int i = 0; i < parts.Length; i++) 3421 if (parts.Length > 1)
2658 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3422 {
3423 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3424
3425 for (int i = 0; i < parts.Length; i++)
3426 {
3427
3428 if (parts[i].UUID != m_rootPart.UUID)
3429 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3430 }
3431
3432 if (m_rootPart.PhysActor != null)
3433 m_rootPart.PhysActor.Building = false;
3434 }
3435 else
3436 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2659 } 3437 }
2660 } 3438 }
2661 3439
@@ -2668,6 +3446,17 @@ namespace OpenSim.Region.Framework.Scenes
2668 } 3446 }
2669 } 3447 }
2670 3448
3449
3450
3451 /// <summary>
3452 /// Gets the number of parts
3453 /// </summary>
3454 /// <returns></returns>
3455 public int GetPartCount()
3456 {
3457 return Parts.Count();
3458 }
3459
2671 /// <summary> 3460 /// <summary>
2672 /// Update the texture entry for this part 3461 /// Update the texture entry for this part
2673 /// </summary> 3462 /// </summary>
@@ -2705,8 +3494,24 @@ namespace OpenSim.Region.Framework.Scenes
2705 { 3494 {
2706 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3495 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2707 3496
3497 bool god = Scene.Permissions.IsGod(AgentID);
3498
3499 if (field == 1 && god)
3500 {
3501 ForEachPart(part =>
3502 {
3503 part.BaseMask = RootPart.BaseMask;
3504 });
3505 }
3506
2708 AdjustChildPrimPermissions(); 3507 AdjustChildPrimPermissions();
2709 3508
3509 if (field == 1 && god) // Base mask was set. Update all child part inventories
3510 {
3511 foreach (SceneObjectPart part in Parts)
3512 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3513 }
3514
2710 HasGroupChanged = true; 3515 HasGroupChanged = true;
2711 3516
2712 // Send the group's properties to all clients once all parts are updated 3517 // Send the group's properties to all clients once all parts are updated
@@ -2752,8 +3557,6 @@ namespace OpenSim.Region.Framework.Scenes
2752 3557
2753 PhysicsActor pa = m_rootPart.PhysActor; 3558 PhysicsActor pa = m_rootPart.PhysActor;
2754 3559
2755 RootPart.StoreUndoState(true);
2756
2757 if (Scene != null) 3560 if (Scene != null)
2758 { 3561 {
2759 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3562 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2781,7 +3584,6 @@ namespace OpenSim.Region.Framework.Scenes
2781 SceneObjectPart obPart = parts[i]; 3584 SceneObjectPart obPart = parts[i];
2782 if (obPart.UUID != m_rootPart.UUID) 3585 if (obPart.UUID != m_rootPart.UUID)
2783 { 3586 {
2784// obPart.IgnoreUndoUpdate = true;
2785 Vector3 oldSize = new Vector3(obPart.Scale); 3587 Vector3 oldSize = new Vector3(obPart.Scale);
2786 3588
2787 float f = 1.0f; 3589 float f = 1.0f;
@@ -2893,8 +3695,6 @@ namespace OpenSim.Region.Framework.Scenes
2893 z *= a; 3695 z *= a;
2894 } 3696 }
2895 } 3697 }
2896
2897// obPart.IgnoreUndoUpdate = false;
2898 } 3698 }
2899 } 3699 }
2900 } 3700 }
@@ -2904,9 +3704,7 @@ namespace OpenSim.Region.Framework.Scenes
2904 prevScale.Y *= y; 3704 prevScale.Y *= y;
2905 prevScale.Z *= z; 3705 prevScale.Z *= z;
2906 3706
2907// RootPart.IgnoreUndoUpdate = true;
2908 RootPart.Resize(prevScale); 3707 RootPart.Resize(prevScale);
2909// RootPart.IgnoreUndoUpdate = false;
2910 3708
2911 for (int i = 0; i < parts.Length; i++) 3709 for (int i = 0; i < parts.Length; i++)
2912 { 3710 {
@@ -2914,8 +3712,6 @@ namespace OpenSim.Region.Framework.Scenes
2914 3712
2915 if (obPart.UUID != m_rootPart.UUID) 3713 if (obPart.UUID != m_rootPart.UUID)
2916 { 3714 {
2917 obPart.IgnoreUndoUpdate = true;
2918
2919 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3715 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2920 currentpos.X *= x; 3716 currentpos.X *= x;
2921 currentpos.Y *= y; 3717 currentpos.Y *= y;
@@ -2928,16 +3724,12 @@ namespace OpenSim.Region.Framework.Scenes
2928 3724
2929 obPart.Resize(newSize); 3725 obPart.Resize(newSize);
2930 obPart.UpdateOffSet(currentpos); 3726 obPart.UpdateOffSet(currentpos);
2931
2932 obPart.IgnoreUndoUpdate = false;
2933 } 3727 }
2934 3728
2935// obPart.IgnoreUndoUpdate = false; 3729 HasGroupChanged = true;
2936// obPart.StoreUndoState(); 3730 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3731 ScheduleGroupForTerseUpdate();
2937 } 3732 }
2938
2939// m_log.DebugFormat(
2940// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2941 } 3733 }
2942 3734
2943 #endregion 3735 #endregion
@@ -2950,14 +3742,6 @@ namespace OpenSim.Region.Framework.Scenes
2950 /// <param name="pos"></param> 3742 /// <param name="pos"></param>
2951 public void UpdateGroupPosition(Vector3 pos) 3743 public void UpdateGroupPosition(Vector3 pos)
2952 { 3744 {
2953// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2954
2955 RootPart.StoreUndoState(true);
2956
2957// SceneObjectPart[] parts = m_parts.GetArray();
2958// for (int i = 0; i < parts.Length; i++)
2959// parts[i].StoreUndoState();
2960
2961 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3745 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2962 { 3746 {
2963 if (IsAttachment) 3747 if (IsAttachment)
@@ -2990,21 +3774,17 @@ namespace OpenSim.Region.Framework.Scenes
2990 /// </summary> 3774 /// </summary>
2991 /// <param name="pos"></param> 3775 /// <param name="pos"></param>
2992 /// <param name="localID"></param> 3776 /// <param name="localID"></param>
3777 ///
3778
2993 public void UpdateSinglePosition(Vector3 pos, uint localID) 3779 public void UpdateSinglePosition(Vector3 pos, uint localID)
2994 { 3780 {
2995 SceneObjectPart part = GetPart(localID); 3781 SceneObjectPart part = GetPart(localID);
2996 3782
2997// SceneObjectPart[] parts = m_parts.GetArray();
2998// for (int i = 0; i < parts.Length; i++)
2999// parts[i].StoreUndoState();
3000
3001 if (part != null) 3783 if (part != null)
3002 { 3784 {
3003// m_log.DebugFormat( 3785// unlock parts position change
3004// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3786 if (m_rootPart.PhysActor != null)
3005 3787 m_rootPart.PhysActor.Building = true;
3006 part.StoreUndoState(false);
3007 part.IgnoreUndoUpdate = true;
3008 3788
3009 if (part.UUID == m_rootPart.UUID) 3789 if (part.UUID == m_rootPart.UUID)
3010 { 3790 {
@@ -3015,8 +3795,10 @@ namespace OpenSim.Region.Framework.Scenes
3015 part.UpdateOffSet(pos); 3795 part.UpdateOffSet(pos);
3016 } 3796 }
3017 3797
3798 if (m_rootPart.PhysActor != null)
3799 m_rootPart.PhysActor.Building = false;
3800
3018 HasGroupChanged = true; 3801 HasGroupChanged = true;
3019 part.IgnoreUndoUpdate = false;
3020 } 3802 }
3021 } 3803 }
3022 3804
@@ -3026,13 +3808,7 @@ namespace OpenSim.Region.Framework.Scenes
3026 /// <param name="pos"></param> 3808 /// <param name="pos"></param>
3027 public void UpdateRootPosition(Vector3 pos) 3809 public void UpdateRootPosition(Vector3 pos)
3028 { 3810 {
3029// m_log.DebugFormat( 3811 // needs to be called with phys building true
3030// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3031
3032// SceneObjectPart[] parts = m_parts.GetArray();
3033// for (int i = 0; i < parts.Length; i++)
3034// parts[i].StoreUndoState();
3035
3036 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3812 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3037 Vector3 oldPos = 3813 Vector3 oldPos =
3038 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3814 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3055,7 +3831,14 @@ namespace OpenSim.Region.Framework.Scenes
3055 AbsolutePosition = newPos; 3831 AbsolutePosition = newPos;
3056 3832
3057 HasGroupChanged = true; 3833 HasGroupChanged = true;
3058 ScheduleGroupForTerseUpdate(); 3834 if (m_rootPart.Undoing)
3835 {
3836 ScheduleGroupForFullUpdate();
3837 }
3838 else
3839 {
3840 ScheduleGroupForTerseUpdate();
3841 }
3059 } 3842 }
3060 3843
3061 #endregion 3844 #endregion
@@ -3068,24 +3851,16 @@ namespace OpenSim.Region.Framework.Scenes
3068 /// <param name="rot"></param> 3851 /// <param name="rot"></param>
3069 public void UpdateGroupRotationR(Quaternion rot) 3852 public void UpdateGroupRotationR(Quaternion rot)
3070 { 3853 {
3071// m_log.DebugFormat(
3072// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3073
3074// SceneObjectPart[] parts = m_parts.GetArray();
3075// for (int i = 0; i < parts.Length; i++)
3076// parts[i].StoreUndoState();
3077
3078 m_rootPart.StoreUndoState(true);
3079
3080 m_rootPart.UpdateRotation(rot); 3854 m_rootPart.UpdateRotation(rot);
3081 3855
3856/* this is done by rootpart RotationOffset set called by UpdateRotation
3082 PhysicsActor actor = m_rootPart.PhysActor; 3857 PhysicsActor actor = m_rootPart.PhysActor;
3083 if (actor != null) 3858 if (actor != null)
3084 { 3859 {
3085 actor.Orientation = m_rootPart.RotationOffset; 3860 actor.Orientation = m_rootPart.RotationOffset;
3086 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3861 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3087 } 3862 }
3088 3863*/
3089 HasGroupChanged = true; 3864 HasGroupChanged = true;
3090 ScheduleGroupForTerseUpdate(); 3865 ScheduleGroupForTerseUpdate();
3091 } 3866 }
@@ -3097,16 +3872,6 @@ namespace OpenSim.Region.Framework.Scenes
3097 /// <param name="rot"></param> 3872 /// <param name="rot"></param>
3098 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3873 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3099 { 3874 {
3100// m_log.DebugFormat(
3101// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3102
3103// SceneObjectPart[] parts = m_parts.GetArray();
3104// for (int i = 0; i < parts.Length; i++)
3105// parts[i].StoreUndoState();
3106
3107 RootPart.StoreUndoState(true);
3108 RootPart.IgnoreUndoUpdate = true;
3109
3110 m_rootPart.UpdateRotation(rot); 3875 m_rootPart.UpdateRotation(rot);
3111 3876
3112 PhysicsActor actor = m_rootPart.PhysActor; 3877 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3125,8 +3890,6 @@ namespace OpenSim.Region.Framework.Scenes
3125 3890
3126 HasGroupChanged = true; 3891 HasGroupChanged = true;
3127 ScheduleGroupForTerseUpdate(); 3892 ScheduleGroupForTerseUpdate();
3128
3129 RootPart.IgnoreUndoUpdate = false;
3130 } 3893 }
3131 3894
3132 /// <summary> 3895 /// <summary>
@@ -3139,13 +3902,11 @@ namespace OpenSim.Region.Framework.Scenes
3139 SceneObjectPart part = GetPart(localID); 3902 SceneObjectPart part = GetPart(localID);
3140 3903
3141 SceneObjectPart[] parts = m_parts.GetArray(); 3904 SceneObjectPart[] parts = m_parts.GetArray();
3142 for (int i = 0; i < parts.Length; i++)
3143 parts[i].StoreUndoState();
3144 3905
3145 if (part != null) 3906 if (part != null)
3146 { 3907 {
3147// m_log.DebugFormat( 3908 if (m_rootPart.PhysActor != null)
3148// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3909 m_rootPart.PhysActor.Building = true;
3149 3910
3150 if (part.UUID == m_rootPart.UUID) 3911 if (part.UUID == m_rootPart.UUID)
3151 { 3912 {
@@ -3155,6 +3916,9 @@ namespace OpenSim.Region.Framework.Scenes
3155 { 3916 {
3156 part.UpdateRotation(rot); 3917 part.UpdateRotation(rot);
3157 } 3918 }
3919
3920 if (m_rootPart.PhysActor != null)
3921 m_rootPart.PhysActor.Building = false;
3158 } 3922 }
3159 } 3923 }
3160 3924
@@ -3168,12 +3932,8 @@ namespace OpenSim.Region.Framework.Scenes
3168 SceneObjectPart part = GetPart(localID); 3932 SceneObjectPart part = GetPart(localID);
3169 if (part != null) 3933 if (part != null)
3170 { 3934 {
3171// m_log.DebugFormat( 3935 if (m_rootPart.PhysActor != null)
3172// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3936 m_rootPart.PhysActor.Building = true;
3173// part.Name, part.LocalId, rot);
3174
3175 part.StoreUndoState();
3176 part.IgnoreUndoUpdate = true;
3177 3937
3178 if (part.UUID == m_rootPart.UUID) 3938 if (part.UUID == m_rootPart.UUID)
3179 { 3939 {
@@ -3186,7 +3946,8 @@ namespace OpenSim.Region.Framework.Scenes
3186 part.OffsetPosition = pos; 3946 part.OffsetPosition = pos;
3187 } 3947 }
3188 3948
3189 part.IgnoreUndoUpdate = false; 3949 if (m_rootPart.PhysActor != null)
3950 m_rootPart.PhysActor.Building = false;
3190 } 3951 }
3191 } 3952 }
3192 3953
@@ -3196,15 +3957,12 @@ namespace OpenSim.Region.Framework.Scenes
3196 /// <param name="rot"></param> 3957 /// <param name="rot"></param>
3197 public void UpdateRootRotation(Quaternion rot) 3958 public void UpdateRootRotation(Quaternion rot)
3198 { 3959 {
3199// m_log.DebugFormat( 3960 // needs to be called with phys building true
3200// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3201// Name, LocalId, rot);
3202
3203 Quaternion axRot = rot; 3961 Quaternion axRot = rot;
3204 Quaternion oldParentRot = m_rootPart.RotationOffset; 3962 Quaternion oldParentRot = m_rootPart.RotationOffset;
3205 3963
3206 m_rootPart.StoreUndoState(); 3964 //Don't use UpdateRotation because it schedules an update prematurely
3207 m_rootPart.UpdateRotation(rot); 3965 m_rootPart.RotationOffset = rot;
3208 3966
3209 PhysicsActor pa = m_rootPart.PhysActor; 3967 PhysicsActor pa = m_rootPart.PhysActor;
3210 3968
@@ -3220,35 +3978,145 @@ namespace OpenSim.Region.Framework.Scenes
3220 SceneObjectPart prim = parts[i]; 3978 SceneObjectPart prim = parts[i];
3221 if (prim.UUID != m_rootPart.UUID) 3979 if (prim.UUID != m_rootPart.UUID)
3222 { 3980 {
3223 prim.IgnoreUndoUpdate = true; 3981 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3982 NewRot = Quaternion.Inverse(axRot) * NewRot;
3983 prim.RotationOffset = NewRot;
3984
3224 Vector3 axPos = prim.OffsetPosition; 3985 Vector3 axPos = prim.OffsetPosition;
3986
3225 axPos *= oldParentRot; 3987 axPos *= oldParentRot;
3226 axPos *= Quaternion.Inverse(axRot); 3988 axPos *= Quaternion.Inverse(axRot);
3227 prim.OffsetPosition = axPos; 3989 prim.OffsetPosition = axPos;
3228 Quaternion primsRot = prim.RotationOffset; 3990 }
3229 Quaternion newRot = oldParentRot * primsRot; 3991 }
3230 newRot = Quaternion.Inverse(axRot) * newRot;
3231 prim.RotationOffset = newRot;
3232 prim.ScheduleTerseUpdate();
3233 prim.IgnoreUndoUpdate = false;
3234 }
3235 }
3236
3237// for (int i = 0; i < parts.Length; i++)
3238// {
3239// SceneObjectPart childpart = parts[i];
3240// if (childpart != m_rootPart)
3241// {
3242//// childpart.IgnoreUndoUpdate = false;
3243//// childpart.StoreUndoState();
3244// }
3245// }
3246 3992
3247 m_rootPart.ScheduleTerseUpdate(); 3993 HasGroupChanged = true;
3994 ScheduleGroupForFullUpdate();
3995 }
3248 3996
3249// m_log.DebugFormat( 3997 private enum updatetype :int
3250// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3998 {
3251// Name, LocalId, rot); 3999 none = 0,
4000 partterse = 1,
4001 partfull = 2,
4002 groupterse = 3,
4003 groupfull = 4
4004 }
4005
4006 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4007 {
4008 // TODO this still as excessive *.Schedule*Update()s
4009
4010 if (part != null && part.ParentGroup != null)
4011 {
4012 ObjectChangeType change = data.change;
4013 bool togroup = ((change & ObjectChangeType.Group) != 0);
4014 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4015
4016 SceneObjectGroup group = part.ParentGroup;
4017 PhysicsActor pha = group.RootPart.PhysActor;
4018
4019 updatetype updateType = updatetype.none;
4020
4021 if (togroup)
4022 {
4023 // related to group
4024 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4025 {
4026 if ((change & ObjectChangeType.Rotation) != 0)
4027 {
4028 group.RootPart.UpdateRotation(data.rotation);
4029 updateType = updatetype.none;
4030 }
4031 if ((change & ObjectChangeType.Position) != 0)
4032 {
4033 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4034 UpdateGroupPosition(data.position);
4035 updateType = updatetype.groupterse;
4036 }
4037 else
4038 // ugly rotation update of all parts
4039 {
4040 group.ResetChildPrimPhysicsPositions();
4041 }
4042
4043 }
4044 if ((change & ObjectChangeType.Scale) != 0)
4045 {
4046 if (pha != null)
4047 pha.Building = true;
4048
4049 group.GroupResize(data.scale);
4050 updateType = updatetype.none;
4051
4052 if (pha != null)
4053 pha.Building = false;
4054 }
4055 }
4056 else
4057 {
4058 // related to single prim in a link-set ( ie group)
4059 if (pha != null)
4060 pha.Building = true;
4061
4062 // root part is special
4063 // parts offset positions or rotations need to change also
4064
4065 if (part == group.RootPart)
4066 {
4067 if ((change & ObjectChangeType.Rotation) != 0)
4068 group.UpdateRootRotation(data.rotation);
4069 if ((change & ObjectChangeType.Position) != 0)
4070 group.UpdateRootPosition(data.position);
4071 if ((change & ObjectChangeType.Scale) != 0)
4072 part.Resize(data.scale);
4073 }
4074 else
4075 {
4076 if ((change & ObjectChangeType.Position) != 0)
4077 {
4078 part.OffsetPosition = data.position;
4079 updateType = updatetype.partterse;
4080 }
4081 if ((change & ObjectChangeType.Rotation) != 0)
4082 {
4083 part.UpdateRotation(data.rotation);
4084 updateType = updatetype.none;
4085 }
4086 if ((change & ObjectChangeType.Scale) != 0)
4087 {
4088 part.Resize(data.scale);
4089 updateType = updatetype.none;
4090 }
4091 }
4092
4093 if (pha != null)
4094 pha.Building = false;
4095 }
4096
4097 if (updateType != updatetype.none)
4098 {
4099 group.HasGroupChanged = true;
4100
4101 switch (updateType)
4102 {
4103 case updatetype.partterse:
4104 part.ScheduleTerseUpdate();
4105 break;
4106 case updatetype.partfull:
4107 part.ScheduleFullUpdate();
4108 break;
4109 case updatetype.groupterse:
4110 group.ScheduleGroupForTerseUpdate();
4111 break;
4112 case updatetype.groupfull:
4113 group.ScheduleGroupForFullUpdate();
4114 break;
4115 default:
4116 break;
4117 }
4118 }
4119 }
3252 } 4120 }
3253 4121
3254 #endregion 4122 #endregion
@@ -3289,6 +4157,8 @@ namespace OpenSim.Region.Framework.Scenes
3289 waypoint.handle = handle; 4157 waypoint.handle = handle;
3290 lock (m_rotTargets) 4158 lock (m_rotTargets)
3291 { 4159 {
4160 if (m_rotTargets.Count >= 8)
4161 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3292 m_rotTargets.Add(handle, waypoint); 4162 m_rotTargets.Add(handle, waypoint);
3293 } 4163 }
3294 m_scene.AddGroupTarget(this); 4164 m_scene.AddGroupTarget(this);
@@ -3314,6 +4184,8 @@ namespace OpenSim.Region.Framework.Scenes
3314 waypoint.handle = handle; 4184 waypoint.handle = handle;
3315 lock (m_targets) 4185 lock (m_targets)
3316 { 4186 {
4187 if (m_targets.Count >= 8)
4188 m_targets.Remove(m_targets.ElementAt(0).Key);
3317 m_targets.Add(handle, waypoint); 4189 m_targets.Add(handle, waypoint);
3318 } 4190 }
3319 m_scene.AddGroupTarget(this); 4191 m_scene.AddGroupTarget(this);
@@ -3347,10 +4219,11 @@ namespace OpenSim.Region.Framework.Scenes
3347 scriptPosTarget target = m_targets[idx]; 4219 scriptPosTarget target = m_targets[idx];
3348 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4220 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3349 { 4221 {
4222 at_target = true;
4223
3350 // trigger at_target 4224 // trigger at_target
3351 if (m_scriptListens_atTarget) 4225 if (m_scriptListens_atTarget)
3352 { 4226 {
3353 at_target = true;
3354 scriptPosTarget att = new scriptPosTarget(); 4227 scriptPosTarget att = new scriptPosTarget();
3355 att.targetPos = target.targetPos; 4228 att.targetPos = target.targetPos;
3356 att.tolerance = target.tolerance; 4229 att.tolerance = target.tolerance;
@@ -3468,11 +4341,50 @@ namespace OpenSim.Region.Framework.Scenes
3468 } 4341 }
3469 } 4342 }
3470 } 4343 }
3471 4344
4345 public Vector3 GetGeometricCenter()
4346 {
4347 // this is not real geometric center but a average of positions relative to root prim acording to
4348 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4349 // ignoring tortured prims details since sl also seems to ignore
4350 // so no real use in doing it on physics
4351
4352 Vector3 gc = Vector3.Zero;
4353
4354 int nparts = m_parts.Count;
4355 if (nparts <= 1)
4356 return gc;
4357
4358 SceneObjectPart[] parts = m_parts.GetArray();
4359 nparts = parts.Length; // just in case it changed
4360 if (nparts <= 1)
4361 return gc;
4362
4363 Quaternion parentRot = RootPart.RotationOffset;
4364 Vector3 pPos;
4365
4366 // average all parts positions
4367 for (int i = 0; i < nparts; i++)
4368 {
4369 // do it directly
4370 // gc += parts[i].GetWorldPosition();
4371 if (parts[i] != RootPart)
4372 {
4373 pPos = parts[i].OffsetPosition;
4374 gc += pPos;
4375 }
4376
4377 }
4378 gc /= nparts;
4379
4380 // relative to root:
4381// gc -= AbsolutePosition;
4382 return gc;
4383 }
4384
3472 public float GetMass() 4385 public float GetMass()
3473 { 4386 {
3474 float retmass = 0f; 4387 float retmass = 0f;
3475
3476 SceneObjectPart[] parts = m_parts.GetArray(); 4388 SceneObjectPart[] parts = m_parts.GetArray();
3477 for (int i = 0; i < parts.Length; i++) 4389 for (int i = 0; i < parts.Length; i++)
3478 retmass += parts[i].GetMass(); 4390 retmass += parts[i].GetMass();
@@ -3480,6 +4392,39 @@ namespace OpenSim.Region.Framework.Scenes
3480 return retmass; 4392 return retmass;
3481 } 4393 }
3482 4394
4395 // center of mass of full object
4396 public Vector3 GetCenterOfMass()
4397 {
4398 PhysicsActor pa = RootPart.PhysActor;
4399
4400 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4401 {
4402 // physics knows better about center of mass of physical prims
4403 Vector3 tmp = pa.CenterOfMass;
4404 return tmp;
4405 }
4406
4407 Vector3 Ptot = Vector3.Zero;
4408 float totmass = 0f;
4409 float m;
4410
4411 SceneObjectPart[] parts = m_parts.GetArray();
4412 for (int i = 0; i < parts.Length; i++)
4413 {
4414 m = parts[i].GetMass();
4415 Ptot += parts[i].GetPartCenterOfMass() * m;
4416 totmass += m;
4417 }
4418
4419 if (totmass == 0)
4420 totmass = 0;
4421 else
4422 totmass = 1 / totmass;
4423 Ptot *= totmass;
4424
4425 return Ptot;
4426 }
4427
3483 /// <summary> 4428 /// <summary>
3484 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4429 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3485 /// the physics engine can use it. 4430 /// the physics engine can use it.
@@ -3659,6 +4604,14 @@ namespace OpenSim.Region.Framework.Scenes
3659 FromItemID = uuid; 4604 FromItemID = uuid;
3660 } 4605 }
3661 4606
4607 public void ResetOwnerChangeFlag()
4608 {
4609 ForEachPart(delegate(SceneObjectPart part)
4610 {
4611 part.ResetOwnerChangeFlag();
4612 });
4613 }
4614
3662 #endregion 4615 #endregion
3663 } 4616 }
3664} 4617}