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.cs1362
1 files changed, 1143 insertions, 219 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index ac26be7..f1df6d6 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 }
@@ -271,10 +318,10 @@ namespace OpenSim.Region.Framework.Scenes
271 318
272 private bool m_scriptListens_atTarget; 319 private bool m_scriptListens_atTarget;
273 private bool m_scriptListens_notAtTarget; 320 private bool m_scriptListens_notAtTarget;
274
275 private bool m_scriptListens_atRotTarget; 321 private bool m_scriptListens_atRotTarget;
276 private bool m_scriptListens_notAtRotTarget; 322 private bool m_scriptListens_notAtRotTarget;
277 323
324 public bool m_dupeInProgress = false;
278 internal Dictionary<UUID, string> m_savedScriptState; 325 internal Dictionary<UUID, string> m_savedScriptState;
279 326
280 #region Properties 327 #region Properties
@@ -311,6 +358,16 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_parts.Count; } 358 get { return m_parts.Count; }
312 } 359 }
313 360
361// protected Quaternion m_rotation = Quaternion.Identity;
362//
363// public virtual Quaternion Rotation
364// {
365// get { return m_rotation; }
366// set {
367// m_rotation = value;
368// }
369// }
370
314 public Quaternion GroupRotation 371 public Quaternion GroupRotation
315 { 372 {
316 get { return m_rootPart.RotationOffset; } 373 get { return m_rootPart.RotationOffset; }
@@ -417,7 +474,15 @@ namespace OpenSim.Region.Framework.Scenes
417 { 474 {
418 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 475 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
419 } 476 }
420 477
478
479
480 private struct avtocrossInfo
481 {
482 public ScenePresence av;
483 public uint ParentID;
484 }
485
421 /// <summary> 486 /// <summary>
422 /// The absolute position of this scene object in the scene 487 /// The absolute position of this scene object in the scene
423 /// </summary> 488 /// </summary>
@@ -430,14 +495,136 @@ namespace OpenSim.Region.Framework.Scenes
430 495
431 if (Scene != null) 496 if (Scene != null)
432 { 497 {
433 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 498 // 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)) 499 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
500 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
501 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
502 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
435 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 503 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
436 { 504 {
437 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 505 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
506 uint x = 0;
507 uint y = 0;
508 string version = String.Empty;
509 Vector3 newpos = Vector3.Zero;
510 OpenSim.Services.Interfaces.GridRegion destination = null;
511
512 if (m_rootPart.KeyframeMotion != null)
513 m_rootPart.KeyframeMotion.StartCrossingCheck();
514
515 bool canCross = true;
516 foreach (ScenePresence av in m_linkedAvatars)
517 {
518 // We need to cross these agents. First, let's find
519 // out if any of them can't cross for some reason.
520 // We have to deny the crossing entirely if any
521 // of them are banned. Alternatively, we could
522 // unsit banned agents....
523
524
525 // We set the avatar position as being the object
526 // position to get the region to send to
527 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
528 {
529 canCross = false;
530 break;
531 }
532
533 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
534 }
535
536 if (canCross)
537 {
538 // We unparent the SP quietly so that it won't
539 // be made to stand up
540
541 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
542
543 foreach (ScenePresence av in m_linkedAvatars)
544 {
545 avtocrossInfo avinfo = new avtocrossInfo();
546 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
547 if (parentPart != null)
548 av.ParentUUID = parentPart.UUID;
549
550 avinfo.av = av;
551 avinfo.ParentID = av.ParentID;
552 avsToCross.Add(avinfo);
553
554 av.ParentID = 0;
555 }
556
557 // m_linkedAvatars.Clear();
558 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
559
560 // Normalize
561 if (val.X >= Constants.RegionSize)
562 val.X -= Constants.RegionSize;
563 if (val.Y >= Constants.RegionSize)
564 val.Y -= Constants.RegionSize;
565 if (val.X < 0)
566 val.X += Constants.RegionSize;
567 if (val.Y < 0)
568 val.Y += Constants.RegionSize;
569
570 // If it's deleted, crossing was successful
571 if (IsDeleted)
572 {
573 // foreach (ScenePresence av in m_linkedAvatars)
574 foreach (avtocrossInfo avinfo in avsToCross)
575 {
576 ScenePresence av = avinfo.av;
577 if (!av.IsInTransit) // just in case...
578 {
579 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
580
581 av.IsInTransit = true;
582
583 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
584 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
585 }
586 else
587 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
588 }
589 avsToCross.Clear();
590 return;
591 }
592 else // cross failed, put avas back ??
593 {
594 foreach (avtocrossInfo avinfo in avsToCross)
595 {
596 ScenePresence av = avinfo.av;
597 av.ParentUUID = UUID.Zero;
598 av.ParentID = avinfo.ParentID;
599// m_linkedAvatars.Add(av);
600 }
601 }
602 avsToCross.Clear();
603
604 }
605 else
606 {
607 if (m_rootPart.KeyframeMotion != null)
608 m_rootPart.KeyframeMotion.CrossingFailure();
609
610 if (RootPart.PhysActor != null)
611 {
612 RootPart.PhysActor.CrossingFailure();
613 }
614 }
615 Vector3 oldp = AbsolutePosition;
616 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
617 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
618 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
438 } 619 }
439 } 620 }
440 621
622/* don't see the need but worse don't see where is restored to false if things stay in
623 foreach (SceneObjectPart part in m_parts.GetArray())
624 {
625 part.IgnoreUndoUpdate = true;
626 }
627 */
441 if (RootPart.GetStatusSandbox()) 628 if (RootPart.GetStatusSandbox())
442 { 629 {
443 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 630 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -455,9 +642,38 @@ namespace OpenSim.Region.Framework.Scenes
455 // Restuff the new GroupPosition into each SOP of the linkset. 642 // Restuff the new GroupPosition into each SOP of the linkset.
456 // This has the affect of resetting and tainting the physics actors. 643 // This has the affect of resetting and tainting the physics actors.
457 SceneObjectPart[] parts = m_parts.GetArray(); 644 SceneObjectPart[] parts = m_parts.GetArray();
458 for (int i = 0; i < parts.Length; i++) 645 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
459 parts[i].GroupPosition = val; 646 if (m_dupeInProgress)
647 triggerScriptEvent = false;
648 foreach (SceneObjectPart part in parts)
649 {
650 part.GroupPosition = val;
651 if (triggerScriptEvent)
652 part.TriggerScriptChangedEvent(Changed.POSITION);
653 }
460 654
655/*
656 This seems not needed and should not be needed:
657 sp absolute position depends on sit part absolute position fixed above.
658 sp ParentPosition is not used anywhere.
659 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
660 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
661
662 if (!m_dupeInProgress)
663 {
664 foreach (ScenePresence av in m_linkedAvatars)
665 {
666 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
667 if (p != null && m_parts.TryGetValue(p.UUID, out p))
668 {
669 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
670 av.AbsolutePosition += offset;
671// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
672 av.SendAvatarDataToAllAgents();
673 }
674 }
675 }
676*/
461 //if (m_rootPart.PhysActor != null) 677 //if (m_rootPart.PhysActor != null)
462 //{ 678 //{
463 //m_rootPart.PhysActor.Position = 679 //m_rootPart.PhysActor.Position =
@@ -471,6 +687,40 @@ namespace OpenSim.Region.Framework.Scenes
471 } 687 }
472 } 688 }
473 689
690 public override Vector3 Velocity
691 {
692 get { return RootPart.Velocity; }
693 set { RootPart.Velocity = value; }
694 }
695
696 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
697 {
698 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
699 ScenePresence agent = icon.EndInvoke(iar);
700
701 //// If the cross was successful, this agent is a child agent
702 if (agent.IsChildAgent)
703 {
704 if (agent.ParentUUID != UUID.Zero)
705 {
706 agent.ParentPart = null;
707// agent.ParentPosition = Vector3.Zero;
708// agent.ParentUUID = UUID.Zero;
709 }
710 }
711
712 agent.ParentUUID = UUID.Zero;
713
714// agent.Reset();
715// else // Not successful
716// agent.RestoreInCurrentScene();
717
718 // In any case
719 agent.IsInTransit = false;
720
721 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
722 }
723
474 public override uint LocalId 724 public override uint LocalId
475 { 725 {
476 get { return m_rootPart.LocalId; } 726 get { return m_rootPart.LocalId; }
@@ -541,6 +791,11 @@ namespace OpenSim.Region.Framework.Scenes
541 m_isSelected = value; 791 m_isSelected = value;
542 // Tell physics engine that group is selected 792 // Tell physics engine that group is selected
543 793
794 // this is not right
795 // but ode engines should only really need to know about root part
796 // so they can put entire object simulation on hold and not colliding
797 // keep as was for now
798
544 PhysicsActor pa = m_rootPart.PhysActor; 799 PhysicsActor pa = m_rootPart.PhysActor;
545 if (pa != null) 800 if (pa != null)
546 { 801 {
@@ -557,6 +812,42 @@ namespace OpenSim.Region.Framework.Scenes
557 childPa.Selected = value; 812 childPa.Selected = value;
558 } 813 }
559 } 814 }
815 if (RootPart.KeyframeMotion != null)
816 RootPart.KeyframeMotion.Selected = value;
817 }
818 }
819
820 public void PartSelectChanged(bool partSelect)
821 {
822 // any part selected makes group selected
823 if (m_isSelected == partSelect)
824 return;
825
826 if (partSelect)
827 {
828 IsSelected = partSelect;
829// if (!IsAttachment)
830// ScheduleGroupForFullUpdate();
831 }
832 else
833 {
834 // bad bad bad 2 heavy for large linksets
835 // since viewer does send lot of (un)selects
836 // this needs to be replaced by a specific list or count ?
837 // but that will require extra code in several places
838
839 SceneObjectPart[] parts = m_parts.GetArray();
840 for (int i = 0; i < parts.Length; i++)
841 {
842 SceneObjectPart part = parts[i];
843 if (part.IsSelected)
844 return;
845 }
846 IsSelected = partSelect;
847 if (!IsAttachment)
848 {
849 ScheduleGroupForFullUpdate();
850 }
560 } 851 }
561 } 852 }
562 853
@@ -642,6 +933,7 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 933 /// </summary>
643 public SceneObjectGroup() 934 public SceneObjectGroup()
644 { 935 {
936
645 } 937 }
646 938
647 /// <summary> 939 /// <summary>
@@ -659,8 +951,8 @@ namespace OpenSim.Region.Framework.Scenes
659 /// Constructor. This object is added to the scene later via AttachToScene() 951 /// Constructor. This object is added to the scene later via AttachToScene()
660 /// </summary> 952 /// </summary>
661 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 953 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
662 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 954 {
663 { 955 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
664 } 956 }
665 957
666 /// <summary> 958 /// <summary>
@@ -695,6 +987,9 @@ namespace OpenSim.Region.Framework.Scenes
695 /// </summary> 987 /// </summary>
696 public virtual void AttachToBackup() 988 public virtual void AttachToBackup()
697 { 989 {
990 if (IsAttachment) return;
991 m_scene.SceneGraph.FireAttachToBackup(this);
992
698 if (InSceneBackup) 993 if (InSceneBackup)
699 { 994 {
700 //m_log.DebugFormat( 995 //m_log.DebugFormat(
@@ -737,6 +1032,13 @@ namespace OpenSim.Region.Framework.Scenes
737 1032
738 ApplyPhysics(); 1033 ApplyPhysics();
739 1034
1035 if (RootPart.PhysActor != null)
1036 RootPart.Force = RootPart.Force;
1037 if (RootPart.PhysActor != null)
1038 RootPart.Torque = RootPart.Torque;
1039 if (RootPart.PhysActor != null)
1040 RootPart.Buoyancy = RootPart.Buoyancy;
1041
740 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1042 // 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. 1043 // for the same object with very different properties. The caller must schedule the update.
742 //ScheduleGroupForFullUpdate(); 1044 //ScheduleGroupForFullUpdate();
@@ -752,6 +1054,10 @@ namespace OpenSim.Region.Framework.Scenes
752 EntityIntersection result = new EntityIntersection(); 1054 EntityIntersection result = new EntityIntersection();
753 1055
754 SceneObjectPart[] parts = m_parts.GetArray(); 1056 SceneObjectPart[] parts = m_parts.GetArray();
1057
1058 // Find closest hit here
1059 float idist = float.MaxValue;
1060
755 for (int i = 0; i < parts.Length; i++) 1061 for (int i = 0; i < parts.Length; i++)
756 { 1062 {
757 SceneObjectPart part = parts[i]; 1063 SceneObjectPart part = parts[i];
@@ -766,11 +1072,6 @@ namespace OpenSim.Region.Framework.Scenes
766 1072
767 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1073 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
768 1074
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) 1075 if (inter.HitTF)
775 { 1076 {
776 // We need to find the closest prim to return to the testcaller along the ray 1077 // We need to find the closest prim to return to the testcaller along the ray
@@ -781,10 +1082,11 @@ namespace OpenSim.Region.Framework.Scenes
781 result.obj = part; 1082 result.obj = part;
782 result.normal = inter.normal; 1083 result.normal = inter.normal;
783 result.distance = inter.distance; 1084 result.distance = inter.distance;
1085
1086 idist = inter.distance;
784 } 1087 }
785 } 1088 }
786 } 1089 }
787
788 return result; 1090 return result;
789 } 1091 }
790 1092
@@ -796,25 +1098,27 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <returns></returns> 1098 /// <returns></returns>
797 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1099 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
798 { 1100 {
799 maxX = -256f; 1101 maxX = float.MinValue;
800 maxY = -256f; 1102 maxY = float.MinValue;
801 maxZ = -256f; 1103 maxZ = float.MinValue;
802 minX = 256f; 1104 minX = float.MaxValue;
803 minY = 256f; 1105 minY = float.MaxValue;
804 minZ = 8192f; 1106 minZ = float.MaxValue;
805 1107
806 SceneObjectPart[] parts = m_parts.GetArray(); 1108 SceneObjectPart[] parts = m_parts.GetArray();
807 for (int i = 0; i < parts.Length; i++) 1109 foreach (SceneObjectPart part in parts)
808 { 1110 {
809 SceneObjectPart part = parts[i];
810
811 Vector3 worldPos = part.GetWorldPosition(); 1111 Vector3 worldPos = part.GetWorldPosition();
812 Vector3 offset = worldPos - AbsolutePosition; 1112 Vector3 offset = worldPos - AbsolutePosition;
813 Quaternion worldRot; 1113 Quaternion worldRot;
814 if (part.ParentID == 0) 1114 if (part.ParentID == 0)
1115 {
815 worldRot = part.RotationOffset; 1116 worldRot = part.RotationOffset;
1117 }
816 else 1118 else
1119 {
817 worldRot = part.GetWorldRotation(); 1120 worldRot = part.GetWorldRotation();
1121 }
818 1122
819 Vector3 frontTopLeft; 1123 Vector3 frontTopLeft;
820 Vector3 frontTopRight; 1124 Vector3 frontTopRight;
@@ -826,6 +1130,8 @@ namespace OpenSim.Region.Framework.Scenes
826 Vector3 backBottomLeft; 1130 Vector3 backBottomLeft;
827 Vector3 backBottomRight; 1131 Vector3 backBottomRight;
828 1132
1133 // Vector3[] corners = new Vector3[8];
1134
829 Vector3 orig = Vector3.Zero; 1135 Vector3 orig = Vector3.Zero;
830 1136
831 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1137 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -860,6 +1166,38 @@ namespace OpenSim.Region.Framework.Scenes
860 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1166 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
861 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1167 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
862 1168
1169
1170
1171 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1172 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1173 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1174 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1175 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1176 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1177 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1178 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1179
1180 //for (int i = 0; i < 8; i++)
1181 //{
1182 // corners[i] = corners[i] * worldRot;
1183 // corners[i] += offset;
1184
1185 // if (corners[i].X > maxX)
1186 // maxX = corners[i].X;
1187 // if (corners[i].X < minX)
1188 // minX = corners[i].X;
1189
1190 // if (corners[i].Y > maxY)
1191 // maxY = corners[i].Y;
1192 // if (corners[i].Y < minY)
1193 // minY = corners[i].Y;
1194
1195 // if (corners[i].Z > maxZ)
1196 // maxZ = corners[i].Y;
1197 // if (corners[i].Z < minZ)
1198 // minZ = corners[i].Z;
1199 //}
1200
863 frontTopLeft = frontTopLeft * worldRot; 1201 frontTopLeft = frontTopLeft * worldRot;
864 frontTopRight = frontTopRight * worldRot; 1202 frontTopRight = frontTopRight * worldRot;
865 frontBottomLeft = frontBottomLeft * worldRot; 1203 frontBottomLeft = frontBottomLeft * worldRot;
@@ -881,6 +1219,15 @@ namespace OpenSim.Region.Framework.Scenes
881 backTopLeft += offset; 1219 backTopLeft += offset;
882 backTopRight += offset; 1220 backTopRight += offset;
883 1221
1222 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1223 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1224 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1225 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1226 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1227 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1228 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1229 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1230
884 if (frontTopRight.X > maxX) 1231 if (frontTopRight.X > maxX)
885 maxX = frontTopRight.X; 1232 maxX = frontTopRight.X;
886 if (frontTopLeft.X > maxX) 1233 if (frontTopLeft.X > maxX)
@@ -1024,17 +1371,118 @@ namespace OpenSim.Region.Framework.Scenes
1024 1371
1025 #endregion 1372 #endregion
1026 1373
1374 public void GetResourcesCosts(SceneObjectPart apart,
1375 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1376 {
1377 // this information may need to be cached
1378
1379 float cost;
1380 float tmpcost;
1381
1382 bool ComplexCost = false;
1383
1384 SceneObjectPart p;
1385 SceneObjectPart[] parts;
1386
1387 lock (m_parts)
1388 {
1389 parts = m_parts.GetArray();
1390 }
1391
1392 int nparts = parts.Length;
1393
1394
1395 for (int i = 0; i < nparts; i++)
1396 {
1397 p = parts[i];
1398
1399 if (p.UsesComplexCost)
1400 {
1401 ComplexCost = true;
1402 break;
1403 }
1404 }
1405
1406 if (ComplexCost)
1407 {
1408 linksetResCost = 0;
1409 linksetPhysCost = 0;
1410 partCost = 0;
1411 partPhysCost = 0;
1412
1413 for (int i = 0; i < nparts; i++)
1414 {
1415 p = parts[i];
1416
1417 cost = p.StreamingCost;
1418 tmpcost = p.SimulationCost;
1419 if (tmpcost > cost)
1420 cost = tmpcost;
1421 tmpcost = p.PhysicsCost;
1422 if (tmpcost > cost)
1423 cost = tmpcost;
1424
1425 linksetPhysCost += tmpcost;
1426 linksetResCost += cost;
1427
1428 if (p == apart)
1429 {
1430 partCost = cost;
1431 partPhysCost = tmpcost;
1432 }
1433 }
1434 }
1435 else
1436 {
1437 partPhysCost = 1.0f;
1438 partCost = 1.0f;
1439 linksetResCost = (float)nparts;
1440 linksetPhysCost = linksetResCost;
1441 }
1442 }
1443
1444 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1445 {
1446 SceneObjectPart p;
1447 SceneObjectPart[] parts;
1448
1449 lock (m_parts)
1450 {
1451 parts = m_parts.GetArray();
1452 }
1453
1454 int nparts = parts.Length;
1455
1456 PhysCost = 0;
1457 StreamCost = 0;
1458 SimulCost = 0;
1459
1460 for (int i = 0; i < nparts; i++)
1461 {
1462 p = parts[i];
1463
1464 StreamCost += p.StreamingCost;
1465 SimulCost += p.SimulationCost;
1466 PhysCost += p.PhysicsCost;
1467 }
1468 }
1469
1027 public void SaveScriptedState(XmlTextWriter writer) 1470 public void SaveScriptedState(XmlTextWriter writer)
1028 { 1471 {
1472 SaveScriptedState(writer, false);
1473 }
1474
1475 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1476 {
1029 XmlDocument doc = new XmlDocument(); 1477 XmlDocument doc = new XmlDocument();
1030 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1478 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1031 1479
1032 SceneObjectPart[] parts = m_parts.GetArray(); 1480 SceneObjectPart[] parts = m_parts.GetArray();
1033 for (int i = 0; i < parts.Length; i++) 1481 for (int i = 0; i < parts.Length; i++)
1034 { 1482 {
1035 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1483 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1036 foreach (KeyValuePair<UUID, string> kvp in pstates) 1484 foreach (KeyValuePair<UUID, string> kvp in pstates)
1037 states.Add(kvp.Key, kvp.Value); 1485 states[kvp.Key] = kvp.Value;
1038 } 1486 }
1039 1487
1040 if (states.Count > 0) 1488 if (states.Count > 0)
@@ -1054,6 +1502,169 @@ namespace OpenSim.Region.Framework.Scenes
1054 } 1502 }
1055 1503
1056 /// <summary> 1504 /// <summary>
1505 /// Add the avatar to this linkset (avatar is sat).
1506 /// </summary>
1507 /// <param name="agentID"></param>
1508 public void AddAvatar(UUID agentID)
1509 {
1510 ScenePresence presence;
1511 if (m_scene.TryGetScenePresence(agentID, out presence))
1512 {
1513 if (!m_linkedAvatars.Contains(presence))
1514 {
1515 m_linkedAvatars.Add(presence);
1516 }
1517 }
1518 }
1519
1520 /// <summary>
1521 /// Delete the avatar from this linkset (avatar is unsat).
1522 /// </summary>
1523 /// <param name="agentID"></param>
1524 public void DeleteAvatar(UUID agentID)
1525 {
1526 ScenePresence presence;
1527 if (m_scene.TryGetScenePresence(agentID, out presence))
1528 {
1529 if (m_linkedAvatars.Contains(presence))
1530 {
1531 m_linkedAvatars.Remove(presence);
1532 }
1533 }
1534 }
1535
1536 /// <summary>
1537 /// Returns the list of linked presences (avatars sat on this group)
1538 /// </summary>
1539 /// <param name="agentID"></param>
1540 public List<ScenePresence> GetLinkedAvatars()
1541 {
1542 return m_linkedAvatars;
1543 }
1544
1545 /// <summary>
1546 /// Attach this scene object to the given avatar.
1547 /// </summary>
1548 /// <param name="agentID"></param>
1549 /// <param name="attachmentpoint"></param>
1550 /// <param name="AttachOffset"></param>
1551 private void AttachToAgent(
1552 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1553 {
1554 if (avatar != null)
1555 {
1556 // don't attach attachments to child agents
1557 if (avatar.IsChildAgent) return;
1558
1559 // Remove from database and parcel prim count
1560 m_scene.DeleteFromStorage(so.UUID);
1561 m_scene.EventManager.TriggerParcelPrimCountTainted();
1562
1563 so.AttachedAvatar = avatar.UUID;
1564
1565 if (so.RootPart.PhysActor != null)
1566 {
1567 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1568 so.RootPart.PhysActor = null;
1569 }
1570
1571 so.AbsolutePosition = attachOffset;
1572 so.RootPart.AttachedPos = attachOffset;
1573 so.IsAttachment = true;
1574 so.RootPart.SetParentLocalId(avatar.LocalId);
1575 so.AttachmentPoint = attachmentpoint;
1576
1577 avatar.AddAttachment(this);
1578
1579 if (!silent)
1580 {
1581 // Killing it here will cause the client to deselect it
1582 // It then reappears on the avatar, deselected
1583 // through the full update below
1584 //
1585 if (IsSelected)
1586 {
1587 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1588 }
1589
1590 IsSelected = false; // fudge....
1591 ScheduleGroupForFullUpdate();
1592 }
1593 }
1594 else
1595 {
1596 m_log.WarnFormat(
1597 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1598 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1599 }
1600 }
1601
1602 public byte GetAttachmentPoint()
1603 {
1604 return m_rootPart.Shape.State;
1605 }
1606
1607 public void DetachToGround()
1608 {
1609 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1610 if (avatar == null)
1611 return;
1612
1613 avatar.RemoveAttachment(this);
1614
1615 Vector3 detachedpos = new Vector3(127f,127f,127f);
1616 if (avatar == null)
1617 return;
1618
1619 detachedpos = avatar.AbsolutePosition;
1620 FromItemID = UUID.Zero;
1621
1622 AbsolutePosition = detachedpos;
1623 AttachedAvatar = UUID.Zero;
1624
1625 //SceneObjectPart[] parts = m_parts.GetArray();
1626 //for (int i = 0; i < parts.Length; i++)
1627 // parts[i].AttachedAvatar = UUID.Zero;
1628
1629 m_rootPart.SetParentLocalId(0);
1630 AttachmentPoint = (byte)0;
1631 // must check if buildind should be true or false here
1632 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1633 HasGroupChanged = true;
1634 RootPart.Rezzed = DateTime.Now;
1635 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1636 AttachToBackup();
1637 m_scene.EventManager.TriggerParcelPrimCountTainted();
1638 m_rootPart.ScheduleFullUpdate();
1639 m_rootPart.ClearUndoState();
1640 }
1641
1642 public void DetachToInventoryPrep()
1643 {
1644 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1645 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1646 if (avatar != null)
1647 {
1648 //detachedpos = avatar.AbsolutePosition;
1649 avatar.RemoveAttachment(this);
1650 }
1651
1652 AttachedAvatar = UUID.Zero;
1653
1654 /*SceneObjectPart[] parts = m_parts.GetArray();
1655 for (int i = 0; i < parts.Length; i++)
1656 parts[i].AttachedAvatar = UUID.Zero;*/
1657
1658 m_rootPart.SetParentLocalId(0);
1659 //m_rootPart.SetAttachmentPoint((byte)0);
1660 IsAttachment = false;
1661 AbsolutePosition = m_rootPart.AttachedPos;
1662 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1663 //AttachToBackup();
1664 //m_rootPart.ScheduleFullUpdate();
1665 }
1666
1667 /// <summary>
1057 /// 1668 ///
1058 /// </summary> 1669 /// </summary>
1059 /// <param name="part"></param> 1670 /// <param name="part"></param>
@@ -1093,7 +1704,10 @@ namespace OpenSim.Region.Framework.Scenes
1093 public void AddPart(SceneObjectPart part) 1704 public void AddPart(SceneObjectPart part)
1094 { 1705 {
1095 part.SetParent(this); 1706 part.SetParent(this);
1096 part.LinkNum = m_parts.Add(part.UUID, part); 1707 m_parts.Add(part.UUID, part);
1708
1709 part.LinkNum = m_parts.Count;
1710
1097 if (part.LinkNum == 2) 1711 if (part.LinkNum == 2)
1098 RootPart.LinkNum = 1; 1712 RootPart.LinkNum = 1;
1099 } 1713 }
@@ -1184,7 +1798,7 @@ namespace OpenSim.Region.Framework.Scenes
1184// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1798// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1185// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1799// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1186 1800
1187 part.StoreUndoState(); 1801// part.StoreUndoState();
1188 part.OnGrab(offsetPos, remoteClient); 1802 part.OnGrab(offsetPos, remoteClient);
1189 } 1803 }
1190 1804
@@ -1204,6 +1818,11 @@ namespace OpenSim.Region.Framework.Scenes
1204 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1818 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1205 public void DeleteGroupFromScene(bool silent) 1819 public void DeleteGroupFromScene(bool silent)
1206 { 1820 {
1821 // We need to keep track of this state in case this group is still queued for backup.
1822 IsDeleted = true;
1823
1824 DetachFromBackup();
1825
1207 SceneObjectPart[] parts = m_parts.GetArray(); 1826 SceneObjectPart[] parts = m_parts.GetArray();
1208 for (int i = 0; i < parts.Length; i++) 1827 for (int i = 0; i < parts.Length; i++)
1209 { 1828 {
@@ -1227,6 +1846,7 @@ namespace OpenSim.Region.Framework.Scenes
1227 } 1846 }
1228 }); 1847 });
1229 } 1848 }
1849
1230 } 1850 }
1231 1851
1232 public void AddScriptLPS(int count) 1852 public void AddScriptLPS(int count)
@@ -1296,28 +1916,43 @@ namespace OpenSim.Region.Framework.Scenes
1296 /// </summary> 1916 /// </summary>
1297 public void ApplyPhysics() 1917 public void ApplyPhysics()
1298 { 1918 {
1299 // Apply physics to the root prim
1300 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1301
1302 // Apply physics to child prims
1303 SceneObjectPart[] parts = m_parts.GetArray(); 1919 SceneObjectPart[] parts = m_parts.GetArray();
1304 if (parts.Length > 1) 1920 if (parts.Length > 1)
1305 { 1921 {
1922 ResetChildPrimPhysicsPositions();
1923
1924 // Apply physics to the root prim
1925 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1926
1927
1306 for (int i = 0; i < parts.Length; i++) 1928 for (int i = 0; i < parts.Length; i++)
1307 { 1929 {
1308 SceneObjectPart part = parts[i]; 1930 SceneObjectPart part = parts[i];
1309 if (part.LocalId != m_rootPart.LocalId) 1931 if (part.LocalId != m_rootPart.LocalId)
1310 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1932 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1311 } 1933 }
1312
1313 // Hack to get the physics scene geometries in the right spot 1934 // Hack to get the physics scene geometries in the right spot
1314 ResetChildPrimPhysicsPositions(); 1935// ResetChildPrimPhysicsPositions();
1936 if (m_rootPart.PhysActor != null)
1937 {
1938 m_rootPart.PhysActor.Building = false;
1939 }
1940 }
1941 else
1942 {
1943 // Apply physics to the root prim
1944 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1315 } 1945 }
1316 } 1946 }
1317 1947
1318 public void SetOwnerId(UUID userId) 1948 public void SetOwnerId(UUID userId)
1319 { 1949 {
1320 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1950 ForEachPart(delegate(SceneObjectPart part)
1951 {
1952
1953 part.OwnerID = userId;
1954
1955 });
1321 } 1956 }
1322 1957
1323 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1958 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1349,11 +1984,17 @@ namespace OpenSim.Region.Framework.Scenes
1349 return; 1984 return;
1350 } 1985 }
1351 1986
1987 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1988 return;
1989
1352 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1990 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1353 // any exception propogate upwards. 1991 // any exception propogate upwards.
1354 try 1992 try
1355 { 1993 {
1356 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1994 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1995 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
1996 m_scene.LoadingPrims) // Land may not be valid yet
1997
1357 { 1998 {
1358 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1999 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1359 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2000 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1380,6 +2021,7 @@ namespace OpenSim.Region.Framework.Scenes
1380 } 2021 }
1381 } 2022 }
1382 } 2023 }
2024
1383 } 2025 }
1384 2026
1385 if (m_scene.UseBackup && HasGroupChanged) 2027 if (m_scene.UseBackup && HasGroupChanged)
@@ -1387,10 +2029,30 @@ namespace OpenSim.Region.Framework.Scenes
1387 // don't backup while it's selected or you're asking for changes mid stream. 2029 // don't backup while it's selected or you're asking for changes mid stream.
1388 if (isTimeToPersist() || forcedBackup) 2030 if (isTimeToPersist() || forcedBackup)
1389 { 2031 {
2032 if (m_rootPart.PhysActor != null &&
2033 (!m_rootPart.PhysActor.IsPhysical))
2034 {
2035 // Possible ghost prim
2036 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2037 {
2038 foreach (SceneObjectPart part in m_parts.GetArray())
2039 {
2040 // Re-set physics actor positions and
2041 // orientations
2042 part.GroupPosition = m_rootPart.GroupPosition;
2043 }
2044 }
2045 }
1390// m_log.DebugFormat( 2046// m_log.DebugFormat(
1391// "[SCENE]: Storing {0}, {1} in {2}", 2047// "[SCENE]: Storing {0}, {1} in {2}",
1392// Name, UUID, m_scene.RegionInfo.RegionName); 2048// Name, UUID, m_scene.RegionInfo.RegionName);
1393 2049
2050 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2051 {
2052 RootPart.Shape.State = 0;
2053 ScheduleGroupForFullUpdate();
2054 }
2055
1394 SceneObjectGroup backup_group = Copy(false); 2056 SceneObjectGroup backup_group = Copy(false);
1395 backup_group.RootPart.Velocity = RootPart.Velocity; 2057 backup_group.RootPart.Velocity = RootPart.Velocity;
1396 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2058 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1400,6 +2062,16 @@ namespace OpenSim.Region.Framework.Scenes
1400 HasGroupChangedDueToDelink = false; 2062 HasGroupChangedDueToDelink = false;
1401 2063
1402 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2064 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2065/*
2066 backup_group.ForEachPart(delegate(SceneObjectPart part)
2067 {
2068 if (part.KeyframeMotion != null)
2069 {
2070 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2071// part.KeyframeMotion.UpdateSceneObject(this);
2072 }
2073 });
2074*/
1403 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2075 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1404 2076
1405 backup_group.ForEachPart(delegate(SceneObjectPart part) 2077 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1456,10 +2128,14 @@ namespace OpenSim.Region.Framework.Scenes
1456 /// <returns></returns> 2128 /// <returns></returns>
1457 public SceneObjectGroup Copy(bool userExposed) 2129 public SceneObjectGroup Copy(bool userExposed)
1458 { 2130 {
2131 m_dupeInProgress = true;
1459 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2132 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1460 dupe.m_isBackedUp = false; 2133 dupe.m_isBackedUp = false;
1461 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2134 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1462 2135
2136 // new group as no sitting avatars
2137 dupe.m_linkedAvatars = new List<ScenePresence>();
2138
1463 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2139 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1464 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2140 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1465 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2141 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1470,7 +2146,7 @@ namespace OpenSim.Region.Framework.Scenes
1470 // This is only necessary when userExposed is false! 2146 // This is only necessary when userExposed is false!
1471 2147
1472 bool previousAttachmentStatus = dupe.IsAttachment; 2148 bool previousAttachmentStatus = dupe.IsAttachment;
1473 2149
1474 if (!userExposed) 2150 if (!userExposed)
1475 dupe.IsAttachment = true; 2151 dupe.IsAttachment = true;
1476 2152
@@ -1483,16 +2159,17 @@ namespace OpenSim.Region.Framework.Scenes
1483 2159
1484 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2160 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1485 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2161 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2162
1486 2163
1487 if (userExposed) 2164 if (userExposed)
1488 dupe.m_rootPart.TrimPermissions(); 2165 dupe.m_rootPart.TrimPermissions();
1489 2166
1490 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2167 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1491 2168
1492 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2169 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1493 { 2170 {
1494 return p1.LinkNum.CompareTo(p2.LinkNum); 2171 return p1.LinkNum.CompareTo(p2.LinkNum);
1495 } 2172 }
1496 ); 2173 );
1497 2174
1498 foreach (SceneObjectPart part in partList) 2175 foreach (SceneObjectPart part in partList)
@@ -1502,41 +2179,56 @@ namespace OpenSim.Region.Framework.Scenes
1502 { 2179 {
1503 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2180 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1504 newPart.LinkNum = part.LinkNum; 2181 newPart.LinkNum = part.LinkNum;
1505 } 2182 if (userExposed)
2183 newPart.ParentID = dupe.m_rootPart.LocalId;
2184 }
1506 else 2185 else
1507 { 2186 {
1508 newPart = dupe.m_rootPart; 2187 newPart = dupe.m_rootPart;
1509 } 2188 }
2189/*
2190 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2191 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1510 2192
1511 // Need to duplicate the physics actor as well 2193 // Need to duplicate the physics actor as well
1512 PhysicsActor originalPartPa = part.PhysActor; 2194 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1513 if (originalPartPa != null && userExposed)
1514 { 2195 {
1515 PrimitiveBaseShape pbs = newPart.Shape; 2196 PrimitiveBaseShape pbs = newPart.Shape;
1516
1517 newPart.PhysActor 2197 newPart.PhysActor
1518 = m_scene.PhysicsScene.AddPrimShape( 2198 = m_scene.PhysicsScene.AddPrimShape(
1519 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2199 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1520 pbs, 2200 pbs,
1521 newPart.AbsolutePosition, 2201 newPart.AbsolutePosition,
1522 newPart.Scale, 2202 newPart.Scale,
1523 newPart.RotationOffset, 2203 newPart.GetWorldRotation(),
1524 originalPartPa.IsPhysical, 2204 isphys,
2205 isphan,
1525 newPart.LocalId); 2206 newPart.LocalId);
1526 2207
1527 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2208 newPart.DoPhysicsPropertyUpdate(isphys, true);
1528 } 2209 */
2210 if (userExposed)
2211 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2212// }
2213 // copy keyframemotion
2214 if (part.KeyframeMotion != null)
2215 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1529 } 2216 }
1530 2217
1531 if (userExposed) 2218 if (userExposed)
1532 { 2219 {
1533 dupe.UpdateParentIDs(); 2220// done above dupe.UpdateParentIDs();
2221
2222 if (dupe.m_rootPart.PhysActor != null)
2223 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2224
1534 dupe.HasGroupChanged = true; 2225 dupe.HasGroupChanged = true;
1535 dupe.AttachToBackup(); 2226 dupe.AttachToBackup();
1536 2227
1537 ScheduleGroupForFullUpdate(); 2228 ScheduleGroupForFullUpdate();
1538 } 2229 }
1539 2230
2231 m_dupeInProgress = false;
1540 return dupe; 2232 return dupe;
1541 } 2233 }
1542 2234
@@ -1548,11 +2240,24 @@ namespace OpenSim.Region.Framework.Scenes
1548 /// <param name="cGroupID"></param> 2240 /// <param name="cGroupID"></param>
1549 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2241 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1550 { 2242 {
1551 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2243 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2244 // give newpart a new local ID lettng old part keep same
2245 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2246 newpart.LocalId = m_scene.AllocateLocalId();
2247
2248 SetRootPart(newpart);
2249 if (userExposed)
2250 RootPart.Velocity = Vector3.Zero; // In case source is moving
1552 } 2251 }
1553 2252
1554 public void ScriptSetPhysicsStatus(bool usePhysics) 2253 public void ScriptSetPhysicsStatus(bool usePhysics)
1555 { 2254 {
2255 if (usePhysics)
2256 {
2257 if (RootPart.KeyframeMotion != null)
2258 RootPart.KeyframeMotion.Stop();
2259 RootPart.KeyframeMotion = null;
2260 }
1556 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2261 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1557 } 2262 }
1558 2263
@@ -1600,13 +2305,14 @@ namespace OpenSim.Region.Framework.Scenes
1600 2305
1601 if (pa != null) 2306 if (pa != null)
1602 { 2307 {
1603 pa.AddForce(impulse, true); 2308 // false to be applied as a impulse
2309 pa.AddForce(impulse, false);
1604 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2310 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1605 } 2311 }
1606 } 2312 }
1607 } 2313 }
1608 2314
1609 public void applyAngularImpulse(Vector3 impulse) 2315 public void ApplyAngularImpulse(Vector3 impulse)
1610 { 2316 {
1611 PhysicsActor pa = RootPart.PhysActor; 2317 PhysicsActor pa = RootPart.PhysActor;
1612 2318
@@ -1614,21 +2320,8 @@ namespace OpenSim.Region.Framework.Scenes
1614 { 2320 {
1615 if (!IsAttachment) 2321 if (!IsAttachment)
1616 { 2322 {
1617 pa.AddAngularForce(impulse, true); 2323 // false to be applied as a impulse
1618 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2324 pa.AddAngularForce(impulse, false);
1619 }
1620 }
1621 }
1622
1623 public void setAngularImpulse(Vector3 impulse)
1624 {
1625 PhysicsActor pa = RootPart.PhysActor;
1626
1627 if (pa != null)
1628 {
1629 if (!IsAttachment)
1630 {
1631 pa.Torque = impulse;
1632 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2325 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1633 } 2326 }
1634 } 2327 }
@@ -1636,20 +2329,10 @@ namespace OpenSim.Region.Framework.Scenes
1636 2329
1637 public Vector3 GetTorque() 2330 public Vector3 GetTorque()
1638 { 2331 {
1639 PhysicsActor pa = RootPart.PhysActor; 2332 return RootPart.Torque;
1640
1641 if (pa != null)
1642 {
1643 if (!IsAttachment)
1644 {
1645 Vector3 torque = pa.Torque;
1646 return torque;
1647 }
1648 }
1649
1650 return Vector3.Zero;
1651 } 2333 }
1652 2334
2335 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1653 public void moveToTarget(Vector3 target, float tau) 2336 public void moveToTarget(Vector3 target, float tau)
1654 { 2337 {
1655 if (IsAttachment) 2338 if (IsAttachment)
@@ -1681,6 +2364,46 @@ namespace OpenSim.Region.Framework.Scenes
1681 pa.PIDActive = false; 2364 pa.PIDActive = false;
1682 } 2365 }
1683 2366
2367 public void rotLookAt(Quaternion target, float strength, float damping)
2368 {
2369 SceneObjectPart rootpart = m_rootPart;
2370 if (rootpart != null)
2371 {
2372 if (IsAttachment)
2373 {
2374 /*
2375 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2376 if (avatar != null)
2377 {
2378 Rotate the Av?
2379 } */
2380 }
2381 else
2382 {
2383 if (rootpart.PhysActor != null)
2384 { // APID must be implemented in your physics system for this to function.
2385 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2386 rootpart.PhysActor.APIDStrength = strength;
2387 rootpart.PhysActor.APIDDamping = damping;
2388 rootpart.PhysActor.APIDActive = true;
2389 }
2390 }
2391 }
2392 }
2393
2394 public void stopLookAt()
2395 {
2396 SceneObjectPart rootpart = m_rootPart;
2397 if (rootpart != null)
2398 {
2399 if (rootpart.PhysActor != null)
2400 { // APID must be implemented in your physics system for this to function.
2401 rootpart.PhysActor.APIDActive = false;
2402 }
2403 }
2404
2405 }
2406
1684 /// <summary> 2407 /// <summary>
1685 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2408 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1686 /// </summary> 2409 /// </summary>
@@ -1697,7 +2420,7 @@ namespace OpenSim.Region.Framework.Scenes
1697 { 2420 {
1698 pa.PIDHoverHeight = height; 2421 pa.PIDHoverHeight = height;
1699 pa.PIDHoverType = hoverType; 2422 pa.PIDHoverType = hoverType;
1700 pa.PIDTau = tau; 2423 pa.PIDHoverTau = tau;
1701 pa.PIDHoverActive = true; 2424 pa.PIDHoverActive = true;
1702 } 2425 }
1703 else 2426 else
@@ -1737,7 +2460,12 @@ namespace OpenSim.Region.Framework.Scenes
1737 /// <param name="cGroupID"></param> 2460 /// <param name="cGroupID"></param>
1738 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2461 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1739 { 2462 {
1740 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2463 // give new ID to the new part, letting old keep original
2464 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2465 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2466 newPart.LocalId = m_scene.AllocateLocalId();
2467 newPart.SetParent(this);
2468
1741 AddPart(newPart); 2469 AddPart(newPart);
1742 2470
1743 SetPartAsNonRoot(newPart); 2471 SetPartAsNonRoot(newPart);
@@ -1876,11 +2604,11 @@ namespace OpenSim.Region.Framework.Scenes
1876 /// Immediately send a full update for this scene object. 2604 /// Immediately send a full update for this scene object.
1877 /// </summary> 2605 /// </summary>
1878 public void SendGroupFullUpdate() 2606 public void SendGroupFullUpdate()
1879 { 2607 {
1880 if (IsDeleted) 2608 if (IsDeleted)
1881 return; 2609 return;
1882 2610
1883// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2611// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1884 2612
1885 RootPart.SendFullUpdateToAllClients(); 2613 RootPart.SendFullUpdateToAllClients();
1886 2614
@@ -2036,6 +2764,11 @@ namespace OpenSim.Region.Framework.Scenes
2036 // 'linkPart' == the root of the group being linked into this group 2764 // 'linkPart' == the root of the group being linked into this group
2037 SceneObjectPart linkPart = objectGroup.m_rootPart; 2765 SceneObjectPart linkPart = objectGroup.m_rootPart;
2038 2766
2767 if (m_rootPart.PhysActor != null)
2768 m_rootPart.PhysActor.Building = true;
2769 if (linkPart.PhysActor != null)
2770 linkPart.PhysActor.Building = true;
2771
2039 // physics flags from group to be applied to linked parts 2772 // physics flags from group to be applied to linked parts
2040 bool grpusephys = UsesPhysics; 2773 bool grpusephys = UsesPhysics;
2041 bool grptemporary = IsTemporary; 2774 bool grptemporary = IsTemporary;
@@ -2061,12 +2794,12 @@ namespace OpenSim.Region.Framework.Scenes
2061 Vector3 axPos = linkPart.OffsetPosition; 2794 Vector3 axPos = linkPart.OffsetPosition;
2062 // Rotate the linking root SOP's position to be relative to the new root prim 2795 // Rotate the linking root SOP's position to be relative to the new root prim
2063 Quaternion parentRot = m_rootPart.RotationOffset; 2796 Quaternion parentRot = m_rootPart.RotationOffset;
2064 axPos *= Quaternion.Inverse(parentRot); 2797 axPos *= Quaternion.Conjugate(parentRot);
2065 linkPart.OffsetPosition = axPos; 2798 linkPart.OffsetPosition = axPos;
2066 2799
2067 // Make the linking root SOP's rotation relative to the new root prim 2800 // Make the linking root SOP's rotation relative to the new root prim
2068 Quaternion oldRot = linkPart.RotationOffset; 2801 Quaternion oldRot = linkPart.RotationOffset;
2069 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2802 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2070 linkPart.RotationOffset = newRot; 2803 linkPart.RotationOffset = newRot;
2071 2804
2072 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2805 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2100,7 +2833,7 @@ namespace OpenSim.Region.Framework.Scenes
2100 linkPart.CreateSelected = true; 2833 linkPart.CreateSelected = true;
2101 2834
2102 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2835 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2103 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2836 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2104 2837
2105 // If the added SOP is physical, also tell the physics engine about the link relationship. 2838 // If the added SOP is physical, also tell the physics engine about the link relationship.
2106 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2839 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2110,6 +2843,7 @@ namespace OpenSim.Region.Framework.Scenes
2110 } 2843 }
2111 2844
2112 linkPart.LinkNum = linkNum++; 2845 linkPart.LinkNum = linkNum++;
2846 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2113 2847
2114 // Get a list of the SOP's in the old group in order of their linknum's. 2848 // Get a list of the SOP's in the old group in order of their linknum's.
2115 SceneObjectPart[] ogParts = objectGroup.Parts; 2849 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2128,7 +2862,7 @@ namespace OpenSim.Region.Framework.Scenes
2128 2862
2129 // Update the physics flags for the newly added SOP 2863 // Update the physics flags for the newly added SOP
2130 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2864 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2131 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2865 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2132 2866
2133 // If the added SOP is physical, also tell the physics engine about the link relationship. 2867 // If the added SOP is physical, also tell the physics engine about the link relationship.
2134 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2868 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2146,7 +2880,7 @@ namespace OpenSim.Region.Framework.Scenes
2146 objectGroup.IsDeleted = true; 2880 objectGroup.IsDeleted = true;
2147 2881
2148 objectGroup.m_parts.Clear(); 2882 objectGroup.m_parts.Clear();
2149 2883
2150 // Can't do this yet since backup still makes use of the root part without any synchronization 2884 // Can't do this yet since backup still makes use of the root part without any synchronization
2151// objectGroup.m_rootPart = null; 2885// objectGroup.m_rootPart = null;
2152 2886
@@ -2160,6 +2894,9 @@ namespace OpenSim.Region.Framework.Scenes
2160 // unmoved prims! 2894 // unmoved prims!
2161 ResetChildPrimPhysicsPositions(); 2895 ResetChildPrimPhysicsPositions();
2162 2896
2897 if (m_rootPart.PhysActor != null)
2898 m_rootPart.PhysActor.Building = false;
2899
2163 //HasGroupChanged = true; 2900 //HasGroupChanged = true;
2164 //ScheduleGroupForFullUpdate(); 2901 //ScheduleGroupForFullUpdate();
2165 } 2902 }
@@ -2227,7 +2964,10 @@ namespace OpenSim.Region.Framework.Scenes
2227// m_log.DebugFormat( 2964// m_log.DebugFormat(
2228// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2965// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2229// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2966// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2230 2967
2968 if (m_rootPart.PhysActor != null)
2969 m_rootPart.PhysActor.Building = true;
2970
2231 linkPart.ClearUndoState(); 2971 linkPart.ClearUndoState();
2232 2972
2233 Vector3 worldPos = linkPart.GetWorldPosition(); 2973 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2298,6 +3038,14 @@ namespace OpenSim.Region.Framework.Scenes
2298 3038
2299 // When we delete a group, we currently have to force persist to the database if the object id has changed 3039 // When we delete a group, we currently have to force persist to the database if the object id has changed
2300 // (since delete works by deleting all rows which have a given object id) 3040 // (since delete works by deleting all rows which have a given object id)
3041
3042 // this is as it seems to be in sl now
3043 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3044 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3045
3046 if (m_rootPart.PhysActor != null)
3047 m_rootPart.PhysActor.Building = false;
3048
2301 objectGroup.HasGroupChangedDueToDelink = true; 3049 objectGroup.HasGroupChangedDueToDelink = true;
2302 3050
2303 return objectGroup; 3051 return objectGroup;
@@ -2309,6 +3057,8 @@ namespace OpenSim.Region.Framework.Scenes
2309 /// <param name="objectGroup"></param> 3057 /// <param name="objectGroup"></param>
2310 public virtual void DetachFromBackup() 3058 public virtual void DetachFromBackup()
2311 { 3059 {
3060 if (m_scene != null)
3061 m_scene.SceneGraph.FireDetachFromBackup(this);
2312 if (m_isBackedUp && Scene != null) 3062 if (m_isBackedUp && Scene != null)
2313 m_scene.EventManager.OnBackup -= ProcessBackup; 3063 m_scene.EventManager.OnBackup -= ProcessBackup;
2314 3064
@@ -2329,7 +3079,8 @@ namespace OpenSim.Region.Framework.Scenes
2329 Vector3 axPos = part.OffsetPosition; 3079 Vector3 axPos = part.OffsetPosition;
2330 axPos *= parentRot; 3080 axPos *= parentRot;
2331 part.OffsetPosition = axPos; 3081 part.OffsetPosition = axPos;
2332 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3082 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3083 part.GroupPosition = newPos;
2333 part.OffsetPosition = Vector3.Zero; 3084 part.OffsetPosition = Vector3.Zero;
2334 3085
2335 // Compution our rotation to be not relative to the old parent 3086 // Compution our rotation to be not relative to the old parent
@@ -2344,7 +3095,7 @@ namespace OpenSim.Region.Framework.Scenes
2344 part.LinkNum = linkNum; 3095 part.LinkNum = linkNum;
2345 3096
2346 // Compute the new position of this SOP relative to the group position 3097 // Compute the new position of this SOP relative to the group position
2347 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3098 part.OffsetPosition = newPos - AbsolutePosition;
2348 3099
2349 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3100 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2350 // It would have the affect of setting the physics engine position multiple 3101 // It would have the affect of setting the physics engine position multiple
@@ -2354,18 +3105,19 @@ namespace OpenSim.Region.Framework.Scenes
2354 // Rotate the relative position by the rotation of the group 3105 // Rotate the relative position by the rotation of the group
2355 Quaternion rootRotation = m_rootPart.RotationOffset; 3106 Quaternion rootRotation = m_rootPart.RotationOffset;
2356 Vector3 pos = part.OffsetPosition; 3107 Vector3 pos = part.OffsetPosition;
2357 pos *= Quaternion.Inverse(rootRotation); 3108 pos *= Quaternion.Conjugate(rootRotation);
2358 part.OffsetPosition = pos; 3109 part.OffsetPosition = pos;
2359 3110
2360 // Compute the SOP's rotation relative to the rotation of the group. 3111 // Compute the SOP's rotation relative to the rotation of the group.
2361 parentRot = m_rootPart.RotationOffset; 3112 parentRot = m_rootPart.RotationOffset;
2362 oldRot = part.RotationOffset; 3113 oldRot = part.RotationOffset;
2363 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3114 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2364 part.RotationOffset = newRot; 3115 part.RotationOffset = newRot;
2365 3116
2366 // Since this SOP's state has changed, push those changes into the physics engine 3117 // Since this SOP's state has changed, push those changes into the physics engine
2367 // and the simulator. 3118 // and the simulator.
2368 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3119 // done on caller
3120// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2369 } 3121 }
2370 3122
2371 /// <summary> 3123 /// <summary>
@@ -2387,10 +3139,14 @@ namespace OpenSim.Region.Framework.Scenes
2387 { 3139 {
2388 if (!m_rootPart.BlockGrab) 3140 if (!m_rootPart.BlockGrab)
2389 { 3141 {
2390 Vector3 llmoveforce = pos - AbsolutePosition; 3142/* Vector3 llmoveforce = pos - AbsolutePosition;
2391 Vector3 grabforce = llmoveforce; 3143 Vector3 grabforce = llmoveforce;
2392 grabforce = (grabforce / 10) * pa.Mass; 3144 grabforce = (grabforce / 10) * pa.Mass;
2393 pa.AddForce(grabforce, true); 3145 */
3146 // empirically convert distance diference to a impulse
3147 Vector3 grabforce = pos - AbsolutePosition;
3148 grabforce = grabforce * (pa.Mass/ 10.0f);
3149 pa.AddForce(grabforce, false);
2394 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3150 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2395 } 3151 }
2396 } 3152 }
@@ -2586,6 +3342,8 @@ namespace OpenSim.Region.Framework.Scenes
2586 /// <param name="SetVolumeDetect"></param> 3342 /// <param name="SetVolumeDetect"></param>
2587 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3343 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2588 { 3344 {
3345 HasGroupChanged = true;
3346
2589 SceneObjectPart selectionPart = GetPart(localID); 3347 SceneObjectPart selectionPart = GetPart(localID);
2590 3348
2591 if (SetTemporary && Scene != null) 3349 if (SetTemporary && Scene != null)
@@ -2616,8 +3374,22 @@ namespace OpenSim.Region.Framework.Scenes
2616 } 3374 }
2617 } 3375 }
2618 3376
2619 for (int i = 0; i < parts.Length; i++) 3377 if (parts.Length > 1)
2620 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3378 {
3379 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3380
3381 for (int i = 0; i < parts.Length; i++)
3382 {
3383
3384 if (parts[i].UUID != m_rootPart.UUID)
3385 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3386 }
3387
3388 if (m_rootPart.PhysActor != null)
3389 m_rootPart.PhysActor.Building = false;
3390 }
3391 else
3392 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2621 } 3393 }
2622 } 3394 }
2623 3395
@@ -2630,6 +3402,17 @@ namespace OpenSim.Region.Framework.Scenes
2630 } 3402 }
2631 } 3403 }
2632 3404
3405
3406
3407 /// <summary>
3408 /// Gets the number of parts
3409 /// </summary>
3410 /// <returns></returns>
3411 public int GetPartCount()
3412 {
3413 return Parts.Count();
3414 }
3415
2633 /// <summary> 3416 /// <summary>
2634 /// Update the texture entry for this part 3417 /// Update the texture entry for this part
2635 /// </summary> 3418 /// </summary>
@@ -2700,11 +3483,6 @@ namespace OpenSim.Region.Framework.Scenes
2700 /// <param name="scale"></param> 3483 /// <param name="scale"></param>
2701 public void GroupResize(Vector3 scale) 3484 public void GroupResize(Vector3 scale)
2702 { 3485 {
2703// m_log.DebugFormat(
2704// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2705
2706 RootPart.StoreUndoState(true);
2707
2708 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3486 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
2709 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); 3487 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
2710 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); 3488 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
@@ -2731,7 +3509,6 @@ namespace OpenSim.Region.Framework.Scenes
2731 SceneObjectPart obPart = parts[i]; 3509 SceneObjectPart obPart = parts[i];
2732 if (obPart.UUID != m_rootPart.UUID) 3510 if (obPart.UUID != m_rootPart.UUID)
2733 { 3511 {
2734// obPart.IgnoreUndoUpdate = true;
2735 Vector3 oldSize = new Vector3(obPart.Scale); 3512 Vector3 oldSize = new Vector3(obPart.Scale);
2736 3513
2737 float f = 1.0f; 3514 float f = 1.0f;
@@ -2843,8 +3620,6 @@ namespace OpenSim.Region.Framework.Scenes
2843 z *= a; 3620 z *= a;
2844 } 3621 }
2845 } 3622 }
2846
2847// obPart.IgnoreUndoUpdate = false;
2848 } 3623 }
2849 } 3624 }
2850 } 3625 }
@@ -2854,9 +3629,7 @@ namespace OpenSim.Region.Framework.Scenes
2854 prevScale.Y *= y; 3629 prevScale.Y *= y;
2855 prevScale.Z *= z; 3630 prevScale.Z *= z;
2856 3631
2857// RootPart.IgnoreUndoUpdate = true;
2858 RootPart.Resize(prevScale); 3632 RootPart.Resize(prevScale);
2859// RootPart.IgnoreUndoUpdate = false;
2860 3633
2861 parts = m_parts.GetArray(); 3634 parts = m_parts.GetArray();
2862 for (int i = 0; i < parts.Length; i++) 3635 for (int i = 0; i < parts.Length; i++)
@@ -2865,8 +3638,6 @@ namespace OpenSim.Region.Framework.Scenes
2865 3638
2866 if (obPart.UUID != m_rootPart.UUID) 3639 if (obPart.UUID != m_rootPart.UUID)
2867 { 3640 {
2868 obPart.IgnoreUndoUpdate = true;
2869
2870 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3641 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2871 currentpos.X *= x; 3642 currentpos.X *= x;
2872 currentpos.Y *= y; 3643 currentpos.Y *= y;
@@ -2879,16 +3650,12 @@ namespace OpenSim.Region.Framework.Scenes
2879 3650
2880 obPart.Resize(newSize); 3651 obPart.Resize(newSize);
2881 obPart.UpdateOffSet(currentpos); 3652 obPart.UpdateOffSet(currentpos);
2882
2883 obPart.IgnoreUndoUpdate = false;
2884 } 3653 }
2885 3654
2886// obPart.IgnoreUndoUpdate = false; 3655 HasGroupChanged = true;
2887// obPart.StoreUndoState(); 3656 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3657 ScheduleGroupForTerseUpdate();
2888 } 3658 }
2889
2890// m_log.DebugFormat(
2891// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2892 } 3659 }
2893 3660
2894 #endregion 3661 #endregion
@@ -2901,14 +3668,6 @@ namespace OpenSim.Region.Framework.Scenes
2901 /// <param name="pos"></param> 3668 /// <param name="pos"></param>
2902 public void UpdateGroupPosition(Vector3 pos) 3669 public void UpdateGroupPosition(Vector3 pos)
2903 { 3670 {
2904// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2905
2906 RootPart.StoreUndoState(true);
2907
2908// SceneObjectPart[] parts = m_parts.GetArray();
2909// for (int i = 0; i < parts.Length; i++)
2910// parts[i].StoreUndoState();
2911
2912 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3671 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2913 { 3672 {
2914 if (IsAttachment) 3673 if (IsAttachment)
@@ -2941,21 +3700,17 @@ namespace OpenSim.Region.Framework.Scenes
2941 /// </summary> 3700 /// </summary>
2942 /// <param name="pos"></param> 3701 /// <param name="pos"></param>
2943 /// <param name="localID"></param> 3702 /// <param name="localID"></param>
3703 ///
3704
2944 public void UpdateSinglePosition(Vector3 pos, uint localID) 3705 public void UpdateSinglePosition(Vector3 pos, uint localID)
2945 { 3706 {
2946 SceneObjectPart part = GetPart(localID); 3707 SceneObjectPart part = GetPart(localID);
2947 3708
2948// SceneObjectPart[] parts = m_parts.GetArray();
2949// for (int i = 0; i < parts.Length; i++)
2950// parts[i].StoreUndoState();
2951
2952 if (part != null) 3709 if (part != null)
2953 { 3710 {
2954// m_log.DebugFormat( 3711// unlock parts position change
2955// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3712 if (m_rootPart.PhysActor != null)
2956 3713 m_rootPart.PhysActor.Building = true;
2957 part.StoreUndoState(false);
2958 part.IgnoreUndoUpdate = true;
2959 3714
2960 if (part.UUID == m_rootPart.UUID) 3715 if (part.UUID == m_rootPart.UUID)
2961 { 3716 {
@@ -2966,8 +3721,10 @@ namespace OpenSim.Region.Framework.Scenes
2966 part.UpdateOffSet(pos); 3721 part.UpdateOffSet(pos);
2967 } 3722 }
2968 3723
3724 if (m_rootPart.PhysActor != null)
3725 m_rootPart.PhysActor.Building = false;
3726
2969 HasGroupChanged = true; 3727 HasGroupChanged = true;
2970 part.IgnoreUndoUpdate = false;
2971 } 3728 }
2972 } 3729 }
2973 3730
@@ -2977,13 +3734,7 @@ namespace OpenSim.Region.Framework.Scenes
2977 /// <param name="pos"></param> 3734 /// <param name="pos"></param>
2978 public void UpdateRootPosition(Vector3 pos) 3735 public void UpdateRootPosition(Vector3 pos)
2979 { 3736 {
2980// m_log.DebugFormat( 3737 // needs to be called with phys building true
2981// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2982
2983// SceneObjectPart[] parts = m_parts.GetArray();
2984// for (int i = 0; i < parts.Length; i++)
2985// parts[i].StoreUndoState();
2986
2987 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3738 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2988 Vector3 oldPos = 3739 Vector3 oldPos =
2989 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3740 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3006,7 +3757,14 @@ namespace OpenSim.Region.Framework.Scenes
3006 AbsolutePosition = newPos; 3757 AbsolutePosition = newPos;
3007 3758
3008 HasGroupChanged = true; 3759 HasGroupChanged = true;
3009 ScheduleGroupForTerseUpdate(); 3760 if (m_rootPart.Undoing)
3761 {
3762 ScheduleGroupForFullUpdate();
3763 }
3764 else
3765 {
3766 ScheduleGroupForTerseUpdate();
3767 }
3010 } 3768 }
3011 3769
3012 #endregion 3770 #endregion
@@ -3019,24 +3777,16 @@ namespace OpenSim.Region.Framework.Scenes
3019 /// <param name="rot"></param> 3777 /// <param name="rot"></param>
3020 public void UpdateGroupRotationR(Quaternion rot) 3778 public void UpdateGroupRotationR(Quaternion rot)
3021 { 3779 {
3022// m_log.DebugFormat(
3023// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3024
3025// SceneObjectPart[] parts = m_parts.GetArray();
3026// for (int i = 0; i < parts.Length; i++)
3027// parts[i].StoreUndoState();
3028
3029 m_rootPart.StoreUndoState(true);
3030
3031 m_rootPart.UpdateRotation(rot); 3780 m_rootPart.UpdateRotation(rot);
3032 3781
3782/* this is done by rootpart RotationOffset set called by UpdateRotation
3033 PhysicsActor actor = m_rootPart.PhysActor; 3783 PhysicsActor actor = m_rootPart.PhysActor;
3034 if (actor != null) 3784 if (actor != null)
3035 { 3785 {
3036 actor.Orientation = m_rootPart.RotationOffset; 3786 actor.Orientation = m_rootPart.RotationOffset;
3037 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3787 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3038 } 3788 }
3039 3789*/
3040 HasGroupChanged = true; 3790 HasGroupChanged = true;
3041 ScheduleGroupForTerseUpdate(); 3791 ScheduleGroupForTerseUpdate();
3042 } 3792 }
@@ -3048,16 +3798,6 @@ namespace OpenSim.Region.Framework.Scenes
3048 /// <param name="rot"></param> 3798 /// <param name="rot"></param>
3049 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3799 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3050 { 3800 {
3051// m_log.DebugFormat(
3052// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3053
3054// SceneObjectPart[] parts = m_parts.GetArray();
3055// for (int i = 0; i < parts.Length; i++)
3056// parts[i].StoreUndoState();
3057
3058 RootPart.StoreUndoState(true);
3059 RootPart.IgnoreUndoUpdate = true;
3060
3061 m_rootPart.UpdateRotation(rot); 3801 m_rootPart.UpdateRotation(rot);
3062 3802
3063 PhysicsActor actor = m_rootPart.PhysActor; 3803 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3076,8 +3816,6 @@ namespace OpenSim.Region.Framework.Scenes
3076 3816
3077 HasGroupChanged = true; 3817 HasGroupChanged = true;
3078 ScheduleGroupForTerseUpdate(); 3818 ScheduleGroupForTerseUpdate();
3079
3080 RootPart.IgnoreUndoUpdate = false;
3081 } 3819 }
3082 3820
3083 /// <summary> 3821 /// <summary>
@@ -3090,13 +3828,11 @@ namespace OpenSim.Region.Framework.Scenes
3090 SceneObjectPart part = GetPart(localID); 3828 SceneObjectPart part = GetPart(localID);
3091 3829
3092 SceneObjectPart[] parts = m_parts.GetArray(); 3830 SceneObjectPart[] parts = m_parts.GetArray();
3093 for (int i = 0; i < parts.Length; i++)
3094 parts[i].StoreUndoState();
3095 3831
3096 if (part != null) 3832 if (part != null)
3097 { 3833 {
3098// m_log.DebugFormat( 3834 if (m_rootPart.PhysActor != null)
3099// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3835 m_rootPart.PhysActor.Building = true;
3100 3836
3101 if (part.UUID == m_rootPart.UUID) 3837 if (part.UUID == m_rootPart.UUID)
3102 { 3838 {
@@ -3106,6 +3842,9 @@ namespace OpenSim.Region.Framework.Scenes
3106 { 3842 {
3107 part.UpdateRotation(rot); 3843 part.UpdateRotation(rot);
3108 } 3844 }
3845
3846 if (m_rootPart.PhysActor != null)
3847 m_rootPart.PhysActor.Building = false;
3109 } 3848 }
3110 } 3849 }
3111 3850
@@ -3119,12 +3858,8 @@ namespace OpenSim.Region.Framework.Scenes
3119 SceneObjectPart part = GetPart(localID); 3858 SceneObjectPart part = GetPart(localID);
3120 if (part != null) 3859 if (part != null)
3121 { 3860 {
3122// m_log.DebugFormat( 3861 if (m_rootPart.PhysActor != null)
3123// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3862 m_rootPart.PhysActor.Building = true;
3124// part.Name, part.LocalId, rot);
3125
3126 part.StoreUndoState();
3127 part.IgnoreUndoUpdate = true;
3128 3863
3129 if (part.UUID == m_rootPart.UUID) 3864 if (part.UUID == m_rootPart.UUID)
3130 { 3865 {
@@ -3137,7 +3872,8 @@ namespace OpenSim.Region.Framework.Scenes
3137 part.OffsetPosition = pos; 3872 part.OffsetPosition = pos;
3138 } 3873 }
3139 3874
3140 part.IgnoreUndoUpdate = false; 3875 if (m_rootPart.PhysActor != null)
3876 m_rootPart.PhysActor.Building = false;
3141 } 3877 }
3142 } 3878 }
3143 3879
@@ -3147,15 +3883,12 @@ namespace OpenSim.Region.Framework.Scenes
3147 /// <param name="rot"></param> 3883 /// <param name="rot"></param>
3148 public void UpdateRootRotation(Quaternion rot) 3884 public void UpdateRootRotation(Quaternion rot)
3149 { 3885 {
3150// m_log.DebugFormat( 3886 // needs to be called with phys building true
3151// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3152// Name, LocalId, rot);
3153
3154 Quaternion axRot = rot; 3887 Quaternion axRot = rot;
3155 Quaternion oldParentRot = m_rootPart.RotationOffset; 3888 Quaternion oldParentRot = m_rootPart.RotationOffset;
3156 3889
3157 m_rootPart.StoreUndoState(); 3890 //Don't use UpdateRotation because it schedules an update prematurely
3158 m_rootPart.UpdateRotation(rot); 3891 m_rootPart.RotationOffset = rot;
3159 3892
3160 PhysicsActor pa = m_rootPart.PhysActor; 3893 PhysicsActor pa = m_rootPart.PhysActor;
3161 3894
@@ -3171,35 +3904,145 @@ namespace OpenSim.Region.Framework.Scenes
3171 SceneObjectPart prim = parts[i]; 3904 SceneObjectPart prim = parts[i];
3172 if (prim.UUID != m_rootPart.UUID) 3905 if (prim.UUID != m_rootPart.UUID)
3173 { 3906 {
3174 prim.IgnoreUndoUpdate = true; 3907 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3908 NewRot = Quaternion.Inverse(axRot) * NewRot;
3909 prim.RotationOffset = NewRot;
3910
3175 Vector3 axPos = prim.OffsetPosition; 3911 Vector3 axPos = prim.OffsetPosition;
3912
3176 axPos *= oldParentRot; 3913 axPos *= oldParentRot;
3177 axPos *= Quaternion.Inverse(axRot); 3914 axPos *= Quaternion.Inverse(axRot);
3178 prim.OffsetPosition = axPos; 3915 prim.OffsetPosition = axPos;
3179 Quaternion primsRot = prim.RotationOffset; 3916 }
3180 Quaternion newRot = oldParentRot * primsRot; 3917 }
3181 newRot = Quaternion.Inverse(axRot) * newRot;
3182 prim.RotationOffset = newRot;
3183 prim.ScheduleTerseUpdate();
3184 prim.IgnoreUndoUpdate = false;
3185 }
3186 }
3187
3188// for (int i = 0; i < parts.Length; i++)
3189// {
3190// SceneObjectPart childpart = parts[i];
3191// if (childpart != m_rootPart)
3192// {
3193//// childpart.IgnoreUndoUpdate = false;
3194//// childpart.StoreUndoState();
3195// }
3196// }
3197 3918
3198 m_rootPart.ScheduleTerseUpdate(); 3919 HasGroupChanged = true;
3920 ScheduleGroupForFullUpdate();
3921 }
3199 3922
3200// m_log.DebugFormat( 3923 private enum updatetype :int
3201// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3924 {
3202// Name, LocalId, rot); 3925 none = 0,
3926 partterse = 1,
3927 partfull = 2,
3928 groupterse = 3,
3929 groupfull = 4
3930 }
3931
3932 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3933 {
3934 // TODO this still as excessive *.Schedule*Update()s
3935
3936 if (part != null && part.ParentGroup != null)
3937 {
3938 ObjectChangeType change = data.change;
3939 bool togroup = ((change & ObjectChangeType.Group) != 0);
3940 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3941
3942 SceneObjectGroup group = part.ParentGroup;
3943 PhysicsActor pha = group.RootPart.PhysActor;
3944
3945 updatetype updateType = updatetype.none;
3946
3947 if (togroup)
3948 {
3949 // related to group
3950 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3951 {
3952 if ((change & ObjectChangeType.Rotation) != 0)
3953 {
3954 group.RootPart.UpdateRotation(data.rotation);
3955 updateType = updatetype.none;
3956 }
3957 if ((change & ObjectChangeType.Position) != 0)
3958 {
3959 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3960 UpdateGroupPosition(data.position);
3961 updateType = updatetype.groupterse;
3962 }
3963 else
3964 // ugly rotation update of all parts
3965 {
3966 group.ResetChildPrimPhysicsPositions();
3967 }
3968
3969 }
3970 if ((change & ObjectChangeType.Scale) != 0)
3971 {
3972 if (pha != null)
3973 pha.Building = true;
3974
3975 group.GroupResize(data.scale);
3976 updateType = updatetype.none;
3977
3978 if (pha != null)
3979 pha.Building = false;
3980 }
3981 }
3982 else
3983 {
3984 // related to single prim in a link-set ( ie group)
3985 if (pha != null)
3986 pha.Building = true;
3987
3988 // root part is special
3989 // parts offset positions or rotations need to change also
3990
3991 if (part == group.RootPart)
3992 {
3993 if ((change & ObjectChangeType.Rotation) != 0)
3994 group.UpdateRootRotation(data.rotation);
3995 if ((change & ObjectChangeType.Position) != 0)
3996 group.UpdateRootPosition(data.position);
3997 if ((change & ObjectChangeType.Scale) != 0)
3998 part.Resize(data.scale);
3999 }
4000 else
4001 {
4002 if ((change & ObjectChangeType.Position) != 0)
4003 {
4004 part.OffsetPosition = data.position;
4005 updateType = updatetype.partterse;
4006 }
4007 if ((change & ObjectChangeType.Rotation) != 0)
4008 {
4009 part.UpdateRotation(data.rotation);
4010 updateType = updatetype.none;
4011 }
4012 if ((change & ObjectChangeType.Scale) != 0)
4013 {
4014 part.Resize(data.scale);
4015 updateType = updatetype.none;
4016 }
4017 }
4018
4019 if (pha != null)
4020 pha.Building = false;
4021 }
4022
4023 if (updateType != updatetype.none)
4024 {
4025 group.HasGroupChanged = true;
4026
4027 switch (updateType)
4028 {
4029 case updatetype.partterse:
4030 part.ScheduleTerseUpdate();
4031 break;
4032 case updatetype.partfull:
4033 part.ScheduleFullUpdate();
4034 break;
4035 case updatetype.groupterse:
4036 group.ScheduleGroupForTerseUpdate();
4037 break;
4038 case updatetype.groupfull:
4039 group.ScheduleGroupForFullUpdate();
4040 break;
4041 default:
4042 break;
4043 }
4044 }
4045 }
3203 } 4046 }
3204 4047
3205 #endregion 4048 #endregion
@@ -3298,10 +4141,11 @@ namespace OpenSim.Region.Framework.Scenes
3298 scriptPosTarget target = m_targets[idx]; 4141 scriptPosTarget target = m_targets[idx];
3299 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4142 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3300 { 4143 {
4144 at_target = true;
4145
3301 // trigger at_target 4146 // trigger at_target
3302 if (m_scriptListens_atTarget) 4147 if (m_scriptListens_atTarget)
3303 { 4148 {
3304 at_target = true;
3305 scriptPosTarget att = new scriptPosTarget(); 4149 scriptPosTarget att = new scriptPosTarget();
3306 att.targetPos = target.targetPos; 4150 att.targetPos = target.targetPos;
3307 att.tolerance = target.tolerance; 4151 att.tolerance = target.tolerance;
@@ -3419,11 +4263,50 @@ namespace OpenSim.Region.Framework.Scenes
3419 } 4263 }
3420 } 4264 }
3421 } 4265 }
3422 4266
4267 public Vector3 GetGeometricCenter()
4268 {
4269 // this is not real geometric center but a average of positions relative to root prim acording to
4270 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4271 // ignoring tortured prims details since sl also seems to ignore
4272 // so no real use in doing it on physics
4273
4274 Vector3 gc = Vector3.Zero;
4275
4276 int nparts = m_parts.Count;
4277 if (nparts <= 1)
4278 return gc;
4279
4280 SceneObjectPart[] parts = m_parts.GetArray();
4281 nparts = parts.Length; // just in case it changed
4282 if (nparts <= 1)
4283 return gc;
4284
4285 Quaternion parentRot = RootPart.RotationOffset;
4286 Vector3 pPos;
4287
4288 // average all parts positions
4289 for (int i = 0; i < nparts; i++)
4290 {
4291 // do it directly
4292 // gc += parts[i].GetWorldPosition();
4293 if (parts[i] != RootPart)
4294 {
4295 pPos = parts[i].OffsetPosition;
4296 gc += pPos;
4297 }
4298
4299 }
4300 gc /= nparts;
4301
4302 // relative to root:
4303// gc -= AbsolutePosition;
4304 return gc;
4305 }
4306
3423 public float GetMass() 4307 public float GetMass()
3424 { 4308 {
3425 float retmass = 0f; 4309 float retmass = 0f;
3426
3427 SceneObjectPart[] parts = m_parts.GetArray(); 4310 SceneObjectPart[] parts = m_parts.GetArray();
3428 for (int i = 0; i < parts.Length; i++) 4311 for (int i = 0; i < parts.Length; i++)
3429 retmass += parts[i].GetMass(); 4312 retmass += parts[i].GetMass();
@@ -3431,6 +4314,39 @@ namespace OpenSim.Region.Framework.Scenes
3431 return retmass; 4314 return retmass;
3432 } 4315 }
3433 4316
4317 // center of mass of full object
4318 public Vector3 GetCenterOfMass()
4319 {
4320 PhysicsActor pa = RootPart.PhysActor;
4321
4322 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4323 {
4324 // physics knows better about center of mass of physical prims
4325 Vector3 tmp = pa.CenterOfMass;
4326 return tmp;
4327 }
4328
4329 Vector3 Ptot = Vector3.Zero;
4330 float totmass = 0f;
4331 float m;
4332
4333 SceneObjectPart[] parts = m_parts.GetArray();
4334 for (int i = 0; i < parts.Length; i++)
4335 {
4336 m = parts[i].GetMass();
4337 Ptot += parts[i].GetPartCenterOfMass() * m;
4338 totmass += m;
4339 }
4340
4341 if (totmass == 0)
4342 totmass = 0;
4343 else
4344 totmass = 1 / totmass;
4345 Ptot *= totmass;
4346
4347 return Ptot;
4348 }
4349
3434 /// <summary> 4350 /// <summary>
3435 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4351 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3436 /// the physics engine can use it. 4352 /// the physics engine can use it.
@@ -3598,6 +4514,14 @@ namespace OpenSim.Region.Framework.Scenes
3598 FromItemID = uuid; 4514 FromItemID = uuid;
3599 } 4515 }
3600 4516
4517 public void ResetOwnerChangeFlag()
4518 {
4519 ForEachPart(delegate(SceneObjectPart part)
4520 {
4521 part.ResetOwnerChangeFlag();
4522 });
4523 }
4524
3601 #endregion 4525 #endregion
3602 } 4526 }
3603} 4527}