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.cs1358
1 files changed, 1139 insertions, 219 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index b4a155e..0448c25 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, x, y, 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
@@ -1488,11 +2164,11 @@ namespace OpenSim.Region.Framework.Scenes
1488 dupe.m_rootPart.TrimPermissions(); 2164 dupe.m_rootPart.TrimPermissions();
1489 2165
1490 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2166 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1491 2167
1492 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2168 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1493 { 2169 {
1494 return p1.LinkNum.CompareTo(p2.LinkNum); 2170 return p1.LinkNum.CompareTo(p2.LinkNum);
1495 } 2171 }
1496 ); 2172 );
1497 2173
1498 foreach (SceneObjectPart part in partList) 2174 foreach (SceneObjectPart part in partList)
@@ -1502,41 +2178,53 @@ namespace OpenSim.Region.Framework.Scenes
1502 { 2178 {
1503 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2179 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1504 newPart.LinkNum = part.LinkNum; 2180 newPart.LinkNum = part.LinkNum;
1505 } 2181 if (userExposed)
2182 newPart.ParentID = dupe.m_rootPart.LocalId;
2183 }
1506 else 2184 else
1507 { 2185 {
1508 newPart = dupe.m_rootPart; 2186 newPart = dupe.m_rootPart;
1509 } 2187 }
2188/*
2189 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2190 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1510 2191
1511 // Need to duplicate the physics actor as well 2192 // Need to duplicate the physics actor as well
1512 PhysicsActor originalPartPa = part.PhysActor; 2193 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1513 if (originalPartPa != null && userExposed)
1514 { 2194 {
1515 PrimitiveBaseShape pbs = newPart.Shape; 2195 PrimitiveBaseShape pbs = newPart.Shape;
1516
1517 newPart.PhysActor 2196 newPart.PhysActor
1518 = m_scene.PhysicsScene.AddPrimShape( 2197 = m_scene.PhysicsScene.AddPrimShape(
1519 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2198 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1520 pbs, 2199 pbs,
1521 newPart.AbsolutePosition, 2200 newPart.AbsolutePosition,
1522 newPart.Scale, 2201 newPart.Scale,
1523 newPart.RotationOffset, 2202 newPart.GetWorldRotation(),
1524 originalPartPa.IsPhysical, 2203 isphys,
2204 isphan,
1525 newPart.LocalId); 2205 newPart.LocalId);
1526 2206
1527 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2207 newPart.DoPhysicsPropertyUpdate(isphys, true);
1528 } 2208 */
2209 if (userExposed)
2210 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2211// }
1529 } 2212 }
1530 2213
1531 if (userExposed) 2214 if (userExposed)
1532 { 2215 {
1533 dupe.UpdateParentIDs(); 2216// done above dupe.UpdateParentIDs();
2217
2218 if (dupe.m_rootPart.PhysActor != null)
2219 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2220
1534 dupe.HasGroupChanged = true; 2221 dupe.HasGroupChanged = true;
1535 dupe.AttachToBackup(); 2222 dupe.AttachToBackup();
1536 2223
1537 ScheduleGroupForFullUpdate(); 2224 ScheduleGroupForFullUpdate();
1538 } 2225 }
1539 2226
2227 m_dupeInProgress = false;
1540 return dupe; 2228 return dupe;
1541 } 2229 }
1542 2230
@@ -1548,11 +2236,24 @@ namespace OpenSim.Region.Framework.Scenes
1548 /// <param name="cGroupID"></param> 2236 /// <param name="cGroupID"></param>
1549 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2237 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1550 { 2238 {
1551 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2239 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2240 // give newpart a new local ID lettng old part keep same
2241 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2242 newpart.LocalId = m_scene.AllocateLocalId();
2243
2244 SetRootPart(newpart);
2245 if (userExposed)
2246 RootPart.Velocity = Vector3.Zero; // In case source is moving
1552 } 2247 }
1553 2248
1554 public void ScriptSetPhysicsStatus(bool usePhysics) 2249 public void ScriptSetPhysicsStatus(bool usePhysics)
1555 { 2250 {
2251 if (usePhysics)
2252 {
2253 if (RootPart.KeyframeMotion != null)
2254 RootPart.KeyframeMotion.Stop();
2255 RootPart.KeyframeMotion = null;
2256 }
1556 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2257 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1557 } 2258 }
1558 2259
@@ -1600,13 +2301,14 @@ namespace OpenSim.Region.Framework.Scenes
1600 2301
1601 if (pa != null) 2302 if (pa != null)
1602 { 2303 {
1603 pa.AddForce(impulse, true); 2304 // false to be applied as a impulse
2305 pa.AddForce(impulse, false);
1604 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2306 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1605 } 2307 }
1606 } 2308 }
1607 } 2309 }
1608 2310
1609 public void applyAngularImpulse(Vector3 impulse) 2311 public void ApplyAngularImpulse(Vector3 impulse)
1610 { 2312 {
1611 PhysicsActor pa = RootPart.PhysActor; 2313 PhysicsActor pa = RootPart.PhysActor;
1612 2314
@@ -1614,21 +2316,8 @@ namespace OpenSim.Region.Framework.Scenes
1614 { 2316 {
1615 if (!IsAttachment) 2317 if (!IsAttachment)
1616 { 2318 {
1617 pa.AddAngularForce(impulse, true); 2319 // false to be applied as a impulse
1618 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2320 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); 2321 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1633 } 2322 }
1634 } 2323 }
@@ -1636,20 +2325,10 @@ namespace OpenSim.Region.Framework.Scenes
1636 2325
1637 public Vector3 GetTorque() 2326 public Vector3 GetTorque()
1638 { 2327 {
1639 PhysicsActor pa = RootPart.PhysActor; 2328 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 } 2329 }
1652 2330
2331 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1653 public void moveToTarget(Vector3 target, float tau) 2332 public void moveToTarget(Vector3 target, float tau)
1654 { 2333 {
1655 if (IsAttachment) 2334 if (IsAttachment)
@@ -1681,6 +2360,46 @@ namespace OpenSim.Region.Framework.Scenes
1681 pa.PIDActive = false; 2360 pa.PIDActive = false;
1682 } 2361 }
1683 2362
2363 public void rotLookAt(Quaternion target, float strength, float damping)
2364 {
2365 SceneObjectPart rootpart = m_rootPart;
2366 if (rootpart != null)
2367 {
2368 if (IsAttachment)
2369 {
2370 /*
2371 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2372 if (avatar != null)
2373 {
2374 Rotate the Av?
2375 } */
2376 }
2377 else
2378 {
2379 if (rootpart.PhysActor != null)
2380 { // APID must be implemented in your physics system for this to function.
2381 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2382 rootpart.PhysActor.APIDStrength = strength;
2383 rootpart.PhysActor.APIDDamping = damping;
2384 rootpart.PhysActor.APIDActive = true;
2385 }
2386 }
2387 }
2388 }
2389
2390 public void stopLookAt()
2391 {
2392 SceneObjectPart rootpart = m_rootPart;
2393 if (rootpart != null)
2394 {
2395 if (rootpart.PhysActor != null)
2396 { // APID must be implemented in your physics system for this to function.
2397 rootpart.PhysActor.APIDActive = false;
2398 }
2399 }
2400
2401 }
2402
1684 /// <summary> 2403 /// <summary>
1685 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2404 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1686 /// </summary> 2405 /// </summary>
@@ -1697,7 +2416,7 @@ namespace OpenSim.Region.Framework.Scenes
1697 { 2416 {
1698 pa.PIDHoverHeight = height; 2417 pa.PIDHoverHeight = height;
1699 pa.PIDHoverType = hoverType; 2418 pa.PIDHoverType = hoverType;
1700 pa.PIDTau = tau; 2419 pa.PIDHoverTau = tau;
1701 pa.PIDHoverActive = true; 2420 pa.PIDHoverActive = true;
1702 } 2421 }
1703 else 2422 else
@@ -1737,7 +2456,12 @@ namespace OpenSim.Region.Framework.Scenes
1737 /// <param name="cGroupID"></param> 2456 /// <param name="cGroupID"></param>
1738 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2457 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1739 { 2458 {
1740 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2459 // give new ID to the new part, letting old keep original
2460 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2461 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2462 newPart.LocalId = m_scene.AllocateLocalId();
2463 newPart.SetParent(this);
2464
1741 AddPart(newPart); 2465 AddPart(newPart);
1742 2466
1743 SetPartAsNonRoot(newPart); 2467 SetPartAsNonRoot(newPart);
@@ -1876,11 +2600,11 @@ namespace OpenSim.Region.Framework.Scenes
1876 /// Immediately send a full update for this scene object. 2600 /// Immediately send a full update for this scene object.
1877 /// </summary> 2601 /// </summary>
1878 public void SendGroupFullUpdate() 2602 public void SendGroupFullUpdate()
1879 { 2603 {
1880 if (IsDeleted) 2604 if (IsDeleted)
1881 return; 2605 return;
1882 2606
1883// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2607// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1884 2608
1885 RootPart.SendFullUpdateToAllClients(); 2609 RootPart.SendFullUpdateToAllClients();
1886 2610
@@ -2017,6 +2741,11 @@ namespace OpenSim.Region.Framework.Scenes
2017 // 'linkPart' == the root of the group being linked into this group 2741 // 'linkPart' == the root of the group being linked into this group
2018 SceneObjectPart linkPart = objectGroup.m_rootPart; 2742 SceneObjectPart linkPart = objectGroup.m_rootPart;
2019 2743
2744 if (m_rootPart.PhysActor != null)
2745 m_rootPart.PhysActor.Building = true;
2746 if (linkPart.PhysActor != null)
2747 linkPart.PhysActor.Building = true;
2748
2020 // physics flags from group to be applied to linked parts 2749 // physics flags from group to be applied to linked parts
2021 bool grpusephys = UsesPhysics; 2750 bool grpusephys = UsesPhysics;
2022 bool grptemporary = IsTemporary; 2751 bool grptemporary = IsTemporary;
@@ -2042,12 +2771,12 @@ namespace OpenSim.Region.Framework.Scenes
2042 Vector3 axPos = linkPart.OffsetPosition; 2771 Vector3 axPos = linkPart.OffsetPosition;
2043 // Rotate the linking root SOP's position to be relative to the new root prim 2772 // Rotate the linking root SOP's position to be relative to the new root prim
2044 Quaternion parentRot = m_rootPart.RotationOffset; 2773 Quaternion parentRot = m_rootPart.RotationOffset;
2045 axPos *= Quaternion.Inverse(parentRot); 2774 axPos *= Quaternion.Conjugate(parentRot);
2046 linkPart.OffsetPosition = axPos; 2775 linkPart.OffsetPosition = axPos;
2047 2776
2048 // Make the linking root SOP's rotation relative to the new root prim 2777 // Make the linking root SOP's rotation relative to the new root prim
2049 Quaternion oldRot = linkPart.RotationOffset; 2778 Quaternion oldRot = linkPart.RotationOffset;
2050 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2779 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2051 linkPart.RotationOffset = newRot; 2780 linkPart.RotationOffset = newRot;
2052 2781
2053 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2782 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2081,7 +2810,7 @@ namespace OpenSim.Region.Framework.Scenes
2081 linkPart.CreateSelected = true; 2810 linkPart.CreateSelected = true;
2082 2811
2083 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2812 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2084 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2813 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2085 2814
2086 // If the added SOP is physical, also tell the physics engine about the link relationship. 2815 // If the added SOP is physical, also tell the physics engine about the link relationship.
2087 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2816 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2091,6 +2820,7 @@ namespace OpenSim.Region.Framework.Scenes
2091 } 2820 }
2092 2821
2093 linkPart.LinkNum = linkNum++; 2822 linkPart.LinkNum = linkNum++;
2823 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2094 2824
2095 // Get a list of the SOP's in the old group in order of their linknum's. 2825 // Get a list of the SOP's in the old group in order of their linknum's.
2096 SceneObjectPart[] ogParts = objectGroup.Parts; 2826 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2109,7 +2839,7 @@ namespace OpenSim.Region.Framework.Scenes
2109 2839
2110 // Update the physics flags for the newly added SOP 2840 // Update the physics flags for the newly added SOP
2111 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2841 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2112 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2842 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2113 2843
2114 // If the added SOP is physical, also tell the physics engine about the link relationship. 2844 // If the added SOP is physical, also tell the physics engine about the link relationship.
2115 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2845 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2127,7 +2857,7 @@ namespace OpenSim.Region.Framework.Scenes
2127 objectGroup.IsDeleted = true; 2857 objectGroup.IsDeleted = true;
2128 2858
2129 objectGroup.m_parts.Clear(); 2859 objectGroup.m_parts.Clear();
2130 2860
2131 // Can't do this yet since backup still makes use of the root part without any synchronization 2861 // Can't do this yet since backup still makes use of the root part without any synchronization
2132// objectGroup.m_rootPart = null; 2862// objectGroup.m_rootPart = null;
2133 2863
@@ -2141,6 +2871,9 @@ namespace OpenSim.Region.Framework.Scenes
2141 // unmoved prims! 2871 // unmoved prims!
2142 ResetChildPrimPhysicsPositions(); 2872 ResetChildPrimPhysicsPositions();
2143 2873
2874 if (m_rootPart.PhysActor != null)
2875 m_rootPart.PhysActor.Building = false;
2876
2144 //HasGroupChanged = true; 2877 //HasGroupChanged = true;
2145 //ScheduleGroupForFullUpdate(); 2878 //ScheduleGroupForFullUpdate();
2146 } 2879 }
@@ -2208,7 +2941,10 @@ namespace OpenSim.Region.Framework.Scenes
2208// m_log.DebugFormat( 2941// m_log.DebugFormat(
2209// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2942// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2210// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2943// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2211 2944
2945 if (m_rootPart.PhysActor != null)
2946 m_rootPart.PhysActor.Building = true;
2947
2212 linkPart.ClearUndoState(); 2948 linkPart.ClearUndoState();
2213 2949
2214 Vector3 worldPos = linkPart.GetWorldPosition(); 2950 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2279,6 +3015,14 @@ namespace OpenSim.Region.Framework.Scenes
2279 3015
2280 // When we delete a group, we currently have to force persist to the database if the object id has changed 3016 // When we delete a group, we currently have to force persist to the database if the object id has changed
2281 // (since delete works by deleting all rows which have a given object id) 3017 // (since delete works by deleting all rows which have a given object id)
3018
3019 // this is as it seems to be in sl now
3020 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3021 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3022
3023 if (m_rootPart.PhysActor != null)
3024 m_rootPart.PhysActor.Building = false;
3025
2282 objectGroup.HasGroupChangedDueToDelink = true; 3026 objectGroup.HasGroupChangedDueToDelink = true;
2283 3027
2284 return objectGroup; 3028 return objectGroup;
@@ -2290,6 +3034,8 @@ namespace OpenSim.Region.Framework.Scenes
2290 /// <param name="objectGroup"></param> 3034 /// <param name="objectGroup"></param>
2291 public virtual void DetachFromBackup() 3035 public virtual void DetachFromBackup()
2292 { 3036 {
3037 if (m_scene != null)
3038 m_scene.SceneGraph.FireDetachFromBackup(this);
2293 if (m_isBackedUp && Scene != null) 3039 if (m_isBackedUp && Scene != null)
2294 m_scene.EventManager.OnBackup -= ProcessBackup; 3040 m_scene.EventManager.OnBackup -= ProcessBackup;
2295 3041
@@ -2310,7 +3056,8 @@ namespace OpenSim.Region.Framework.Scenes
2310 Vector3 axPos = part.OffsetPosition; 3056 Vector3 axPos = part.OffsetPosition;
2311 axPos *= parentRot; 3057 axPos *= parentRot;
2312 part.OffsetPosition = axPos; 3058 part.OffsetPosition = axPos;
2313 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3059 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3060 part.GroupPosition = newPos;
2314 part.OffsetPosition = Vector3.Zero; 3061 part.OffsetPosition = Vector3.Zero;
2315 3062
2316 // Compution our rotation to be not relative to the old parent 3063 // Compution our rotation to be not relative to the old parent
@@ -2325,7 +3072,7 @@ namespace OpenSim.Region.Framework.Scenes
2325 part.LinkNum = linkNum; 3072 part.LinkNum = linkNum;
2326 3073
2327 // Compute the new position of this SOP relative to the group position 3074 // Compute the new position of this SOP relative to the group position
2328 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3075 part.OffsetPosition = newPos - AbsolutePosition;
2329 3076
2330 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3077 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2331 // It would have the affect of setting the physics engine position multiple 3078 // It would have the affect of setting the physics engine position multiple
@@ -2335,18 +3082,19 @@ namespace OpenSim.Region.Framework.Scenes
2335 // Rotate the relative position by the rotation of the group 3082 // Rotate the relative position by the rotation of the group
2336 Quaternion rootRotation = m_rootPart.RotationOffset; 3083 Quaternion rootRotation = m_rootPart.RotationOffset;
2337 Vector3 pos = part.OffsetPosition; 3084 Vector3 pos = part.OffsetPosition;
2338 pos *= Quaternion.Inverse(rootRotation); 3085 pos *= Quaternion.Conjugate(rootRotation);
2339 part.OffsetPosition = pos; 3086 part.OffsetPosition = pos;
2340 3087
2341 // Compute the SOP's rotation relative to the rotation of the group. 3088 // Compute the SOP's rotation relative to the rotation of the group.
2342 parentRot = m_rootPart.RotationOffset; 3089 parentRot = m_rootPart.RotationOffset;
2343 oldRot = part.RotationOffset; 3090 oldRot = part.RotationOffset;
2344 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3091 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2345 part.RotationOffset = newRot; 3092 part.RotationOffset = newRot;
2346 3093
2347 // Since this SOP's state has changed, push those changes into the physics engine 3094 // Since this SOP's state has changed, push those changes into the physics engine
2348 // and the simulator. 3095 // and the simulator.
2349 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3096 // done on caller
3097// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2350 } 3098 }
2351 3099
2352 /// <summary> 3100 /// <summary>
@@ -2368,10 +3116,14 @@ namespace OpenSim.Region.Framework.Scenes
2368 { 3116 {
2369 if (!m_rootPart.BlockGrab) 3117 if (!m_rootPart.BlockGrab)
2370 { 3118 {
2371 Vector3 llmoveforce = pos - AbsolutePosition; 3119/* Vector3 llmoveforce = pos - AbsolutePosition;
2372 Vector3 grabforce = llmoveforce; 3120 Vector3 grabforce = llmoveforce;
2373 grabforce = (grabforce / 10) * pa.Mass; 3121 grabforce = (grabforce / 10) * pa.Mass;
2374 pa.AddForce(grabforce, true); 3122 */
3123 // empirically convert distance diference to a impulse
3124 Vector3 grabforce = pos - AbsolutePosition;
3125 grabforce = grabforce * (pa.Mass/ 10.0f);
3126 pa.AddForce(grabforce, false);
2375 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3127 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2376 } 3128 }
2377 } 3129 }
@@ -2567,6 +3319,8 @@ namespace OpenSim.Region.Framework.Scenes
2567 /// <param name="SetVolumeDetect"></param> 3319 /// <param name="SetVolumeDetect"></param>
2568 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3320 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2569 { 3321 {
3322 HasGroupChanged = true;
3323
2570 SceneObjectPart selectionPart = GetPart(localID); 3324 SceneObjectPart selectionPart = GetPart(localID);
2571 3325
2572 if (SetTemporary && Scene != null) 3326 if (SetTemporary && Scene != null)
@@ -2597,8 +3351,22 @@ namespace OpenSim.Region.Framework.Scenes
2597 } 3351 }
2598 } 3352 }
2599 3353
2600 for (int i = 0; i < parts.Length; i++) 3354 if (parts.Length > 1)
2601 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3355 {
3356 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3357
3358 for (int i = 0; i < parts.Length; i++)
3359 {
3360
3361 if (parts[i].UUID != m_rootPart.UUID)
3362 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3363 }
3364
3365 if (m_rootPart.PhysActor != null)
3366 m_rootPart.PhysActor.Building = false;
3367 }
3368 else
3369 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2602 } 3370 }
2603 } 3371 }
2604 3372
@@ -2611,6 +3379,17 @@ namespace OpenSim.Region.Framework.Scenes
2611 } 3379 }
2612 } 3380 }
2613 3381
3382
3383
3384 /// <summary>
3385 /// Gets the number of parts
3386 /// </summary>
3387 /// <returns></returns>
3388 public int GetPartCount()
3389 {
3390 return Parts.Count();
3391 }
3392
2614 /// <summary> 3393 /// <summary>
2615 /// Update the texture entry for this part 3394 /// Update the texture entry for this part
2616 /// </summary> 3395 /// </summary>
@@ -2681,11 +3460,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 /// <param name="scale"></param> 3460 /// <param name="scale"></param>
2682 public void GroupResize(Vector3 scale) 3461 public void GroupResize(Vector3 scale)
2683 { 3462 {
2684// m_log.DebugFormat(
2685// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2686
2687 RootPart.StoreUndoState(true);
2688
2689 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3463 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
2690 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); 3464 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
2691 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); 3465 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
@@ -2712,7 +3486,6 @@ namespace OpenSim.Region.Framework.Scenes
2712 SceneObjectPart obPart = parts[i]; 3486 SceneObjectPart obPart = parts[i];
2713 if (obPart.UUID != m_rootPart.UUID) 3487 if (obPart.UUID != m_rootPart.UUID)
2714 { 3488 {
2715// obPart.IgnoreUndoUpdate = true;
2716 Vector3 oldSize = new Vector3(obPart.Scale); 3489 Vector3 oldSize = new Vector3(obPart.Scale);
2717 3490
2718 float f = 1.0f; 3491 float f = 1.0f;
@@ -2824,8 +3597,6 @@ namespace OpenSim.Region.Framework.Scenes
2824 z *= a; 3597 z *= a;
2825 } 3598 }
2826 } 3599 }
2827
2828// obPart.IgnoreUndoUpdate = false;
2829 } 3600 }
2830 } 3601 }
2831 } 3602 }
@@ -2835,9 +3606,7 @@ namespace OpenSim.Region.Framework.Scenes
2835 prevScale.Y *= y; 3606 prevScale.Y *= y;
2836 prevScale.Z *= z; 3607 prevScale.Z *= z;
2837 3608
2838// RootPart.IgnoreUndoUpdate = true;
2839 RootPart.Resize(prevScale); 3609 RootPart.Resize(prevScale);
2840// RootPart.IgnoreUndoUpdate = false;
2841 3610
2842 parts = m_parts.GetArray(); 3611 parts = m_parts.GetArray();
2843 for (int i = 0; i < parts.Length; i++) 3612 for (int i = 0; i < parts.Length; i++)
@@ -2846,8 +3615,6 @@ namespace OpenSim.Region.Framework.Scenes
2846 3615
2847 if (obPart.UUID != m_rootPart.UUID) 3616 if (obPart.UUID != m_rootPart.UUID)
2848 { 3617 {
2849 obPart.IgnoreUndoUpdate = true;
2850
2851 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3618 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2852 currentpos.X *= x; 3619 currentpos.X *= x;
2853 currentpos.Y *= y; 3620 currentpos.Y *= y;
@@ -2860,16 +3627,12 @@ namespace OpenSim.Region.Framework.Scenes
2860 3627
2861 obPart.Resize(newSize); 3628 obPart.Resize(newSize);
2862 obPart.UpdateOffSet(currentpos); 3629 obPart.UpdateOffSet(currentpos);
2863
2864 obPart.IgnoreUndoUpdate = false;
2865 } 3630 }
2866 3631
2867// obPart.IgnoreUndoUpdate = false; 3632 HasGroupChanged = true;
2868// obPart.StoreUndoState(); 3633 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3634 ScheduleGroupForTerseUpdate();
2869 } 3635 }
2870
2871// m_log.DebugFormat(
2872// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2873 } 3636 }
2874 3637
2875 #endregion 3638 #endregion
@@ -2882,14 +3645,6 @@ namespace OpenSim.Region.Framework.Scenes
2882 /// <param name="pos"></param> 3645 /// <param name="pos"></param>
2883 public void UpdateGroupPosition(Vector3 pos) 3646 public void UpdateGroupPosition(Vector3 pos)
2884 { 3647 {
2885// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2886
2887 RootPart.StoreUndoState(true);
2888
2889// SceneObjectPart[] parts = m_parts.GetArray();
2890// for (int i = 0; i < parts.Length; i++)
2891// parts[i].StoreUndoState();
2892
2893 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3648 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2894 { 3649 {
2895 if (IsAttachment) 3650 if (IsAttachment)
@@ -2922,21 +3677,17 @@ namespace OpenSim.Region.Framework.Scenes
2922 /// </summary> 3677 /// </summary>
2923 /// <param name="pos"></param> 3678 /// <param name="pos"></param>
2924 /// <param name="localID"></param> 3679 /// <param name="localID"></param>
3680 ///
3681
2925 public void UpdateSinglePosition(Vector3 pos, uint localID) 3682 public void UpdateSinglePosition(Vector3 pos, uint localID)
2926 { 3683 {
2927 SceneObjectPart part = GetPart(localID); 3684 SceneObjectPart part = GetPart(localID);
2928 3685
2929// SceneObjectPart[] parts = m_parts.GetArray();
2930// for (int i = 0; i < parts.Length; i++)
2931// parts[i].StoreUndoState();
2932
2933 if (part != null) 3686 if (part != null)
2934 { 3687 {
2935// m_log.DebugFormat( 3688// unlock parts position change
2936// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3689 if (m_rootPart.PhysActor != null)
2937 3690 m_rootPart.PhysActor.Building = true;
2938 part.StoreUndoState(false);
2939 part.IgnoreUndoUpdate = true;
2940 3691
2941 if (part.UUID == m_rootPart.UUID) 3692 if (part.UUID == m_rootPart.UUID)
2942 { 3693 {
@@ -2947,8 +3698,10 @@ namespace OpenSim.Region.Framework.Scenes
2947 part.UpdateOffSet(pos); 3698 part.UpdateOffSet(pos);
2948 } 3699 }
2949 3700
3701 if (m_rootPart.PhysActor != null)
3702 m_rootPart.PhysActor.Building = false;
3703
2950 HasGroupChanged = true; 3704 HasGroupChanged = true;
2951 part.IgnoreUndoUpdate = false;
2952 } 3705 }
2953 } 3706 }
2954 3707
@@ -2958,13 +3711,7 @@ namespace OpenSim.Region.Framework.Scenes
2958 /// <param name="pos"></param> 3711 /// <param name="pos"></param>
2959 public void UpdateRootPosition(Vector3 pos) 3712 public void UpdateRootPosition(Vector3 pos)
2960 { 3713 {
2961// m_log.DebugFormat( 3714 // needs to be called with phys building true
2962// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2963
2964// SceneObjectPart[] parts = m_parts.GetArray();
2965// for (int i = 0; i < parts.Length; i++)
2966// parts[i].StoreUndoState();
2967
2968 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3715 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2969 Vector3 oldPos = 3716 Vector3 oldPos =
2970 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3717 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2987,7 +3734,14 @@ namespace OpenSim.Region.Framework.Scenes
2987 AbsolutePosition = newPos; 3734 AbsolutePosition = newPos;
2988 3735
2989 HasGroupChanged = true; 3736 HasGroupChanged = true;
2990 ScheduleGroupForTerseUpdate(); 3737 if (m_rootPart.Undoing)
3738 {
3739 ScheduleGroupForFullUpdate();
3740 }
3741 else
3742 {
3743 ScheduleGroupForTerseUpdate();
3744 }
2991 } 3745 }
2992 3746
2993 #endregion 3747 #endregion
@@ -3000,24 +3754,16 @@ namespace OpenSim.Region.Framework.Scenes
3000 /// <param name="rot"></param> 3754 /// <param name="rot"></param>
3001 public void UpdateGroupRotationR(Quaternion rot) 3755 public void UpdateGroupRotationR(Quaternion rot)
3002 { 3756 {
3003// m_log.DebugFormat(
3004// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3005
3006// SceneObjectPart[] parts = m_parts.GetArray();
3007// for (int i = 0; i < parts.Length; i++)
3008// parts[i].StoreUndoState();
3009
3010 m_rootPart.StoreUndoState(true);
3011
3012 m_rootPart.UpdateRotation(rot); 3757 m_rootPart.UpdateRotation(rot);
3013 3758
3759/* this is done by rootpart RotationOffset set called by UpdateRotation
3014 PhysicsActor actor = m_rootPart.PhysActor; 3760 PhysicsActor actor = m_rootPart.PhysActor;
3015 if (actor != null) 3761 if (actor != null)
3016 { 3762 {
3017 actor.Orientation = m_rootPart.RotationOffset; 3763 actor.Orientation = m_rootPart.RotationOffset;
3018 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3764 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3019 } 3765 }
3020 3766*/
3021 HasGroupChanged = true; 3767 HasGroupChanged = true;
3022 ScheduleGroupForTerseUpdate(); 3768 ScheduleGroupForTerseUpdate();
3023 } 3769 }
@@ -3029,16 +3775,6 @@ namespace OpenSim.Region.Framework.Scenes
3029 /// <param name="rot"></param> 3775 /// <param name="rot"></param>
3030 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3776 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3031 { 3777 {
3032// m_log.DebugFormat(
3033// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3034
3035// SceneObjectPart[] parts = m_parts.GetArray();
3036// for (int i = 0; i < parts.Length; i++)
3037// parts[i].StoreUndoState();
3038
3039 RootPart.StoreUndoState(true);
3040 RootPart.IgnoreUndoUpdate = true;
3041
3042 m_rootPart.UpdateRotation(rot); 3778 m_rootPart.UpdateRotation(rot);
3043 3779
3044 PhysicsActor actor = m_rootPart.PhysActor; 3780 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3057,8 +3793,6 @@ namespace OpenSim.Region.Framework.Scenes
3057 3793
3058 HasGroupChanged = true; 3794 HasGroupChanged = true;
3059 ScheduleGroupForTerseUpdate(); 3795 ScheduleGroupForTerseUpdate();
3060
3061 RootPart.IgnoreUndoUpdate = false;
3062 } 3796 }
3063 3797
3064 /// <summary> 3798 /// <summary>
@@ -3071,13 +3805,11 @@ namespace OpenSim.Region.Framework.Scenes
3071 SceneObjectPart part = GetPart(localID); 3805 SceneObjectPart part = GetPart(localID);
3072 3806
3073 SceneObjectPart[] parts = m_parts.GetArray(); 3807 SceneObjectPart[] parts = m_parts.GetArray();
3074 for (int i = 0; i < parts.Length; i++)
3075 parts[i].StoreUndoState();
3076 3808
3077 if (part != null) 3809 if (part != null)
3078 { 3810 {
3079// m_log.DebugFormat( 3811 if (m_rootPart.PhysActor != null)
3080// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3812 m_rootPart.PhysActor.Building = true;
3081 3813
3082 if (part.UUID == m_rootPart.UUID) 3814 if (part.UUID == m_rootPart.UUID)
3083 { 3815 {
@@ -3087,6 +3819,9 @@ namespace OpenSim.Region.Framework.Scenes
3087 { 3819 {
3088 part.UpdateRotation(rot); 3820 part.UpdateRotation(rot);
3089 } 3821 }
3822
3823 if (m_rootPart.PhysActor != null)
3824 m_rootPart.PhysActor.Building = false;
3090 } 3825 }
3091 } 3826 }
3092 3827
@@ -3100,12 +3835,8 @@ namespace OpenSim.Region.Framework.Scenes
3100 SceneObjectPart part = GetPart(localID); 3835 SceneObjectPart part = GetPart(localID);
3101 if (part != null) 3836 if (part != null)
3102 { 3837 {
3103// m_log.DebugFormat( 3838 if (m_rootPart.PhysActor != null)
3104// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3839 m_rootPart.PhysActor.Building = true;
3105// part.Name, part.LocalId, rot);
3106
3107 part.StoreUndoState();
3108 part.IgnoreUndoUpdate = true;
3109 3840
3110 if (part.UUID == m_rootPart.UUID) 3841 if (part.UUID == m_rootPart.UUID)
3111 { 3842 {
@@ -3118,7 +3849,8 @@ namespace OpenSim.Region.Framework.Scenes
3118 part.OffsetPosition = pos; 3849 part.OffsetPosition = pos;
3119 } 3850 }
3120 3851
3121 part.IgnoreUndoUpdate = false; 3852 if (m_rootPart.PhysActor != null)
3853 m_rootPart.PhysActor.Building = false;
3122 } 3854 }
3123 } 3855 }
3124 3856
@@ -3128,15 +3860,12 @@ namespace OpenSim.Region.Framework.Scenes
3128 /// <param name="rot"></param> 3860 /// <param name="rot"></param>
3129 public void UpdateRootRotation(Quaternion rot) 3861 public void UpdateRootRotation(Quaternion rot)
3130 { 3862 {
3131// m_log.DebugFormat( 3863 // needs to be called with phys building true
3132// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3133// Name, LocalId, rot);
3134
3135 Quaternion axRot = rot; 3864 Quaternion axRot = rot;
3136 Quaternion oldParentRot = m_rootPart.RotationOffset; 3865 Quaternion oldParentRot = m_rootPart.RotationOffset;
3137 3866
3138 m_rootPart.StoreUndoState(); 3867 //Don't use UpdateRotation because it schedules an update prematurely
3139 m_rootPart.UpdateRotation(rot); 3868 m_rootPart.RotationOffset = rot;
3140 3869
3141 PhysicsActor pa = m_rootPart.PhysActor; 3870 PhysicsActor pa = m_rootPart.PhysActor;
3142 3871
@@ -3152,35 +3881,145 @@ namespace OpenSim.Region.Framework.Scenes
3152 SceneObjectPart prim = parts[i]; 3881 SceneObjectPart prim = parts[i];
3153 if (prim.UUID != m_rootPart.UUID) 3882 if (prim.UUID != m_rootPart.UUID)
3154 { 3883 {
3155 prim.IgnoreUndoUpdate = true; 3884 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3885 NewRot = Quaternion.Inverse(axRot) * NewRot;
3886 prim.RotationOffset = NewRot;
3887
3156 Vector3 axPos = prim.OffsetPosition; 3888 Vector3 axPos = prim.OffsetPosition;
3889
3157 axPos *= oldParentRot; 3890 axPos *= oldParentRot;
3158 axPos *= Quaternion.Inverse(axRot); 3891 axPos *= Quaternion.Inverse(axRot);
3159 prim.OffsetPosition = axPos; 3892 prim.OffsetPosition = axPos;
3160 Quaternion primsRot = prim.RotationOffset; 3893 }
3161 Quaternion newRot = oldParentRot * primsRot; 3894 }
3162 newRot = Quaternion.Inverse(axRot) * newRot;
3163 prim.RotationOffset = newRot;
3164 prim.ScheduleTerseUpdate();
3165 prim.IgnoreUndoUpdate = false;
3166 }
3167 }
3168
3169// for (int i = 0; i < parts.Length; i++)
3170// {
3171// SceneObjectPart childpart = parts[i];
3172// if (childpart != m_rootPart)
3173// {
3174//// childpart.IgnoreUndoUpdate = false;
3175//// childpart.StoreUndoState();
3176// }
3177// }
3178 3895
3179 m_rootPart.ScheduleTerseUpdate(); 3896 HasGroupChanged = true;
3897 ScheduleGroupForFullUpdate();
3898 }
3180 3899
3181// m_log.DebugFormat( 3900 private enum updatetype :int
3182// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3901 {
3183// Name, LocalId, rot); 3902 none = 0,
3903 partterse = 1,
3904 partfull = 2,
3905 groupterse = 3,
3906 groupfull = 4
3907 }
3908
3909 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3910 {
3911 // TODO this still as excessive *.Schedule*Update()s
3912
3913 if (part != null && part.ParentGroup != null)
3914 {
3915 ObjectChangeType change = data.change;
3916 bool togroup = ((change & ObjectChangeType.Group) != 0);
3917 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3918
3919 SceneObjectGroup group = part.ParentGroup;
3920 PhysicsActor pha = group.RootPart.PhysActor;
3921
3922 updatetype updateType = updatetype.none;
3923
3924 if (togroup)
3925 {
3926 // related to group
3927 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3928 {
3929 if ((change & ObjectChangeType.Rotation) != 0)
3930 {
3931 group.RootPart.UpdateRotation(data.rotation);
3932 updateType = updatetype.none;
3933 }
3934 if ((change & ObjectChangeType.Position) != 0)
3935 {
3936 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3937 UpdateGroupPosition(data.position);
3938 updateType = updatetype.groupterse;
3939 }
3940 else
3941 // ugly rotation update of all parts
3942 {
3943 group.ResetChildPrimPhysicsPositions();
3944 }
3945
3946 }
3947 if ((change & ObjectChangeType.Scale) != 0)
3948 {
3949 if (pha != null)
3950 pha.Building = true;
3951
3952 group.GroupResize(data.scale);
3953 updateType = updatetype.none;
3954
3955 if (pha != null)
3956 pha.Building = false;
3957 }
3958 }
3959 else
3960 {
3961 // related to single prim in a link-set ( ie group)
3962 if (pha != null)
3963 pha.Building = true;
3964
3965 // root part is special
3966 // parts offset positions or rotations need to change also
3967
3968 if (part == group.RootPart)
3969 {
3970 if ((change & ObjectChangeType.Rotation) != 0)
3971 group.UpdateRootRotation(data.rotation);
3972 if ((change & ObjectChangeType.Position) != 0)
3973 group.UpdateRootPosition(data.position);
3974 if ((change & ObjectChangeType.Scale) != 0)
3975 part.Resize(data.scale);
3976 }
3977 else
3978 {
3979 if ((change & ObjectChangeType.Position) != 0)
3980 {
3981 part.OffsetPosition = data.position;
3982 updateType = updatetype.partterse;
3983 }
3984 if ((change & ObjectChangeType.Rotation) != 0)
3985 {
3986 part.UpdateRotation(data.rotation);
3987 updateType = updatetype.none;
3988 }
3989 if ((change & ObjectChangeType.Scale) != 0)
3990 {
3991 part.Resize(data.scale);
3992 updateType = updatetype.none;
3993 }
3994 }
3995
3996 if (pha != null)
3997 pha.Building = false;
3998 }
3999
4000 if (updateType != updatetype.none)
4001 {
4002 group.HasGroupChanged = true;
4003
4004 switch (updateType)
4005 {
4006 case updatetype.partterse:
4007 part.ScheduleTerseUpdate();
4008 break;
4009 case updatetype.partfull:
4010 part.ScheduleFullUpdate();
4011 break;
4012 case updatetype.groupterse:
4013 group.ScheduleGroupForTerseUpdate();
4014 break;
4015 case updatetype.groupfull:
4016 group.ScheduleGroupForFullUpdate();
4017 break;
4018 default:
4019 break;
4020 }
4021 }
4022 }
3184 } 4023 }
3185 4024
3186 #endregion 4025 #endregion
@@ -3279,10 +4118,11 @@ namespace OpenSim.Region.Framework.Scenes
3279 scriptPosTarget target = m_targets[idx]; 4118 scriptPosTarget target = m_targets[idx];
3280 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4119 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3281 { 4120 {
4121 at_target = true;
4122
3282 // trigger at_target 4123 // trigger at_target
3283 if (m_scriptListens_atTarget) 4124 if (m_scriptListens_atTarget)
3284 { 4125 {
3285 at_target = true;
3286 scriptPosTarget att = new scriptPosTarget(); 4126 scriptPosTarget att = new scriptPosTarget();
3287 att.targetPos = target.targetPos; 4127 att.targetPos = target.targetPos;
3288 att.tolerance = target.tolerance; 4128 att.tolerance = target.tolerance;
@@ -3400,11 +4240,50 @@ namespace OpenSim.Region.Framework.Scenes
3400 } 4240 }
3401 } 4241 }
3402 } 4242 }
3403 4243
4244 public Vector3 GetGeometricCenter()
4245 {
4246 // this is not real geometric center but a average of positions relative to root prim acording to
4247 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4248 // ignoring tortured prims details since sl also seems to ignore
4249 // so no real use in doing it on physics
4250
4251 Vector3 gc = Vector3.Zero;
4252
4253 int nparts = m_parts.Count;
4254 if (nparts <= 1)
4255 return gc;
4256
4257 SceneObjectPart[] parts = m_parts.GetArray();
4258 nparts = parts.Length; // just in case it changed
4259 if (nparts <= 1)
4260 return gc;
4261
4262 Quaternion parentRot = RootPart.RotationOffset;
4263 Vector3 pPos;
4264
4265 // average all parts positions
4266 for (int i = 0; i < nparts; i++)
4267 {
4268 // do it directly
4269 // gc += parts[i].GetWorldPosition();
4270 if (parts[i] != RootPart)
4271 {
4272 pPos = parts[i].OffsetPosition;
4273 gc += pPos;
4274 }
4275
4276 }
4277 gc /= nparts;
4278
4279 // relative to root:
4280// gc -= AbsolutePosition;
4281 return gc;
4282 }
4283
3404 public float GetMass() 4284 public float GetMass()
3405 { 4285 {
3406 float retmass = 0f; 4286 float retmass = 0f;
3407
3408 SceneObjectPart[] parts = m_parts.GetArray(); 4287 SceneObjectPart[] parts = m_parts.GetArray();
3409 for (int i = 0; i < parts.Length; i++) 4288 for (int i = 0; i < parts.Length; i++)
3410 retmass += parts[i].GetMass(); 4289 retmass += parts[i].GetMass();
@@ -3412,6 +4291,39 @@ namespace OpenSim.Region.Framework.Scenes
3412 return retmass; 4291 return retmass;
3413 } 4292 }
3414 4293
4294 // center of mass of full object
4295 public Vector3 GetCenterOfMass()
4296 {
4297 PhysicsActor pa = RootPart.PhysActor;
4298
4299 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4300 {
4301 // physics knows better about center of mass of physical prims
4302 Vector3 tmp = pa.CenterOfMass;
4303 return tmp;
4304 }
4305
4306 Vector3 Ptot = Vector3.Zero;
4307 float totmass = 0f;
4308 float m;
4309
4310 SceneObjectPart[] parts = m_parts.GetArray();
4311 for (int i = 0; i < parts.Length; i++)
4312 {
4313 m = parts[i].GetMass();
4314 Ptot += parts[i].GetPartCenterOfMass() * m;
4315 totmass += m;
4316 }
4317
4318 if (totmass == 0)
4319 totmass = 0;
4320 else
4321 totmass = 1 / totmass;
4322 Ptot *= totmass;
4323
4324 return Ptot;
4325 }
4326
3415 /// <summary> 4327 /// <summary>
3416 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4328 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3417 /// the physics engine can use it. 4329 /// the physics engine can use it.
@@ -3579,6 +4491,14 @@ namespace OpenSim.Region.Framework.Scenes
3579 FromItemID = uuid; 4491 FromItemID = uuid;
3580 } 4492 }
3581 4493
4494 public void ResetOwnerChangeFlag()
4495 {
4496 ForEachPart(delegate(SceneObjectPart part)
4497 {
4498 part.ResetOwnerChangeFlag();
4499 });
4500 }
4501
3582 #endregion 4502 #endregion
3583 } 4503 }
3584} 4504}