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.cs1472
1 files changed, 1223 insertions, 249 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 9e7a986..86f60bb 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,10 +542,130 @@ namespace OpenSim.Region.Framework.Scenes
455 || Scene.TestBorderCross(val, Cardinals.S)) 542 || Scene.TestBorderCross(val, Cardinals.S))
456 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 543 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
457 { 544 {
458 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 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
552 if (m_rootPart.KeyframeMotion != null)
553 m_rootPart.KeyframeMotion.StartCrossingCheck();
554
555 bool canCross = true;
556 foreach (ScenePresence av in m_linkedAvatars)
557 {
558 // We need to cross these agents. First, let's find
559 // out if any of them can't cross for some reason.
560 // We have to deny the crossing entirely if any
561 // of them are banned. Alternatively, we could
562 // unsit banned agents....
563
564
565 // We set the avatar position as being the object
566 // position to get the region to send to
567 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
568 {
569 canCross = false;
570 break;
571 }
572
573 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
574 }
575
576 if (canCross)
577 {
578 // We unparent the SP quietly so that it won't
579 // be made to stand up
580
581 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
582
583 foreach (ScenePresence av in m_linkedAvatars)
584 {
585 avtocrossInfo avinfo = new avtocrossInfo();
586 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
587 if (parentPart != null)
588 av.ParentUUID = parentPart.UUID;
589
590 avinfo.av = av;
591 avinfo.ParentID = av.ParentID;
592 avsToCross.Add(avinfo);
593
594 av.PrevSitOffset = av.OffsetPosition;
595 av.ParentID = 0;
596 }
597
598 // m_linkedAvatars.Clear();
599 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
600
601 // Normalize
602 if (val.X >= Constants.RegionSize)
603 val.X -= Constants.RegionSize;
604 if (val.Y >= Constants.RegionSize)
605 val.Y -= Constants.RegionSize;
606 if (val.X < 0)
607 val.X += Constants.RegionSize;
608 if (val.Y < 0)
609 val.Y += Constants.RegionSize;
610
611 // If it's deleted, crossing was successful
612 if (IsDeleted)
613 {
614 // foreach (ScenePresence av in m_linkedAvatars)
615 foreach (avtocrossInfo avinfo in avsToCross)
616 {
617 ScenePresence av = avinfo.av;
618 if (!av.IsInTransit) // just in case...
619 {
620 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
621
622 av.IsInTransit = true;
623
624 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
625 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
626 }
627 else
628 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
629 }
630 avsToCross.Clear();
631 return;
632 }
633 else // cross failed, put avas back ??
634 {
635 foreach (avtocrossInfo avinfo in avsToCross)
636 {
637 ScenePresence av = avinfo.av;
638 av.ParentUUID = UUID.Zero;
639 av.ParentID = avinfo.ParentID;
640// m_linkedAvatars.Add(av);
641 }
642 }
643 avsToCross.Clear();
644
645 }
646 else
647 {
648 if (m_rootPart.KeyframeMotion != null)
649 m_rootPart.KeyframeMotion.CrossingFailure();
650
651 if (RootPart.PhysActor != null)
652 {
653 RootPart.PhysActor.CrossingFailure();
654 }
655 }
656 Vector3 oldp = AbsolutePosition;
657 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
658 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
659 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
459 } 660 }
460 } 661 }
461 662
663/* don't see the need but worse don't see where is restored to false if things stay in
664 foreach (SceneObjectPart part in m_parts.GetArray())
665 {
666 part.IgnoreUndoUpdate = true;
667 }
668 */
462 if (RootPart.GetStatusSandbox()) 669 if (RootPart.GetStatusSandbox())
463 { 670 {
464 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 671 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -476,9 +683,38 @@ namespace OpenSim.Region.Framework.Scenes
476 // Restuff the new GroupPosition into each SOP of the linkset. 683 // Restuff the new GroupPosition into each SOP of the linkset.
477 // This has the affect of resetting and tainting the physics actors. 684 // This has the affect of resetting and tainting the physics actors.
478 SceneObjectPart[] parts = m_parts.GetArray(); 685 SceneObjectPart[] parts = m_parts.GetArray();
479 for (int i = 0; i < parts.Length; i++) 686 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
480 parts[i].GroupPosition = val; 687 if (m_dupeInProgress)
688 triggerScriptEvent = false;
689 foreach (SceneObjectPart part in parts)
690 {
691 part.GroupPosition = val;
692 if (triggerScriptEvent)
693 part.TriggerScriptChangedEvent(Changed.POSITION);
694 }
481 695
696/*
697 This seems not needed and should not be needed:
698 sp absolute position depends on sit part absolute position fixed above.
699 sp ParentPosition is not used anywhere.
700 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
701 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
702
703 if (!m_dupeInProgress)
704 {
705 foreach (ScenePresence av in m_linkedAvatars)
706 {
707 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
708 if (p != null && m_parts.TryGetValue(p.UUID, out p))
709 {
710 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
711 av.AbsolutePosition += offset;
712// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
713 av.SendAvatarDataToAllAgents();
714 }
715 }
716 }
717*/
482 //if (m_rootPart.PhysActor != null) 718 //if (m_rootPart.PhysActor != null)
483 //{ 719 //{
484 //m_rootPart.PhysActor.Position = 720 //m_rootPart.PhysActor.Position =
@@ -492,6 +728,40 @@ namespace OpenSim.Region.Framework.Scenes
492 } 728 }
493 } 729 }
494 730
731 public override Vector3 Velocity
732 {
733 get { return RootPart.Velocity; }
734 set { RootPart.Velocity = value; }
735 }
736
737 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
738 {
739 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
740 ScenePresence agent = icon.EndInvoke(iar);
741
742 //// If the cross was successful, this agent is a child agent
743 if (agent.IsChildAgent)
744 {
745 if (agent.ParentUUID != UUID.Zero)
746 {
747 agent.ParentPart = null;
748// agent.ParentPosition = Vector3.Zero;
749// agent.ParentUUID = UUID.Zero;
750 }
751 }
752
753 agent.ParentUUID = UUID.Zero;
754
755// agent.Reset();
756// else // Not successful
757// agent.RestoreInCurrentScene();
758
759 // In any case
760 agent.IsInTransit = false;
761
762 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
763 }
764
495 public override uint LocalId 765 public override uint LocalId
496 { 766 {
497 get { return m_rootPart.LocalId; } 767 get { return m_rootPart.LocalId; }
@@ -562,6 +832,11 @@ namespace OpenSim.Region.Framework.Scenes
562 m_isSelected = value; 832 m_isSelected = value;
563 // Tell physics engine that group is selected 833 // Tell physics engine that group is selected
564 834
835 // this is not right
836 // but ode engines should only really need to know about root part
837 // so they can put entire object simulation on hold and not colliding
838 // keep as was for now
839
565 PhysicsActor pa = m_rootPart.PhysActor; 840 PhysicsActor pa = m_rootPart.PhysActor;
566 if (pa != null) 841 if (pa != null)
567 { 842 {
@@ -578,6 +853,42 @@ namespace OpenSim.Region.Framework.Scenes
578 childPa.Selected = value; 853 childPa.Selected = value;
579 } 854 }
580 } 855 }
856 if (RootPart.KeyframeMotion != null)
857 RootPart.KeyframeMotion.Selected = value;
858 }
859 }
860
861 public void PartSelectChanged(bool partSelect)
862 {
863 // any part selected makes group selected
864 if (m_isSelected == partSelect)
865 return;
866
867 if (partSelect)
868 {
869 IsSelected = partSelect;
870// if (!IsAttachment)
871// ScheduleGroupForFullUpdate();
872 }
873 else
874 {
875 // bad bad bad 2 heavy for large linksets
876 // since viewer does send lot of (un)selects
877 // this needs to be replaced by a specific list or count ?
878 // but that will require extra code in several places
879
880 SceneObjectPart[] parts = m_parts.GetArray();
881 for (int i = 0; i < parts.Length; i++)
882 {
883 SceneObjectPart part = parts[i];
884 if (part.IsSelected)
885 return;
886 }
887 IsSelected = partSelect;
888 if (!IsAttachment)
889 {
890 ScheduleGroupForFullUpdate();
891 }
581 } 892 }
582 } 893 }
583 894
@@ -675,6 +986,7 @@ namespace OpenSim.Region.Framework.Scenes
675 /// </summary> 986 /// </summary>
676 public SceneObjectGroup() 987 public SceneObjectGroup()
677 { 988 {
989
678 } 990 }
679 991
680 /// <summary> 992 /// <summary>
@@ -692,8 +1004,8 @@ namespace OpenSim.Region.Framework.Scenes
692 /// Constructor. This object is added to the scene later via AttachToScene() 1004 /// Constructor. This object is added to the scene later via AttachToScene()
693 /// </summary> 1005 /// </summary>
694 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 1006 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
695 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 1007 {
696 { 1008 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
697 } 1009 }
698 1010
699 /// <summary> 1011 /// <summary>
@@ -728,6 +1040,9 @@ namespace OpenSim.Region.Framework.Scenes
728 /// </summary> 1040 /// </summary>
729 public virtual void AttachToBackup() 1041 public virtual void AttachToBackup()
730 { 1042 {
1043 if (IsAttachment) return;
1044 m_scene.SceneGraph.FireAttachToBackup(this);
1045
731 if (InSceneBackup) 1046 if (InSceneBackup)
732 { 1047 {
733 //m_log.DebugFormat( 1048 //m_log.DebugFormat(
@@ -758,6 +1073,11 @@ namespace OpenSim.Region.Framework.Scenes
758 for (int i = 0; i < parts.Length; i++) 1073 for (int i = 0; i < parts.Length; i++)
759 { 1074 {
760 SceneObjectPart part = parts[i]; 1075 SceneObjectPart part = parts[i];
1076 if (part.KeyframeMotion != null)
1077 {
1078 part.KeyframeMotion.UpdateSceneObject(this);
1079 }
1080
761 if (Object.ReferenceEquals(part, m_rootPart)) 1081 if (Object.ReferenceEquals(part, m_rootPart))
762 continue; 1082 continue;
763 1083
@@ -770,6 +1090,13 @@ namespace OpenSim.Region.Framework.Scenes
770 1090
771 ApplyPhysics(); 1091 ApplyPhysics();
772 1092
1093 if (RootPart.PhysActor != null)
1094 RootPart.Force = RootPart.Force;
1095 if (RootPart.PhysActor != null)
1096 RootPart.Torque = RootPart.Torque;
1097 if (RootPart.PhysActor != null)
1098 RootPart.Buoyancy = RootPart.Buoyancy;
1099
773 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1100 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
774 // for the same object with very different properties. The caller must schedule the update. 1101 // for the same object with very different properties. The caller must schedule the update.
775 //ScheduleGroupForFullUpdate(); 1102 //ScheduleGroupForFullUpdate();
@@ -785,6 +1112,10 @@ namespace OpenSim.Region.Framework.Scenes
785 EntityIntersection result = new EntityIntersection(); 1112 EntityIntersection result = new EntityIntersection();
786 1113
787 SceneObjectPart[] parts = m_parts.GetArray(); 1114 SceneObjectPart[] parts = m_parts.GetArray();
1115
1116 // Find closest hit here
1117 float idist = float.MaxValue;
1118
788 for (int i = 0; i < parts.Length; i++) 1119 for (int i = 0; i < parts.Length; i++)
789 { 1120 {
790 SceneObjectPart part = parts[i]; 1121 SceneObjectPart part = parts[i];
@@ -799,11 +1130,6 @@ namespace OpenSim.Region.Framework.Scenes
799 1130
800 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1131 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
801 1132
802 // This may need to be updated to the maximum draw distance possible..
803 // We might (and probably will) be checking for prim creation from other sims
804 // when the camera crosses the border.
805 float idist = Constants.RegionSize;
806
807 if (inter.HitTF) 1133 if (inter.HitTF)
808 { 1134 {
809 // We need to find the closest prim to return to the testcaller along the ray 1135 // We need to find the closest prim to return to the testcaller along the ray
@@ -814,10 +1140,11 @@ namespace OpenSim.Region.Framework.Scenes
814 result.obj = part; 1140 result.obj = part;
815 result.normal = inter.normal; 1141 result.normal = inter.normal;
816 result.distance = inter.distance; 1142 result.distance = inter.distance;
1143
1144 idist = inter.distance;
817 } 1145 }
818 } 1146 }
819 } 1147 }
820
821 return result; 1148 return result;
822 } 1149 }
823 1150
@@ -829,25 +1156,27 @@ namespace OpenSim.Region.Framework.Scenes
829 /// <returns></returns> 1156 /// <returns></returns>
830 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1157 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
831 { 1158 {
832 maxX = -256f; 1159 maxX = float.MinValue;
833 maxY = -256f; 1160 maxY = float.MinValue;
834 maxZ = -256f; 1161 maxZ = float.MinValue;
835 minX = 256f; 1162 minX = float.MaxValue;
836 minY = 256f; 1163 minY = float.MaxValue;
837 minZ = 8192f; 1164 minZ = float.MaxValue;
838 1165
839 SceneObjectPart[] parts = m_parts.GetArray(); 1166 SceneObjectPart[] parts = m_parts.GetArray();
840 for (int i = 0; i < parts.Length; i++) 1167 foreach (SceneObjectPart part in parts)
841 { 1168 {
842 SceneObjectPart part = parts[i];
843
844 Vector3 worldPos = part.GetWorldPosition(); 1169 Vector3 worldPos = part.GetWorldPosition();
845 Vector3 offset = worldPos - AbsolutePosition; 1170 Vector3 offset = worldPos - AbsolutePosition;
846 Quaternion worldRot; 1171 Quaternion worldRot;
847 if (part.ParentID == 0) 1172 if (part.ParentID == 0)
1173 {
848 worldRot = part.RotationOffset; 1174 worldRot = part.RotationOffset;
1175 }
849 else 1176 else
1177 {
850 worldRot = part.GetWorldRotation(); 1178 worldRot = part.GetWorldRotation();
1179 }
851 1180
852 Vector3 frontTopLeft; 1181 Vector3 frontTopLeft;
853 Vector3 frontTopRight; 1182 Vector3 frontTopRight;
@@ -859,6 +1188,8 @@ namespace OpenSim.Region.Framework.Scenes
859 Vector3 backBottomLeft; 1188 Vector3 backBottomLeft;
860 Vector3 backBottomRight; 1189 Vector3 backBottomRight;
861 1190
1191 // Vector3[] corners = new Vector3[8];
1192
862 Vector3 orig = Vector3.Zero; 1193 Vector3 orig = Vector3.Zero;
863 1194
864 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1195 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -893,6 +1224,38 @@ namespace OpenSim.Region.Framework.Scenes
893 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1224 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
894 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1225 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
895 1226
1227
1228
1229 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1230 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1231 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1232 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1233 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1234 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1235 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1236 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1237
1238 //for (int i = 0; i < 8; i++)
1239 //{
1240 // corners[i] = corners[i] * worldRot;
1241 // corners[i] += offset;
1242
1243 // if (corners[i].X > maxX)
1244 // maxX = corners[i].X;
1245 // if (corners[i].X < minX)
1246 // minX = corners[i].X;
1247
1248 // if (corners[i].Y > maxY)
1249 // maxY = corners[i].Y;
1250 // if (corners[i].Y < minY)
1251 // minY = corners[i].Y;
1252
1253 // if (corners[i].Z > maxZ)
1254 // maxZ = corners[i].Y;
1255 // if (corners[i].Z < minZ)
1256 // minZ = corners[i].Z;
1257 //}
1258
896 frontTopLeft = frontTopLeft * worldRot; 1259 frontTopLeft = frontTopLeft * worldRot;
897 frontTopRight = frontTopRight * worldRot; 1260 frontTopRight = frontTopRight * worldRot;
898 frontBottomLeft = frontBottomLeft * worldRot; 1261 frontBottomLeft = frontBottomLeft * worldRot;
@@ -914,6 +1277,15 @@ namespace OpenSim.Region.Framework.Scenes
914 backTopLeft += offset; 1277 backTopLeft += offset;
915 backTopRight += offset; 1278 backTopRight += offset;
916 1279
1280 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1281 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1282 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1283 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1284 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1285 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1286 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1287 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1288
917 if (frontTopRight.X > maxX) 1289 if (frontTopRight.X > maxX)
918 maxX = frontTopRight.X; 1290 maxX = frontTopRight.X;
919 if (frontTopLeft.X > maxX) 1291 if (frontTopLeft.X > maxX)
@@ -1057,17 +1429,118 @@ namespace OpenSim.Region.Framework.Scenes
1057 1429
1058 #endregion 1430 #endregion
1059 1431
1432 public void GetResourcesCosts(SceneObjectPart apart,
1433 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1434 {
1435 // this information may need to be cached
1436
1437 float cost;
1438 float tmpcost;
1439
1440 bool ComplexCost = false;
1441
1442 SceneObjectPart p;
1443 SceneObjectPart[] parts;
1444
1445 lock (m_parts)
1446 {
1447 parts = m_parts.GetArray();
1448 }
1449
1450 int nparts = parts.Length;
1451
1452
1453 for (int i = 0; i < nparts; i++)
1454 {
1455 p = parts[i];
1456
1457 if (p.UsesComplexCost)
1458 {
1459 ComplexCost = true;
1460 break;
1461 }
1462 }
1463
1464 if (ComplexCost)
1465 {
1466 linksetResCost = 0;
1467 linksetPhysCost = 0;
1468 partCost = 0;
1469 partPhysCost = 0;
1470
1471 for (int i = 0; i < nparts; i++)
1472 {
1473 p = parts[i];
1474
1475 cost = p.StreamingCost;
1476 tmpcost = p.SimulationCost;
1477 if (tmpcost > cost)
1478 cost = tmpcost;
1479 tmpcost = p.PhysicsCost;
1480 if (tmpcost > cost)
1481 cost = tmpcost;
1482
1483 linksetPhysCost += tmpcost;
1484 linksetResCost += cost;
1485
1486 if (p == apart)
1487 {
1488 partCost = cost;
1489 partPhysCost = tmpcost;
1490 }
1491 }
1492 }
1493 else
1494 {
1495 partPhysCost = 1.0f;
1496 partCost = 1.0f;
1497 linksetResCost = (float)nparts;
1498 linksetPhysCost = linksetResCost;
1499 }
1500 }
1501
1502 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1503 {
1504 SceneObjectPart p;
1505 SceneObjectPart[] parts;
1506
1507 lock (m_parts)
1508 {
1509 parts = m_parts.GetArray();
1510 }
1511
1512 int nparts = parts.Length;
1513
1514 PhysCost = 0;
1515 StreamCost = 0;
1516 SimulCost = 0;
1517
1518 for (int i = 0; i < nparts; i++)
1519 {
1520 p = parts[i];
1521
1522 StreamCost += p.StreamingCost;
1523 SimulCost += p.SimulationCost;
1524 PhysCost += p.PhysicsCost;
1525 }
1526 }
1527
1060 public void SaveScriptedState(XmlTextWriter writer) 1528 public void SaveScriptedState(XmlTextWriter writer)
1061 { 1529 {
1530 SaveScriptedState(writer, false);
1531 }
1532
1533 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1534 {
1062 XmlDocument doc = new XmlDocument(); 1535 XmlDocument doc = new XmlDocument();
1063 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1536 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1064 1537
1065 SceneObjectPart[] parts = m_parts.GetArray(); 1538 SceneObjectPart[] parts = m_parts.GetArray();
1066 for (int i = 0; i < parts.Length; i++) 1539 for (int i = 0; i < parts.Length; i++)
1067 { 1540 {
1068 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1541 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1069 foreach (KeyValuePair<UUID, string> kvp in pstates) 1542 foreach (KeyValuePair<UUID, string> kvp in pstates)
1070 states.Add(kvp.Key, kvp.Value); 1543 states[kvp.Key] = kvp.Value;
1071 } 1544 }
1072 1545
1073 if (states.Count > 0) 1546 if (states.Count > 0)
@@ -1087,6 +1560,169 @@ namespace OpenSim.Region.Framework.Scenes
1087 } 1560 }
1088 1561
1089 /// <summary> 1562 /// <summary>
1563 /// Add the avatar to this linkset (avatar is sat).
1564 /// </summary>
1565 /// <param name="agentID"></param>
1566 public void AddAvatar(UUID agentID)
1567 {
1568 ScenePresence presence;
1569 if (m_scene.TryGetScenePresence(agentID, out presence))
1570 {
1571 if (!m_linkedAvatars.Contains(presence))
1572 {
1573 m_linkedAvatars.Add(presence);
1574 }
1575 }
1576 }
1577
1578 /// <summary>
1579 /// Delete the avatar from this linkset (avatar is unsat).
1580 /// </summary>
1581 /// <param name="agentID"></param>
1582 public void DeleteAvatar(UUID agentID)
1583 {
1584 ScenePresence presence;
1585 if (m_scene.TryGetScenePresence(agentID, out presence))
1586 {
1587 if (m_linkedAvatars.Contains(presence))
1588 {
1589 m_linkedAvatars.Remove(presence);
1590 }
1591 }
1592 }
1593
1594 /// <summary>
1595 /// Returns the list of linked presences (avatars sat on this group)
1596 /// </summary>
1597 /// <param name="agentID"></param>
1598 public List<ScenePresence> GetLinkedAvatars()
1599 {
1600 return m_linkedAvatars;
1601 }
1602
1603 /// <summary>
1604 /// Attach this scene object to the given avatar.
1605 /// </summary>
1606 /// <param name="agentID"></param>
1607 /// <param name="attachmentpoint"></param>
1608 /// <param name="AttachOffset"></param>
1609 private void AttachToAgent(
1610 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1611 {
1612 if (avatar != null)
1613 {
1614 // don't attach attachments to child agents
1615 if (avatar.IsChildAgent) return;
1616
1617 // Remove from database and parcel prim count
1618 m_scene.DeleteFromStorage(so.UUID);
1619 m_scene.EventManager.TriggerParcelPrimCountTainted();
1620
1621 so.AttachedAvatar = avatar.UUID;
1622
1623 if (so.RootPart.PhysActor != null)
1624 {
1625 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1626 so.RootPart.PhysActor = null;
1627 }
1628
1629 so.AbsolutePosition = attachOffset;
1630 so.RootPart.AttachedPos = attachOffset;
1631 so.IsAttachment = true;
1632 so.RootPart.SetParentLocalId(avatar.LocalId);
1633 so.AttachmentPoint = attachmentpoint;
1634
1635 avatar.AddAttachment(this);
1636
1637 if (!silent)
1638 {
1639 // Killing it here will cause the client to deselect it
1640 // It then reappears on the avatar, deselected
1641 // through the full update below
1642 //
1643 if (IsSelected)
1644 {
1645 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1646 }
1647
1648 IsSelected = false; // fudge....
1649 ScheduleGroupForFullUpdate();
1650 }
1651 }
1652 else
1653 {
1654 m_log.WarnFormat(
1655 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1656 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1657 }
1658 }
1659
1660 public byte GetAttachmentPoint()
1661 {
1662 return m_rootPart.Shape.State;
1663 }
1664
1665 public void DetachToGround()
1666 {
1667 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1668 if (avatar == null)
1669 return;
1670
1671 avatar.RemoveAttachment(this);
1672
1673 Vector3 detachedpos = new Vector3(127f,127f,127f);
1674 if (avatar == null)
1675 return;
1676
1677 detachedpos = avatar.AbsolutePosition;
1678 FromItemID = UUID.Zero;
1679
1680 AbsolutePosition = detachedpos;
1681 AttachedAvatar = UUID.Zero;
1682
1683 //SceneObjectPart[] parts = m_parts.GetArray();
1684 //for (int i = 0; i < parts.Length; i++)
1685 // parts[i].AttachedAvatar = UUID.Zero;
1686
1687 m_rootPart.SetParentLocalId(0);
1688 AttachmentPoint = (byte)0;
1689 // must check if buildind should be true or false here
1690 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1691 HasGroupChanged = true;
1692 RootPart.Rezzed = DateTime.Now;
1693 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1694 AttachToBackup();
1695 m_scene.EventManager.TriggerParcelPrimCountTainted();
1696 m_rootPart.ScheduleFullUpdate();
1697 m_rootPart.ClearUndoState();
1698 }
1699
1700 public void DetachToInventoryPrep()
1701 {
1702 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1703 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1704 if (avatar != null)
1705 {
1706 //detachedpos = avatar.AbsolutePosition;
1707 avatar.RemoveAttachment(this);
1708 }
1709
1710 AttachedAvatar = UUID.Zero;
1711
1712 /*SceneObjectPart[] parts = m_parts.GetArray();
1713 for (int i = 0; i < parts.Length; i++)
1714 parts[i].AttachedAvatar = UUID.Zero;*/
1715
1716 m_rootPart.SetParentLocalId(0);
1717 //m_rootPart.SetAttachmentPoint((byte)0);
1718 IsAttachment = false;
1719 AbsolutePosition = m_rootPart.AttachedPos;
1720 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1721 //AttachToBackup();
1722 //m_rootPart.ScheduleFullUpdate();
1723 }
1724
1725 /// <summary>
1090 /// 1726 ///
1091 /// </summary> 1727 /// </summary>
1092 /// <param name="part"></param> 1728 /// <param name="part"></param>
@@ -1126,7 +1762,10 @@ namespace OpenSim.Region.Framework.Scenes
1126 public void AddPart(SceneObjectPart part) 1762 public void AddPart(SceneObjectPart part)
1127 { 1763 {
1128 part.SetParent(this); 1764 part.SetParent(this);
1129 part.LinkNum = m_parts.Add(part.UUID, part); 1765 m_parts.Add(part.UUID, part);
1766
1767 part.LinkNum = m_parts.Count;
1768
1130 if (part.LinkNum == 2) 1769 if (part.LinkNum == 2)
1131 RootPart.LinkNum = 1; 1770 RootPart.LinkNum = 1;
1132 } 1771 }
@@ -1152,6 +1791,14 @@ namespace OpenSim.Region.Framework.Scenes
1152 parts[i].UUID = UUID.Random(); 1791 parts[i].UUID = UUID.Random();
1153 } 1792 }
1154 1793
1794 // helper provided for parts.
1795 public int GetSceneMaxUndo()
1796 {
1797 if (m_scene != null)
1798 return m_scene.MaxUndoCount;
1799 return 5;
1800 }
1801
1155 // justincc: I don't believe this hack is needed any longer, especially since the physics 1802 // justincc: I don't believe this hack is needed any longer, especially since the physics
1156 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1803 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1157 // this method was preventing proper reload of scene objects. 1804 // this method was preventing proper reload of scene objects.
@@ -1209,7 +1856,7 @@ namespace OpenSim.Region.Framework.Scenes
1209// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1856// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1210// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1857// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1211 1858
1212 part.StoreUndoState(); 1859// part.StoreUndoState();
1213 part.OnGrab(offsetPos, remoteClient); 1860 part.OnGrab(offsetPos, remoteClient);
1214 } 1861 }
1215 1862
@@ -1229,28 +1876,36 @@ namespace OpenSim.Region.Framework.Scenes
1229 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1876 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1230 public void DeleteGroupFromScene(bool silent) 1877 public void DeleteGroupFromScene(bool silent)
1231 { 1878 {
1879 // We need to keep track of this state in case this group is still queued for backup.
1880 IsDeleted = true;
1881
1882 DetachFromBackup();
1883
1232 SceneObjectPart[] parts = m_parts.GetArray(); 1884 SceneObjectPart[] parts = m_parts.GetArray();
1233 for (int i = 0; i < parts.Length; i++) 1885 for (int i = 0; i < parts.Length; i++)
1234 { 1886 {
1235 SceneObjectPart part = parts[i]; 1887 SceneObjectPart part = parts[i];
1236 1888
1237 Scene.ForEachRootScenePresence(delegate(ScenePresence avatar) 1889 if (Scene != null)
1238 { 1890 {
1239 if (avatar.ParentID == LocalId) 1891 Scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
1240 avatar.StandUp();
1241
1242 if (!silent)
1243 { 1892 {
1244 part.ClearUpdateSchedule(); 1893 if (avatar.ParentID == LocalId)
1245 if (part == m_rootPart) 1894 avatar.StandUp();
1895
1896 if (!silent)
1246 { 1897 {
1247 if (!IsAttachment 1898 part.ClearUpdateSchedule();
1248 || AttachedAvatar == avatar.ControllingClient.AgentId 1899 if (part == m_rootPart)
1249 || !HasPrivateAttachmentPoint) 1900 {
1250 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1901 if (!IsAttachment
1902 || AttachedAvatar == avatar.ControllingClient.AgentId
1903 || !HasPrivateAttachmentPoint)
1904 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId });
1905 }
1251 } 1906 }
1252 } 1907 });
1253 }); 1908 }
1254 } 1909 }
1255 } 1910 }
1256 1911
@@ -1321,28 +1976,43 @@ namespace OpenSim.Region.Framework.Scenes
1321 /// </summary> 1976 /// </summary>
1322 public void ApplyPhysics() 1977 public void ApplyPhysics()
1323 { 1978 {
1324 // Apply physics to the root prim
1325 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1326
1327 // Apply physics to child prims
1328 SceneObjectPart[] parts = m_parts.GetArray(); 1979 SceneObjectPart[] parts = m_parts.GetArray();
1329 if (parts.Length > 1) 1980 if (parts.Length > 1)
1330 { 1981 {
1982 ResetChildPrimPhysicsPositions();
1983
1984 // Apply physics to the root prim
1985 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1986
1987
1331 for (int i = 0; i < parts.Length; i++) 1988 for (int i = 0; i < parts.Length; i++)
1332 { 1989 {
1333 SceneObjectPart part = parts[i]; 1990 SceneObjectPart part = parts[i];
1334 if (part.LocalId != m_rootPart.LocalId) 1991 if (part.LocalId != m_rootPart.LocalId)
1335 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1992 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1336 } 1993 }
1337
1338 // Hack to get the physics scene geometries in the right spot 1994 // Hack to get the physics scene geometries in the right spot
1339 ResetChildPrimPhysicsPositions(); 1995// ResetChildPrimPhysicsPositions();
1996 if (m_rootPart.PhysActor != null)
1997 {
1998 m_rootPart.PhysActor.Building = false;
1999 }
2000 }
2001 else
2002 {
2003 // Apply physics to the root prim
2004 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1340 } 2005 }
1341 } 2006 }
1342 2007
1343 public void SetOwnerId(UUID userId) 2008 public void SetOwnerId(UUID userId)
1344 { 2009 {
1345 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2010 ForEachPart(delegate(SceneObjectPart part)
2011 {
2012
2013 part.OwnerID = userId;
2014
2015 });
1346 } 2016 }
1347 2017
1348 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2018 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1374,11 +2044,17 @@ namespace OpenSim.Region.Framework.Scenes
1374 return; 2044 return;
1375 } 2045 }
1376 2046
2047 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2048 return;
2049
1377 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2050 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1378 // any exception propogate upwards. 2051 // any exception propogate upwards.
1379 try 2052 try
1380 { 2053 {
1381 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2054 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2055 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2056 m_scene.LoadingPrims) // Land may not be valid yet
2057
1382 { 2058 {
1383 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2059 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1384 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2060 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1405,6 +2081,7 @@ namespace OpenSim.Region.Framework.Scenes
1405 } 2081 }
1406 } 2082 }
1407 } 2083 }
2084
1408 } 2085 }
1409 2086
1410 if (m_scene.UseBackup && HasGroupChanged) 2087 if (m_scene.UseBackup && HasGroupChanged)
@@ -1412,10 +2089,30 @@ namespace OpenSim.Region.Framework.Scenes
1412 // don't backup while it's selected or you're asking for changes mid stream. 2089 // don't backup while it's selected or you're asking for changes mid stream.
1413 if (isTimeToPersist() || forcedBackup) 2090 if (isTimeToPersist() || forcedBackup)
1414 { 2091 {
2092 if (m_rootPart.PhysActor != null &&
2093 (!m_rootPart.PhysActor.IsPhysical))
2094 {
2095 // Possible ghost prim
2096 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2097 {
2098 foreach (SceneObjectPart part in m_parts.GetArray())
2099 {
2100 // Re-set physics actor positions and
2101 // orientations
2102 part.GroupPosition = m_rootPart.GroupPosition;
2103 }
2104 }
2105 }
1415// m_log.DebugFormat( 2106// m_log.DebugFormat(
1416// "[SCENE]: Storing {0}, {1} in {2}", 2107// "[SCENE]: Storing {0}, {1} in {2}",
1417// Name, UUID, m_scene.RegionInfo.RegionName); 2108// Name, UUID, m_scene.RegionInfo.RegionName);
1418 2109
2110 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2111 {
2112 RootPart.Shape.State = 0;
2113 ScheduleGroupForFullUpdate();
2114 }
2115
1419 SceneObjectGroup backup_group = Copy(false); 2116 SceneObjectGroup backup_group = Copy(false);
1420 backup_group.RootPart.Velocity = RootPart.Velocity; 2117 backup_group.RootPart.Velocity = RootPart.Velocity;
1421 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2118 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1425,6 +2122,16 @@ namespace OpenSim.Region.Framework.Scenes
1425 HasGroupChangedDueToDelink = false; 2122 HasGroupChangedDueToDelink = false;
1426 2123
1427 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2124 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2125/*
2126 backup_group.ForEachPart(delegate(SceneObjectPart part)
2127 {
2128 if (part.KeyframeMotion != null)
2129 {
2130 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2131// part.KeyframeMotion.UpdateSceneObject(this);
2132 }
2133 });
2134*/
1428 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2135 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1429 2136
1430 backup_group.ForEachPart(delegate(SceneObjectPart part) 2137 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1481,10 +2188,14 @@ namespace OpenSim.Region.Framework.Scenes
1481 /// <returns></returns> 2188 /// <returns></returns>
1482 public SceneObjectGroup Copy(bool userExposed) 2189 public SceneObjectGroup Copy(bool userExposed)
1483 { 2190 {
2191 m_dupeInProgress = true;
1484 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2192 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1485 dupe.m_isBackedUp = false; 2193 dupe.m_isBackedUp = false;
1486 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2194 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1487 2195
2196 // new group as no sitting avatars
2197 dupe.m_linkedAvatars = new List<ScenePresence>();
2198
1488 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2199 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1489 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2200 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1490 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2201 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1495,7 +2206,7 @@ namespace OpenSim.Region.Framework.Scenes
1495 // This is only necessary when userExposed is false! 2206 // This is only necessary when userExposed is false!
1496 2207
1497 bool previousAttachmentStatus = dupe.IsAttachment; 2208 bool previousAttachmentStatus = dupe.IsAttachment;
1498 2209
1499 if (!userExposed) 2210 if (!userExposed)
1500 dupe.IsAttachment = true; 2211 dupe.IsAttachment = true;
1501 2212
@@ -1508,16 +2219,17 @@ namespace OpenSim.Region.Framework.Scenes
1508 2219
1509 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2220 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1510 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2221 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2222
1511 2223
1512 if (userExposed) 2224 if (userExposed)
1513 dupe.m_rootPart.TrimPermissions(); 2225 dupe.m_rootPart.TrimPermissions();
1514 2226
1515 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2227 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1516 2228
1517 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2229 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1518 { 2230 {
1519 return p1.LinkNum.CompareTo(p2.LinkNum); 2231 return p1.LinkNum.CompareTo(p2.LinkNum);
1520 } 2232 }
1521 ); 2233 );
1522 2234
1523 foreach (SceneObjectPart part in partList) 2235 foreach (SceneObjectPart part in partList)
@@ -1527,41 +2239,56 @@ namespace OpenSim.Region.Framework.Scenes
1527 { 2239 {
1528 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2240 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1529 newPart.LinkNum = part.LinkNum; 2241 newPart.LinkNum = part.LinkNum;
1530 } 2242 if (userExposed)
2243 newPart.ParentID = dupe.m_rootPart.LocalId;
2244 }
1531 else 2245 else
1532 { 2246 {
1533 newPart = dupe.m_rootPart; 2247 newPart = dupe.m_rootPart;
1534 } 2248 }
2249/*
2250 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2251 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1535 2252
1536 // Need to duplicate the physics actor as well 2253 // Need to duplicate the physics actor as well
1537 PhysicsActor originalPartPa = part.PhysActor; 2254 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1538 if (originalPartPa != null && userExposed)
1539 { 2255 {
1540 PrimitiveBaseShape pbs = newPart.Shape; 2256 PrimitiveBaseShape pbs = newPart.Shape;
1541
1542 newPart.PhysActor 2257 newPart.PhysActor
1543 = m_scene.PhysicsScene.AddPrimShape( 2258 = m_scene.PhysicsScene.AddPrimShape(
1544 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2259 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1545 pbs, 2260 pbs,
1546 newPart.AbsolutePosition, 2261 newPart.AbsolutePosition,
1547 newPart.Scale, 2262 newPart.Scale,
1548 newPart.RotationOffset, 2263 newPart.GetWorldRotation(),
1549 originalPartPa.IsPhysical, 2264 isphys,
2265 isphan,
1550 newPart.LocalId); 2266 newPart.LocalId);
1551 2267
1552 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2268 newPart.DoPhysicsPropertyUpdate(isphys, true);
1553 } 2269 */
2270 if (userExposed)
2271 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2272// }
2273 // copy keyframemotion
2274 if (part.KeyframeMotion != null)
2275 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1554 } 2276 }
1555 2277
1556 if (userExposed) 2278 if (userExposed)
1557 { 2279 {
1558 dupe.UpdateParentIDs(); 2280// done above dupe.UpdateParentIDs();
2281
2282 if (dupe.m_rootPart.PhysActor != null)
2283 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2284
1559 dupe.HasGroupChanged = true; 2285 dupe.HasGroupChanged = true;
1560 dupe.AttachToBackup(); 2286 dupe.AttachToBackup();
1561 2287
1562 ScheduleGroupForFullUpdate(); 2288 ScheduleGroupForFullUpdate();
1563 } 2289 }
1564 2290
2291 m_dupeInProgress = false;
1565 return dupe; 2292 return dupe;
1566 } 2293 }
1567 2294
@@ -1573,11 +2300,24 @@ namespace OpenSim.Region.Framework.Scenes
1573 /// <param name="cGroupID"></param> 2300 /// <param name="cGroupID"></param>
1574 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2301 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1575 { 2302 {
1576 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2303 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2304 // give newpart a new local ID lettng old part keep same
2305 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2306 newpart.LocalId = m_scene.AllocateLocalId();
2307
2308 SetRootPart(newpart);
2309 if (userExposed)
2310 RootPart.Velocity = Vector3.Zero; // In case source is moving
1577 } 2311 }
1578 2312
1579 public void ScriptSetPhysicsStatus(bool usePhysics) 2313 public void ScriptSetPhysicsStatus(bool usePhysics)
1580 { 2314 {
2315 if (usePhysics)
2316 {
2317 if (RootPart.KeyframeMotion != null)
2318 RootPart.KeyframeMotion.Stop();
2319 RootPart.KeyframeMotion = null;
2320 }
1581 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2321 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1582 } 2322 }
1583 2323
@@ -1625,13 +2365,14 @@ namespace OpenSim.Region.Framework.Scenes
1625 2365
1626 if (pa != null) 2366 if (pa != null)
1627 { 2367 {
1628 pa.AddForce(impulse, true); 2368 // false to be applied as a impulse
2369 pa.AddForce(impulse, false);
1629 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2370 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1630 } 2371 }
1631 } 2372 }
1632 } 2373 }
1633 2374
1634 public void applyAngularImpulse(Vector3 impulse) 2375 public void ApplyAngularImpulse(Vector3 impulse)
1635 { 2376 {
1636 PhysicsActor pa = RootPart.PhysActor; 2377 PhysicsActor pa = RootPart.PhysActor;
1637 2378
@@ -1639,21 +2380,8 @@ namespace OpenSim.Region.Framework.Scenes
1639 { 2380 {
1640 if (!IsAttachment) 2381 if (!IsAttachment)
1641 { 2382 {
1642 pa.AddAngularForce(impulse, true); 2383 // false to be applied as a impulse
1643 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2384 pa.AddAngularForce(impulse, false);
1644 }
1645 }
1646 }
1647
1648 public void setAngularImpulse(Vector3 impulse)
1649 {
1650 PhysicsActor pa = RootPart.PhysActor;
1651
1652 if (pa != null)
1653 {
1654 if (!IsAttachment)
1655 {
1656 pa.Torque = impulse;
1657 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2385 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1658 } 2386 }
1659 } 2387 }
@@ -1661,20 +2389,10 @@ namespace OpenSim.Region.Framework.Scenes
1661 2389
1662 public Vector3 GetTorque() 2390 public Vector3 GetTorque()
1663 { 2391 {
1664 PhysicsActor pa = RootPart.PhysActor; 2392 return RootPart.Torque;
1665
1666 if (pa != null)
1667 {
1668 if (!IsAttachment)
1669 {
1670 Vector3 torque = pa.Torque;
1671 return torque;
1672 }
1673 }
1674
1675 return Vector3.Zero;
1676 } 2393 }
1677 2394
2395 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1678 public void moveToTarget(Vector3 target, float tau) 2396 public void moveToTarget(Vector3 target, float tau)
1679 { 2397 {
1680 if (IsAttachment) 2398 if (IsAttachment)
@@ -1704,8 +2422,50 @@ namespace OpenSim.Region.Framework.Scenes
1704 2422
1705 if (pa != null) 2423 if (pa != null)
1706 pa.PIDActive = false; 2424 pa.PIDActive = false;
2425
2426 RootPart.ScheduleTerseUpdate(); // send a stop information
1707 } 2427 }
1708 2428
2429 public void rotLookAt(Quaternion target, float strength, float damping)
2430 {
2431 SceneObjectPart rootpart = m_rootPart;
2432 if (rootpart != null)
2433 {
2434 if (IsAttachment)
2435 {
2436 /*
2437 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2438 if (avatar != null)
2439 {
2440 Rotate the Av?
2441 } */
2442 }
2443 else
2444 {
2445 if (rootpart.PhysActor != null)
2446 { // APID must be implemented in your physics system for this to function.
2447 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2448 rootpart.PhysActor.APIDStrength = strength;
2449 rootpart.PhysActor.APIDDamping = damping;
2450 rootpart.PhysActor.APIDActive = true;
2451 }
2452 }
2453 }
2454 }
2455
2456 public void stopLookAt()
2457 {
2458 SceneObjectPart rootpart = m_rootPart;
2459 if (rootpart != null)
2460 {
2461 if (rootpart.PhysActor != null)
2462 { // APID must be implemented in your physics system for this to function.
2463 rootpart.PhysActor.APIDActive = false;
2464 }
2465 }
2466
2467 }
2468
1709 /// <summary> 2469 /// <summary>
1710 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2470 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1711 /// </summary> 2471 /// </summary>
@@ -1722,7 +2482,7 @@ namespace OpenSim.Region.Framework.Scenes
1722 { 2482 {
1723 pa.PIDHoverHeight = height; 2483 pa.PIDHoverHeight = height;
1724 pa.PIDHoverType = hoverType; 2484 pa.PIDHoverType = hoverType;
1725 pa.PIDTau = tau; 2485 pa.PIDHoverTau = tau;
1726 pa.PIDHoverActive = true; 2486 pa.PIDHoverActive = true;
1727 } 2487 }
1728 else 2488 else
@@ -1762,7 +2522,12 @@ namespace OpenSim.Region.Framework.Scenes
1762 /// <param name="cGroupID"></param> 2522 /// <param name="cGroupID"></param>
1763 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2523 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1764 { 2524 {
1765 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2525 // give new ID to the new part, letting old keep original
2526 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2527 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2528 newPart.LocalId = m_scene.AllocateLocalId();
2529 newPart.SetParent(this);
2530
1766 AddPart(newPart); 2531 AddPart(newPart);
1767 2532
1768 SetPartAsNonRoot(newPart); 2533 SetPartAsNonRoot(newPart);
@@ -1812,6 +2577,7 @@ namespace OpenSim.Region.Framework.Scenes
1812 2577
1813 #endregion 2578 #endregion
1814 2579
2580
1815 public override void Update() 2581 public override void Update()
1816 { 2582 {
1817 // Check that the group was not deleted before the scheduled update 2583 // Check that the group was not deleted before the scheduled update
@@ -1830,19 +2596,8 @@ namespace OpenSim.Region.Framework.Scenes
1830 // check to see if the physical position or rotation warrant an update. 2596 // check to see if the physical position or rotation warrant an update.
1831 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2597 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
1832 { 2598 {
1833 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2599 // rootpart SendScheduledUpdates will check if a update is needed
1834 2600 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1835 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
1836 {
1837 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1838 lastPhysGroupPos = AbsolutePosition;
1839 }
1840
1841 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
1842 {
1843 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1844 lastPhysGroupRot = GroupRotation;
1845 }
1846 } 2601 }
1847 2602
1848 SceneObjectPart[] parts = m_parts.GetArray(); 2603 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1901,11 +2656,11 @@ namespace OpenSim.Region.Framework.Scenes
1901 /// Immediately send a full update for this scene object. 2656 /// Immediately send a full update for this scene object.
1902 /// </summary> 2657 /// </summary>
1903 public void SendGroupFullUpdate() 2658 public void SendGroupFullUpdate()
1904 { 2659 {
1905 if (IsDeleted) 2660 if (IsDeleted)
1906 return; 2661 return;
1907 2662
1908// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2663// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1909 2664
1910 RootPart.SendFullUpdateToAllClients(); 2665 RootPart.SendFullUpdateToAllClients();
1911 2666
@@ -2061,6 +2816,11 @@ namespace OpenSim.Region.Framework.Scenes
2061 // 'linkPart' == the root of the group being linked into this group 2816 // 'linkPart' == the root of the group being linked into this group
2062 SceneObjectPart linkPart = objectGroup.m_rootPart; 2817 SceneObjectPart linkPart = objectGroup.m_rootPart;
2063 2818
2819 if (m_rootPart.PhysActor != null)
2820 m_rootPart.PhysActor.Building = true;
2821 if (linkPart.PhysActor != null)
2822 linkPart.PhysActor.Building = true;
2823
2064 // physics flags from group to be applied to linked parts 2824 // physics flags from group to be applied to linked parts
2065 bool grpusephys = UsesPhysics; 2825 bool grpusephys = UsesPhysics;
2066 bool grptemporary = IsTemporary; 2826 bool grptemporary = IsTemporary;
@@ -2086,12 +2846,12 @@ namespace OpenSim.Region.Framework.Scenes
2086 Vector3 axPos = linkPart.OffsetPosition; 2846 Vector3 axPos = linkPart.OffsetPosition;
2087 // Rotate the linking root SOP's position to be relative to the new root prim 2847 // Rotate the linking root SOP's position to be relative to the new root prim
2088 Quaternion parentRot = m_rootPart.RotationOffset; 2848 Quaternion parentRot = m_rootPart.RotationOffset;
2089 axPos *= Quaternion.Inverse(parentRot); 2849 axPos *= Quaternion.Conjugate(parentRot);
2090 linkPart.OffsetPosition = axPos; 2850 linkPart.OffsetPosition = axPos;
2091 2851
2092 // Make the linking root SOP's rotation relative to the new root prim 2852 // Make the linking root SOP's rotation relative to the new root prim
2093 Quaternion oldRot = linkPart.RotationOffset; 2853 Quaternion oldRot = linkPart.RotationOffset;
2094 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2854 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2095 linkPart.RotationOffset = newRot; 2855 linkPart.RotationOffset = newRot;
2096 2856
2097 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2857 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2125,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
2125 linkPart.CreateSelected = true; 2885 linkPart.CreateSelected = true;
2126 2886
2127 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2887 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2128 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2888 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2129 2889
2130 // If the added SOP is physical, also tell the physics engine about the link relationship. 2890 // If the added SOP is physical, also tell the physics engine about the link relationship.
2131 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2891 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2135,6 +2895,7 @@ namespace OpenSim.Region.Framework.Scenes
2135 } 2895 }
2136 2896
2137 linkPart.LinkNum = linkNum++; 2897 linkPart.LinkNum = linkNum++;
2898 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2138 2899
2139 // Get a list of the SOP's in the old group in order of their linknum's. 2900 // Get a list of the SOP's in the old group in order of their linknum's.
2140 SceneObjectPart[] ogParts = objectGroup.Parts; 2901 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2153,7 +2914,7 @@ namespace OpenSim.Region.Framework.Scenes
2153 2914
2154 // Update the physics flags for the newly added SOP 2915 // Update the physics flags for the newly added SOP
2155 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2916 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2156 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2917 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2157 2918
2158 // If the added SOP is physical, also tell the physics engine about the link relationship. 2919 // If the added SOP is physical, also tell the physics engine about the link relationship.
2159 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2920 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2171,7 +2932,7 @@ namespace OpenSim.Region.Framework.Scenes
2171 objectGroup.IsDeleted = true; 2932 objectGroup.IsDeleted = true;
2172 2933
2173 objectGroup.m_parts.Clear(); 2934 objectGroup.m_parts.Clear();
2174 2935
2175 // Can't do this yet since backup still makes use of the root part without any synchronization 2936 // Can't do this yet since backup still makes use of the root part without any synchronization
2176// objectGroup.m_rootPart = null; 2937// objectGroup.m_rootPart = null;
2177 2938
@@ -2185,6 +2946,9 @@ namespace OpenSim.Region.Framework.Scenes
2185 // unmoved prims! 2946 // unmoved prims!
2186 ResetChildPrimPhysicsPositions(); 2947 ResetChildPrimPhysicsPositions();
2187 2948
2949 if (m_rootPart.PhysActor != null)
2950 m_rootPart.PhysActor.Building = false;
2951
2188 //HasGroupChanged = true; 2952 //HasGroupChanged = true;
2189 //ScheduleGroupForFullUpdate(); 2953 //ScheduleGroupForFullUpdate();
2190 } 2954 }
@@ -2252,7 +3016,10 @@ namespace OpenSim.Region.Framework.Scenes
2252// m_log.DebugFormat( 3016// m_log.DebugFormat(
2253// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3017// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2254// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3018// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2255 3019
3020 if (m_rootPart.PhysActor != null)
3021 m_rootPart.PhysActor.Building = true;
3022
2256 linkPart.ClearUndoState(); 3023 linkPart.ClearUndoState();
2257 3024
2258 Vector3 worldPos = linkPart.GetWorldPosition(); 3025 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2323,6 +3090,14 @@ namespace OpenSim.Region.Framework.Scenes
2323 3090
2324 // When we delete a group, we currently have to force persist to the database if the object id has changed 3091 // When we delete a group, we currently have to force persist to the database if the object id has changed
2325 // (since delete works by deleting all rows which have a given object id) 3092 // (since delete works by deleting all rows which have a given object id)
3093
3094 // this is as it seems to be in sl now
3095 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3096 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3097
3098 if (m_rootPart.PhysActor != null)
3099 m_rootPart.PhysActor.Building = false;
3100
2326 objectGroup.HasGroupChangedDueToDelink = true; 3101 objectGroup.HasGroupChangedDueToDelink = true;
2327 3102
2328 return objectGroup; 3103 return objectGroup;
@@ -2334,6 +3109,8 @@ namespace OpenSim.Region.Framework.Scenes
2334 /// <param name="objectGroup"></param> 3109 /// <param name="objectGroup"></param>
2335 public virtual void DetachFromBackup() 3110 public virtual void DetachFromBackup()
2336 { 3111 {
3112 if (m_scene != null)
3113 m_scene.SceneGraph.FireDetachFromBackup(this);
2337 if (m_isBackedUp && Scene != null) 3114 if (m_isBackedUp && Scene != null)
2338 m_scene.EventManager.OnBackup -= ProcessBackup; 3115 m_scene.EventManager.OnBackup -= ProcessBackup;
2339 3116
@@ -2354,7 +3131,8 @@ namespace OpenSim.Region.Framework.Scenes
2354 Vector3 axPos = part.OffsetPosition; 3131 Vector3 axPos = part.OffsetPosition;
2355 axPos *= parentRot; 3132 axPos *= parentRot;
2356 part.OffsetPosition = axPos; 3133 part.OffsetPosition = axPos;
2357 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3134 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3135 part.GroupPosition = newPos;
2358 part.OffsetPosition = Vector3.Zero; 3136 part.OffsetPosition = Vector3.Zero;
2359 3137
2360 // Compution our rotation to be not relative to the old parent 3138 // Compution our rotation to be not relative to the old parent
@@ -2369,7 +3147,7 @@ namespace OpenSim.Region.Framework.Scenes
2369 part.LinkNum = linkNum; 3147 part.LinkNum = linkNum;
2370 3148
2371 // Compute the new position of this SOP relative to the group position 3149 // Compute the new position of this SOP relative to the group position
2372 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3150 part.OffsetPosition = newPos - AbsolutePosition;
2373 3151
2374 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3152 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2375 // It would have the affect of setting the physics engine position multiple 3153 // It would have the affect of setting the physics engine position multiple
@@ -2379,18 +3157,19 @@ namespace OpenSim.Region.Framework.Scenes
2379 // Rotate the relative position by the rotation of the group 3157 // Rotate the relative position by the rotation of the group
2380 Quaternion rootRotation = m_rootPart.RotationOffset; 3158 Quaternion rootRotation = m_rootPart.RotationOffset;
2381 Vector3 pos = part.OffsetPosition; 3159 Vector3 pos = part.OffsetPosition;
2382 pos *= Quaternion.Inverse(rootRotation); 3160 pos *= Quaternion.Conjugate(rootRotation);
2383 part.OffsetPosition = pos; 3161 part.OffsetPosition = pos;
2384 3162
2385 // Compute the SOP's rotation relative to the rotation of the group. 3163 // Compute the SOP's rotation relative to the rotation of the group.
2386 parentRot = m_rootPart.RotationOffset; 3164 parentRot = m_rootPart.RotationOffset;
2387 oldRot = part.RotationOffset; 3165 oldRot = part.RotationOffset;
2388 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3166 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2389 part.RotationOffset = newRot; 3167 part.RotationOffset = newRot;
2390 3168
2391 // Since this SOP's state has changed, push those changes into the physics engine 3169 // Since this SOP's state has changed, push those changes into the physics engine
2392 // and the simulator. 3170 // and the simulator.
2393 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3171 // done on caller
3172// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2394 } 3173 }
2395 3174
2396 /// <summary> 3175 /// <summary>
@@ -2412,10 +3191,14 @@ namespace OpenSim.Region.Framework.Scenes
2412 { 3191 {
2413 if (!m_rootPart.BlockGrab) 3192 if (!m_rootPart.BlockGrab)
2414 { 3193 {
2415 Vector3 llmoveforce = pos - AbsolutePosition; 3194/* Vector3 llmoveforce = pos - AbsolutePosition;
2416 Vector3 grabforce = llmoveforce; 3195 Vector3 grabforce = llmoveforce;
2417 grabforce = (grabforce / 10) * pa.Mass; 3196 grabforce = (grabforce / 10) * pa.Mass;
2418 pa.AddForce(grabforce, true); 3197 */
3198 // empirically convert distance diference to a impulse
3199 Vector3 grabforce = pos - AbsolutePosition;
3200 grabforce = grabforce * (pa.Mass/ 10.0f);
3201 pa.AddForce(grabforce, false);
2419 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3202 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2420 } 3203 }
2421 } 3204 }
@@ -2611,6 +3394,8 @@ namespace OpenSim.Region.Framework.Scenes
2611 /// <param name="SetVolumeDetect"></param> 3394 /// <param name="SetVolumeDetect"></param>
2612 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3395 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2613 { 3396 {
3397 HasGroupChanged = true;
3398
2614 SceneObjectPart selectionPart = GetPart(localID); 3399 SceneObjectPart selectionPart = GetPart(localID);
2615 3400
2616 if (SetTemporary && Scene != null) 3401 if (SetTemporary && Scene != null)
@@ -2641,8 +3426,22 @@ namespace OpenSim.Region.Framework.Scenes
2641 } 3426 }
2642 } 3427 }
2643 3428
2644 for (int i = 0; i < parts.Length; i++) 3429 if (parts.Length > 1)
2645 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3430 {
3431 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3432
3433 for (int i = 0; i < parts.Length; i++)
3434 {
3435
3436 if (parts[i].UUID != m_rootPart.UUID)
3437 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3438 }
3439
3440 if (m_rootPart.PhysActor != null)
3441 m_rootPart.PhysActor.Building = false;
3442 }
3443 else
3444 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2646 } 3445 }
2647 } 3446 }
2648 3447
@@ -2655,6 +3454,17 @@ namespace OpenSim.Region.Framework.Scenes
2655 } 3454 }
2656 } 3455 }
2657 3456
3457
3458
3459 /// <summary>
3460 /// Gets the number of parts
3461 /// </summary>
3462 /// <returns></returns>
3463 public int GetPartCount()
3464 {
3465 return Parts.Count();
3466 }
3467
2658 /// <summary> 3468 /// <summary>
2659 /// Update the texture entry for this part 3469 /// Update the texture entry for this part
2660 /// </summary> 3470 /// </summary>
@@ -2681,8 +3491,8 @@ namespace OpenSim.Region.Framework.Scenes
2681 part.ClonePermissions(RootPart); 3491 part.ClonePermissions(RootPart);
2682 }); 3492 });
2683 3493
2684 uint lockMask = ~(uint)PermissionMask.Move; 3494 uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify);
2685 uint lockBit = RootPart.OwnerMask & (uint)PermissionMask.Move; 3495 uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify);
2686 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask); 3496 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
2687 RootPart.ScheduleFullUpdate(); 3497 RootPart.ScheduleFullUpdate();
2688 } 3498 }
@@ -2692,8 +3502,24 @@ namespace OpenSim.Region.Framework.Scenes
2692 { 3502 {
2693 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3503 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2694 3504
3505 bool god = Scene.Permissions.IsGod(AgentID);
3506
3507 if (field == 1 && god)
3508 {
3509 ForEachPart(part =>
3510 {
3511 part.BaseMask = RootPart.BaseMask;
3512 });
3513 }
3514
2695 AdjustChildPrimPermissions(); 3515 AdjustChildPrimPermissions();
2696 3516
3517 if (field == 1 && god) // Base mask was set. Update all child part inventories
3518 {
3519 foreach (SceneObjectPart part in Parts)
3520 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3521 }
3522
2697 HasGroupChanged = true; 3523 HasGroupChanged = true;
2698 3524
2699 // Send the group's properties to all clients once all parts are updated 3525 // Send the group's properties to all clients once all parts are updated
@@ -2739,8 +3565,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 3565
2740 PhysicsActor pa = m_rootPart.PhysActor; 3566 PhysicsActor pa = m_rootPart.PhysActor;
2741 3567
2742 RootPart.StoreUndoState(true);
2743
2744 if (Scene != null) 3568 if (Scene != null)
2745 { 3569 {
2746 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3570 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2768,7 +3592,6 @@ namespace OpenSim.Region.Framework.Scenes
2768 SceneObjectPart obPart = parts[i]; 3592 SceneObjectPart obPart = parts[i];
2769 if (obPart.UUID != m_rootPart.UUID) 3593 if (obPart.UUID != m_rootPart.UUID)
2770 { 3594 {
2771// obPart.IgnoreUndoUpdate = true;
2772 Vector3 oldSize = new Vector3(obPart.Scale); 3595 Vector3 oldSize = new Vector3(obPart.Scale);
2773 3596
2774 float f = 1.0f; 3597 float f = 1.0f;
@@ -2880,8 +3703,6 @@ namespace OpenSim.Region.Framework.Scenes
2880 z *= a; 3703 z *= a;
2881 } 3704 }
2882 } 3705 }
2883
2884// obPart.IgnoreUndoUpdate = false;
2885 } 3706 }
2886 } 3707 }
2887 } 3708 }
@@ -2891,9 +3712,7 @@ namespace OpenSim.Region.Framework.Scenes
2891 prevScale.Y *= y; 3712 prevScale.Y *= y;
2892 prevScale.Z *= z; 3713 prevScale.Z *= z;
2893 3714
2894// RootPart.IgnoreUndoUpdate = true;
2895 RootPart.Resize(prevScale); 3715 RootPart.Resize(prevScale);
2896// RootPart.IgnoreUndoUpdate = false;
2897 3716
2898 for (int i = 0; i < parts.Length; i++) 3717 for (int i = 0; i < parts.Length; i++)
2899 { 3718 {
@@ -2901,8 +3720,6 @@ namespace OpenSim.Region.Framework.Scenes
2901 3720
2902 if (obPart.UUID != m_rootPart.UUID) 3721 if (obPart.UUID != m_rootPart.UUID)
2903 { 3722 {
2904 obPart.IgnoreUndoUpdate = true;
2905
2906 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3723 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2907 currentpos.X *= x; 3724 currentpos.X *= x;
2908 currentpos.Y *= y; 3725 currentpos.Y *= y;
@@ -2915,16 +3732,12 @@ namespace OpenSim.Region.Framework.Scenes
2915 3732
2916 obPart.Resize(newSize); 3733 obPart.Resize(newSize);
2917 obPart.UpdateOffSet(currentpos); 3734 obPart.UpdateOffSet(currentpos);
2918
2919 obPart.IgnoreUndoUpdate = false;
2920 } 3735 }
2921 3736
2922// obPart.IgnoreUndoUpdate = false; 3737 HasGroupChanged = true;
2923// obPart.StoreUndoState(); 3738 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3739 ScheduleGroupForTerseUpdate();
2924 } 3740 }
2925
2926// m_log.DebugFormat(
2927// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2928 } 3741 }
2929 3742
2930 #endregion 3743 #endregion
@@ -2937,14 +3750,6 @@ namespace OpenSim.Region.Framework.Scenes
2937 /// <param name="pos"></param> 3750 /// <param name="pos"></param>
2938 public void UpdateGroupPosition(Vector3 pos) 3751 public void UpdateGroupPosition(Vector3 pos)
2939 { 3752 {
2940// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2941
2942 RootPart.StoreUndoState(true);
2943
2944// SceneObjectPart[] parts = m_parts.GetArray();
2945// for (int i = 0; i < parts.Length; i++)
2946// parts[i].StoreUndoState();
2947
2948 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3753 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2949 { 3754 {
2950 if (IsAttachment) 3755 if (IsAttachment)
@@ -2977,21 +3782,17 @@ namespace OpenSim.Region.Framework.Scenes
2977 /// </summary> 3782 /// </summary>
2978 /// <param name="pos"></param> 3783 /// <param name="pos"></param>
2979 /// <param name="localID"></param> 3784 /// <param name="localID"></param>
3785 ///
3786
2980 public void UpdateSinglePosition(Vector3 pos, uint localID) 3787 public void UpdateSinglePosition(Vector3 pos, uint localID)
2981 { 3788 {
2982 SceneObjectPart part = GetPart(localID); 3789 SceneObjectPart part = GetPart(localID);
2983 3790
2984// SceneObjectPart[] parts = m_parts.GetArray();
2985// for (int i = 0; i < parts.Length; i++)
2986// parts[i].StoreUndoState();
2987
2988 if (part != null) 3791 if (part != null)
2989 { 3792 {
2990// m_log.DebugFormat( 3793// unlock parts position change
2991// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3794 if (m_rootPart.PhysActor != null)
2992 3795 m_rootPart.PhysActor.Building = true;
2993 part.StoreUndoState(false);
2994 part.IgnoreUndoUpdate = true;
2995 3796
2996 if (part.UUID == m_rootPart.UUID) 3797 if (part.UUID == m_rootPart.UUID)
2997 { 3798 {
@@ -3002,8 +3803,10 @@ namespace OpenSim.Region.Framework.Scenes
3002 part.UpdateOffSet(pos); 3803 part.UpdateOffSet(pos);
3003 } 3804 }
3004 3805
3806 if (m_rootPart.PhysActor != null)
3807 m_rootPart.PhysActor.Building = false;
3808
3005 HasGroupChanged = true; 3809 HasGroupChanged = true;
3006 part.IgnoreUndoUpdate = false;
3007 } 3810 }
3008 } 3811 }
3009 3812
@@ -3013,13 +3816,7 @@ namespace OpenSim.Region.Framework.Scenes
3013 /// <param name="pos"></param> 3816 /// <param name="pos"></param>
3014 public void UpdateRootPosition(Vector3 pos) 3817 public void UpdateRootPosition(Vector3 pos)
3015 { 3818 {
3016// m_log.DebugFormat( 3819 // needs to be called with phys building true
3017// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3018
3019// SceneObjectPart[] parts = m_parts.GetArray();
3020// for (int i = 0; i < parts.Length; i++)
3021// parts[i].StoreUndoState();
3022
3023 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3820 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3024 Vector3 oldPos = 3821 Vector3 oldPos =
3025 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3822 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3042,7 +3839,14 @@ namespace OpenSim.Region.Framework.Scenes
3042 AbsolutePosition = newPos; 3839 AbsolutePosition = newPos;
3043 3840
3044 HasGroupChanged = true; 3841 HasGroupChanged = true;
3045 ScheduleGroupForTerseUpdate(); 3842 if (m_rootPart.Undoing)
3843 {
3844 ScheduleGroupForFullUpdate();
3845 }
3846 else
3847 {
3848 ScheduleGroupForTerseUpdate();
3849 }
3046 } 3850 }
3047 3851
3048 #endregion 3852 #endregion
@@ -3055,24 +3859,16 @@ namespace OpenSim.Region.Framework.Scenes
3055 /// <param name="rot"></param> 3859 /// <param name="rot"></param>
3056 public void UpdateGroupRotationR(Quaternion rot) 3860 public void UpdateGroupRotationR(Quaternion rot)
3057 { 3861 {
3058// m_log.DebugFormat(
3059// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3060
3061// SceneObjectPart[] parts = m_parts.GetArray();
3062// for (int i = 0; i < parts.Length; i++)
3063// parts[i].StoreUndoState();
3064
3065 m_rootPart.StoreUndoState(true);
3066
3067 m_rootPart.UpdateRotation(rot); 3862 m_rootPart.UpdateRotation(rot);
3068 3863
3864/* this is done by rootpart RotationOffset set called by UpdateRotation
3069 PhysicsActor actor = m_rootPart.PhysActor; 3865 PhysicsActor actor = m_rootPart.PhysActor;
3070 if (actor != null) 3866 if (actor != null)
3071 { 3867 {
3072 actor.Orientation = m_rootPart.RotationOffset; 3868 actor.Orientation = m_rootPart.RotationOffset;
3073 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3869 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3074 } 3870 }
3075 3871*/
3076 HasGroupChanged = true; 3872 HasGroupChanged = true;
3077 ScheduleGroupForTerseUpdate(); 3873 ScheduleGroupForTerseUpdate();
3078 } 3874 }
@@ -3084,16 +3880,6 @@ namespace OpenSim.Region.Framework.Scenes
3084 /// <param name="rot"></param> 3880 /// <param name="rot"></param>
3085 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3881 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3086 { 3882 {
3087// m_log.DebugFormat(
3088// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3089
3090// SceneObjectPart[] parts = m_parts.GetArray();
3091// for (int i = 0; i < parts.Length; i++)
3092// parts[i].StoreUndoState();
3093
3094 RootPart.StoreUndoState(true);
3095 RootPart.IgnoreUndoUpdate = true;
3096
3097 m_rootPart.UpdateRotation(rot); 3883 m_rootPart.UpdateRotation(rot);
3098 3884
3099 PhysicsActor actor = m_rootPart.PhysActor; 3885 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3112,8 +3898,6 @@ namespace OpenSim.Region.Framework.Scenes
3112 3898
3113 HasGroupChanged = true; 3899 HasGroupChanged = true;
3114 ScheduleGroupForTerseUpdate(); 3900 ScheduleGroupForTerseUpdate();
3115
3116 RootPart.IgnoreUndoUpdate = false;
3117 } 3901 }
3118 3902
3119 /// <summary> 3903 /// <summary>
@@ -3126,13 +3910,11 @@ namespace OpenSim.Region.Framework.Scenes
3126 SceneObjectPart part = GetPart(localID); 3910 SceneObjectPart part = GetPart(localID);
3127 3911
3128 SceneObjectPart[] parts = m_parts.GetArray(); 3912 SceneObjectPart[] parts = m_parts.GetArray();
3129 for (int i = 0; i < parts.Length; i++)
3130 parts[i].StoreUndoState();
3131 3913
3132 if (part != null) 3914 if (part != null)
3133 { 3915 {
3134// m_log.DebugFormat( 3916 if (m_rootPart.PhysActor != null)
3135// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3917 m_rootPart.PhysActor.Building = true;
3136 3918
3137 if (part.UUID == m_rootPart.UUID) 3919 if (part.UUID == m_rootPart.UUID)
3138 { 3920 {
@@ -3142,6 +3924,9 @@ namespace OpenSim.Region.Framework.Scenes
3142 { 3924 {
3143 part.UpdateRotation(rot); 3925 part.UpdateRotation(rot);
3144 } 3926 }
3927
3928 if (m_rootPart.PhysActor != null)
3929 m_rootPart.PhysActor.Building = false;
3145 } 3930 }
3146 } 3931 }
3147 3932
@@ -3155,12 +3940,8 @@ namespace OpenSim.Region.Framework.Scenes
3155 SceneObjectPart part = GetPart(localID); 3940 SceneObjectPart part = GetPart(localID);
3156 if (part != null) 3941 if (part != null)
3157 { 3942 {
3158// m_log.DebugFormat( 3943 if (m_rootPart.PhysActor != null)
3159// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3944 m_rootPart.PhysActor.Building = true;
3160// part.Name, part.LocalId, rot);
3161
3162 part.StoreUndoState();
3163 part.IgnoreUndoUpdate = true;
3164 3945
3165 if (part.UUID == m_rootPart.UUID) 3946 if (part.UUID == m_rootPart.UUID)
3166 { 3947 {
@@ -3173,7 +3954,8 @@ namespace OpenSim.Region.Framework.Scenes
3173 part.OffsetPosition = pos; 3954 part.OffsetPosition = pos;
3174 } 3955 }
3175 3956
3176 part.IgnoreUndoUpdate = false; 3957 if (m_rootPart.PhysActor != null)
3958 m_rootPart.PhysActor.Building = false;
3177 } 3959 }
3178 } 3960 }
3179 3961
@@ -3183,15 +3965,12 @@ namespace OpenSim.Region.Framework.Scenes
3183 /// <param name="rot"></param> 3965 /// <param name="rot"></param>
3184 public void UpdateRootRotation(Quaternion rot) 3966 public void UpdateRootRotation(Quaternion rot)
3185 { 3967 {
3186// m_log.DebugFormat( 3968 // needs to be called with phys building true
3187// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3188// Name, LocalId, rot);
3189
3190 Quaternion axRot = rot; 3969 Quaternion axRot = rot;
3191 Quaternion oldParentRot = m_rootPart.RotationOffset; 3970 Quaternion oldParentRot = m_rootPart.RotationOffset;
3192 3971
3193 m_rootPart.StoreUndoState(); 3972 //Don't use UpdateRotation because it schedules an update prematurely
3194 m_rootPart.UpdateRotation(rot); 3973 m_rootPart.RotationOffset = rot;
3195 3974
3196 PhysicsActor pa = m_rootPart.PhysActor; 3975 PhysicsActor pa = m_rootPart.PhysActor;
3197 3976
@@ -3207,35 +3986,145 @@ namespace OpenSim.Region.Framework.Scenes
3207 SceneObjectPart prim = parts[i]; 3986 SceneObjectPart prim = parts[i];
3208 if (prim.UUID != m_rootPart.UUID) 3987 if (prim.UUID != m_rootPart.UUID)
3209 { 3988 {
3210 prim.IgnoreUndoUpdate = true; 3989 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3990 NewRot = Quaternion.Inverse(axRot) * NewRot;
3991 prim.RotationOffset = NewRot;
3992
3211 Vector3 axPos = prim.OffsetPosition; 3993 Vector3 axPos = prim.OffsetPosition;
3994
3212 axPos *= oldParentRot; 3995 axPos *= oldParentRot;
3213 axPos *= Quaternion.Inverse(axRot); 3996 axPos *= Quaternion.Inverse(axRot);
3214 prim.OffsetPosition = axPos; 3997 prim.OffsetPosition = axPos;
3215 Quaternion primsRot = prim.RotationOffset; 3998 }
3216 Quaternion newRot = oldParentRot * primsRot; 3999 }
3217 newRot = Quaternion.Inverse(axRot) * newRot;
3218 prim.RotationOffset = newRot;
3219 prim.ScheduleTerseUpdate();
3220 prim.IgnoreUndoUpdate = false;
3221 }
3222 }
3223
3224// for (int i = 0; i < parts.Length; i++)
3225// {
3226// SceneObjectPart childpart = parts[i];
3227// if (childpart != m_rootPart)
3228// {
3229//// childpart.IgnoreUndoUpdate = false;
3230//// childpart.StoreUndoState();
3231// }
3232// }
3233 4000
3234 m_rootPart.ScheduleTerseUpdate(); 4001 HasGroupChanged = true;
4002 ScheduleGroupForFullUpdate();
4003 }
3235 4004
3236// m_log.DebugFormat( 4005 private enum updatetype :int
3237// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4006 {
3238// Name, LocalId, rot); 4007 none = 0,
4008 partterse = 1,
4009 partfull = 2,
4010 groupterse = 3,
4011 groupfull = 4
4012 }
4013
4014 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4015 {
4016 // TODO this still as excessive *.Schedule*Update()s
4017
4018 if (part != null && part.ParentGroup != null)
4019 {
4020 ObjectChangeType change = data.change;
4021 bool togroup = ((change & ObjectChangeType.Group) != 0);
4022 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4023
4024 SceneObjectGroup group = part.ParentGroup;
4025 PhysicsActor pha = group.RootPart.PhysActor;
4026
4027 updatetype updateType = updatetype.none;
4028
4029 if (togroup)
4030 {
4031 // related to group
4032 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4033 {
4034 if ((change & ObjectChangeType.Rotation) != 0)
4035 {
4036 group.RootPart.UpdateRotation(data.rotation);
4037 updateType = updatetype.none;
4038 }
4039 if ((change & ObjectChangeType.Position) != 0)
4040 {
4041 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4042 UpdateGroupPosition(data.position);
4043 updateType = updatetype.groupterse;
4044 }
4045 else
4046 // ugly rotation update of all parts
4047 {
4048 group.ResetChildPrimPhysicsPositions();
4049 }
4050
4051 }
4052 if ((change & ObjectChangeType.Scale) != 0)
4053 {
4054 if (pha != null)
4055 pha.Building = true;
4056
4057 group.GroupResize(data.scale);
4058 updateType = updatetype.none;
4059
4060 if (pha != null)
4061 pha.Building = false;
4062 }
4063 }
4064 else
4065 {
4066 // related to single prim in a link-set ( ie group)
4067 if (pha != null)
4068 pha.Building = true;
4069
4070 // root part is special
4071 // parts offset positions or rotations need to change also
4072
4073 if (part == group.RootPart)
4074 {
4075 if ((change & ObjectChangeType.Rotation) != 0)
4076 group.UpdateRootRotation(data.rotation);
4077 if ((change & ObjectChangeType.Position) != 0)
4078 group.UpdateRootPosition(data.position);
4079 if ((change & ObjectChangeType.Scale) != 0)
4080 part.Resize(data.scale);
4081 }
4082 else
4083 {
4084 if ((change & ObjectChangeType.Position) != 0)
4085 {
4086 part.OffsetPosition = data.position;
4087 updateType = updatetype.partterse;
4088 }
4089 if ((change & ObjectChangeType.Rotation) != 0)
4090 {
4091 part.UpdateRotation(data.rotation);
4092 updateType = updatetype.none;
4093 }
4094 if ((change & ObjectChangeType.Scale) != 0)
4095 {
4096 part.Resize(data.scale);
4097 updateType = updatetype.none;
4098 }
4099 }
4100
4101 if (pha != null)
4102 pha.Building = false;
4103 }
4104
4105 if (updateType != updatetype.none)
4106 {
4107 group.HasGroupChanged = true;
4108
4109 switch (updateType)
4110 {
4111 case updatetype.partterse:
4112 part.ScheduleTerseUpdate();
4113 break;
4114 case updatetype.partfull:
4115 part.ScheduleFullUpdate();
4116 break;
4117 case updatetype.groupterse:
4118 group.ScheduleGroupForTerseUpdate();
4119 break;
4120 case updatetype.groupfull:
4121 group.ScheduleGroupForFullUpdate();
4122 break;
4123 default:
4124 break;
4125 }
4126 }
4127 }
3239 } 4128 }
3240 4129
3241 #endregion 4130 #endregion
@@ -3276,6 +4165,8 @@ namespace OpenSim.Region.Framework.Scenes
3276 waypoint.handle = handle; 4165 waypoint.handle = handle;
3277 lock (m_rotTargets) 4166 lock (m_rotTargets)
3278 { 4167 {
4168 if (m_rotTargets.Count >= 8)
4169 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3279 m_rotTargets.Add(handle, waypoint); 4170 m_rotTargets.Add(handle, waypoint);
3280 } 4171 }
3281 m_scene.AddGroupTarget(this); 4172 m_scene.AddGroupTarget(this);
@@ -3301,6 +4192,8 @@ namespace OpenSim.Region.Framework.Scenes
3301 waypoint.handle = handle; 4192 waypoint.handle = handle;
3302 lock (m_targets) 4193 lock (m_targets)
3303 { 4194 {
4195 if (m_targets.Count >= 8)
4196 m_targets.Remove(m_targets.ElementAt(0).Key);
3304 m_targets.Add(handle, waypoint); 4197 m_targets.Add(handle, waypoint);
3305 } 4198 }
3306 m_scene.AddGroupTarget(this); 4199 m_scene.AddGroupTarget(this);
@@ -3334,10 +4227,11 @@ namespace OpenSim.Region.Framework.Scenes
3334 scriptPosTarget target = m_targets[idx]; 4227 scriptPosTarget target = m_targets[idx];
3335 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4228 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3336 { 4229 {
4230 at_target = true;
4231
3337 // trigger at_target 4232 // trigger at_target
3338 if (m_scriptListens_atTarget) 4233 if (m_scriptListens_atTarget)
3339 { 4234 {
3340 at_target = true;
3341 scriptPosTarget att = new scriptPosTarget(); 4235 scriptPosTarget att = new scriptPosTarget();
3342 att.targetPos = target.targetPos; 4236 att.targetPos = target.targetPos;
3343 att.tolerance = target.tolerance; 4237 att.tolerance = target.tolerance;
@@ -3455,11 +4349,50 @@ namespace OpenSim.Region.Framework.Scenes
3455 } 4349 }
3456 } 4350 }
3457 } 4351 }
3458 4352
4353 public Vector3 GetGeometricCenter()
4354 {
4355 // this is not real geometric center but a average of positions relative to root prim acording to
4356 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4357 // ignoring tortured prims details since sl also seems to ignore
4358 // so no real use in doing it on physics
4359
4360 Vector3 gc = Vector3.Zero;
4361
4362 int nparts = m_parts.Count;
4363 if (nparts <= 1)
4364 return gc;
4365
4366 SceneObjectPart[] parts = m_parts.GetArray();
4367 nparts = parts.Length; // just in case it changed
4368 if (nparts <= 1)
4369 return gc;
4370
4371 Quaternion parentRot = RootPart.RotationOffset;
4372 Vector3 pPos;
4373
4374 // average all parts positions
4375 for (int i = 0; i < nparts; i++)
4376 {
4377 // do it directly
4378 // gc += parts[i].GetWorldPosition();
4379 if (parts[i] != RootPart)
4380 {
4381 pPos = parts[i].OffsetPosition;
4382 gc += pPos;
4383 }
4384
4385 }
4386 gc /= nparts;
4387
4388 // relative to root:
4389// gc -= AbsolutePosition;
4390 return gc;
4391 }
4392
3459 public float GetMass() 4393 public float GetMass()
3460 { 4394 {
3461 float retmass = 0f; 4395 float retmass = 0f;
3462
3463 SceneObjectPart[] parts = m_parts.GetArray(); 4396 SceneObjectPart[] parts = m_parts.GetArray();
3464 for (int i = 0; i < parts.Length; i++) 4397 for (int i = 0; i < parts.Length; i++)
3465 retmass += parts[i].GetMass(); 4398 retmass += parts[i].GetMass();
@@ -3467,6 +4400,39 @@ namespace OpenSim.Region.Framework.Scenes
3467 return retmass; 4400 return retmass;
3468 } 4401 }
3469 4402
4403 // center of mass of full object
4404 public Vector3 GetCenterOfMass()
4405 {
4406 PhysicsActor pa = RootPart.PhysActor;
4407
4408 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4409 {
4410 // physics knows better about center of mass of physical prims
4411 Vector3 tmp = pa.CenterOfMass;
4412 return tmp;
4413 }
4414
4415 Vector3 Ptot = Vector3.Zero;
4416 float totmass = 0f;
4417 float m;
4418
4419 SceneObjectPart[] parts = m_parts.GetArray();
4420 for (int i = 0; i < parts.Length; i++)
4421 {
4422 m = parts[i].GetMass();
4423 Ptot += parts[i].GetPartCenterOfMass() * m;
4424 totmass += m;
4425 }
4426
4427 if (totmass == 0)
4428 totmass = 0;
4429 else
4430 totmass = 1 / totmass;
4431 Ptot *= totmass;
4432
4433 return Ptot;
4434 }
4435
3470 /// <summary> 4436 /// <summary>
3471 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4437 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3472 /// the physics engine can use it. 4438 /// the physics engine can use it.
@@ -3646,6 +4612,14 @@ namespace OpenSim.Region.Framework.Scenes
3646 FromItemID = uuid; 4612 FromItemID = uuid;
3647 } 4613 }
3648 4614
4615 public void ResetOwnerChangeFlag()
4616 {
4617 ForEachPart(delegate(SceneObjectPart part)
4618 {
4619 part.ResetOwnerChangeFlag();
4620 });
4621 }
4622
3649 #endregion 4623 #endregion
3650 } 4624 }
3651} 4625}