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.cs1359
1 files changed, 1136 insertions, 223 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 1e900a0..11d703a 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
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.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -42,6 +43,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
42 43
43namespace OpenSim.Region.Framework.Scenes 44namespace OpenSim.Region.Framework.Scenes
44{ 45{
46
45 [Flags] 47 [Flags]
46 public enum scriptEvents 48 public enum scriptEvents
47 { 49 {
@@ -105,8 +107,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 107 /// since the group's last persistent backup
106 /// </summary> 108 /// </summary>
107 private bool m_hasGroupChanged = false; 109 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 110 private long timeFirstChanged = 0;
109 private long timeLastChanged; 111 private long timeLastChanged = 0;
112 private long m_maxPersistTime = 0;
113 private long m_minPersistTime = 0;
114 private Random m_rand;
115 private bool m_suspendUpdates;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
117
118 public bool areUpdatesSuspended
119 {
120 get
121 {
122 return m_suspendUpdates;
123 }
124 set
125 {
126 m_suspendUpdates = value;
127 if (!value)
128 {
129 QueueForUpdateCheck();
130 }
131 }
132 }
110 133
111 public bool HasGroupChanged 134 public bool HasGroupChanged
112 { 135 {
@@ -114,9 +137,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 137 {
115 if (value) 138 if (value)
116 { 139 {
140 if (m_isBackedUp)
141 {
142 m_scene.SceneGraph.FireChangeBackup(this);
143 }
117 timeLastChanged = DateTime.Now.Ticks; 144 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 145 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 146 timeFirstChanged = DateTime.Now.Ticks;
147 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
148 {
149 if (m_rand == null)
150 {
151 byte[] val = new byte[16];
152 m_rootPart.UUID.ToBytes(val, 0);
153 m_rand = new Random(BitConverter.ToInt32(val, 0));
154 }
155
156 if (m_scene.GetRootAgentCount() == 0)
157 {
158 //If the region is empty, this change has been made by an automated process
159 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
160
161 float factor = 1.5f + (float)(m_rand.NextDouble());
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
164 }
165 else
166 {
167 //If the region is not empty, we want to obey the minimum and maximum persist times
168 //but add a random factor so we stagger the object persistance a little
169 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
170 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
171 }
172 }
120 } 173 }
121 m_hasGroupChanged = value; 174 m_hasGroupChanged = value;
122 175
@@ -131,7 +184,7 @@ namespace OpenSim.Region.Framework.Scenes
131 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 184 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
132 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 185 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 186 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 187 public bool HasGroupChangedDueToDelink { get; set; }
135 188
136 private bool isTimeToPersist() 189 private bool isTimeToPersist()
137 { 190 {
@@ -141,8 +194,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 194 return false;
142 if (m_scene.ShuttingDown) 195 if (m_scene.ShuttingDown)
143 return true; 196 return true;
197
198 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
199 {
200 m_maxPersistTime = m_scene.m_persistAfter;
201 m_minPersistTime = m_scene.m_dontPersistBefore;
202 }
203
144 long currentTime = DateTime.Now.Ticks; 204 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 205
206 if (timeLastChanged == 0) timeLastChanged = currentTime;
207 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
208
209 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 210 return true;
147 return false; 211 return false;
148 } 212 }
@@ -261,10 +325,10 @@ namespace OpenSim.Region.Framework.Scenes
261 325
262 private bool m_scriptListens_atTarget; 326 private bool m_scriptListens_atTarget;
263 private bool m_scriptListens_notAtTarget; 327 private bool m_scriptListens_notAtTarget;
264
265 private bool m_scriptListens_atRotTarget; 328 private bool m_scriptListens_atRotTarget;
266 private bool m_scriptListens_notAtRotTarget; 329 private bool m_scriptListens_notAtRotTarget;
267 330
331 public bool m_dupeInProgress = false;
268 internal Dictionary<UUID, string> m_savedScriptState; 332 internal Dictionary<UUID, string> m_savedScriptState;
269 333
270 #region Properties 334 #region Properties
@@ -301,6 +365,16 @@ namespace OpenSim.Region.Framework.Scenes
301 get { return m_parts.Count; } 365 get { return m_parts.Count; }
302 } 366 }
303 367
368// protected Quaternion m_rotation = Quaternion.Identity;
369//
370// public virtual Quaternion Rotation
371// {
372// get { return m_rotation; }
373// set {
374// m_rotation = value;
375// }
376// }
377
304 public Quaternion GroupRotation 378 public Quaternion GroupRotation
305 { 379 {
306 get { return m_rootPart.RotationOffset; } 380 get { return m_rootPart.RotationOffset; }
@@ -407,7 +481,15 @@ namespace OpenSim.Region.Framework.Scenes
407 { 481 {
408 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 482 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
409 } 483 }
410 484
485
486
487 private struct avtocrossInfo
488 {
489 public ScenePresence av;
490 public uint ParentID;
491 }
492
411 /// <summary> 493 /// <summary>
412 /// The absolute position of this scene object in the scene 494 /// The absolute position of this scene object in the scene
413 /// </summary> 495 /// </summary>
@@ -420,14 +502,128 @@ namespace OpenSim.Region.Framework.Scenes
420 502
421 if (Scene != null) 503 if (Scene != null)
422 { 504 {
423 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 505 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
424 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 506 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
507 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
508 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
509 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
425 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 510 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
426 { 511 {
427 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 512 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
513 uint x = 0;
514 uint y = 0;
515 string version = String.Empty;
516 Vector3 newpos = Vector3.Zero;
517 OpenSim.Services.Interfaces.GridRegion destination = null;
518
519 bool canCross = true;
520 foreach (ScenePresence av in m_linkedAvatars)
521 {
522 // We need to cross these agents. First, let's find
523 // out if any of them can't cross for some reason.
524 // We have to deny the crossing entirely if any
525 // of them are banned. Alternatively, we could
526 // unsit banned agents....
527
528
529 // We set the avatar position as being the object
530 // position to get the region to send to
531 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
532 {
533 canCross = false;
534 break;
535 }
536
537 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
538 }
539
540 if (canCross)
541 {
542 // We unparent the SP quietly so that it won't
543 // be made to stand up
544
545 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
546
547 foreach (ScenePresence av in m_linkedAvatars)
548 {
549 avtocrossInfo avinfo = new avtocrossInfo();
550 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
551 if (parentPart != null)
552 av.ParentUUID = parentPart.UUID;
553
554 avinfo.av = av;
555 avinfo.ParentID = av.ParentID;
556 avsToCross.Add(avinfo);
557
558 av.ParentID = 0;
559 }
560
561// m_linkedAvatars.Clear();
562 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
563
564 // Normalize
565 if (val.X >= Constants.RegionSize)
566 val.X -= Constants.RegionSize;
567 if (val.Y >= Constants.RegionSize)
568 val.Y -= Constants.RegionSize;
569 if (val.X < 0)
570 val.X += Constants.RegionSize;
571 if (val.Y < 0)
572 val.Y += Constants.RegionSize;
573
574 // If it's deleted, crossing was successful
575 if (IsDeleted)
576 {
577 // foreach (ScenePresence av in m_linkedAvatars)
578 foreach (avtocrossInfo avinfo in avsToCross)
579 {
580 ScenePresence av = avinfo.av;
581 if (!av.IsInTransit) // just in case...
582 {
583 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
584
585 av.IsInTransit = true;
586
587 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
588 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
589 }
590 else
591 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
592 }
593 avsToCross.Clear();
594 return;
595 }
596 else // cross failed, put avas back ??
597 {
598 foreach (avtocrossInfo avinfo in avsToCross)
599 {
600 ScenePresence av = avinfo.av;
601 av.ParentUUID = UUID.Zero;
602 av.ParentID = avinfo.ParentID;
603// m_linkedAvatars.Add(av);
604 }
605 }
606 avsToCross.Clear();
607
608 }
609 else if (RootPart.PhysActor != null)
610 {
611 RootPart.PhysActor.CrossingFailure();
612 }
613
614 Vector3 oldp = AbsolutePosition;
615 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
616 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
617 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
428 } 618 }
429 } 619 }
430 620
621/* don't see the need but worse don't see where is restored to false if things stay in
622 foreach (SceneObjectPart part in m_parts.GetArray())
623 {
624 part.IgnoreUndoUpdate = true;
625 }
626 */
431 if (RootPart.GetStatusSandbox()) 627 if (RootPart.GetStatusSandbox())
432 { 628 {
433 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 629 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -441,10 +637,30 @@ namespace OpenSim.Region.Framework.Scenes
441 return; 637 return;
442 } 638 }
443 } 639 }
444
445 SceneObjectPart[] parts = m_parts.GetArray(); 640 SceneObjectPart[] parts = m_parts.GetArray();
446 for (int i = 0; i < parts.Length; i++) 641 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
447 parts[i].GroupPosition = val; 642 if (m_dupeInProgress)
643 triggerScriptEvent = false;
644 foreach (SceneObjectPart part in parts)
645 {
646 part.GroupPosition = val;
647 if (triggerScriptEvent)
648 part.TriggerScriptChangedEvent(Changed.POSITION);
649 }
650 if (!m_dupeInProgress)
651 {
652 foreach (ScenePresence av in m_linkedAvatars)
653 {
654 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
655 if (p != null && m_parts.TryGetValue(p.UUID, out p))
656 {
657 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
658 av.AbsolutePosition += offset;
659 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
660 av.SendAvatarDataToAllAgents();
661 }
662 }
663 }
448 664
449 //if (m_rootPart.PhysActor != null) 665 //if (m_rootPart.PhysActor != null)
450 //{ 666 //{
@@ -459,6 +675,40 @@ namespace OpenSim.Region.Framework.Scenes
459 } 675 }
460 } 676 }
461 677
678 public override Vector3 Velocity
679 {
680 get { return RootPart.Velocity; }
681 set { RootPart.Velocity = value; }
682 }
683
684 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
685 {
686 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
687 ScenePresence agent = icon.EndInvoke(iar);
688
689 //// If the cross was successful, this agent is a child agent
690 if (agent.IsChildAgent)
691 {
692 if (agent.ParentUUID != UUID.Zero)
693 {
694 agent.ParentPart = null;
695 agent.ParentPosition = Vector3.Zero;
696 // agent.ParentUUID = UUID.Zero;
697 }
698 }
699
700 agent.ParentUUID = UUID.Zero;
701
702// agent.Reset();
703// else // Not successful
704// agent.RestoreInCurrentScene();
705
706 // In any case
707 agent.IsInTransit = false;
708
709 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
710 }
711
462 public override uint LocalId 712 public override uint LocalId
463 { 713 {
464 get { return m_rootPart.LocalId; } 714 get { return m_rootPart.LocalId; }
@@ -529,6 +779,11 @@ namespace OpenSim.Region.Framework.Scenes
529 m_isSelected = value; 779 m_isSelected = value;
530 // Tell physics engine that group is selected 780 // Tell physics engine that group is selected
531 781
782 // this is not right
783 // but ode engines should only really need to know about root part
784 // so they can put entire object simulation on hold and not colliding
785 // keep as was for now
786
532 PhysicsActor pa = m_rootPart.PhysActor; 787 PhysicsActor pa = m_rootPart.PhysActor;
533 if (pa != null) 788 if (pa != null)
534 { 789 {
@@ -545,6 +800,42 @@ namespace OpenSim.Region.Framework.Scenes
545 childPa.Selected = value; 800 childPa.Selected = value;
546 } 801 }
547 } 802 }
803 if (RootPart.KeyframeMotion != null)
804 RootPart.KeyframeMotion.Selected = value;
805 }
806 }
807
808 public void PartSelectChanged(bool partSelect)
809 {
810 // any part selected makes group selected
811 if (m_isSelected == partSelect)
812 return;
813
814 if (partSelect)
815 {
816 IsSelected = partSelect;
817// if (!IsAttachment)
818// ScheduleGroupForFullUpdate();
819 }
820 else
821 {
822 // bad bad bad 2 heavy for large linksets
823 // since viewer does send lot of (un)selects
824 // this needs to be replaced by a specific list or count ?
825 // but that will require extra code in several places
826
827 SceneObjectPart[] parts = m_parts.GetArray();
828 for (int i = 0; i < parts.Length; i++)
829 {
830 SceneObjectPart part = parts[i];
831 if (part.IsSelected)
832 return;
833 }
834 IsSelected = partSelect;
835 if (!IsAttachment)
836 {
837 ScheduleGroupForFullUpdate();
838 }
548 } 839 }
549 } 840 }
550 841
@@ -622,6 +913,7 @@ namespace OpenSim.Region.Framework.Scenes
622 /// </summary> 913 /// </summary>
623 public SceneObjectGroup() 914 public SceneObjectGroup()
624 { 915 {
916
625 } 917 }
626 918
627 /// <summary> 919 /// <summary>
@@ -638,7 +930,7 @@ namespace OpenSim.Region.Framework.Scenes
638 /// Constructor. This object is added to the scene later via AttachToScene() 930 /// Constructor. This object is added to the scene later via AttachToScene()
639 /// </summary> 931 /// </summary>
640 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 932 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
641 { 933 {
642 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 934 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
643 } 935 }
644 936
@@ -674,6 +966,9 @@ namespace OpenSim.Region.Framework.Scenes
674 /// </summary> 966 /// </summary>
675 public virtual void AttachToBackup() 967 public virtual void AttachToBackup()
676 { 968 {
969 if (IsAttachment) return;
970 m_scene.SceneGraph.FireAttachToBackup(this);
971
677 if (InSceneBackup) 972 if (InSceneBackup)
678 { 973 {
679 //m_log.DebugFormat( 974 //m_log.DebugFormat(
@@ -716,6 +1011,13 @@ namespace OpenSim.Region.Framework.Scenes
716 1011
717 ApplyPhysics(); 1012 ApplyPhysics();
718 1013
1014 if (RootPart.PhysActor != null)
1015 RootPart.Force = RootPart.Force;
1016 if (RootPart.PhysActor != null)
1017 RootPart.Torque = RootPart.Torque;
1018 if (RootPart.PhysActor != null)
1019 RootPart.Buoyancy = RootPart.Buoyancy;
1020
719 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1021 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
720 // for the same object with very different properties. The caller must schedule the update. 1022 // for the same object with very different properties. The caller must schedule the update.
721 //ScheduleGroupForFullUpdate(); 1023 //ScheduleGroupForFullUpdate();
@@ -731,6 +1033,10 @@ namespace OpenSim.Region.Framework.Scenes
731 EntityIntersection result = new EntityIntersection(); 1033 EntityIntersection result = new EntityIntersection();
732 1034
733 SceneObjectPart[] parts = m_parts.GetArray(); 1035 SceneObjectPart[] parts = m_parts.GetArray();
1036
1037 // Find closest hit here
1038 float idist = float.MaxValue;
1039
734 for (int i = 0; i < parts.Length; i++) 1040 for (int i = 0; i < parts.Length; i++)
735 { 1041 {
736 SceneObjectPart part = parts[i]; 1042 SceneObjectPart part = parts[i];
@@ -745,11 +1051,6 @@ namespace OpenSim.Region.Framework.Scenes
745 1051
746 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1052 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
747 1053
748 // This may need to be updated to the maximum draw distance possible..
749 // We might (and probably will) be checking for prim creation from other sims
750 // when the camera crosses the border.
751 float idist = Constants.RegionSize;
752
753 if (inter.HitTF) 1054 if (inter.HitTF)
754 { 1055 {
755 // We need to find the closest prim to return to the testcaller along the ray 1056 // We need to find the closest prim to return to the testcaller along the ray
@@ -760,10 +1061,11 @@ namespace OpenSim.Region.Framework.Scenes
760 result.obj = part; 1061 result.obj = part;
761 result.normal = inter.normal; 1062 result.normal = inter.normal;
762 result.distance = inter.distance; 1063 result.distance = inter.distance;
1064
1065 idist = inter.distance;
763 } 1066 }
764 } 1067 }
765 } 1068 }
766
767 return result; 1069 return result;
768 } 1070 }
769 1071
@@ -775,25 +1077,27 @@ namespace OpenSim.Region.Framework.Scenes
775 /// <returns></returns> 1077 /// <returns></returns>
776 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1078 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
777 { 1079 {
778 maxX = -256f; 1080 maxX = float.MinValue;
779 maxY = -256f; 1081 maxY = float.MinValue;
780 maxZ = -256f; 1082 maxZ = float.MinValue;
781 minX = 256f; 1083 minX = float.MaxValue;
782 minY = 256f; 1084 minY = float.MaxValue;
783 minZ = 8192f; 1085 minZ = float.MaxValue;
784 1086
785 SceneObjectPart[] parts = m_parts.GetArray(); 1087 SceneObjectPart[] parts = m_parts.GetArray();
786 for (int i = 0; i < parts.Length; i++) 1088 foreach (SceneObjectPart part in parts)
787 { 1089 {
788 SceneObjectPart part = parts[i];
789
790 Vector3 worldPos = part.GetWorldPosition(); 1090 Vector3 worldPos = part.GetWorldPosition();
791 Vector3 offset = worldPos - AbsolutePosition; 1091 Vector3 offset = worldPos - AbsolutePosition;
792 Quaternion worldRot; 1092 Quaternion worldRot;
793 if (part.ParentID == 0) 1093 if (part.ParentID == 0)
1094 {
794 worldRot = part.RotationOffset; 1095 worldRot = part.RotationOffset;
1096 }
795 else 1097 else
1098 {
796 worldRot = part.GetWorldRotation(); 1099 worldRot = part.GetWorldRotation();
1100 }
797 1101
798 Vector3 frontTopLeft; 1102 Vector3 frontTopLeft;
799 Vector3 frontTopRight; 1103 Vector3 frontTopRight;
@@ -805,6 +1109,8 @@ namespace OpenSim.Region.Framework.Scenes
805 Vector3 backBottomLeft; 1109 Vector3 backBottomLeft;
806 Vector3 backBottomRight; 1110 Vector3 backBottomRight;
807 1111
1112 // Vector3[] corners = new Vector3[8];
1113
808 Vector3 orig = Vector3.Zero; 1114 Vector3 orig = Vector3.Zero;
809 1115
810 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1116 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -839,6 +1145,38 @@ namespace OpenSim.Region.Framework.Scenes
839 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1145 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
840 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1146 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
841 1147
1148
1149
1150 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1151 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1152 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1153 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1154 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1155 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1156 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1157 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1158
1159 //for (int i = 0; i < 8; i++)
1160 //{
1161 // corners[i] = corners[i] * worldRot;
1162 // corners[i] += offset;
1163
1164 // if (corners[i].X > maxX)
1165 // maxX = corners[i].X;
1166 // if (corners[i].X < minX)
1167 // minX = corners[i].X;
1168
1169 // if (corners[i].Y > maxY)
1170 // maxY = corners[i].Y;
1171 // if (corners[i].Y < minY)
1172 // minY = corners[i].Y;
1173
1174 // if (corners[i].Z > maxZ)
1175 // maxZ = corners[i].Y;
1176 // if (corners[i].Z < minZ)
1177 // minZ = corners[i].Z;
1178 //}
1179
842 frontTopLeft = frontTopLeft * worldRot; 1180 frontTopLeft = frontTopLeft * worldRot;
843 frontTopRight = frontTopRight * worldRot; 1181 frontTopRight = frontTopRight * worldRot;
844 frontBottomLeft = frontBottomLeft * worldRot; 1182 frontBottomLeft = frontBottomLeft * worldRot;
@@ -860,6 +1198,15 @@ namespace OpenSim.Region.Framework.Scenes
860 backTopLeft += offset; 1198 backTopLeft += offset;
861 backTopRight += offset; 1199 backTopRight += offset;
862 1200
1201 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1202 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1203 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1204 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1205 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1206 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1207 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1208 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1209
863 if (frontTopRight.X > maxX) 1210 if (frontTopRight.X > maxX)
864 maxX = frontTopRight.X; 1211 maxX = frontTopRight.X;
865 if (frontTopLeft.X > maxX) 1212 if (frontTopLeft.X > maxX)
@@ -1003,17 +1350,118 @@ namespace OpenSim.Region.Framework.Scenes
1003 1350
1004 #endregion 1351 #endregion
1005 1352
1353 public void GetResourcesCosts(SceneObjectPart apart,
1354 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1355 {
1356 // this information may need to be cached
1357
1358 float cost;
1359 float tmpcost;
1360
1361 bool ComplexCost = false;
1362
1363 SceneObjectPart p;
1364 SceneObjectPart[] parts;
1365
1366 lock (m_parts)
1367 {
1368 parts = m_parts.GetArray();
1369 }
1370
1371 int nparts = parts.Length;
1372
1373
1374 for (int i = 0; i < nparts; i++)
1375 {
1376 p = parts[i];
1377
1378 if (p.UsesComplexCost)
1379 {
1380 ComplexCost = true;
1381 break;
1382 }
1383 }
1384
1385 if (ComplexCost)
1386 {
1387 linksetResCost = 0;
1388 linksetPhysCost = 0;
1389 partCost = 0;
1390 partPhysCost = 0;
1391
1392 for (int i = 0; i < nparts; i++)
1393 {
1394 p = parts[i];
1395
1396 cost = p.StreamingCost;
1397 tmpcost = p.SimulationCost;
1398 if (tmpcost > cost)
1399 cost = tmpcost;
1400 tmpcost = p.PhysicsCost;
1401 if (tmpcost > cost)
1402 cost = tmpcost;
1403
1404 linksetPhysCost += tmpcost;
1405 linksetResCost += cost;
1406
1407 if (p == apart)
1408 {
1409 partCost = cost;
1410 partPhysCost = tmpcost;
1411 }
1412 }
1413 }
1414 else
1415 {
1416 partPhysCost = 1.0f;
1417 partCost = 1.0f;
1418 linksetResCost = (float)nparts;
1419 linksetPhysCost = linksetResCost;
1420 }
1421 }
1422
1423 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1424 {
1425 SceneObjectPart p;
1426 SceneObjectPart[] parts;
1427
1428 lock (m_parts)
1429 {
1430 parts = m_parts.GetArray();
1431 }
1432
1433 int nparts = parts.Length;
1434
1435 PhysCost = 0;
1436 StreamCost = 0;
1437 SimulCost = 0;
1438
1439 for (int i = 0; i < nparts; i++)
1440 {
1441 p = parts[i];
1442
1443 StreamCost += p.StreamingCost;
1444 SimulCost += p.SimulationCost;
1445 PhysCost += p.PhysicsCost;
1446 }
1447 }
1448
1006 public void SaveScriptedState(XmlTextWriter writer) 1449 public void SaveScriptedState(XmlTextWriter writer)
1007 { 1450 {
1451 SaveScriptedState(writer, false);
1452 }
1453
1454 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1455 {
1008 XmlDocument doc = new XmlDocument(); 1456 XmlDocument doc = new XmlDocument();
1009 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1457 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1010 1458
1011 SceneObjectPart[] parts = m_parts.GetArray(); 1459 SceneObjectPart[] parts = m_parts.GetArray();
1012 for (int i = 0; i < parts.Length; i++) 1460 for (int i = 0; i < parts.Length; i++)
1013 { 1461 {
1014 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1462 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1015 foreach (KeyValuePair<UUID, string> kvp in pstates) 1463 foreach (KeyValuePair<UUID, string> kvp in pstates)
1016 states.Add(kvp.Key, kvp.Value); 1464 states[kvp.Key] = kvp.Value;
1017 } 1465 }
1018 1466
1019 if (states.Count > 0) 1467 if (states.Count > 0)
@@ -1033,6 +1481,169 @@ namespace OpenSim.Region.Framework.Scenes
1033 } 1481 }
1034 1482
1035 /// <summary> 1483 /// <summary>
1484 /// Add the avatar to this linkset (avatar is sat).
1485 /// </summary>
1486 /// <param name="agentID"></param>
1487 public void AddAvatar(UUID agentID)
1488 {
1489 ScenePresence presence;
1490 if (m_scene.TryGetScenePresence(agentID, out presence))
1491 {
1492 if (!m_linkedAvatars.Contains(presence))
1493 {
1494 m_linkedAvatars.Add(presence);
1495 }
1496 }
1497 }
1498
1499 /// <summary>
1500 /// Delete the avatar from this linkset (avatar is unsat).
1501 /// </summary>
1502 /// <param name="agentID"></param>
1503 public void DeleteAvatar(UUID agentID)
1504 {
1505 ScenePresence presence;
1506 if (m_scene.TryGetScenePresence(agentID, out presence))
1507 {
1508 if (m_linkedAvatars.Contains(presence))
1509 {
1510 m_linkedAvatars.Remove(presence);
1511 }
1512 }
1513 }
1514
1515 /// <summary>
1516 /// Returns the list of linked presences (avatars sat on this group)
1517 /// </summary>
1518 /// <param name="agentID"></param>
1519 public List<ScenePresence> GetLinkedAvatars()
1520 {
1521 return m_linkedAvatars;
1522 }
1523
1524 /// <summary>
1525 /// Attach this scene object to the given avatar.
1526 /// </summary>
1527 /// <param name="agentID"></param>
1528 /// <param name="attachmentpoint"></param>
1529 /// <param name="AttachOffset"></param>
1530 private void AttachToAgent(
1531 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1532 {
1533 if (avatar != null)
1534 {
1535 // don't attach attachments to child agents
1536 if (avatar.IsChildAgent) return;
1537
1538 // Remove from database and parcel prim count
1539 m_scene.DeleteFromStorage(so.UUID);
1540 m_scene.EventManager.TriggerParcelPrimCountTainted();
1541
1542 so.AttachedAvatar = avatar.UUID;
1543
1544 if (so.RootPart.PhysActor != null)
1545 {
1546 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1547 so.RootPart.PhysActor = null;
1548 }
1549
1550 so.AbsolutePosition = attachOffset;
1551 so.RootPart.AttachedPos = attachOffset;
1552 so.IsAttachment = true;
1553 so.RootPart.SetParentLocalId(avatar.LocalId);
1554 so.AttachmentPoint = attachmentpoint;
1555
1556 avatar.AddAttachment(this);
1557
1558 if (!silent)
1559 {
1560 // Killing it here will cause the client to deselect it
1561 // It then reappears on the avatar, deselected
1562 // through the full update below
1563 //
1564 if (IsSelected)
1565 {
1566 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1567 }
1568
1569 IsSelected = false; // fudge....
1570 ScheduleGroupForFullUpdate();
1571 }
1572 }
1573 else
1574 {
1575 m_log.WarnFormat(
1576 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1577 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1578 }
1579 }
1580
1581 public byte GetAttachmentPoint()
1582 {
1583 return m_rootPart.Shape.State;
1584 }
1585
1586 public void DetachToGround()
1587 {
1588 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1589 if (avatar == null)
1590 return;
1591
1592 avatar.RemoveAttachment(this);
1593
1594 Vector3 detachedpos = new Vector3(127f,127f,127f);
1595 if (avatar == null)
1596 return;
1597
1598 detachedpos = avatar.AbsolutePosition;
1599 FromItemID = UUID.Zero;
1600
1601 AbsolutePosition = detachedpos;
1602 AttachedAvatar = UUID.Zero;
1603
1604 //SceneObjectPart[] parts = m_parts.GetArray();
1605 //for (int i = 0; i < parts.Length; i++)
1606 // parts[i].AttachedAvatar = UUID.Zero;
1607
1608 m_rootPart.SetParentLocalId(0);
1609 AttachmentPoint = (byte)0;
1610 // must check if buildind should be true or false here
1611 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1612 HasGroupChanged = true;
1613 RootPart.Rezzed = DateTime.Now;
1614 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1615 AttachToBackup();
1616 m_scene.EventManager.TriggerParcelPrimCountTainted();
1617 m_rootPart.ScheduleFullUpdate();
1618 m_rootPart.ClearUndoState();
1619 }
1620
1621 public void DetachToInventoryPrep()
1622 {
1623 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1624 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1625 if (avatar != null)
1626 {
1627 //detachedpos = avatar.AbsolutePosition;
1628 avatar.RemoveAttachment(this);
1629 }
1630
1631 AttachedAvatar = UUID.Zero;
1632
1633 /*SceneObjectPart[] parts = m_parts.GetArray();
1634 for (int i = 0; i < parts.Length; i++)
1635 parts[i].AttachedAvatar = UUID.Zero;*/
1636
1637 m_rootPart.SetParentLocalId(0);
1638 //m_rootPart.SetAttachmentPoint((byte)0);
1639 IsAttachment = false;
1640 AbsolutePosition = m_rootPart.AttachedPos;
1641 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1642 //AttachToBackup();
1643 //m_rootPart.ScheduleFullUpdate();
1644 }
1645
1646 /// <summary>
1036 /// 1647 ///
1037 /// </summary> 1648 /// </summary>
1038 /// <param name="part"></param> 1649 /// <param name="part"></param>
@@ -1082,7 +1693,10 @@ namespace OpenSim.Region.Framework.Scenes
1082 public void AddPart(SceneObjectPart part) 1693 public void AddPart(SceneObjectPart part)
1083 { 1694 {
1084 part.SetParent(this); 1695 part.SetParent(this);
1085 part.LinkNum = m_parts.Add(part.UUID, part); 1696 m_parts.Add(part.UUID, part);
1697
1698 part.LinkNum = m_parts.Count;
1699
1086 if (part.LinkNum == 2) 1700 if (part.LinkNum == 2)
1087 RootPart.LinkNum = 1; 1701 RootPart.LinkNum = 1;
1088 } 1702 }
@@ -1170,7 +1784,7 @@ namespace OpenSim.Region.Framework.Scenes
1170// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1784// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1171// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1785// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1172 1786
1173 part.StoreUndoState(); 1787// part.StoreUndoState();
1174 part.OnGrab(offsetPos, remoteClient); 1788 part.OnGrab(offsetPos, remoteClient);
1175 } 1789 }
1176 1790
@@ -1190,6 +1804,11 @@ namespace OpenSim.Region.Framework.Scenes
1190 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1804 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1191 public void DeleteGroupFromScene(bool silent) 1805 public void DeleteGroupFromScene(bool silent)
1192 { 1806 {
1807 // We need to keep track of this state in case this group is still queued for backup.
1808 IsDeleted = true;
1809
1810 DetachFromBackup();
1811
1193 SceneObjectPart[] parts = m_parts.GetArray(); 1812 SceneObjectPart[] parts = m_parts.GetArray();
1194 for (int i = 0; i < parts.Length; i++) 1813 for (int i = 0; i < parts.Length; i++)
1195 { 1814 {
@@ -1213,6 +1832,7 @@ namespace OpenSim.Region.Framework.Scenes
1213 } 1832 }
1214 }); 1833 });
1215 } 1834 }
1835
1216 } 1836 }
1217 1837
1218 public void AddScriptLPS(int count) 1838 public void AddScriptLPS(int count)
@@ -1282,28 +1902,43 @@ namespace OpenSim.Region.Framework.Scenes
1282 /// </summary> 1902 /// </summary>
1283 public void ApplyPhysics() 1903 public void ApplyPhysics()
1284 { 1904 {
1285 // Apply physics to the root prim
1286 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1287
1288 // Apply physics to child prims
1289 SceneObjectPart[] parts = m_parts.GetArray(); 1905 SceneObjectPart[] parts = m_parts.GetArray();
1290 if (parts.Length > 1) 1906 if (parts.Length > 1)
1291 { 1907 {
1908 ResetChildPrimPhysicsPositions();
1909
1910 // Apply physics to the root prim
1911 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1912
1913
1292 for (int i = 0; i < parts.Length; i++) 1914 for (int i = 0; i < parts.Length; i++)
1293 { 1915 {
1294 SceneObjectPart part = parts[i]; 1916 SceneObjectPart part = parts[i];
1295 if (part.LocalId != m_rootPart.LocalId) 1917 if (part.LocalId != m_rootPart.LocalId)
1296 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1918 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1297 } 1919 }
1298
1299 // Hack to get the physics scene geometries in the right spot 1920 // Hack to get the physics scene geometries in the right spot
1300 ResetChildPrimPhysicsPositions(); 1921// ResetChildPrimPhysicsPositions();
1922 if (m_rootPart.PhysActor != null)
1923 {
1924 m_rootPart.PhysActor.Building = false;
1925 }
1926 }
1927 else
1928 {
1929 // Apply physics to the root prim
1930 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1301 } 1931 }
1302 } 1932 }
1303 1933
1304 public void SetOwnerId(UUID userId) 1934 public void SetOwnerId(UUID userId)
1305 { 1935 {
1306 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1936 ForEachPart(delegate(SceneObjectPart part)
1937 {
1938
1939 part.OwnerID = userId;
1940
1941 });
1307 } 1942 }
1308 1943
1309 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1944 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1335,11 +1970,17 @@ namespace OpenSim.Region.Framework.Scenes
1335 return; 1970 return;
1336 } 1971 }
1337 1972
1973 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1974 return;
1975
1338 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1976 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1339 // any exception propogate upwards. 1977 // any exception propogate upwards.
1340 try 1978 try
1341 { 1979 {
1342 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1980 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1981 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1982 m_scene.LoadingPrims) // Land may not be valid yet
1983
1343 { 1984 {
1344 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1985 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1345 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1986 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1366,6 +2007,7 @@ namespace OpenSim.Region.Framework.Scenes
1366 } 2007 }
1367 } 2008 }
1368 } 2009 }
2010
1369 } 2011 }
1370 2012
1371 if (m_scene.UseBackup && HasGroupChanged) 2013 if (m_scene.UseBackup && HasGroupChanged)
@@ -1373,10 +2015,30 @@ namespace OpenSim.Region.Framework.Scenes
1373 // don't backup while it's selected or you're asking for changes mid stream. 2015 // don't backup while it's selected or you're asking for changes mid stream.
1374 if (isTimeToPersist() || forcedBackup) 2016 if (isTimeToPersist() || forcedBackup)
1375 { 2017 {
2018 if (m_rootPart.PhysActor != null &&
2019 (!m_rootPart.PhysActor.IsPhysical))
2020 {
2021 // Possible ghost prim
2022 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2023 {
2024 foreach (SceneObjectPart part in m_parts.GetArray())
2025 {
2026 // Re-set physics actor positions and
2027 // orientations
2028 part.GroupPosition = m_rootPart.GroupPosition;
2029 }
2030 }
2031 }
1376// m_log.DebugFormat( 2032// m_log.DebugFormat(
1377// "[SCENE]: Storing {0}, {1} in {2}", 2033// "[SCENE]: Storing {0}, {1} in {2}",
1378// Name, UUID, m_scene.RegionInfo.RegionName); 2034// Name, UUID, m_scene.RegionInfo.RegionName);
1379 2035
2036 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2037 {
2038 RootPart.Shape.State = 0;
2039 ScheduleGroupForFullUpdate();
2040 }
2041
1380 SceneObjectGroup backup_group = Copy(false); 2042 SceneObjectGroup backup_group = Copy(false);
1381 backup_group.RootPart.Velocity = RootPart.Velocity; 2043 backup_group.RootPart.Velocity = RootPart.Velocity;
1382 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2044 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1390,6 +2052,11 @@ namespace OpenSim.Region.Framework.Scenes
1390 2052
1391 backup_group.ForEachPart(delegate(SceneObjectPart part) 2053 backup_group.ForEachPart(delegate(SceneObjectPart part)
1392 { 2054 {
2055 if (part.KeyframeMotion != null)
2056 {
2057 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2058 part.KeyframeMotion.UpdateSceneObject(this);
2059 }
1393 part.Inventory.ProcessInventoryBackup(datastore); 2060 part.Inventory.ProcessInventoryBackup(datastore);
1394 }); 2061 });
1395 2062
@@ -1442,10 +2109,14 @@ namespace OpenSim.Region.Framework.Scenes
1442 /// <returns></returns> 2109 /// <returns></returns>
1443 public SceneObjectGroup Copy(bool userExposed) 2110 public SceneObjectGroup Copy(bool userExposed)
1444 { 2111 {
2112 m_dupeInProgress = true;
1445 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2113 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1446 dupe.m_isBackedUp = false; 2114 dupe.m_isBackedUp = false;
1447 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2115 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1448 2116
2117 // new group as no sitting avatars
2118 dupe.m_linkedAvatars = new List<ScenePresence>();
2119
1449 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2120 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1450 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2121 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1451 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2122 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1456,7 +2127,7 @@ namespace OpenSim.Region.Framework.Scenes
1456 // This is only necessary when userExposed is false! 2127 // This is only necessary when userExposed is false!
1457 2128
1458 bool previousAttachmentStatus = dupe.IsAttachment; 2129 bool previousAttachmentStatus = dupe.IsAttachment;
1459 2130
1460 if (!userExposed) 2131 if (!userExposed)
1461 dupe.IsAttachment = true; 2132 dupe.IsAttachment = true;
1462 2133
@@ -1474,11 +2145,11 @@ namespace OpenSim.Region.Framework.Scenes
1474 dupe.m_rootPart.TrimPermissions(); 2145 dupe.m_rootPart.TrimPermissions();
1475 2146
1476 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2147 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1477 2148
1478 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2149 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1479 { 2150 {
1480 return p1.LinkNum.CompareTo(p2.LinkNum); 2151 return p1.LinkNum.CompareTo(p2.LinkNum);
1481 } 2152 }
1482 ); 2153 );
1483 2154
1484 foreach (SceneObjectPart part in partList) 2155 foreach (SceneObjectPart part in partList)
@@ -1488,41 +2159,53 @@ namespace OpenSim.Region.Framework.Scenes
1488 { 2159 {
1489 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2160 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1490 newPart.LinkNum = part.LinkNum; 2161 newPart.LinkNum = part.LinkNum;
1491 } 2162 if (userExposed)
2163 newPart.ParentID = dupe.m_rootPart.LocalId;
2164 }
1492 else 2165 else
1493 { 2166 {
1494 newPart = dupe.m_rootPart; 2167 newPart = dupe.m_rootPart;
1495 } 2168 }
2169/*
2170 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2171 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1496 2172
1497 // Need to duplicate the physics actor as well 2173 // Need to duplicate the physics actor as well
1498 PhysicsActor originalPartPa = part.PhysActor; 2174 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1499 if (originalPartPa != null && userExposed)
1500 { 2175 {
1501 PrimitiveBaseShape pbs = newPart.Shape; 2176 PrimitiveBaseShape pbs = newPart.Shape;
1502
1503 newPart.PhysActor 2177 newPart.PhysActor
1504 = m_scene.PhysicsScene.AddPrimShape( 2178 = m_scene.PhysicsScene.AddPrimShape(
1505 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2179 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1506 pbs, 2180 pbs,
1507 newPart.AbsolutePosition, 2181 newPart.AbsolutePosition,
1508 newPart.Scale, 2182 newPart.Scale,
1509 newPart.RotationOffset, 2183 newPart.GetWorldRotation(),
1510 originalPartPa.IsPhysical, 2184 isphys,
2185 isphan,
1511 newPart.LocalId); 2186 newPart.LocalId);
1512 2187
1513 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2188 newPart.DoPhysicsPropertyUpdate(isphys, true);
1514 } 2189 */
2190 if (userExposed)
2191 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2192// }
1515 } 2193 }
1516 2194
1517 if (userExposed) 2195 if (userExposed)
1518 { 2196 {
1519 dupe.UpdateParentIDs(); 2197// done above dupe.UpdateParentIDs();
2198
2199 if (dupe.m_rootPart.PhysActor != null)
2200 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2201
1520 dupe.HasGroupChanged = true; 2202 dupe.HasGroupChanged = true;
1521 dupe.AttachToBackup(); 2203 dupe.AttachToBackup();
1522 2204
1523 ScheduleGroupForFullUpdate(); 2205 ScheduleGroupForFullUpdate();
1524 } 2206 }
1525 2207
2208 m_dupeInProgress = false;
1526 return dupe; 2209 return dupe;
1527 } 2210 }
1528 2211
@@ -1534,11 +2217,24 @@ namespace OpenSim.Region.Framework.Scenes
1534 /// <param name="cGroupID"></param> 2217 /// <param name="cGroupID"></param>
1535 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2218 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1536 { 2219 {
1537 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2220 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2221 // give newpart a new local ID lettng old part keep same
2222 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2223 newpart.LocalId = m_scene.AllocateLocalId();
2224
2225 SetRootPart(newpart);
2226 if (userExposed)
2227 RootPart.Velocity = Vector3.Zero; // In case source is moving
1538 } 2228 }
1539 2229
1540 public void ScriptSetPhysicsStatus(bool usePhysics) 2230 public void ScriptSetPhysicsStatus(bool usePhysics)
1541 { 2231 {
2232 if (usePhysics)
2233 {
2234 if (RootPart.KeyframeMotion != null)
2235 RootPart.KeyframeMotion.Stop();
2236 RootPart.KeyframeMotion = null;
2237 }
1542 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2238 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1543 } 2239 }
1544 2240
@@ -1586,13 +2282,14 @@ namespace OpenSim.Region.Framework.Scenes
1586 2282
1587 if (pa != null) 2283 if (pa != null)
1588 { 2284 {
1589 pa.AddForce(impulse, true); 2285 // false to be applied as a impulse
2286 pa.AddForce(impulse, false);
1590 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2287 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1591 } 2288 }
1592 } 2289 }
1593 } 2290 }
1594 2291
1595 public void applyAngularImpulse(Vector3 impulse) 2292 public void ApplyAngularImpulse(Vector3 impulse)
1596 { 2293 {
1597 PhysicsActor pa = RootPart.PhysActor; 2294 PhysicsActor pa = RootPart.PhysActor;
1598 2295
@@ -1600,21 +2297,8 @@ namespace OpenSim.Region.Framework.Scenes
1600 { 2297 {
1601 if (!IsAttachment) 2298 if (!IsAttachment)
1602 { 2299 {
1603 pa.AddAngularForce(impulse, true); 2300 // false to be applied as a impulse
1604 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2301 pa.AddAngularForce(impulse, false);
1605 }
1606 }
1607 }
1608
1609 public void setAngularImpulse(Vector3 impulse)
1610 {
1611 PhysicsActor pa = RootPart.PhysActor;
1612
1613 if (pa != null)
1614 {
1615 if (!IsAttachment)
1616 {
1617 pa.Torque = impulse;
1618 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2302 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1619 } 2303 }
1620 } 2304 }
@@ -1622,20 +2306,10 @@ namespace OpenSim.Region.Framework.Scenes
1622 2306
1623 public Vector3 GetTorque() 2307 public Vector3 GetTorque()
1624 { 2308 {
1625 PhysicsActor pa = RootPart.PhysActor; 2309 return RootPart.Torque;
1626
1627 if (pa != null)
1628 {
1629 if (!IsAttachment)
1630 {
1631 Vector3 torque = pa.Torque;
1632 return torque;
1633 }
1634 }
1635
1636 return Vector3.Zero;
1637 } 2310 }
1638 2311
2312 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1639 public void moveToTarget(Vector3 target, float tau) 2313 public void moveToTarget(Vector3 target, float tau)
1640 { 2314 {
1641 if (IsAttachment) 2315 if (IsAttachment)
@@ -1667,6 +2341,46 @@ namespace OpenSim.Region.Framework.Scenes
1667 pa.PIDActive = false; 2341 pa.PIDActive = false;
1668 } 2342 }
1669 2343
2344 public void rotLookAt(Quaternion target, float strength, float damping)
2345 {
2346 SceneObjectPart rootpart = m_rootPart;
2347 if (rootpart != null)
2348 {
2349 if (IsAttachment)
2350 {
2351 /*
2352 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2353 if (avatar != null)
2354 {
2355 Rotate the Av?
2356 } */
2357 }
2358 else
2359 {
2360 if (rootpart.PhysActor != null)
2361 { // APID must be implemented in your physics system for this to function.
2362 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2363 rootpart.PhysActor.APIDStrength = strength;
2364 rootpart.PhysActor.APIDDamping = damping;
2365 rootpart.PhysActor.APIDActive = true;
2366 }
2367 }
2368 }
2369 }
2370
2371 public void stopLookAt()
2372 {
2373 SceneObjectPart rootpart = m_rootPart;
2374 if (rootpart != null)
2375 {
2376 if (rootpart.PhysActor != null)
2377 { // APID must be implemented in your physics system for this to function.
2378 rootpart.PhysActor.APIDActive = false;
2379 }
2380 }
2381
2382 }
2383
1670 /// <summary> 2384 /// <summary>
1671 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2385 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1672 /// </summary> 2386 /// </summary>
@@ -1683,7 +2397,7 @@ namespace OpenSim.Region.Framework.Scenes
1683 { 2397 {
1684 pa.PIDHoverHeight = height; 2398 pa.PIDHoverHeight = height;
1685 pa.PIDHoverType = hoverType; 2399 pa.PIDHoverType = hoverType;
1686 pa.PIDTau = tau; 2400 pa.PIDHoverTau = tau;
1687 pa.PIDHoverActive = true; 2401 pa.PIDHoverActive = true;
1688 } 2402 }
1689 else 2403 else
@@ -1723,7 +2437,12 @@ namespace OpenSim.Region.Framework.Scenes
1723 /// <param name="cGroupID"></param> 2437 /// <param name="cGroupID"></param>
1724 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2438 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1725 { 2439 {
1726 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2440 // give new ID to the new part, letting old keep original
2441 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2442 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2443 newPart.LocalId = m_scene.AllocateLocalId();
2444 newPart.SetParent(this);
2445
1727 AddPart(newPart); 2446 AddPart(newPart);
1728 2447
1729 SetPartAsNonRoot(newPart); 2448 SetPartAsNonRoot(newPart);
@@ -1852,11 +2571,11 @@ namespace OpenSim.Region.Framework.Scenes
1852 /// Immediately send a full update for this scene object. 2571 /// Immediately send a full update for this scene object.
1853 /// </summary> 2572 /// </summary>
1854 public void SendGroupFullUpdate() 2573 public void SendGroupFullUpdate()
1855 { 2574 {
1856 if (IsDeleted) 2575 if (IsDeleted)
1857 return; 2576 return;
1858 2577
1859// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2578// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1860 2579
1861 RootPart.SendFullUpdateToAllClients(); 2580 RootPart.SendFullUpdateToAllClients();
1862 2581
@@ -1990,6 +2709,11 @@ namespace OpenSim.Region.Framework.Scenes
1990 2709
1991 SceneObjectPart linkPart = objectGroup.m_rootPart; 2710 SceneObjectPart linkPart = objectGroup.m_rootPart;
1992 2711
2712 if (m_rootPart.PhysActor != null)
2713 m_rootPart.PhysActor.Building = true;
2714 if (linkPart.PhysActor != null)
2715 linkPart.PhysActor.Building = true;
2716
1993 // physics flags from group to be applied to linked parts 2717 // physics flags from group to be applied to linked parts
1994 bool grpusephys = UsesPhysics; 2718 bool grpusephys = UsesPhysics;
1995 bool grptemporary = IsTemporary; 2719 bool grptemporary = IsTemporary;
@@ -1998,19 +2722,21 @@ namespace OpenSim.Region.Framework.Scenes
1998 Quaternion oldRootRotation = linkPart.RotationOffset; 2722 Quaternion oldRootRotation = linkPart.RotationOffset;
1999 2723
2000 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2724 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2725
2001 linkPart.ParentID = m_rootPart.LocalId; 2726 linkPart.ParentID = m_rootPart.LocalId;
2002 linkPart.GroupPosition = AbsolutePosition; 2727
2003 Vector3 axPos = linkPart.OffsetPosition; 2728 linkPart.GroupPosition = AbsolutePosition;
2004 2729
2730 Vector3 axPos = linkPart.OffsetPosition;
2005 Quaternion parentRot = m_rootPart.RotationOffset; 2731 Quaternion parentRot = m_rootPart.RotationOffset;
2006 axPos *= Quaternion.Inverse(parentRot); 2732 axPos *= Quaternion.Conjugate(parentRot);
2007
2008 linkPart.OffsetPosition = axPos; 2733 linkPart.OffsetPosition = axPos;
2734
2009 Quaternion oldRot = linkPart.RotationOffset; 2735 Quaternion oldRot = linkPart.RotationOffset;
2010 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2736 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2011 linkPart.RotationOffset = newRot; 2737 linkPart.RotationOffset = newRot;
2012 2738
2013 linkPart.ParentID = m_rootPart.LocalId; 2739// linkPart.ParentID = m_rootPart.LocalId; done above
2014 2740
2015 if (m_rootPart.LinkNum == 0) 2741 if (m_rootPart.LinkNum == 0)
2016 m_rootPart.LinkNum = 1; 2742 m_rootPart.LinkNum = 1;
@@ -2038,7 +2764,7 @@ namespace OpenSim.Region.Framework.Scenes
2038 linkPart.CreateSelected = true; 2764 linkPart.CreateSelected = true;
2039 2765
2040 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2766 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2041 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2767 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2042 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2768 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2043 { 2769 {
2044 linkPart.PhysActor.link(m_rootPart.PhysActor); 2770 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2046,6 +2772,7 @@ namespace OpenSim.Region.Framework.Scenes
2046 } 2772 }
2047 2773
2048 linkPart.LinkNum = linkNum++; 2774 linkPart.LinkNum = linkNum++;
2775 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2049 2776
2050 SceneObjectPart[] ogParts = objectGroup.Parts; 2777 SceneObjectPart[] ogParts = objectGroup.Parts;
2051 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2778 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2060,7 +2787,7 @@ namespace OpenSim.Region.Framework.Scenes
2060 { 2787 {
2061 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2788 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2062 // let physics know 2789 // let physics know
2063 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2790 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2064 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2791 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2065 { 2792 {
2066 part.PhysActor.link(m_rootPart.PhysActor); 2793 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2075,7 +2802,7 @@ namespace OpenSim.Region.Framework.Scenes
2075 objectGroup.IsDeleted = true; 2802 objectGroup.IsDeleted = true;
2076 2803
2077 objectGroup.m_parts.Clear(); 2804 objectGroup.m_parts.Clear();
2078 2805
2079 // Can't do this yet since backup still makes use of the root part without any synchronization 2806 // Can't do this yet since backup still makes use of the root part without any synchronization
2080// objectGroup.m_rootPart = null; 2807// objectGroup.m_rootPart = null;
2081 2808
@@ -2086,6 +2813,9 @@ namespace OpenSim.Region.Framework.Scenes
2086 // unmoved prims! 2813 // unmoved prims!
2087 ResetChildPrimPhysicsPositions(); 2814 ResetChildPrimPhysicsPositions();
2088 2815
2816 if (m_rootPart.PhysActor != null)
2817 m_rootPart.PhysActor.Building = false;
2818
2089 //HasGroupChanged = true; 2819 //HasGroupChanged = true;
2090 //ScheduleGroupForFullUpdate(); 2820 //ScheduleGroupForFullUpdate();
2091 } 2821 }
@@ -2153,7 +2883,10 @@ namespace OpenSim.Region.Framework.Scenes
2153// m_log.DebugFormat( 2883// m_log.DebugFormat(
2154// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2884// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2155// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2885// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2156 2886
2887 if (m_rootPart.PhysActor != null)
2888 m_rootPart.PhysActor.Building = true;
2889
2157 linkPart.ClearUndoState(); 2890 linkPart.ClearUndoState();
2158 2891
2159 Quaternion worldRot = linkPart.GetWorldRotation(); 2892 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2213,6 +2946,14 @@ namespace OpenSim.Region.Framework.Scenes
2213 2946
2214 // When we delete a group, we currently have to force persist to the database if the object id has changed 2947 // When we delete a group, we currently have to force persist to the database if the object id has changed
2215 // (since delete works by deleting all rows which have a given object id) 2948 // (since delete works by deleting all rows which have a given object id)
2949
2950 // this is as it seems to be in sl now
2951 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2952 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2953
2954 if (m_rootPart.PhysActor != null)
2955 m_rootPart.PhysActor.Building = false;
2956
2216 objectGroup.HasGroupChangedDueToDelink = true; 2957 objectGroup.HasGroupChangedDueToDelink = true;
2217 2958
2218 return objectGroup; 2959 return objectGroup;
@@ -2224,6 +2965,7 @@ namespace OpenSim.Region.Framework.Scenes
2224 /// <param name="objectGroup"></param> 2965 /// <param name="objectGroup"></param>
2225 public virtual void DetachFromBackup() 2966 public virtual void DetachFromBackup()
2226 { 2967 {
2968 m_scene.SceneGraph.FireDetachFromBackup(this);
2227 if (m_isBackedUp && Scene != null) 2969 if (m_isBackedUp && Scene != null)
2228 m_scene.EventManager.OnBackup -= ProcessBackup; 2970 m_scene.EventManager.OnBackup -= ProcessBackup;
2229 2971
@@ -2242,7 +2984,8 @@ namespace OpenSim.Region.Framework.Scenes
2242 2984
2243 axPos *= parentRot; 2985 axPos *= parentRot;
2244 part.OffsetPosition = axPos; 2986 part.OffsetPosition = axPos;
2245 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2987 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2988 part.GroupPosition = newPos;
2246 part.OffsetPosition = Vector3.Zero; 2989 part.OffsetPosition = Vector3.Zero;
2247 part.RotationOffset = worldRot; 2990 part.RotationOffset = worldRot;
2248 2991
@@ -2253,20 +2996,20 @@ namespace OpenSim.Region.Framework.Scenes
2253 2996
2254 part.LinkNum = linkNum; 2997 part.LinkNum = linkNum;
2255 2998
2256 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2999 part.OffsetPosition = newPos - AbsolutePosition;
2257 3000
2258 Quaternion rootRotation = m_rootPart.RotationOffset; 3001 Quaternion rootRotation = m_rootPart.RotationOffset;
2259 3002
2260 Vector3 pos = part.OffsetPosition; 3003 Vector3 pos = part.OffsetPosition;
2261 pos *= Quaternion.Inverse(rootRotation); 3004 pos *= Quaternion.Conjugate(rootRotation);
2262 part.OffsetPosition = pos; 3005 part.OffsetPosition = pos;
2263 3006
2264 parentRot = m_rootPart.RotationOffset; 3007 parentRot = m_rootPart.RotationOffset;
2265 oldRot = part.RotationOffset; 3008 oldRot = part.RotationOffset;
2266 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3009 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2267 part.RotationOffset = newRot; 3010 part.RotationOffset = newRot;
2268 3011
2269 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3012 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2270 } 3013 }
2271 3014
2272 /// <summary> 3015 /// <summary>
@@ -2288,10 +3031,14 @@ namespace OpenSim.Region.Framework.Scenes
2288 { 3031 {
2289 if (!m_rootPart.BlockGrab) 3032 if (!m_rootPart.BlockGrab)
2290 { 3033 {
2291 Vector3 llmoveforce = pos - AbsolutePosition; 3034/* Vector3 llmoveforce = pos - AbsolutePosition;
2292 Vector3 grabforce = llmoveforce; 3035 Vector3 grabforce = llmoveforce;
2293 grabforce = (grabforce / 10) * pa.Mass; 3036 grabforce = (grabforce / 10) * pa.Mass;
2294 pa.AddForce(grabforce, true); 3037 */
3038 // empirically convert distance diference to a impulse
3039 Vector3 grabforce = pos - AbsolutePosition;
3040 grabforce = grabforce * (pa.Mass/ 10.0f);
3041 pa.AddForce(grabforce, false);
2295 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3042 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2296 } 3043 }
2297 } 3044 }
@@ -2517,8 +3264,22 @@ namespace OpenSim.Region.Framework.Scenes
2517 } 3264 }
2518 } 3265 }
2519 3266
2520 for (int i = 0; i < parts.Length; i++) 3267 if (parts.Length > 1)
2521 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3268 {
3269 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3270
3271 for (int i = 0; i < parts.Length; i++)
3272 {
3273
3274 if (parts[i].UUID != m_rootPart.UUID)
3275 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3276 }
3277
3278 if (m_rootPart.PhysActor != null)
3279 m_rootPart.PhysActor.Building = false;
3280 }
3281 else
3282 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2522 } 3283 }
2523 } 3284 }
2524 3285
@@ -2531,6 +3292,17 @@ namespace OpenSim.Region.Framework.Scenes
2531 } 3292 }
2532 } 3293 }
2533 3294
3295
3296
3297 /// <summary>
3298 /// Gets the number of parts
3299 /// </summary>
3300 /// <returns></returns>
3301 public int GetPartCount()
3302 {
3303 return Parts.Count();
3304 }
3305
2534 /// <summary> 3306 /// <summary>
2535 /// Update the texture entry for this part 3307 /// Update the texture entry for this part
2536 /// </summary> 3308 /// </summary>
@@ -2592,11 +3364,6 @@ namespace OpenSim.Region.Framework.Scenes
2592 /// <param name="scale"></param> 3364 /// <param name="scale"></param>
2593 public void GroupResize(Vector3 scale) 3365 public void GroupResize(Vector3 scale)
2594 { 3366 {
2595// m_log.DebugFormat(
2596// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2597
2598 RootPart.StoreUndoState(true);
2599
2600 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3367 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2601 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3368 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2602 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3369 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2623,7 +3390,6 @@ namespace OpenSim.Region.Framework.Scenes
2623 SceneObjectPart obPart = parts[i]; 3390 SceneObjectPart obPart = parts[i];
2624 if (obPart.UUID != m_rootPart.UUID) 3391 if (obPart.UUID != m_rootPart.UUID)
2625 { 3392 {
2626// obPart.IgnoreUndoUpdate = true;
2627 Vector3 oldSize = new Vector3(obPart.Scale); 3393 Vector3 oldSize = new Vector3(obPart.Scale);
2628 3394
2629 float f = 1.0f; 3395 float f = 1.0f;
@@ -2687,8 +3453,6 @@ namespace OpenSim.Region.Framework.Scenes
2687 z *= a; 3453 z *= a;
2688 } 3454 }
2689 } 3455 }
2690
2691// obPart.IgnoreUndoUpdate = false;
2692 } 3456 }
2693 } 3457 }
2694 } 3458 }
@@ -2698,9 +3462,7 @@ namespace OpenSim.Region.Framework.Scenes
2698 prevScale.Y *= y; 3462 prevScale.Y *= y;
2699 prevScale.Z *= z; 3463 prevScale.Z *= z;
2700 3464
2701// RootPart.IgnoreUndoUpdate = true;
2702 RootPart.Resize(prevScale); 3465 RootPart.Resize(prevScale);
2703// RootPart.IgnoreUndoUpdate = false;
2704 3466
2705 parts = m_parts.GetArray(); 3467 parts = m_parts.GetArray();
2706 for (int i = 0; i < parts.Length; i++) 3468 for (int i = 0; i < parts.Length; i++)
@@ -2709,8 +3471,6 @@ namespace OpenSim.Region.Framework.Scenes
2709 3471
2710 if (obPart.UUID != m_rootPart.UUID) 3472 if (obPart.UUID != m_rootPart.UUID)
2711 { 3473 {
2712 obPart.IgnoreUndoUpdate = true;
2713
2714 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3474 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2715 currentpos.X *= x; 3475 currentpos.X *= x;
2716 currentpos.Y *= y; 3476 currentpos.Y *= y;
@@ -2723,16 +3483,12 @@ namespace OpenSim.Region.Framework.Scenes
2723 3483
2724 obPart.Resize(newSize); 3484 obPart.Resize(newSize);
2725 obPart.UpdateOffSet(currentpos); 3485 obPart.UpdateOffSet(currentpos);
2726
2727 obPart.IgnoreUndoUpdate = false;
2728 } 3486 }
2729 3487
2730// obPart.IgnoreUndoUpdate = false; 3488 HasGroupChanged = true;
2731// obPart.StoreUndoState(); 3489 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3490 ScheduleGroupForTerseUpdate();
2732 } 3491 }
2733
2734// m_log.DebugFormat(
2735// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2736 } 3492 }
2737 3493
2738 #endregion 3494 #endregion
@@ -2745,14 +3501,6 @@ namespace OpenSim.Region.Framework.Scenes
2745 /// <param name="pos"></param> 3501 /// <param name="pos"></param>
2746 public void UpdateGroupPosition(Vector3 pos) 3502 public void UpdateGroupPosition(Vector3 pos)
2747 { 3503 {
2748// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2749
2750 RootPart.StoreUndoState(true);
2751
2752// SceneObjectPart[] parts = m_parts.GetArray();
2753// for (int i = 0; i < parts.Length; i++)
2754// parts[i].StoreUndoState();
2755
2756 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3504 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2757 { 3505 {
2758 if (IsAttachment) 3506 if (IsAttachment)
@@ -2785,21 +3533,17 @@ namespace OpenSim.Region.Framework.Scenes
2785 /// </summary> 3533 /// </summary>
2786 /// <param name="pos"></param> 3534 /// <param name="pos"></param>
2787 /// <param name="localID"></param> 3535 /// <param name="localID"></param>
3536 ///
3537
2788 public void UpdateSinglePosition(Vector3 pos, uint localID) 3538 public void UpdateSinglePosition(Vector3 pos, uint localID)
2789 { 3539 {
2790 SceneObjectPart part = GetPart(localID); 3540 SceneObjectPart part = GetPart(localID);
2791 3541
2792// SceneObjectPart[] parts = m_parts.GetArray();
2793// for (int i = 0; i < parts.Length; i++)
2794// parts[i].StoreUndoState();
2795
2796 if (part != null) 3542 if (part != null)
2797 { 3543 {
2798// m_log.DebugFormat( 3544// unlock parts position change
2799// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3545 if (m_rootPart.PhysActor != null)
2800 3546 m_rootPart.PhysActor.Building = true;
2801 part.StoreUndoState(false);
2802 part.IgnoreUndoUpdate = true;
2803 3547
2804 if (part.UUID == m_rootPart.UUID) 3548 if (part.UUID == m_rootPart.UUID)
2805 { 3549 {
@@ -2810,8 +3554,10 @@ namespace OpenSim.Region.Framework.Scenes
2810 part.UpdateOffSet(pos); 3554 part.UpdateOffSet(pos);
2811 } 3555 }
2812 3556
3557 if (m_rootPart.PhysActor != null)
3558 m_rootPart.PhysActor.Building = false;
3559
2813 HasGroupChanged = true; 3560 HasGroupChanged = true;
2814 part.IgnoreUndoUpdate = false;
2815 } 3561 }
2816 } 3562 }
2817 3563
@@ -2821,13 +3567,7 @@ namespace OpenSim.Region.Framework.Scenes
2821 /// <param name="pos"></param> 3567 /// <param name="pos"></param>
2822 public void UpdateRootPosition(Vector3 pos) 3568 public void UpdateRootPosition(Vector3 pos)
2823 { 3569 {
2824// m_log.DebugFormat( 3570 // needs to be called with phys building true
2825// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2826
2827// SceneObjectPart[] parts = m_parts.GetArray();
2828// for (int i = 0; i < parts.Length; i++)
2829// parts[i].StoreUndoState();
2830
2831 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3571 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2832 Vector3 oldPos = 3572 Vector3 oldPos =
2833 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3573 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2850,7 +3590,14 @@ namespace OpenSim.Region.Framework.Scenes
2850 AbsolutePosition = newPos; 3590 AbsolutePosition = newPos;
2851 3591
2852 HasGroupChanged = true; 3592 HasGroupChanged = true;
2853 ScheduleGroupForTerseUpdate(); 3593 if (m_rootPart.Undoing)
3594 {
3595 ScheduleGroupForFullUpdate();
3596 }
3597 else
3598 {
3599 ScheduleGroupForTerseUpdate();
3600 }
2854 } 3601 }
2855 3602
2856 #endregion 3603 #endregion
@@ -2863,24 +3610,16 @@ namespace OpenSim.Region.Framework.Scenes
2863 /// <param name="rot"></param> 3610 /// <param name="rot"></param>
2864 public void UpdateGroupRotationR(Quaternion rot) 3611 public void UpdateGroupRotationR(Quaternion rot)
2865 { 3612 {
2866// m_log.DebugFormat(
2867// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2868
2869// SceneObjectPart[] parts = m_parts.GetArray();
2870// for (int i = 0; i < parts.Length; i++)
2871// parts[i].StoreUndoState();
2872
2873 m_rootPart.StoreUndoState(true);
2874
2875 m_rootPart.UpdateRotation(rot); 3613 m_rootPart.UpdateRotation(rot);
2876 3614
3615/* this is done by rootpart RotationOffset set called by UpdateRotation
2877 PhysicsActor actor = m_rootPart.PhysActor; 3616 PhysicsActor actor = m_rootPart.PhysActor;
2878 if (actor != null) 3617 if (actor != null)
2879 { 3618 {
2880 actor.Orientation = m_rootPart.RotationOffset; 3619 actor.Orientation = m_rootPart.RotationOffset;
2881 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3620 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2882 } 3621 }
2883 3622*/
2884 HasGroupChanged = true; 3623 HasGroupChanged = true;
2885 ScheduleGroupForTerseUpdate(); 3624 ScheduleGroupForTerseUpdate();
2886 } 3625 }
@@ -2892,16 +3631,6 @@ namespace OpenSim.Region.Framework.Scenes
2892 /// <param name="rot"></param> 3631 /// <param name="rot"></param>
2893 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3632 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2894 { 3633 {
2895// m_log.DebugFormat(
2896// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2897
2898// SceneObjectPart[] parts = m_parts.GetArray();
2899// for (int i = 0; i < parts.Length; i++)
2900// parts[i].StoreUndoState();
2901
2902 RootPart.StoreUndoState(true);
2903 RootPart.IgnoreUndoUpdate = true;
2904
2905 m_rootPart.UpdateRotation(rot); 3634 m_rootPart.UpdateRotation(rot);
2906 3635
2907 PhysicsActor actor = m_rootPart.PhysActor; 3636 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2920,8 +3649,6 @@ namespace OpenSim.Region.Framework.Scenes
2920 3649
2921 HasGroupChanged = true; 3650 HasGroupChanged = true;
2922 ScheduleGroupForTerseUpdate(); 3651 ScheduleGroupForTerseUpdate();
2923
2924 RootPart.IgnoreUndoUpdate = false;
2925 } 3652 }
2926 3653
2927 /// <summary> 3654 /// <summary>
@@ -2934,13 +3661,11 @@ namespace OpenSim.Region.Framework.Scenes
2934 SceneObjectPart part = GetPart(localID); 3661 SceneObjectPart part = GetPart(localID);
2935 3662
2936 SceneObjectPart[] parts = m_parts.GetArray(); 3663 SceneObjectPart[] parts = m_parts.GetArray();
2937 for (int i = 0; i < parts.Length; i++)
2938 parts[i].StoreUndoState();
2939 3664
2940 if (part != null) 3665 if (part != null)
2941 { 3666 {
2942// m_log.DebugFormat( 3667 if (m_rootPart.PhysActor != null)
2943// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3668 m_rootPart.PhysActor.Building = true;
2944 3669
2945 if (part.UUID == m_rootPart.UUID) 3670 if (part.UUID == m_rootPart.UUID)
2946 { 3671 {
@@ -2950,6 +3675,9 @@ namespace OpenSim.Region.Framework.Scenes
2950 { 3675 {
2951 part.UpdateRotation(rot); 3676 part.UpdateRotation(rot);
2952 } 3677 }
3678
3679 if (m_rootPart.PhysActor != null)
3680 m_rootPart.PhysActor.Building = false;
2953 } 3681 }
2954 } 3682 }
2955 3683
@@ -2963,12 +3691,8 @@ namespace OpenSim.Region.Framework.Scenes
2963 SceneObjectPart part = GetPart(localID); 3691 SceneObjectPart part = GetPart(localID);
2964 if (part != null) 3692 if (part != null)
2965 { 3693 {
2966// m_log.DebugFormat( 3694 if (m_rootPart.PhysActor != null)
2967// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3695 m_rootPart.PhysActor.Building = true;
2968// part.Name, part.LocalId, rot);
2969
2970 part.StoreUndoState();
2971 part.IgnoreUndoUpdate = true;
2972 3696
2973 if (part.UUID == m_rootPart.UUID) 3697 if (part.UUID == m_rootPart.UUID)
2974 { 3698 {
@@ -2981,7 +3705,8 @@ namespace OpenSim.Region.Framework.Scenes
2981 part.OffsetPosition = pos; 3705 part.OffsetPosition = pos;
2982 } 3706 }
2983 3707
2984 part.IgnoreUndoUpdate = false; 3708 if (m_rootPart.PhysActor != null)
3709 m_rootPart.PhysActor.Building = false;
2985 } 3710 }
2986 } 3711 }
2987 3712
@@ -2991,15 +3716,12 @@ namespace OpenSim.Region.Framework.Scenes
2991 /// <param name="rot"></param> 3716 /// <param name="rot"></param>
2992 public void UpdateRootRotation(Quaternion rot) 3717 public void UpdateRootRotation(Quaternion rot)
2993 { 3718 {
2994// m_log.DebugFormat( 3719 // needs to be called with phys building true
2995// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2996// Name, LocalId, rot);
2997
2998 Quaternion axRot = rot; 3720 Quaternion axRot = rot;
2999 Quaternion oldParentRot = m_rootPart.RotationOffset; 3721 Quaternion oldParentRot = m_rootPart.RotationOffset;
3000 3722
3001 m_rootPart.StoreUndoState(); 3723 //Don't use UpdateRotation because it schedules an update prematurely
3002 m_rootPart.UpdateRotation(rot); 3724 m_rootPart.RotationOffset = rot;
3003 3725
3004 PhysicsActor pa = m_rootPart.PhysActor; 3726 PhysicsActor pa = m_rootPart.PhysActor;
3005 3727
@@ -3015,35 +3737,145 @@ namespace OpenSim.Region.Framework.Scenes
3015 SceneObjectPart prim = parts[i]; 3737 SceneObjectPart prim = parts[i];
3016 if (prim.UUID != m_rootPart.UUID) 3738 if (prim.UUID != m_rootPart.UUID)
3017 { 3739 {
3018 prim.IgnoreUndoUpdate = true; 3740 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3741 NewRot = Quaternion.Inverse(axRot) * NewRot;
3742 prim.RotationOffset = NewRot;
3743
3019 Vector3 axPos = prim.OffsetPosition; 3744 Vector3 axPos = prim.OffsetPosition;
3745
3020 axPos *= oldParentRot; 3746 axPos *= oldParentRot;
3021 axPos *= Quaternion.Inverse(axRot); 3747 axPos *= Quaternion.Inverse(axRot);
3022 prim.OffsetPosition = axPos; 3748 prim.OffsetPosition = axPos;
3023 Quaternion primsRot = prim.RotationOffset; 3749 }
3024 Quaternion newRot = oldParentRot * primsRot; 3750 }
3025 newRot = Quaternion.Inverse(axRot) * newRot; 3751
3026 prim.RotationOffset = newRot; 3752 HasGroupChanged = true;
3027 prim.ScheduleTerseUpdate(); 3753 ScheduleGroupForFullUpdate();
3028 prim.IgnoreUndoUpdate = false; 3754 }
3029 }
3030 }
3031
3032// for (int i = 0; i < parts.Length; i++)
3033// {
3034// SceneObjectPart childpart = parts[i];
3035// if (childpart != m_rootPart)
3036// {
3037//// childpart.IgnoreUndoUpdate = false;
3038//// childpart.StoreUndoState();
3039// }
3040// }
3041 3755
3042 m_rootPart.ScheduleTerseUpdate(); 3756 private enum updatetype :int
3757 {
3758 none = 0,
3759 partterse = 1,
3760 partfull = 2,
3761 groupterse = 3,
3762 groupfull = 4
3763 }
3043 3764
3044// m_log.DebugFormat( 3765 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3045// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3766 {
3046// Name, LocalId, rot); 3767 // TODO this still as excessive *.Schedule*Update()s
3768
3769 if (part != null && part.ParentGroup != null)
3770 {
3771 ObjectChangeType change = data.change;
3772 bool togroup = ((change & ObjectChangeType.Group) != 0);
3773 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3774
3775 SceneObjectGroup group = part.ParentGroup;
3776 PhysicsActor pha = group.RootPart.PhysActor;
3777
3778 updatetype updateType = updatetype.none;
3779
3780 if (togroup)
3781 {
3782 // related to group
3783 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3784 {
3785 if ((change & ObjectChangeType.Rotation) != 0)
3786 {
3787 group.RootPart.UpdateRotation(data.rotation);
3788 updateType = updatetype.none;
3789 }
3790 if ((change & ObjectChangeType.Position) != 0)
3791 {
3792 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3793 UpdateGroupPosition(data.position);
3794 updateType = updatetype.groupterse;
3795 }
3796 else
3797 // ugly rotation update of all parts
3798 {
3799 group.AbsolutePosition = AbsolutePosition;
3800 }
3801
3802 }
3803 if ((change & ObjectChangeType.Scale) != 0)
3804 {
3805 if (pha != null)
3806 pha.Building = true;
3807
3808 group.GroupResize(data.scale);
3809 updateType = updatetype.none;
3810
3811 if (pha != null)
3812 pha.Building = false;
3813 }
3814 }
3815 else
3816 {
3817 // related to single prim in a link-set ( ie group)
3818 if (pha != null)
3819 pha.Building = true;
3820
3821 // root part is special
3822 // parts offset positions or rotations need to change also
3823
3824 if (part == group.RootPart)
3825 {
3826 if ((change & ObjectChangeType.Rotation) != 0)
3827 group.UpdateRootRotation(data.rotation);
3828 if ((change & ObjectChangeType.Position) != 0)
3829 group.UpdateRootPosition(data.position);
3830 if ((change & ObjectChangeType.Scale) != 0)
3831 part.Resize(data.scale);
3832 }
3833 else
3834 {
3835 if ((change & ObjectChangeType.Position) != 0)
3836 {
3837 part.OffsetPosition = data.position;
3838 updateType = updatetype.partterse;
3839 }
3840 if ((change & ObjectChangeType.Rotation) != 0)
3841 {
3842 part.UpdateRotation(data.rotation);
3843 updateType = updatetype.none;
3844 }
3845 if ((change & ObjectChangeType.Scale) != 0)
3846 {
3847 part.Resize(data.scale);
3848 updateType = updatetype.none;
3849 }
3850 }
3851
3852 if (pha != null)
3853 pha.Building = false;
3854 }
3855
3856 if (updateType != updatetype.none)
3857 {
3858 group.HasGroupChanged = true;
3859
3860 switch (updateType)
3861 {
3862 case updatetype.partterse:
3863 part.ScheduleTerseUpdate();
3864 break;
3865 case updatetype.partfull:
3866 part.ScheduleFullUpdate();
3867 break;
3868 case updatetype.groupterse:
3869 group.ScheduleGroupForTerseUpdate();
3870 break;
3871 case updatetype.groupfull:
3872 group.ScheduleGroupForFullUpdate();
3873 break;
3874 default:
3875 break;
3876 }
3877 }
3878 }
3047 } 3879 }
3048 3880
3049 #endregion 3881 #endregion
@@ -3142,10 +3974,11 @@ namespace OpenSim.Region.Framework.Scenes
3142 scriptPosTarget target = m_targets[idx]; 3974 scriptPosTarget target = m_targets[idx];
3143 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 3975 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3144 { 3976 {
3977 at_target = true;
3978
3145 // trigger at_target 3979 // trigger at_target
3146 if (m_scriptListens_atTarget) 3980 if (m_scriptListens_atTarget)
3147 { 3981 {
3148 at_target = true;
3149 scriptPosTarget att = new scriptPosTarget(); 3982 scriptPosTarget att = new scriptPosTarget();
3150 att.targetPos = target.targetPos; 3983 att.targetPos = target.targetPos;
3151 att.tolerance = target.tolerance; 3984 att.tolerance = target.tolerance;
@@ -3263,11 +4096,50 @@ namespace OpenSim.Region.Framework.Scenes
3263 } 4096 }
3264 } 4097 }
3265 } 4098 }
3266 4099
4100 public Vector3 GetGeometricCenter()
4101 {
4102 // this is not real geometric center but a average of positions relative to root prim acording to
4103 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4104 // ignoring tortured prims details since sl also seems to ignore
4105 // so no real use in doing it on physics
4106
4107 Vector3 gc = Vector3.Zero;
4108
4109 int nparts = m_parts.Count;
4110 if (nparts <= 1)
4111 return gc;
4112
4113 SceneObjectPart[] parts = m_parts.GetArray();
4114 nparts = parts.Length; // just in case it changed
4115 if (nparts <= 1)
4116 return gc;
4117
4118 Quaternion parentRot = RootPart.RotationOffset;
4119 Vector3 pPos;
4120
4121 // average all parts positions
4122 for (int i = 0; i < nparts; i++)
4123 {
4124 // do it directly
4125 // gc += parts[i].GetWorldPosition();
4126 if (parts[i] != RootPart)
4127 {
4128 pPos = parts[i].OffsetPosition;
4129 gc += pPos;
4130 }
4131
4132 }
4133 gc /= nparts;
4134
4135 // relative to root:
4136// gc -= AbsolutePosition;
4137 return gc;
4138 }
4139
3267 public float GetMass() 4140 public float GetMass()
3268 { 4141 {
3269 float retmass = 0f; 4142 float retmass = 0f;
3270
3271 SceneObjectPart[] parts = m_parts.GetArray(); 4143 SceneObjectPart[] parts = m_parts.GetArray();
3272 for (int i = 0; i < parts.Length; i++) 4144 for (int i = 0; i < parts.Length; i++)
3273 retmass += parts[i].GetMass(); 4145 retmass += parts[i].GetMass();
@@ -3275,6 +4147,39 @@ namespace OpenSim.Region.Framework.Scenes
3275 return retmass; 4147 return retmass;
3276 } 4148 }
3277 4149
4150 // center of mass of full object
4151 public Vector3 GetCenterOfMass()
4152 {
4153 PhysicsActor pa = RootPart.PhysActor;
4154
4155 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4156 {
4157 // physics knows better about center of mass of physical prims
4158 Vector3 tmp = pa.CenterOfMass;
4159 return tmp;
4160 }
4161
4162 Vector3 Ptot = Vector3.Zero;
4163 float totmass = 0f;
4164 float m;
4165
4166 SceneObjectPart[] parts = m_parts.GetArray();
4167 for (int i = 0; i < parts.Length; i++)
4168 {
4169 m = parts[i].GetMass();
4170 Ptot += parts[i].GetPartCenterOfMass() * m;
4171 totmass += m;
4172 }
4173
4174 if (totmass == 0)
4175 totmass = 0;
4176 else
4177 totmass = 1 / totmass;
4178 Ptot *= totmass;
4179
4180 return Ptot;
4181 }
4182
3278 /// <summary> 4183 /// <summary>
3279 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4184 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3280 /// the physics engine can use it. 4185 /// the physics engine can use it.
@@ -3428,6 +4333,14 @@ namespace OpenSim.Region.Framework.Scenes
3428 FromItemID = uuid; 4333 FromItemID = uuid;
3429 } 4334 }
3430 4335
4336 public void ResetOwnerChangeFlag()
4337 {
4338 ForEachPart(delegate(SceneObjectPart part)
4339 {
4340 part.ResetOwnerChangeFlag();
4341 });
4342 }
4343
3431 #endregion 4344 #endregion
3432 } 4345 }
3433} 4346}