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.cs1395
1 files changed, 1179 insertions, 216 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 1fa6a75..74d2629 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;
@@ -43,6 +44,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
43 44
44namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
45{ 46{
47
46 [Flags] 48 [Flags]
47 public enum scriptEvents 49 public enum scriptEvents
48 { 50 {
@@ -106,8 +108,12 @@ namespace OpenSim.Region.Framework.Scenes
106 /// since the group's last persistent backup 108 /// since the group's last persistent backup
107 /// </summary> 109 /// </summary>
108 private bool m_hasGroupChanged = false; 110 private bool m_hasGroupChanged = false;
109 private long timeFirstChanged; 111 private long timeFirstChanged = 0;
110 private long timeLastChanged; 112 private long timeLastChanged = 0;
113 private long m_maxPersistTime = 0;
114 private long m_minPersistTime = 0;
115 private Random m_rand;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
111 117
112 /// <summary> 118 /// <summary>
113 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 119 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -124,9 +130,39 @@ namespace OpenSim.Region.Framework.Scenes
124 { 130 {
125 if (value) 131 if (value)
126 { 132 {
133 if (m_isBackedUp)
134 {
135 m_scene.SceneGraph.FireChangeBackup(this);
136 }
127 timeLastChanged = DateTime.Now.Ticks; 137 timeLastChanged = DateTime.Now.Ticks;
128 if (!m_hasGroupChanged) 138 if (!m_hasGroupChanged)
129 timeFirstChanged = DateTime.Now.Ticks; 139 timeFirstChanged = DateTime.Now.Ticks;
140 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
141 {
142 if (m_rand == null)
143 {
144 byte[] val = new byte[16];
145 m_rootPart.UUID.ToBytes(val, 0);
146 m_rand = new Random(BitConverter.ToInt32(val, 0));
147 }
148
149 if (m_scene.GetRootAgentCount() == 0)
150 {
151 //If the region is empty, this change has been made by an automated process
152 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
153
154 float factor = 1.5f + (float)(m_rand.NextDouble());
155 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
156 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
157 }
158 else
159 {
160 //If the region is not empty, we want to obey the minimum and maximum persist times
161 //but add a random factor so we stagger the object persistance a little
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
164 }
165 }
130 } 166 }
131 m_hasGroupChanged = value; 167 m_hasGroupChanged = value;
132 168
@@ -141,7 +177,7 @@ namespace OpenSim.Region.Framework.Scenes
141 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 177 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
142 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 178 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
143 /// </summary> 179 /// </summary>
144 public bool HasGroupChangedDueToDelink { get; private set; } 180 public bool HasGroupChangedDueToDelink { get; set; }
145 181
146 private bool isTimeToPersist() 182 private bool isTimeToPersist()
147 { 183 {
@@ -151,8 +187,19 @@ namespace OpenSim.Region.Framework.Scenes
151 return false; 187 return false;
152 if (m_scene.ShuttingDown) 188 if (m_scene.ShuttingDown)
153 return true; 189 return true;
190
191 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
192 {
193 m_maxPersistTime = m_scene.m_persistAfter;
194 m_minPersistTime = m_scene.m_dontPersistBefore;
195 }
196
154 long currentTime = DateTime.Now.Ticks; 197 long currentTime = DateTime.Now.Ticks;
155 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 198
199 if (timeLastChanged == 0) timeLastChanged = currentTime;
200 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
201
202 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
156 return true; 203 return true;
157 return false; 204 return false;
158 } 205 }
@@ -260,6 +307,11 @@ namespace OpenSim.Region.Framework.Scenes
260 307
261 private bool m_isBackedUp; 308 private bool m_isBackedUp;
262 309
310 public bool IsBackedUp
311 {
312 get { return m_isBackedUp; }
313 }
314
263 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 315 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
264 316
265 protected ulong m_regionHandle; 317 protected ulong m_regionHandle;
@@ -271,10 +323,10 @@ namespace OpenSim.Region.Framework.Scenes
271 323
272 private bool m_scriptListens_atTarget; 324 private bool m_scriptListens_atTarget;
273 private bool m_scriptListens_notAtTarget; 325 private bool m_scriptListens_notAtTarget;
274
275 private bool m_scriptListens_atRotTarget; 326 private bool m_scriptListens_atRotTarget;
276 private bool m_scriptListens_notAtRotTarget; 327 private bool m_scriptListens_notAtRotTarget;
277 328
329 public bool m_dupeInProgress = false;
278 internal Dictionary<UUID, string> m_savedScriptState; 330 internal Dictionary<UUID, string> m_savedScriptState;
279 331
280 #region Properties 332 #region Properties
@@ -311,6 +363,16 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_parts.Count; } 363 get { return m_parts.Count; }
312 } 364 }
313 365
366// protected Quaternion m_rotation = Quaternion.Identity;
367//
368// public virtual Quaternion Rotation
369// {
370// get { return m_rotation; }
371// set {
372// m_rotation = value;
373// }
374// }
375
314 public Quaternion GroupRotation 376 public Quaternion GroupRotation
315 { 377 {
316 get { return m_rootPart.RotationOffset; } 378 get { return m_rootPart.RotationOffset; }
@@ -417,7 +479,15 @@ namespace OpenSim.Region.Framework.Scenes
417 { 479 {
418 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 480 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
419 } 481 }
420 482
483
484
485 private struct avtocrossInfo
486 {
487 public ScenePresence av;
488 public uint ParentID;
489 }
490
421 /// <summary> 491 /// <summary>
422 /// The absolute position of this scene object in the scene 492 /// The absolute position of this scene object in the scene
423 /// </summary> 493 /// </summary>
@@ -430,14 +500,136 @@ namespace OpenSim.Region.Framework.Scenes
430 500
431 if (Scene != null) 501 if (Scene != null)
432 { 502 {
433 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 503 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
434 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 504 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
505 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
506 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
507 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
435 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 508 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
436 { 509 {
437 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 510 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
511 uint x = 0;
512 uint y = 0;
513 string version = String.Empty;
514 Vector3 newpos = Vector3.Zero;
515 OpenSim.Services.Interfaces.GridRegion destination = null;
516
517 if (m_rootPart.KeyframeMotion != null)
518 m_rootPart.KeyframeMotion.StartCrossingCheck();
519
520 bool canCross = true;
521 foreach (ScenePresence av in m_linkedAvatars)
522 {
523 // We need to cross these agents. First, let's find
524 // out if any of them can't cross for some reason.
525 // We have to deny the crossing entirely if any
526 // of them are banned. Alternatively, we could
527 // unsit banned agents....
528
529
530 // We set the avatar position as being the object
531 // position to get the region to send to
532 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
533 {
534 canCross = false;
535 break;
536 }
537
538 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
539 }
540
541 if (canCross)
542 {
543 // We unparent the SP quietly so that it won't
544 // be made to stand up
545
546 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
547
548 foreach (ScenePresence av in m_linkedAvatars)
549 {
550 avtocrossInfo avinfo = new avtocrossInfo();
551 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
552 if (parentPart != null)
553 av.ParentUUID = parentPart.UUID;
554
555 avinfo.av = av;
556 avinfo.ParentID = av.ParentID;
557 avsToCross.Add(avinfo);
558
559 av.ParentID = 0;
560 }
561
562 // m_linkedAvatars.Clear();
563 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
564
565 // Normalize
566 if (val.X >= Constants.RegionSize)
567 val.X -= Constants.RegionSize;
568 if (val.Y >= Constants.RegionSize)
569 val.Y -= Constants.RegionSize;
570 if (val.X < 0)
571 val.X += Constants.RegionSize;
572 if (val.Y < 0)
573 val.Y += Constants.RegionSize;
574
575 // If it's deleted, crossing was successful
576 if (IsDeleted)
577 {
578 // foreach (ScenePresence av in m_linkedAvatars)
579 foreach (avtocrossInfo avinfo in avsToCross)
580 {
581 ScenePresence av = avinfo.av;
582 if (!av.IsInTransit) // just in case...
583 {
584 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
585
586 av.IsInTransit = true;
587
588 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
589 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
590 }
591 else
592 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
593 }
594 avsToCross.Clear();
595 return;
596 }
597 else // cross failed, put avas back ??
598 {
599 foreach (avtocrossInfo avinfo in avsToCross)
600 {
601 ScenePresence av = avinfo.av;
602 av.ParentUUID = UUID.Zero;
603 av.ParentID = avinfo.ParentID;
604// m_linkedAvatars.Add(av);
605 }
606 }
607 avsToCross.Clear();
608
609 }
610 else
611 {
612 if (m_rootPart.KeyframeMotion != null)
613 m_rootPart.KeyframeMotion.CrossingFailure();
614
615 if (RootPart.PhysActor != null)
616 {
617 RootPart.PhysActor.CrossingFailure();
618 }
619 }
620 Vector3 oldp = AbsolutePosition;
621 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
622 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
623 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
438 } 624 }
439 } 625 }
440 626
627/* don't see the need but worse don't see where is restored to false if things stay in
628 foreach (SceneObjectPart part in m_parts.GetArray())
629 {
630 part.IgnoreUndoUpdate = true;
631 }
632 */
441 if (RootPart.GetStatusSandbox()) 633 if (RootPart.GetStatusSandbox())
442 { 634 {
443 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 635 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -455,9 +647,38 @@ namespace OpenSim.Region.Framework.Scenes
455 // Restuff the new GroupPosition into each SOP of the linkset. 647 // Restuff the new GroupPosition into each SOP of the linkset.
456 // This has the affect of resetting and tainting the physics actors. 648 // This has the affect of resetting and tainting the physics actors.
457 SceneObjectPart[] parts = m_parts.GetArray(); 649 SceneObjectPart[] parts = m_parts.GetArray();
458 for (int i = 0; i < parts.Length; i++) 650 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
459 parts[i].GroupPosition = val; 651 if (m_dupeInProgress)
652 triggerScriptEvent = false;
653 foreach (SceneObjectPart part in parts)
654 {
655 part.GroupPosition = val;
656 if (triggerScriptEvent)
657 part.TriggerScriptChangedEvent(Changed.POSITION);
658 }
460 659
660/*
661 This seems not needed and should not be needed:
662 sp absolute position depends on sit part absolute position fixed above.
663 sp ParentPosition is not used anywhere.
664 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
665 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
666
667 if (!m_dupeInProgress)
668 {
669 foreach (ScenePresence av in m_linkedAvatars)
670 {
671 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
672 if (p != null && m_parts.TryGetValue(p.UUID, out p))
673 {
674 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
675 av.AbsolutePosition += offset;
676// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
677 av.SendAvatarDataToAllAgents();
678 }
679 }
680 }
681*/
461 //if (m_rootPart.PhysActor != null) 682 //if (m_rootPart.PhysActor != null)
462 //{ 683 //{
463 //m_rootPart.PhysActor.Position = 684 //m_rootPart.PhysActor.Position =
@@ -471,6 +692,40 @@ namespace OpenSim.Region.Framework.Scenes
471 } 692 }
472 } 693 }
473 694
695 public override Vector3 Velocity
696 {
697 get { return RootPart.Velocity; }
698 set { RootPart.Velocity = value; }
699 }
700
701 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
702 {
703 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
704 ScenePresence agent = icon.EndInvoke(iar);
705
706 //// If the cross was successful, this agent is a child agent
707 if (agent.IsChildAgent)
708 {
709 if (agent.ParentUUID != UUID.Zero)
710 {
711 agent.ParentPart = null;
712// agent.ParentPosition = Vector3.Zero;
713// agent.ParentUUID = UUID.Zero;
714 }
715 }
716
717 agent.ParentUUID = UUID.Zero;
718
719// agent.Reset();
720// else // Not successful
721// agent.RestoreInCurrentScene();
722
723 // In any case
724 agent.IsInTransit = false;
725
726 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
727 }
728
474 public override uint LocalId 729 public override uint LocalId
475 { 730 {
476 get { return m_rootPart.LocalId; } 731 get { return m_rootPart.LocalId; }
@@ -541,6 +796,11 @@ namespace OpenSim.Region.Framework.Scenes
541 m_isSelected = value; 796 m_isSelected = value;
542 // Tell physics engine that group is selected 797 // Tell physics engine that group is selected
543 798
799 // this is not right
800 // but ode engines should only really need to know about root part
801 // so they can put entire object simulation on hold and not colliding
802 // keep as was for now
803
544 PhysicsActor pa = m_rootPart.PhysActor; 804 PhysicsActor pa = m_rootPart.PhysActor;
545 if (pa != null) 805 if (pa != null)
546 { 806 {
@@ -557,6 +817,42 @@ namespace OpenSim.Region.Framework.Scenes
557 childPa.Selected = value; 817 childPa.Selected = value;
558 } 818 }
559 } 819 }
820 if (RootPart.KeyframeMotion != null)
821 RootPart.KeyframeMotion.Selected = value;
822 }
823 }
824
825 public void PartSelectChanged(bool partSelect)
826 {
827 // any part selected makes group selected
828 if (m_isSelected == partSelect)
829 return;
830
831 if (partSelect)
832 {
833 IsSelected = partSelect;
834// if (!IsAttachment)
835// ScheduleGroupForFullUpdate();
836 }
837 else
838 {
839 // bad bad bad 2 heavy for large linksets
840 // since viewer does send lot of (un)selects
841 // this needs to be replaced by a specific list or count ?
842 // but that will require extra code in several places
843
844 SceneObjectPart[] parts = m_parts.GetArray();
845 for (int i = 0; i < parts.Length; i++)
846 {
847 SceneObjectPart part = parts[i];
848 if (part.IsSelected)
849 return;
850 }
851 IsSelected = partSelect;
852 if (!IsAttachment)
853 {
854 ScheduleGroupForFullUpdate();
855 }
560 } 856 }
561 } 857 }
562 858
@@ -642,6 +938,7 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 938 /// </summary>
643 public SceneObjectGroup() 939 public SceneObjectGroup()
644 { 940 {
941
645 } 942 }
646 943
647 /// <summary> 944 /// <summary>
@@ -659,8 +956,8 @@ namespace OpenSim.Region.Framework.Scenes
659 /// Constructor. This object is added to the scene later via AttachToScene() 956 /// Constructor. This object is added to the scene later via AttachToScene()
660 /// </summary> 957 /// </summary>
661 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 958 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
662 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 959 {
663 { 960 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
664 } 961 }
665 962
666 /// <summary> 963 /// <summary>
@@ -695,6 +992,9 @@ namespace OpenSim.Region.Framework.Scenes
695 /// </summary> 992 /// </summary>
696 public virtual void AttachToBackup() 993 public virtual void AttachToBackup()
697 { 994 {
995 if (IsAttachment) return;
996 m_scene.SceneGraph.FireAttachToBackup(this);
997
698 if (InSceneBackup) 998 if (InSceneBackup)
699 { 999 {
700 //m_log.DebugFormat( 1000 //m_log.DebugFormat(
@@ -737,6 +1037,13 @@ namespace OpenSim.Region.Framework.Scenes
737 1037
738 ApplyPhysics(); 1038 ApplyPhysics();
739 1039
1040 if (RootPart.PhysActor != null)
1041 RootPart.Force = RootPart.Force;
1042 if (RootPart.PhysActor != null)
1043 RootPart.Torque = RootPart.Torque;
1044 if (RootPart.PhysActor != null)
1045 RootPart.Buoyancy = RootPart.Buoyancy;
1046
740 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1047 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
741 // for the same object with very different properties. The caller must schedule the update. 1048 // for the same object with very different properties. The caller must schedule the update.
742 //ScheduleGroupForFullUpdate(); 1049 //ScheduleGroupForFullUpdate();
@@ -752,6 +1059,10 @@ namespace OpenSim.Region.Framework.Scenes
752 EntityIntersection result = new EntityIntersection(); 1059 EntityIntersection result = new EntityIntersection();
753 1060
754 SceneObjectPart[] parts = m_parts.GetArray(); 1061 SceneObjectPart[] parts = m_parts.GetArray();
1062
1063 // Find closest hit here
1064 float idist = float.MaxValue;
1065
755 for (int i = 0; i < parts.Length; i++) 1066 for (int i = 0; i < parts.Length; i++)
756 { 1067 {
757 SceneObjectPart part = parts[i]; 1068 SceneObjectPart part = parts[i];
@@ -766,11 +1077,6 @@ namespace OpenSim.Region.Framework.Scenes
766 1077
767 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1078 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
768 1079
769 // This may need to be updated to the maximum draw distance possible..
770 // We might (and probably will) be checking for prim creation from other sims
771 // when the camera crosses the border.
772 float idist = Constants.RegionSize;
773
774 if (inter.HitTF) 1080 if (inter.HitTF)
775 { 1081 {
776 // We need to find the closest prim to return to the testcaller along the ray 1082 // We need to find the closest prim to return to the testcaller along the ray
@@ -781,10 +1087,11 @@ namespace OpenSim.Region.Framework.Scenes
781 result.obj = part; 1087 result.obj = part;
782 result.normal = inter.normal; 1088 result.normal = inter.normal;
783 result.distance = inter.distance; 1089 result.distance = inter.distance;
1090
1091 idist = inter.distance;
784 } 1092 }
785 } 1093 }
786 } 1094 }
787
788 return result; 1095 return result;
789 } 1096 }
790 1097
@@ -796,25 +1103,27 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <returns></returns> 1103 /// <returns></returns>
797 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1104 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
798 { 1105 {
799 maxX = -256f; 1106 maxX = float.MinValue;
800 maxY = -256f; 1107 maxY = float.MinValue;
801 maxZ = -256f; 1108 maxZ = float.MinValue;
802 minX = 256f; 1109 minX = float.MaxValue;
803 minY = 256f; 1110 minY = float.MaxValue;
804 minZ = 8192f; 1111 minZ = float.MaxValue;
805 1112
806 SceneObjectPart[] parts = m_parts.GetArray(); 1113 SceneObjectPart[] parts = m_parts.GetArray();
807 for (int i = 0; i < parts.Length; i++) 1114 foreach (SceneObjectPart part in parts)
808 { 1115 {
809 SceneObjectPart part = parts[i];
810
811 Vector3 worldPos = part.GetWorldPosition(); 1116 Vector3 worldPos = part.GetWorldPosition();
812 Vector3 offset = worldPos - AbsolutePosition; 1117 Vector3 offset = worldPos - AbsolutePosition;
813 Quaternion worldRot; 1118 Quaternion worldRot;
814 if (part.ParentID == 0) 1119 if (part.ParentID == 0)
1120 {
815 worldRot = part.RotationOffset; 1121 worldRot = part.RotationOffset;
1122 }
816 else 1123 else
1124 {
817 worldRot = part.GetWorldRotation(); 1125 worldRot = part.GetWorldRotation();
1126 }
818 1127
819 Vector3 frontTopLeft; 1128 Vector3 frontTopLeft;
820 Vector3 frontTopRight; 1129 Vector3 frontTopRight;
@@ -826,6 +1135,8 @@ namespace OpenSim.Region.Framework.Scenes
826 Vector3 backBottomLeft; 1135 Vector3 backBottomLeft;
827 Vector3 backBottomRight; 1136 Vector3 backBottomRight;
828 1137
1138 // Vector3[] corners = new Vector3[8];
1139
829 Vector3 orig = Vector3.Zero; 1140 Vector3 orig = Vector3.Zero;
830 1141
831 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1142 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -860,6 +1171,38 @@ namespace OpenSim.Region.Framework.Scenes
860 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1171 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
861 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1172 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
862 1173
1174
1175
1176 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1177 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1178 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1179 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1180 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1181 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1182 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1183 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1184
1185 //for (int i = 0; i < 8; i++)
1186 //{
1187 // corners[i] = corners[i] * worldRot;
1188 // corners[i] += offset;
1189
1190 // if (corners[i].X > maxX)
1191 // maxX = corners[i].X;
1192 // if (corners[i].X < minX)
1193 // minX = corners[i].X;
1194
1195 // if (corners[i].Y > maxY)
1196 // maxY = corners[i].Y;
1197 // if (corners[i].Y < minY)
1198 // minY = corners[i].Y;
1199
1200 // if (corners[i].Z > maxZ)
1201 // maxZ = corners[i].Y;
1202 // if (corners[i].Z < minZ)
1203 // minZ = corners[i].Z;
1204 //}
1205
863 frontTopLeft = frontTopLeft * worldRot; 1206 frontTopLeft = frontTopLeft * worldRot;
864 frontTopRight = frontTopRight * worldRot; 1207 frontTopRight = frontTopRight * worldRot;
865 frontBottomLeft = frontBottomLeft * worldRot; 1208 frontBottomLeft = frontBottomLeft * worldRot;
@@ -881,6 +1224,15 @@ namespace OpenSim.Region.Framework.Scenes
881 backTopLeft += offset; 1224 backTopLeft += offset;
882 backTopRight += offset; 1225 backTopRight += offset;
883 1226
1227 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1228 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1229 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1230 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1231 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1232 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1233 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1234 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1235
884 if (frontTopRight.X > maxX) 1236 if (frontTopRight.X > maxX)
885 maxX = frontTopRight.X; 1237 maxX = frontTopRight.X;
886 if (frontTopLeft.X > maxX) 1238 if (frontTopLeft.X > maxX)
@@ -1024,17 +1376,118 @@ namespace OpenSim.Region.Framework.Scenes
1024 1376
1025 #endregion 1377 #endregion
1026 1378
1379 public void GetResourcesCosts(SceneObjectPart apart,
1380 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1381 {
1382 // this information may need to be cached
1383
1384 float cost;
1385 float tmpcost;
1386
1387 bool ComplexCost = false;
1388
1389 SceneObjectPart p;
1390 SceneObjectPart[] parts;
1391
1392 lock (m_parts)
1393 {
1394 parts = m_parts.GetArray();
1395 }
1396
1397 int nparts = parts.Length;
1398
1399
1400 for (int i = 0; i < nparts; i++)
1401 {
1402 p = parts[i];
1403
1404 if (p.UsesComplexCost)
1405 {
1406 ComplexCost = true;
1407 break;
1408 }
1409 }
1410
1411 if (ComplexCost)
1412 {
1413 linksetResCost = 0;
1414 linksetPhysCost = 0;
1415 partCost = 0;
1416 partPhysCost = 0;
1417
1418 for (int i = 0; i < nparts; i++)
1419 {
1420 p = parts[i];
1421
1422 cost = p.StreamingCost;
1423 tmpcost = p.SimulationCost;
1424 if (tmpcost > cost)
1425 cost = tmpcost;
1426 tmpcost = p.PhysicsCost;
1427 if (tmpcost > cost)
1428 cost = tmpcost;
1429
1430 linksetPhysCost += tmpcost;
1431 linksetResCost += cost;
1432
1433 if (p == apart)
1434 {
1435 partCost = cost;
1436 partPhysCost = tmpcost;
1437 }
1438 }
1439 }
1440 else
1441 {
1442 partPhysCost = 1.0f;
1443 partCost = 1.0f;
1444 linksetResCost = (float)nparts;
1445 linksetPhysCost = linksetResCost;
1446 }
1447 }
1448
1449 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1450 {
1451 SceneObjectPart p;
1452 SceneObjectPart[] parts;
1453
1454 lock (m_parts)
1455 {
1456 parts = m_parts.GetArray();
1457 }
1458
1459 int nparts = parts.Length;
1460
1461 PhysCost = 0;
1462 StreamCost = 0;
1463 SimulCost = 0;
1464
1465 for (int i = 0; i < nparts; i++)
1466 {
1467 p = parts[i];
1468
1469 StreamCost += p.StreamingCost;
1470 SimulCost += p.SimulationCost;
1471 PhysCost += p.PhysicsCost;
1472 }
1473 }
1474
1027 public void SaveScriptedState(XmlTextWriter writer) 1475 public void SaveScriptedState(XmlTextWriter writer)
1028 { 1476 {
1477 SaveScriptedState(writer, false);
1478 }
1479
1480 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1481 {
1029 XmlDocument doc = new XmlDocument(); 1482 XmlDocument doc = new XmlDocument();
1030 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1483 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1031 1484
1032 SceneObjectPart[] parts = m_parts.GetArray(); 1485 SceneObjectPart[] parts = m_parts.GetArray();
1033 for (int i = 0; i < parts.Length; i++) 1486 for (int i = 0; i < parts.Length; i++)
1034 { 1487 {
1035 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1488 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1036 foreach (KeyValuePair<UUID, string> kvp in pstates) 1489 foreach (KeyValuePair<UUID, string> kvp in pstates)
1037 states.Add(kvp.Key, kvp.Value); 1490 states[kvp.Key] = kvp.Value;
1038 } 1491 }
1039 1492
1040 if (states.Count > 0) 1493 if (states.Count > 0)
@@ -1054,6 +1507,169 @@ namespace OpenSim.Region.Framework.Scenes
1054 } 1507 }
1055 1508
1056 /// <summary> 1509 /// <summary>
1510 /// Add the avatar to this linkset (avatar is sat).
1511 /// </summary>
1512 /// <param name="agentID"></param>
1513 public void AddAvatar(UUID agentID)
1514 {
1515 ScenePresence presence;
1516 if (m_scene.TryGetScenePresence(agentID, out presence))
1517 {
1518 if (!m_linkedAvatars.Contains(presence))
1519 {
1520 m_linkedAvatars.Add(presence);
1521 }
1522 }
1523 }
1524
1525 /// <summary>
1526 /// Delete the avatar from this linkset (avatar is unsat).
1527 /// </summary>
1528 /// <param name="agentID"></param>
1529 public void DeleteAvatar(UUID agentID)
1530 {
1531 ScenePresence presence;
1532 if (m_scene.TryGetScenePresence(agentID, out presence))
1533 {
1534 if (m_linkedAvatars.Contains(presence))
1535 {
1536 m_linkedAvatars.Remove(presence);
1537 }
1538 }
1539 }
1540
1541 /// <summary>
1542 /// Returns the list of linked presences (avatars sat on this group)
1543 /// </summary>
1544 /// <param name="agentID"></param>
1545 public List<ScenePresence> GetLinkedAvatars()
1546 {
1547 return m_linkedAvatars;
1548 }
1549
1550 /// <summary>
1551 /// Attach this scene object to the given avatar.
1552 /// </summary>
1553 /// <param name="agentID"></param>
1554 /// <param name="attachmentpoint"></param>
1555 /// <param name="AttachOffset"></param>
1556 private void AttachToAgent(
1557 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1558 {
1559 if (avatar != null)
1560 {
1561 // don't attach attachments to child agents
1562 if (avatar.IsChildAgent) return;
1563
1564 // Remove from database and parcel prim count
1565 m_scene.DeleteFromStorage(so.UUID);
1566 m_scene.EventManager.TriggerParcelPrimCountTainted();
1567
1568 so.AttachedAvatar = avatar.UUID;
1569
1570 if (so.RootPart.PhysActor != null)
1571 {
1572 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1573 so.RootPart.PhysActor = null;
1574 }
1575
1576 so.AbsolutePosition = attachOffset;
1577 so.RootPart.AttachedPos = attachOffset;
1578 so.IsAttachment = true;
1579 so.RootPart.SetParentLocalId(avatar.LocalId);
1580 so.AttachmentPoint = attachmentpoint;
1581
1582 avatar.AddAttachment(this);
1583
1584 if (!silent)
1585 {
1586 // Killing it here will cause the client to deselect it
1587 // It then reappears on the avatar, deselected
1588 // through the full update below
1589 //
1590 if (IsSelected)
1591 {
1592 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1593 }
1594
1595 IsSelected = false; // fudge....
1596 ScheduleGroupForFullUpdate();
1597 }
1598 }
1599 else
1600 {
1601 m_log.WarnFormat(
1602 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1603 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1604 }
1605 }
1606
1607 public byte GetAttachmentPoint()
1608 {
1609 return m_rootPart.Shape.State;
1610 }
1611
1612 public void DetachToGround()
1613 {
1614 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1615 if (avatar == null)
1616 return;
1617
1618 avatar.RemoveAttachment(this);
1619
1620 Vector3 detachedpos = new Vector3(127f,127f,127f);
1621 if (avatar == null)
1622 return;
1623
1624 detachedpos = avatar.AbsolutePosition;
1625 FromItemID = UUID.Zero;
1626
1627 AbsolutePosition = detachedpos;
1628 AttachedAvatar = UUID.Zero;
1629
1630 //SceneObjectPart[] parts = m_parts.GetArray();
1631 //for (int i = 0; i < parts.Length; i++)
1632 // parts[i].AttachedAvatar = UUID.Zero;
1633
1634 m_rootPart.SetParentLocalId(0);
1635 AttachmentPoint = (byte)0;
1636 // must check if buildind should be true or false here
1637 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1638 HasGroupChanged = true;
1639 RootPart.Rezzed = DateTime.Now;
1640 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1641 AttachToBackup();
1642 m_scene.EventManager.TriggerParcelPrimCountTainted();
1643 m_rootPart.ScheduleFullUpdate();
1644 m_rootPart.ClearUndoState();
1645 }
1646
1647 public void DetachToInventoryPrep()
1648 {
1649 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1650 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1651 if (avatar != null)
1652 {
1653 //detachedpos = avatar.AbsolutePosition;
1654 avatar.RemoveAttachment(this);
1655 }
1656
1657 AttachedAvatar = UUID.Zero;
1658
1659 /*SceneObjectPart[] parts = m_parts.GetArray();
1660 for (int i = 0; i < parts.Length; i++)
1661 parts[i].AttachedAvatar = UUID.Zero;*/
1662
1663 m_rootPart.SetParentLocalId(0);
1664 //m_rootPart.SetAttachmentPoint((byte)0);
1665 IsAttachment = false;
1666 AbsolutePosition = m_rootPart.AttachedPos;
1667 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1668 //AttachToBackup();
1669 //m_rootPart.ScheduleFullUpdate();
1670 }
1671
1672 /// <summary>
1057 /// 1673 ///
1058 /// </summary> 1674 /// </summary>
1059 /// <param name="part"></param> 1675 /// <param name="part"></param>
@@ -1093,7 +1709,10 @@ namespace OpenSim.Region.Framework.Scenes
1093 public void AddPart(SceneObjectPart part) 1709 public void AddPart(SceneObjectPart part)
1094 { 1710 {
1095 part.SetParent(this); 1711 part.SetParent(this);
1096 part.LinkNum = m_parts.Add(part.UUID, part); 1712 m_parts.Add(part.UUID, part);
1713
1714 part.LinkNum = m_parts.Count;
1715
1097 if (part.LinkNum == 2) 1716 if (part.LinkNum == 2)
1098 RootPart.LinkNum = 1; 1717 RootPart.LinkNum = 1;
1099 } 1718 }
@@ -1119,6 +1738,14 @@ namespace OpenSim.Region.Framework.Scenes
1119 parts[i].UUID = UUID.Random(); 1738 parts[i].UUID = UUID.Random();
1120 } 1739 }
1121 1740
1741 // helper provided for parts.
1742 public int GetSceneMaxUndo()
1743 {
1744 if (m_scene != null)
1745 return m_scene.MaxUndoCount;
1746 return 5;
1747 }
1748
1122 // justincc: I don't believe this hack is needed any longer, especially since the physics 1749 // justincc: I don't believe this hack is needed any longer, especially since the physics
1123 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1750 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1124 // this method was preventing proper reload of scene objects. 1751 // this method was preventing proper reload of scene objects.
@@ -1176,7 +1803,7 @@ namespace OpenSim.Region.Framework.Scenes
1176// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1803// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1177// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1804// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1178 1805
1179 part.StoreUndoState(); 1806// part.StoreUndoState();
1180 part.OnGrab(offsetPos, remoteClient); 1807 part.OnGrab(offsetPos, remoteClient);
1181 } 1808 }
1182 1809
@@ -1196,6 +1823,11 @@ namespace OpenSim.Region.Framework.Scenes
1196 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1823 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1197 public void DeleteGroupFromScene(bool silent) 1824 public void DeleteGroupFromScene(bool silent)
1198 { 1825 {
1826 // We need to keep track of this state in case this group is still queued for backup.
1827 IsDeleted = true;
1828
1829 DetachFromBackup();
1830
1199 SceneObjectPart[] parts = m_parts.GetArray(); 1831 SceneObjectPart[] parts = m_parts.GetArray();
1200 for (int i = 0; i < parts.Length; i++) 1832 for (int i = 0; i < parts.Length; i++)
1201 { 1833 {
@@ -1219,6 +1851,7 @@ namespace OpenSim.Region.Framework.Scenes
1219 } 1851 }
1220 }); 1852 });
1221 } 1853 }
1854
1222 } 1855 }
1223 1856
1224 public void AddScriptLPS(int count) 1857 public void AddScriptLPS(int count)
@@ -1288,28 +1921,43 @@ namespace OpenSim.Region.Framework.Scenes
1288 /// </summary> 1921 /// </summary>
1289 public void ApplyPhysics() 1922 public void ApplyPhysics()
1290 { 1923 {
1291 // Apply physics to the root prim
1292 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1293
1294 // Apply physics to child prims
1295 SceneObjectPart[] parts = m_parts.GetArray(); 1924 SceneObjectPart[] parts = m_parts.GetArray();
1296 if (parts.Length > 1) 1925 if (parts.Length > 1)
1297 { 1926 {
1927 ResetChildPrimPhysicsPositions();
1928
1929 // Apply physics to the root prim
1930 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1931
1932
1298 for (int i = 0; i < parts.Length; i++) 1933 for (int i = 0; i < parts.Length; i++)
1299 { 1934 {
1300 SceneObjectPart part = parts[i]; 1935 SceneObjectPart part = parts[i];
1301 if (part.LocalId != m_rootPart.LocalId) 1936 if (part.LocalId != m_rootPart.LocalId)
1302 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1937 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1303 } 1938 }
1304
1305 // Hack to get the physics scene geometries in the right spot 1939 // Hack to get the physics scene geometries in the right spot
1306 ResetChildPrimPhysicsPositions(); 1940// ResetChildPrimPhysicsPositions();
1941 if (m_rootPart.PhysActor != null)
1942 {
1943 m_rootPart.PhysActor.Building = false;
1944 }
1945 }
1946 else
1947 {
1948 // Apply physics to the root prim
1949 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1307 } 1950 }
1308 } 1951 }
1309 1952
1310 public void SetOwnerId(UUID userId) 1953 public void SetOwnerId(UUID userId)
1311 { 1954 {
1312 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1955 ForEachPart(delegate(SceneObjectPart part)
1956 {
1957
1958 part.OwnerID = userId;
1959
1960 });
1313 } 1961 }
1314 1962
1315 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1963 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1341,11 +1989,17 @@ namespace OpenSim.Region.Framework.Scenes
1341 return; 1989 return;
1342 } 1990 }
1343 1991
1992 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1993 return;
1994
1344 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1995 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1345 // any exception propogate upwards. 1996 // any exception propogate upwards.
1346 try 1997 try
1347 { 1998 {
1348 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1999 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2000 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2001 m_scene.LoadingPrims) // Land may not be valid yet
2002
1349 { 2003 {
1350 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2004 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1351 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2005 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1372,6 +2026,7 @@ namespace OpenSim.Region.Framework.Scenes
1372 } 2026 }
1373 } 2027 }
1374 } 2028 }
2029
1375 } 2030 }
1376 2031
1377 if (m_scene.UseBackup && HasGroupChanged) 2032 if (m_scene.UseBackup && HasGroupChanged)
@@ -1379,10 +2034,30 @@ namespace OpenSim.Region.Framework.Scenes
1379 // don't backup while it's selected or you're asking for changes mid stream. 2034 // don't backup while it's selected or you're asking for changes mid stream.
1380 if (isTimeToPersist() || forcedBackup) 2035 if (isTimeToPersist() || forcedBackup)
1381 { 2036 {
2037 if (m_rootPart.PhysActor != null &&
2038 (!m_rootPart.PhysActor.IsPhysical))
2039 {
2040 // Possible ghost prim
2041 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2042 {
2043 foreach (SceneObjectPart part in m_parts.GetArray())
2044 {
2045 // Re-set physics actor positions and
2046 // orientations
2047 part.GroupPosition = m_rootPart.GroupPosition;
2048 }
2049 }
2050 }
1382// m_log.DebugFormat( 2051// m_log.DebugFormat(
1383// "[SCENE]: Storing {0}, {1} in {2}", 2052// "[SCENE]: Storing {0}, {1} in {2}",
1384// Name, UUID, m_scene.RegionInfo.RegionName); 2053// Name, UUID, m_scene.RegionInfo.RegionName);
1385 2054
2055 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2056 {
2057 RootPart.Shape.State = 0;
2058 ScheduleGroupForFullUpdate();
2059 }
2060
1386 SceneObjectGroup backup_group = Copy(false); 2061 SceneObjectGroup backup_group = Copy(false);
1387 backup_group.RootPart.Velocity = RootPart.Velocity; 2062 backup_group.RootPart.Velocity = RootPart.Velocity;
1388 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2063 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1392,6 +2067,16 @@ namespace OpenSim.Region.Framework.Scenes
1392 HasGroupChangedDueToDelink = false; 2067 HasGroupChangedDueToDelink = false;
1393 2068
1394 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2069 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2070/*
2071 backup_group.ForEachPart(delegate(SceneObjectPart part)
2072 {
2073 if (part.KeyframeMotion != null)
2074 {
2075 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2076// part.KeyframeMotion.UpdateSceneObject(this);
2077 }
2078 });
2079*/
1395 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2080 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1396 2081
1397 backup_group.ForEachPart(delegate(SceneObjectPart part) 2082 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1448,10 +2133,14 @@ namespace OpenSim.Region.Framework.Scenes
1448 /// <returns></returns> 2133 /// <returns></returns>
1449 public SceneObjectGroup Copy(bool userExposed) 2134 public SceneObjectGroup Copy(bool userExposed)
1450 { 2135 {
2136 m_dupeInProgress = true;
1451 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2137 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1452 dupe.m_isBackedUp = false; 2138 dupe.m_isBackedUp = false;
1453 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2139 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1454 2140
2141 // new group as no sitting avatars
2142 dupe.m_linkedAvatars = new List<ScenePresence>();
2143
1455 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2144 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1456 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2145 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1457 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2146 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1462,7 +2151,7 @@ namespace OpenSim.Region.Framework.Scenes
1462 // This is only necessary when userExposed is false! 2151 // This is only necessary when userExposed is false!
1463 2152
1464 bool previousAttachmentStatus = dupe.IsAttachment; 2153 bool previousAttachmentStatus = dupe.IsAttachment;
1465 2154
1466 if (!userExposed) 2155 if (!userExposed)
1467 dupe.IsAttachment = true; 2156 dupe.IsAttachment = true;
1468 2157
@@ -1475,16 +2164,17 @@ namespace OpenSim.Region.Framework.Scenes
1475 2164
1476 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2165 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1477 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2166 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2167
1478 2168
1479 if (userExposed) 2169 if (userExposed)
1480 dupe.m_rootPart.TrimPermissions(); 2170 dupe.m_rootPart.TrimPermissions();
1481 2171
1482 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2172 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1483 2173
1484 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2174 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1485 { 2175 {
1486 return p1.LinkNum.CompareTo(p2.LinkNum); 2176 return p1.LinkNum.CompareTo(p2.LinkNum);
1487 } 2177 }
1488 ); 2178 );
1489 2179
1490 foreach (SceneObjectPart part in partList) 2180 foreach (SceneObjectPart part in partList)
@@ -1494,41 +2184,56 @@ namespace OpenSim.Region.Framework.Scenes
1494 { 2184 {
1495 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2185 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1496 newPart.LinkNum = part.LinkNum; 2186 newPart.LinkNum = part.LinkNum;
1497 } 2187 if (userExposed)
2188 newPart.ParentID = dupe.m_rootPart.LocalId;
2189 }
1498 else 2190 else
1499 { 2191 {
1500 newPart = dupe.m_rootPart; 2192 newPart = dupe.m_rootPart;
1501 } 2193 }
2194/*
2195 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2196 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1502 2197
1503 // Need to duplicate the physics actor as well 2198 // Need to duplicate the physics actor as well
1504 PhysicsActor originalPartPa = part.PhysActor; 2199 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1505 if (originalPartPa != null && userExposed)
1506 { 2200 {
1507 PrimitiveBaseShape pbs = newPart.Shape; 2201 PrimitiveBaseShape pbs = newPart.Shape;
1508
1509 newPart.PhysActor 2202 newPart.PhysActor
1510 = m_scene.PhysicsScene.AddPrimShape( 2203 = m_scene.PhysicsScene.AddPrimShape(
1511 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2204 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1512 pbs, 2205 pbs,
1513 newPart.AbsolutePosition, 2206 newPart.AbsolutePosition,
1514 newPart.Scale, 2207 newPart.Scale,
1515 newPart.RotationOffset, 2208 newPart.GetWorldRotation(),
1516 originalPartPa.IsPhysical, 2209 isphys,
2210 isphan,
1517 newPart.LocalId); 2211 newPart.LocalId);
1518 2212
1519 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2213 newPart.DoPhysicsPropertyUpdate(isphys, true);
1520 } 2214 */
2215 if (userExposed)
2216 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2217// }
2218 // copy keyframemotion
2219 if (part.KeyframeMotion != null)
2220 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1521 } 2221 }
1522 2222
1523 if (userExposed) 2223 if (userExposed)
1524 { 2224 {
1525 dupe.UpdateParentIDs(); 2225// done above dupe.UpdateParentIDs();
2226
2227 if (dupe.m_rootPart.PhysActor != null)
2228 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2229
1526 dupe.HasGroupChanged = true; 2230 dupe.HasGroupChanged = true;
1527 dupe.AttachToBackup(); 2231 dupe.AttachToBackup();
1528 2232
1529 ScheduleGroupForFullUpdate(); 2233 ScheduleGroupForFullUpdate();
1530 } 2234 }
1531 2235
2236 m_dupeInProgress = false;
1532 return dupe; 2237 return dupe;
1533 } 2238 }
1534 2239
@@ -1540,11 +2245,24 @@ namespace OpenSim.Region.Framework.Scenes
1540 /// <param name="cGroupID"></param> 2245 /// <param name="cGroupID"></param>
1541 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2246 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1542 { 2247 {
1543 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2248 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2249 // give newpart a new local ID lettng old part keep same
2250 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2251 newpart.LocalId = m_scene.AllocateLocalId();
2252
2253 SetRootPart(newpart);
2254 if (userExposed)
2255 RootPart.Velocity = Vector3.Zero; // In case source is moving
1544 } 2256 }
1545 2257
1546 public void ScriptSetPhysicsStatus(bool usePhysics) 2258 public void ScriptSetPhysicsStatus(bool usePhysics)
1547 { 2259 {
2260 if (usePhysics)
2261 {
2262 if (RootPart.KeyframeMotion != null)
2263 RootPart.KeyframeMotion.Stop();
2264 RootPart.KeyframeMotion = null;
2265 }
1548 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2266 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1549 } 2267 }
1550 2268
@@ -1592,13 +2310,14 @@ namespace OpenSim.Region.Framework.Scenes
1592 2310
1593 if (pa != null) 2311 if (pa != null)
1594 { 2312 {
1595 pa.AddForce(impulse, true); 2313 // false to be applied as a impulse
2314 pa.AddForce(impulse, false);
1596 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2315 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1597 } 2316 }
1598 } 2317 }
1599 } 2318 }
1600 2319
1601 public void applyAngularImpulse(Vector3 impulse) 2320 public void ApplyAngularImpulse(Vector3 impulse)
1602 { 2321 {
1603 PhysicsActor pa = RootPart.PhysActor; 2322 PhysicsActor pa = RootPart.PhysActor;
1604 2323
@@ -1606,21 +2325,8 @@ namespace OpenSim.Region.Framework.Scenes
1606 { 2325 {
1607 if (!IsAttachment) 2326 if (!IsAttachment)
1608 { 2327 {
1609 pa.AddAngularForce(impulse, true); 2328 // false to be applied as a impulse
1610 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2329 pa.AddAngularForce(impulse, false);
1611 }
1612 }
1613 }
1614
1615 public void setAngularImpulse(Vector3 impulse)
1616 {
1617 PhysicsActor pa = RootPart.PhysActor;
1618
1619 if (pa != null)
1620 {
1621 if (!IsAttachment)
1622 {
1623 pa.Torque = impulse;
1624 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2330 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1625 } 2331 }
1626 } 2332 }
@@ -1628,20 +2334,10 @@ namespace OpenSim.Region.Framework.Scenes
1628 2334
1629 public Vector3 GetTorque() 2335 public Vector3 GetTorque()
1630 { 2336 {
1631 PhysicsActor pa = RootPart.PhysActor; 2337 return RootPart.Torque;
1632
1633 if (pa != null)
1634 {
1635 if (!IsAttachment)
1636 {
1637 Vector3 torque = pa.Torque;
1638 return torque;
1639 }
1640 }
1641
1642 return Vector3.Zero;
1643 } 2338 }
1644 2339
2340 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1645 public void moveToTarget(Vector3 target, float tau) 2341 public void moveToTarget(Vector3 target, float tau)
1646 { 2342 {
1647 if (IsAttachment) 2343 if (IsAttachment)
@@ -1673,6 +2369,46 @@ namespace OpenSim.Region.Framework.Scenes
1673 pa.PIDActive = false; 2369 pa.PIDActive = false;
1674 } 2370 }
1675 2371
2372 public void rotLookAt(Quaternion target, float strength, float damping)
2373 {
2374 SceneObjectPart rootpart = m_rootPart;
2375 if (rootpart != null)
2376 {
2377 if (IsAttachment)
2378 {
2379 /*
2380 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2381 if (avatar != null)
2382 {
2383 Rotate the Av?
2384 } */
2385 }
2386 else
2387 {
2388 if (rootpart.PhysActor != null)
2389 { // APID must be implemented in your physics system for this to function.
2390 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2391 rootpart.PhysActor.APIDStrength = strength;
2392 rootpart.PhysActor.APIDDamping = damping;
2393 rootpart.PhysActor.APIDActive = true;
2394 }
2395 }
2396 }
2397 }
2398
2399 public void stopLookAt()
2400 {
2401 SceneObjectPart rootpart = m_rootPart;
2402 if (rootpart != null)
2403 {
2404 if (rootpart.PhysActor != null)
2405 { // APID must be implemented in your physics system for this to function.
2406 rootpart.PhysActor.APIDActive = false;
2407 }
2408 }
2409
2410 }
2411
1676 /// <summary> 2412 /// <summary>
1677 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2413 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1678 /// </summary> 2414 /// </summary>
@@ -1689,7 +2425,7 @@ namespace OpenSim.Region.Framework.Scenes
1689 { 2425 {
1690 pa.PIDHoverHeight = height; 2426 pa.PIDHoverHeight = height;
1691 pa.PIDHoverType = hoverType; 2427 pa.PIDHoverType = hoverType;
1692 pa.PIDTau = tau; 2428 pa.PIDHoverTau = tau;
1693 pa.PIDHoverActive = true; 2429 pa.PIDHoverActive = true;
1694 } 2430 }
1695 else 2431 else
@@ -1729,7 +2465,12 @@ namespace OpenSim.Region.Framework.Scenes
1729 /// <param name="cGroupID"></param> 2465 /// <param name="cGroupID"></param>
1730 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2466 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1731 { 2467 {
1732 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2468 // give new ID to the new part, letting old keep original
2469 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2470 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2471 newPart.LocalId = m_scene.AllocateLocalId();
2472 newPart.SetParent(this);
2473
1733 AddPart(newPart); 2474 AddPart(newPart);
1734 2475
1735 SetPartAsNonRoot(newPart); 2476 SetPartAsNonRoot(newPart);
@@ -1868,11 +2609,11 @@ namespace OpenSim.Region.Framework.Scenes
1868 /// Immediately send a full update for this scene object. 2609 /// Immediately send a full update for this scene object.
1869 /// </summary> 2610 /// </summary>
1870 public void SendGroupFullUpdate() 2611 public void SendGroupFullUpdate()
1871 { 2612 {
1872 if (IsDeleted) 2613 if (IsDeleted)
1873 return; 2614 return;
1874 2615
1875// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2616// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1876 2617
1877 RootPart.SendFullUpdateToAllClients(); 2618 RootPart.SendFullUpdateToAllClients();
1878 2619
@@ -2028,6 +2769,11 @@ namespace OpenSim.Region.Framework.Scenes
2028 // 'linkPart' == the root of the group being linked into this group 2769 // 'linkPart' == the root of the group being linked into this group
2029 SceneObjectPart linkPart = objectGroup.m_rootPart; 2770 SceneObjectPart linkPart = objectGroup.m_rootPart;
2030 2771
2772 if (m_rootPart.PhysActor != null)
2773 m_rootPart.PhysActor.Building = true;
2774 if (linkPart.PhysActor != null)
2775 linkPart.PhysActor.Building = true;
2776
2031 // physics flags from group to be applied to linked parts 2777 // physics flags from group to be applied to linked parts
2032 bool grpusephys = UsesPhysics; 2778 bool grpusephys = UsesPhysics;
2033 bool grptemporary = IsTemporary; 2779 bool grptemporary = IsTemporary;
@@ -2053,12 +2799,12 @@ namespace OpenSim.Region.Framework.Scenes
2053 Vector3 axPos = linkPart.OffsetPosition; 2799 Vector3 axPos = linkPart.OffsetPosition;
2054 // Rotate the linking root SOP's position to be relative to the new root prim 2800 // Rotate the linking root SOP's position to be relative to the new root prim
2055 Quaternion parentRot = m_rootPart.RotationOffset; 2801 Quaternion parentRot = m_rootPart.RotationOffset;
2056 axPos *= Quaternion.Inverse(parentRot); 2802 axPos *= Quaternion.Conjugate(parentRot);
2057 linkPart.OffsetPosition = axPos; 2803 linkPart.OffsetPosition = axPos;
2058 2804
2059 // Make the linking root SOP's rotation relative to the new root prim 2805 // Make the linking root SOP's rotation relative to the new root prim
2060 Quaternion oldRot = linkPart.RotationOffset; 2806 Quaternion oldRot = linkPart.RotationOffset;
2061 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2807 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2062 linkPart.RotationOffset = newRot; 2808 linkPart.RotationOffset = newRot;
2063 2809
2064 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2810 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2092,7 +2838,7 @@ namespace OpenSim.Region.Framework.Scenes
2092 linkPart.CreateSelected = true; 2838 linkPart.CreateSelected = true;
2093 2839
2094 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2840 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2095 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2841 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2096 2842
2097 // If the added SOP is physical, also tell the physics engine about the link relationship. 2843 // If the added SOP is physical, also tell the physics engine about the link relationship.
2098 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2844 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2102,6 +2848,7 @@ namespace OpenSim.Region.Framework.Scenes
2102 } 2848 }
2103 2849
2104 linkPart.LinkNum = linkNum++; 2850 linkPart.LinkNum = linkNum++;
2851 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2105 2852
2106 // Get a list of the SOP's in the old group in order of their linknum's. 2853 // Get a list of the SOP's in the old group in order of their linknum's.
2107 SceneObjectPart[] ogParts = objectGroup.Parts; 2854 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2120,7 +2867,7 @@ namespace OpenSim.Region.Framework.Scenes
2120 2867
2121 // Update the physics flags for the newly added SOP 2868 // Update the physics flags for the newly added SOP
2122 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2869 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2123 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2870 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2124 2871
2125 // If the added SOP is physical, also tell the physics engine about the link relationship. 2872 // If the added SOP is physical, also tell the physics engine about the link relationship.
2126 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2873 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2138,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
2138 objectGroup.IsDeleted = true; 2885 objectGroup.IsDeleted = true;
2139 2886
2140 objectGroup.m_parts.Clear(); 2887 objectGroup.m_parts.Clear();
2141 2888
2142 // Can't do this yet since backup still makes use of the root part without any synchronization 2889 // Can't do this yet since backup still makes use of the root part without any synchronization
2143// objectGroup.m_rootPart = null; 2890// objectGroup.m_rootPart = null;
2144 2891
@@ -2152,6 +2899,9 @@ namespace OpenSim.Region.Framework.Scenes
2152 // unmoved prims! 2899 // unmoved prims!
2153 ResetChildPrimPhysicsPositions(); 2900 ResetChildPrimPhysicsPositions();
2154 2901
2902 if (m_rootPart.PhysActor != null)
2903 m_rootPart.PhysActor.Building = false;
2904
2155 //HasGroupChanged = true; 2905 //HasGroupChanged = true;
2156 //ScheduleGroupForFullUpdate(); 2906 //ScheduleGroupForFullUpdate();
2157 } 2907 }
@@ -2219,7 +2969,10 @@ namespace OpenSim.Region.Framework.Scenes
2219// m_log.DebugFormat( 2969// m_log.DebugFormat(
2220// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2970// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2221// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2971// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2222 2972
2973 if (m_rootPart.PhysActor != null)
2974 m_rootPart.PhysActor.Building = true;
2975
2223 linkPart.ClearUndoState(); 2976 linkPart.ClearUndoState();
2224 2977
2225 Vector3 worldPos = linkPart.GetWorldPosition(); 2978 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2290,6 +3043,14 @@ namespace OpenSim.Region.Framework.Scenes
2290 3043
2291 // When we delete a group, we currently have to force persist to the database if the object id has changed 3044 // When we delete a group, we currently have to force persist to the database if the object id has changed
2292 // (since delete works by deleting all rows which have a given object id) 3045 // (since delete works by deleting all rows which have a given object id)
3046
3047 // this is as it seems to be in sl now
3048 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3049 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3050
3051 if (m_rootPart.PhysActor != null)
3052 m_rootPart.PhysActor.Building = false;
3053
2293 objectGroup.HasGroupChangedDueToDelink = true; 3054 objectGroup.HasGroupChangedDueToDelink = true;
2294 3055
2295 return objectGroup; 3056 return objectGroup;
@@ -2301,6 +3062,8 @@ namespace OpenSim.Region.Framework.Scenes
2301 /// <param name="objectGroup"></param> 3062 /// <param name="objectGroup"></param>
2302 public virtual void DetachFromBackup() 3063 public virtual void DetachFromBackup()
2303 { 3064 {
3065 if (m_scene != null)
3066 m_scene.SceneGraph.FireDetachFromBackup(this);
2304 if (m_isBackedUp && Scene != null) 3067 if (m_isBackedUp && Scene != null)
2305 m_scene.EventManager.OnBackup -= ProcessBackup; 3068 m_scene.EventManager.OnBackup -= ProcessBackup;
2306 3069
@@ -2321,7 +3084,8 @@ namespace OpenSim.Region.Framework.Scenes
2321 Vector3 axPos = part.OffsetPosition; 3084 Vector3 axPos = part.OffsetPosition;
2322 axPos *= parentRot; 3085 axPos *= parentRot;
2323 part.OffsetPosition = axPos; 3086 part.OffsetPosition = axPos;
2324 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3087 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3088 part.GroupPosition = newPos;
2325 part.OffsetPosition = Vector3.Zero; 3089 part.OffsetPosition = Vector3.Zero;
2326 3090
2327 // Compution our rotation to be not relative to the old parent 3091 // Compution our rotation to be not relative to the old parent
@@ -2336,7 +3100,7 @@ namespace OpenSim.Region.Framework.Scenes
2336 part.LinkNum = linkNum; 3100 part.LinkNum = linkNum;
2337 3101
2338 // Compute the new position of this SOP relative to the group position 3102 // Compute the new position of this SOP relative to the group position
2339 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3103 part.OffsetPosition = newPos - AbsolutePosition;
2340 3104
2341 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3105 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2342 // It would have the affect of setting the physics engine position multiple 3106 // It would have the affect of setting the physics engine position multiple
@@ -2346,18 +3110,19 @@ namespace OpenSim.Region.Framework.Scenes
2346 // Rotate the relative position by the rotation of the group 3110 // Rotate the relative position by the rotation of the group
2347 Quaternion rootRotation = m_rootPart.RotationOffset; 3111 Quaternion rootRotation = m_rootPart.RotationOffset;
2348 Vector3 pos = part.OffsetPosition; 3112 Vector3 pos = part.OffsetPosition;
2349 pos *= Quaternion.Inverse(rootRotation); 3113 pos *= Quaternion.Conjugate(rootRotation);
2350 part.OffsetPosition = pos; 3114 part.OffsetPosition = pos;
2351 3115
2352 // Compute the SOP's rotation relative to the rotation of the group. 3116 // Compute the SOP's rotation relative to the rotation of the group.
2353 parentRot = m_rootPart.RotationOffset; 3117 parentRot = m_rootPart.RotationOffset;
2354 oldRot = part.RotationOffset; 3118 oldRot = part.RotationOffset;
2355 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3119 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2356 part.RotationOffset = newRot; 3120 part.RotationOffset = newRot;
2357 3121
2358 // Since this SOP's state has changed, push those changes into the physics engine 3122 // Since this SOP's state has changed, push those changes into the physics engine
2359 // and the simulator. 3123 // and the simulator.
2360 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3124 // done on caller
3125// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2361 } 3126 }
2362 3127
2363 /// <summary> 3128 /// <summary>
@@ -2379,10 +3144,14 @@ namespace OpenSim.Region.Framework.Scenes
2379 { 3144 {
2380 if (!m_rootPart.BlockGrab) 3145 if (!m_rootPart.BlockGrab)
2381 { 3146 {
2382 Vector3 llmoveforce = pos - AbsolutePosition; 3147/* Vector3 llmoveforce = pos - AbsolutePosition;
2383 Vector3 grabforce = llmoveforce; 3148 Vector3 grabforce = llmoveforce;
2384 grabforce = (grabforce / 10) * pa.Mass; 3149 grabforce = (grabforce / 10) * pa.Mass;
2385 pa.AddForce(grabforce, true); 3150 */
3151 // empirically convert distance diference to a impulse
3152 Vector3 grabforce = pos - AbsolutePosition;
3153 grabforce = grabforce * (pa.Mass/ 10.0f);
3154 pa.AddForce(grabforce, false);
2386 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3155 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2387 } 3156 }
2388 } 3157 }
@@ -2578,6 +3347,8 @@ namespace OpenSim.Region.Framework.Scenes
2578 /// <param name="SetVolumeDetect"></param> 3347 /// <param name="SetVolumeDetect"></param>
2579 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3348 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2580 { 3349 {
3350 HasGroupChanged = true;
3351
2581 SceneObjectPart selectionPart = GetPart(localID); 3352 SceneObjectPart selectionPart = GetPart(localID);
2582 3353
2583 if (SetTemporary && Scene != null) 3354 if (SetTemporary && Scene != null)
@@ -2608,8 +3379,22 @@ namespace OpenSim.Region.Framework.Scenes
2608 } 3379 }
2609 } 3380 }
2610 3381
2611 for (int i = 0; i < parts.Length; i++) 3382 if (parts.Length > 1)
2612 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3383 {
3384 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3385
3386 for (int i = 0; i < parts.Length; i++)
3387 {
3388
3389 if (parts[i].UUID != m_rootPart.UUID)
3390 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3391 }
3392
3393 if (m_rootPart.PhysActor != null)
3394 m_rootPart.PhysActor.Building = false;
3395 }
3396 else
3397 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2613 } 3398 }
2614 } 3399 }
2615 3400
@@ -2622,6 +3407,17 @@ namespace OpenSim.Region.Framework.Scenes
2622 } 3407 }
2623 } 3408 }
2624 3409
3410
3411
3412 /// <summary>
3413 /// Gets the number of parts
3414 /// </summary>
3415 /// <returns></returns>
3416 public int GetPartCount()
3417 {
3418 return Parts.Count();
3419 }
3420
2625 /// <summary> 3421 /// <summary>
2626 /// Update the texture entry for this part 3422 /// Update the texture entry for this part
2627 /// </summary> 3423 /// </summary>
@@ -2638,11 +3434,18 @@ namespace OpenSim.Region.Framework.Scenes
2638 3434
2639 public void AdjustChildPrimPermissions() 3435 public void AdjustChildPrimPermissions()
2640 { 3436 {
3437 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits
3438 uint foldedPerms = RootPart.OwnerMask & 3;
3439
2641 ForEachPart(part => 3440 ForEachPart(part =>
2642 { 3441 {
3442 newOwnerMask &= part.BaseMask;
2643 if (part != RootPart) 3443 if (part != RootPart)
2644 part.ClonePermissions(RootPart); 3444 part.ClonePermissions(RootPart);
2645 }); 3445 });
3446
3447 RootPart.OwnerMask = newOwnerMask | foldedPerms;
3448 RootPart.ScheduleFullUpdate();
2646 } 3449 }
2647 3450
2648 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 3451 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2650,8 +3453,24 @@ namespace OpenSim.Region.Framework.Scenes
2650 { 3453 {
2651 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3454 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2652 3455
3456 bool god = Scene.Permissions.IsGod(AgentID);
3457
3458 if (field == 1 && god)
3459 {
3460 ForEachPart(part =>
3461 {
3462 part.BaseMask = RootPart.BaseMask;
3463 });
3464 }
3465
2653 AdjustChildPrimPermissions(); 3466 AdjustChildPrimPermissions();
2654 3467
3468 if (field == 1 && god) // Base mask was set. Update all child part inventories
3469 {
3470 foreach (SceneObjectPart part in Parts)
3471 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3472 }
3473
2655 HasGroupChanged = true; 3474 HasGroupChanged = true;
2656 3475
2657 // Send the group's properties to all clients once all parts are updated 3476 // Send the group's properties to all clients once all parts are updated
@@ -2697,8 +3516,6 @@ namespace OpenSim.Region.Framework.Scenes
2697 3516
2698 PhysicsActor pa = m_rootPart.PhysActor; 3517 PhysicsActor pa = m_rootPart.PhysActor;
2699 3518
2700 RootPart.StoreUndoState(true);
2701
2702 if (Scene != null) 3519 if (Scene != null)
2703 { 3520 {
2704 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3521 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2726,7 +3543,6 @@ namespace OpenSim.Region.Framework.Scenes
2726 SceneObjectPart obPart = parts[i]; 3543 SceneObjectPart obPart = parts[i];
2727 if (obPart.UUID != m_rootPart.UUID) 3544 if (obPart.UUID != m_rootPart.UUID)
2728 { 3545 {
2729// obPart.IgnoreUndoUpdate = true;
2730 Vector3 oldSize = new Vector3(obPart.Scale); 3546 Vector3 oldSize = new Vector3(obPart.Scale);
2731 3547
2732 float f = 1.0f; 3548 float f = 1.0f;
@@ -2838,8 +3654,6 @@ namespace OpenSim.Region.Framework.Scenes
2838 z *= a; 3654 z *= a;
2839 } 3655 }
2840 } 3656 }
2841
2842// obPart.IgnoreUndoUpdate = false;
2843 } 3657 }
2844 } 3658 }
2845 } 3659 }
@@ -2849,9 +3663,7 @@ namespace OpenSim.Region.Framework.Scenes
2849 prevScale.Y *= y; 3663 prevScale.Y *= y;
2850 prevScale.Z *= z; 3664 prevScale.Z *= z;
2851 3665
2852// RootPart.IgnoreUndoUpdate = true;
2853 RootPart.Resize(prevScale); 3666 RootPart.Resize(prevScale);
2854// RootPart.IgnoreUndoUpdate = false;
2855 3667
2856 for (int i = 0; i < parts.Length; i++) 3668 for (int i = 0; i < parts.Length; i++)
2857 { 3669 {
@@ -2859,8 +3671,6 @@ namespace OpenSim.Region.Framework.Scenes
2859 3671
2860 if (obPart.UUID != m_rootPart.UUID) 3672 if (obPart.UUID != m_rootPart.UUID)
2861 { 3673 {
2862 obPart.IgnoreUndoUpdate = true;
2863
2864 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3674 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2865 currentpos.X *= x; 3675 currentpos.X *= x;
2866 currentpos.Y *= y; 3676 currentpos.Y *= y;
@@ -2873,16 +3683,12 @@ namespace OpenSim.Region.Framework.Scenes
2873 3683
2874 obPart.Resize(newSize); 3684 obPart.Resize(newSize);
2875 obPart.UpdateOffSet(currentpos); 3685 obPart.UpdateOffSet(currentpos);
2876
2877 obPart.IgnoreUndoUpdate = false;
2878 } 3686 }
2879 3687
2880// obPart.IgnoreUndoUpdate = false; 3688 HasGroupChanged = true;
2881// obPart.StoreUndoState(); 3689 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3690 ScheduleGroupForTerseUpdate();
2882 } 3691 }
2883
2884// m_log.DebugFormat(
2885// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2886 } 3692 }
2887 3693
2888 #endregion 3694 #endregion
@@ -2895,14 +3701,6 @@ namespace OpenSim.Region.Framework.Scenes
2895 /// <param name="pos"></param> 3701 /// <param name="pos"></param>
2896 public void UpdateGroupPosition(Vector3 pos) 3702 public void UpdateGroupPosition(Vector3 pos)
2897 { 3703 {
2898// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2899
2900 RootPart.StoreUndoState(true);
2901
2902// SceneObjectPart[] parts = m_parts.GetArray();
2903// for (int i = 0; i < parts.Length; i++)
2904// parts[i].StoreUndoState();
2905
2906 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3704 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2907 { 3705 {
2908 if (IsAttachment) 3706 if (IsAttachment)
@@ -2935,21 +3733,17 @@ namespace OpenSim.Region.Framework.Scenes
2935 /// </summary> 3733 /// </summary>
2936 /// <param name="pos"></param> 3734 /// <param name="pos"></param>
2937 /// <param name="localID"></param> 3735 /// <param name="localID"></param>
3736 ///
3737
2938 public void UpdateSinglePosition(Vector3 pos, uint localID) 3738 public void UpdateSinglePosition(Vector3 pos, uint localID)
2939 { 3739 {
2940 SceneObjectPart part = GetPart(localID); 3740 SceneObjectPart part = GetPart(localID);
2941 3741
2942// SceneObjectPart[] parts = m_parts.GetArray();
2943// for (int i = 0; i < parts.Length; i++)
2944// parts[i].StoreUndoState();
2945
2946 if (part != null) 3742 if (part != null)
2947 { 3743 {
2948// m_log.DebugFormat( 3744// unlock parts position change
2949// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3745 if (m_rootPart.PhysActor != null)
2950 3746 m_rootPart.PhysActor.Building = true;
2951 part.StoreUndoState(false);
2952 part.IgnoreUndoUpdate = true;
2953 3747
2954 if (part.UUID == m_rootPart.UUID) 3748 if (part.UUID == m_rootPart.UUID)
2955 { 3749 {
@@ -2960,8 +3754,10 @@ namespace OpenSim.Region.Framework.Scenes
2960 part.UpdateOffSet(pos); 3754 part.UpdateOffSet(pos);
2961 } 3755 }
2962 3756
3757 if (m_rootPart.PhysActor != null)
3758 m_rootPart.PhysActor.Building = false;
3759
2963 HasGroupChanged = true; 3760 HasGroupChanged = true;
2964 part.IgnoreUndoUpdate = false;
2965 } 3761 }
2966 } 3762 }
2967 3763
@@ -2971,13 +3767,7 @@ namespace OpenSim.Region.Framework.Scenes
2971 /// <param name="pos"></param> 3767 /// <param name="pos"></param>
2972 public void UpdateRootPosition(Vector3 pos) 3768 public void UpdateRootPosition(Vector3 pos)
2973 { 3769 {
2974// m_log.DebugFormat( 3770 // needs to be called with phys building true
2975// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2976
2977// SceneObjectPart[] parts = m_parts.GetArray();
2978// for (int i = 0; i < parts.Length; i++)
2979// parts[i].StoreUndoState();
2980
2981 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3771 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2982 Vector3 oldPos = 3772 Vector3 oldPos =
2983 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3773 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3000,7 +3790,14 @@ namespace OpenSim.Region.Framework.Scenes
3000 AbsolutePosition = newPos; 3790 AbsolutePosition = newPos;
3001 3791
3002 HasGroupChanged = true; 3792 HasGroupChanged = true;
3003 ScheduleGroupForTerseUpdate(); 3793 if (m_rootPart.Undoing)
3794 {
3795 ScheduleGroupForFullUpdate();
3796 }
3797 else
3798 {
3799 ScheduleGroupForTerseUpdate();
3800 }
3004 } 3801 }
3005 3802
3006 #endregion 3803 #endregion
@@ -3013,24 +3810,16 @@ namespace OpenSim.Region.Framework.Scenes
3013 /// <param name="rot"></param> 3810 /// <param name="rot"></param>
3014 public void UpdateGroupRotationR(Quaternion rot) 3811 public void UpdateGroupRotationR(Quaternion rot)
3015 { 3812 {
3016// m_log.DebugFormat(
3017// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3018
3019// SceneObjectPart[] parts = m_parts.GetArray();
3020// for (int i = 0; i < parts.Length; i++)
3021// parts[i].StoreUndoState();
3022
3023 m_rootPart.StoreUndoState(true);
3024
3025 m_rootPart.UpdateRotation(rot); 3813 m_rootPart.UpdateRotation(rot);
3026 3814
3815/* this is done by rootpart RotationOffset set called by UpdateRotation
3027 PhysicsActor actor = m_rootPart.PhysActor; 3816 PhysicsActor actor = m_rootPart.PhysActor;
3028 if (actor != null) 3817 if (actor != null)
3029 { 3818 {
3030 actor.Orientation = m_rootPart.RotationOffset; 3819 actor.Orientation = m_rootPart.RotationOffset;
3031 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3820 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3032 } 3821 }
3033 3822*/
3034 HasGroupChanged = true; 3823 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3824 ScheduleGroupForTerseUpdate();
3036 } 3825 }
@@ -3042,16 +3831,6 @@ namespace OpenSim.Region.Framework.Scenes
3042 /// <param name="rot"></param> 3831 /// <param name="rot"></param>
3043 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3832 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3044 { 3833 {
3045// m_log.DebugFormat(
3046// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3047
3048// SceneObjectPart[] parts = m_parts.GetArray();
3049// for (int i = 0; i < parts.Length; i++)
3050// parts[i].StoreUndoState();
3051
3052 RootPart.StoreUndoState(true);
3053 RootPart.IgnoreUndoUpdate = true;
3054
3055 m_rootPart.UpdateRotation(rot); 3834 m_rootPart.UpdateRotation(rot);
3056 3835
3057 PhysicsActor actor = m_rootPart.PhysActor; 3836 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3070,8 +3849,6 @@ namespace OpenSim.Region.Framework.Scenes
3070 3849
3071 HasGroupChanged = true; 3850 HasGroupChanged = true;
3072 ScheduleGroupForTerseUpdate(); 3851 ScheduleGroupForTerseUpdate();
3073
3074 RootPart.IgnoreUndoUpdate = false;
3075 } 3852 }
3076 3853
3077 /// <summary> 3854 /// <summary>
@@ -3084,13 +3861,11 @@ namespace OpenSim.Region.Framework.Scenes
3084 SceneObjectPart part = GetPart(localID); 3861 SceneObjectPart part = GetPart(localID);
3085 3862
3086 SceneObjectPart[] parts = m_parts.GetArray(); 3863 SceneObjectPart[] parts = m_parts.GetArray();
3087 for (int i = 0; i < parts.Length; i++)
3088 parts[i].StoreUndoState();
3089 3864
3090 if (part != null) 3865 if (part != null)
3091 { 3866 {
3092// m_log.DebugFormat( 3867 if (m_rootPart.PhysActor != null)
3093// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3868 m_rootPart.PhysActor.Building = true;
3094 3869
3095 if (part.UUID == m_rootPart.UUID) 3870 if (part.UUID == m_rootPart.UUID)
3096 { 3871 {
@@ -3100,6 +3875,9 @@ namespace OpenSim.Region.Framework.Scenes
3100 { 3875 {
3101 part.UpdateRotation(rot); 3876 part.UpdateRotation(rot);
3102 } 3877 }
3878
3879 if (m_rootPart.PhysActor != null)
3880 m_rootPart.PhysActor.Building = false;
3103 } 3881 }
3104 } 3882 }
3105 3883
@@ -3113,12 +3891,8 @@ namespace OpenSim.Region.Framework.Scenes
3113 SceneObjectPart part = GetPart(localID); 3891 SceneObjectPart part = GetPart(localID);
3114 if (part != null) 3892 if (part != null)
3115 { 3893 {
3116// m_log.DebugFormat( 3894 if (m_rootPart.PhysActor != null)
3117// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3895 m_rootPart.PhysActor.Building = true;
3118// part.Name, part.LocalId, rot);
3119
3120 part.StoreUndoState();
3121 part.IgnoreUndoUpdate = true;
3122 3896
3123 if (part.UUID == m_rootPart.UUID) 3897 if (part.UUID == m_rootPart.UUID)
3124 { 3898 {
@@ -3131,7 +3905,8 @@ namespace OpenSim.Region.Framework.Scenes
3131 part.OffsetPosition = pos; 3905 part.OffsetPosition = pos;
3132 } 3906 }
3133 3907
3134 part.IgnoreUndoUpdate = false; 3908 if (m_rootPart.PhysActor != null)
3909 m_rootPart.PhysActor.Building = false;
3135 } 3910 }
3136 } 3911 }
3137 3912
@@ -3141,15 +3916,12 @@ namespace OpenSim.Region.Framework.Scenes
3141 /// <param name="rot"></param> 3916 /// <param name="rot"></param>
3142 public void UpdateRootRotation(Quaternion rot) 3917 public void UpdateRootRotation(Quaternion rot)
3143 { 3918 {
3144// m_log.DebugFormat( 3919 // needs to be called with phys building true
3145// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3146// Name, LocalId, rot);
3147
3148 Quaternion axRot = rot; 3920 Quaternion axRot = rot;
3149 Quaternion oldParentRot = m_rootPart.RotationOffset; 3921 Quaternion oldParentRot = m_rootPart.RotationOffset;
3150 3922
3151 m_rootPart.StoreUndoState(); 3923 //Don't use UpdateRotation because it schedules an update prematurely
3152 m_rootPart.UpdateRotation(rot); 3924 m_rootPart.RotationOffset = rot;
3153 3925
3154 PhysicsActor pa = m_rootPart.PhysActor; 3926 PhysicsActor pa = m_rootPart.PhysActor;
3155 3927
@@ -3165,35 +3937,145 @@ namespace OpenSim.Region.Framework.Scenes
3165 SceneObjectPart prim = parts[i]; 3937 SceneObjectPart prim = parts[i];
3166 if (prim.UUID != m_rootPart.UUID) 3938 if (prim.UUID != m_rootPart.UUID)
3167 { 3939 {
3168 prim.IgnoreUndoUpdate = true; 3940 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3941 NewRot = Quaternion.Inverse(axRot) * NewRot;
3942 prim.RotationOffset = NewRot;
3943
3169 Vector3 axPos = prim.OffsetPosition; 3944 Vector3 axPos = prim.OffsetPosition;
3945
3170 axPos *= oldParentRot; 3946 axPos *= oldParentRot;
3171 axPos *= Quaternion.Inverse(axRot); 3947 axPos *= Quaternion.Inverse(axRot);
3172 prim.OffsetPosition = axPos; 3948 prim.OffsetPosition = axPos;
3173 Quaternion primsRot = prim.RotationOffset; 3949 }
3174 Quaternion newRot = oldParentRot * primsRot; 3950 }
3175 newRot = Quaternion.Inverse(axRot) * newRot; 3951
3176 prim.RotationOffset = newRot; 3952 HasGroupChanged = true;
3177 prim.ScheduleTerseUpdate(); 3953 ScheduleGroupForFullUpdate();
3178 prim.IgnoreUndoUpdate = false; 3954 }
3179 }
3180 }
3181
3182// for (int i = 0; i < parts.Length; i++)
3183// {
3184// SceneObjectPart childpart = parts[i];
3185// if (childpart != m_rootPart)
3186// {
3187//// childpart.IgnoreUndoUpdate = false;
3188//// childpart.StoreUndoState();
3189// }
3190// }
3191 3955
3192 m_rootPart.ScheduleTerseUpdate(); 3956 private enum updatetype :int
3957 {
3958 none = 0,
3959 partterse = 1,
3960 partfull = 2,
3961 groupterse = 3,
3962 groupfull = 4
3963 }
3193 3964
3194// m_log.DebugFormat( 3965 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3195// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3966 {
3196// Name, LocalId, rot); 3967 // TODO this still as excessive *.Schedule*Update()s
3968
3969 if (part != null && part.ParentGroup != null)
3970 {
3971 ObjectChangeType change = data.change;
3972 bool togroup = ((change & ObjectChangeType.Group) != 0);
3973 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3974
3975 SceneObjectGroup group = part.ParentGroup;
3976 PhysicsActor pha = group.RootPart.PhysActor;
3977
3978 updatetype updateType = updatetype.none;
3979
3980 if (togroup)
3981 {
3982 // related to group
3983 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3984 {
3985 if ((change & ObjectChangeType.Rotation) != 0)
3986 {
3987 group.RootPart.UpdateRotation(data.rotation);
3988 updateType = updatetype.none;
3989 }
3990 if ((change & ObjectChangeType.Position) != 0)
3991 {
3992 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3993 UpdateGroupPosition(data.position);
3994 updateType = updatetype.groupterse;
3995 }
3996 else
3997 // ugly rotation update of all parts
3998 {
3999 group.ResetChildPrimPhysicsPositions();
4000 }
4001
4002 }
4003 if ((change & ObjectChangeType.Scale) != 0)
4004 {
4005 if (pha != null)
4006 pha.Building = true;
4007
4008 group.GroupResize(data.scale);
4009 updateType = updatetype.none;
4010
4011 if (pha != null)
4012 pha.Building = false;
4013 }
4014 }
4015 else
4016 {
4017 // related to single prim in a link-set ( ie group)
4018 if (pha != null)
4019 pha.Building = true;
4020
4021 // root part is special
4022 // parts offset positions or rotations need to change also
4023
4024 if (part == group.RootPart)
4025 {
4026 if ((change & ObjectChangeType.Rotation) != 0)
4027 group.UpdateRootRotation(data.rotation);
4028 if ((change & ObjectChangeType.Position) != 0)
4029 group.UpdateRootPosition(data.position);
4030 if ((change & ObjectChangeType.Scale) != 0)
4031 part.Resize(data.scale);
4032 }
4033 else
4034 {
4035 if ((change & ObjectChangeType.Position) != 0)
4036 {
4037 part.OffsetPosition = data.position;
4038 updateType = updatetype.partterse;
4039 }
4040 if ((change & ObjectChangeType.Rotation) != 0)
4041 {
4042 part.UpdateRotation(data.rotation);
4043 updateType = updatetype.none;
4044 }
4045 if ((change & ObjectChangeType.Scale) != 0)
4046 {
4047 part.Resize(data.scale);
4048 updateType = updatetype.none;
4049 }
4050 }
4051
4052 if (pha != null)
4053 pha.Building = false;
4054 }
4055
4056 if (updateType != updatetype.none)
4057 {
4058 group.HasGroupChanged = true;
4059
4060 switch (updateType)
4061 {
4062 case updatetype.partterse:
4063 part.ScheduleTerseUpdate();
4064 break;
4065 case updatetype.partfull:
4066 part.ScheduleFullUpdate();
4067 break;
4068 case updatetype.groupterse:
4069 group.ScheduleGroupForTerseUpdate();
4070 break;
4071 case updatetype.groupfull:
4072 group.ScheduleGroupForFullUpdate();
4073 break;
4074 default:
4075 break;
4076 }
4077 }
4078 }
3197 } 4079 }
3198 4080
3199 #endregion 4081 #endregion
@@ -3292,10 +4174,11 @@ namespace OpenSim.Region.Framework.Scenes
3292 scriptPosTarget target = m_targets[idx]; 4174 scriptPosTarget target = m_targets[idx];
3293 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4175 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3294 { 4176 {
4177 at_target = true;
4178
3295 // trigger at_target 4179 // trigger at_target
3296 if (m_scriptListens_atTarget) 4180 if (m_scriptListens_atTarget)
3297 { 4181 {
3298 at_target = true;
3299 scriptPosTarget att = new scriptPosTarget(); 4182 scriptPosTarget att = new scriptPosTarget();
3300 att.targetPos = target.targetPos; 4183 att.targetPos = target.targetPos;
3301 att.tolerance = target.tolerance; 4184 att.tolerance = target.tolerance;
@@ -3413,11 +4296,50 @@ namespace OpenSim.Region.Framework.Scenes
3413 } 4296 }
3414 } 4297 }
3415 } 4298 }
3416 4299
4300 public Vector3 GetGeometricCenter()
4301 {
4302 // this is not real geometric center but a average of positions relative to root prim acording to
4303 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4304 // ignoring tortured prims details since sl also seems to ignore
4305 // so no real use in doing it on physics
4306
4307 Vector3 gc = Vector3.Zero;
4308
4309 int nparts = m_parts.Count;
4310 if (nparts <= 1)
4311 return gc;
4312
4313 SceneObjectPart[] parts = m_parts.GetArray();
4314 nparts = parts.Length; // just in case it changed
4315 if (nparts <= 1)
4316 return gc;
4317
4318 Quaternion parentRot = RootPart.RotationOffset;
4319 Vector3 pPos;
4320
4321 // average all parts positions
4322 for (int i = 0; i < nparts; i++)
4323 {
4324 // do it directly
4325 // gc += parts[i].GetWorldPosition();
4326 if (parts[i] != RootPart)
4327 {
4328 pPos = parts[i].OffsetPosition;
4329 gc += pPos;
4330 }
4331
4332 }
4333 gc /= nparts;
4334
4335 // relative to root:
4336// gc -= AbsolutePosition;
4337 return gc;
4338 }
4339
3417 public float GetMass() 4340 public float GetMass()
3418 { 4341 {
3419 float retmass = 0f; 4342 float retmass = 0f;
3420
3421 SceneObjectPart[] parts = m_parts.GetArray(); 4343 SceneObjectPart[] parts = m_parts.GetArray();
3422 for (int i = 0; i < parts.Length; i++) 4344 for (int i = 0; i < parts.Length; i++)
3423 retmass += parts[i].GetMass(); 4345 retmass += parts[i].GetMass();
@@ -3425,6 +4347,39 @@ namespace OpenSim.Region.Framework.Scenes
3425 return retmass; 4347 return retmass;
3426 } 4348 }
3427 4349
4350 // center of mass of full object
4351 public Vector3 GetCenterOfMass()
4352 {
4353 PhysicsActor pa = RootPart.PhysActor;
4354
4355 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4356 {
4357 // physics knows better about center of mass of physical prims
4358 Vector3 tmp = pa.CenterOfMass;
4359 return tmp;
4360 }
4361
4362 Vector3 Ptot = Vector3.Zero;
4363 float totmass = 0f;
4364 float m;
4365
4366 SceneObjectPart[] parts = m_parts.GetArray();
4367 for (int i = 0; i < parts.Length; i++)
4368 {
4369 m = parts[i].GetMass();
4370 Ptot += parts[i].GetPartCenterOfMass() * m;
4371 totmass += m;
4372 }
4373
4374 if (totmass == 0)
4375 totmass = 0;
4376 else
4377 totmass = 1 / totmass;
4378 Ptot *= totmass;
4379
4380 return Ptot;
4381 }
4382
3428 /// <summary> 4383 /// <summary>
3429 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4384 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3430 /// the physics engine can use it. 4385 /// the physics engine can use it.
@@ -3593,6 +4548,14 @@ namespace OpenSim.Region.Framework.Scenes
3593 FromItemID = uuid; 4548 FromItemID = uuid;
3594 } 4549 }
3595 4550
4551 public void ResetOwnerChangeFlag()
4552 {
4553 ForEachPart(delegate(SceneObjectPart part)
4554 {
4555 part.ResetOwnerChangeFlag();
4556 });
4557 }
4558
3596 #endregion 4559 #endregion
3597 } 4560 }
3598} 4561}