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.cs1353
1 files changed, 1131 insertions, 222 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 619296e..5aeee52 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 {
@@ -1205,13 +1824,14 @@ namespace OpenSim.Region.Framework.Scenes
1205 part.ClearUpdateSchedule(); 1824 part.ClearUpdateSchedule();
1206 if (part == m_rootPart) 1825 if (part == m_rootPart)
1207 { 1826 {
1208 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || 1827 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) ||
1209 (AttachmentPoint < 31) || (AttachmentPoint > 38)) 1828 (AttachmentPoint < 31) || (AttachmentPoint > 38))
1210 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1829 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId });
1211 } 1830 }
1212 } 1831 }
1213 }); 1832 });
1214 } 1833 }
1834
1215 } 1835 }
1216 1836
1217 public void AddScriptLPS(int count) 1837 public void AddScriptLPS(int count)
@@ -1281,28 +1901,43 @@ namespace OpenSim.Region.Framework.Scenes
1281 /// </summary> 1901 /// </summary>
1282 public void ApplyPhysics() 1902 public void ApplyPhysics()
1283 { 1903 {
1284 // Apply physics to the root prim
1285 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1286
1287 // Apply physics to child prims
1288 SceneObjectPart[] parts = m_parts.GetArray(); 1904 SceneObjectPart[] parts = m_parts.GetArray();
1289 if (parts.Length > 1) 1905 if (parts.Length > 1)
1290 { 1906 {
1907 ResetChildPrimPhysicsPositions();
1908
1909 // Apply physics to the root prim
1910 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1911
1912
1291 for (int i = 0; i < parts.Length; i++) 1913 for (int i = 0; i < parts.Length; i++)
1292 { 1914 {
1293 SceneObjectPart part = parts[i]; 1915 SceneObjectPart part = parts[i];
1294 if (part.LocalId != m_rootPart.LocalId) 1916 if (part.LocalId != m_rootPart.LocalId)
1295 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1917 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1296 } 1918 }
1297
1298 // Hack to get the physics scene geometries in the right spot 1919 // Hack to get the physics scene geometries in the right spot
1299 ResetChildPrimPhysicsPositions(); 1920// ResetChildPrimPhysicsPositions();
1921 if (m_rootPart.PhysActor != null)
1922 {
1923 m_rootPart.PhysActor.Building = false;
1924 }
1925 }
1926 else
1927 {
1928 // Apply physics to the root prim
1929 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1300 } 1930 }
1301 } 1931 }
1302 1932
1303 public void SetOwnerId(UUID userId) 1933 public void SetOwnerId(UUID userId)
1304 { 1934 {
1305 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1935 ForEachPart(delegate(SceneObjectPart part)
1936 {
1937
1938 part.OwnerID = userId;
1939
1940 });
1306 } 1941 }
1307 1942
1308 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1943 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1334,11 +1969,17 @@ namespace OpenSim.Region.Framework.Scenes
1334 return; 1969 return;
1335 } 1970 }
1336 1971
1972 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1973 return;
1974
1337 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1975 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1338 // any exception propogate upwards. 1976 // any exception propogate upwards.
1339 try 1977 try
1340 { 1978 {
1341 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1979 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1980 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1981 m_scene.LoadingPrims) // Land may not be valid yet
1982
1342 { 1983 {
1343 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1984 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1344 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1985 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1365,6 +2006,7 @@ namespace OpenSim.Region.Framework.Scenes
1365 } 2006 }
1366 } 2007 }
1367 } 2008 }
2009
1368 } 2010 }
1369 2011
1370 if (m_scene.UseBackup && HasGroupChanged) 2012 if (m_scene.UseBackup && HasGroupChanged)
@@ -1372,10 +2014,30 @@ namespace OpenSim.Region.Framework.Scenes
1372 // don't backup while it's selected or you're asking for changes mid stream. 2014 // don't backup while it's selected or you're asking for changes mid stream.
1373 if (isTimeToPersist() || forcedBackup) 2015 if (isTimeToPersist() || forcedBackup)
1374 { 2016 {
2017 if (m_rootPart.PhysActor != null &&
2018 (!m_rootPart.PhysActor.IsPhysical))
2019 {
2020 // Possible ghost prim
2021 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2022 {
2023 foreach (SceneObjectPart part in m_parts.GetArray())
2024 {
2025 // Re-set physics actor positions and
2026 // orientations
2027 part.GroupPosition = m_rootPart.GroupPosition;
2028 }
2029 }
2030 }
1375// m_log.DebugFormat( 2031// m_log.DebugFormat(
1376// "[SCENE]: Storing {0}, {1} in {2}", 2032// "[SCENE]: Storing {0}, {1} in {2}",
1377// Name, UUID, m_scene.RegionInfo.RegionName); 2033// Name, UUID, m_scene.RegionInfo.RegionName);
1378 2034
2035 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2036 {
2037 RootPart.Shape.State = 0;
2038 ScheduleGroupForFullUpdate();
2039 }
2040
1379 SceneObjectGroup backup_group = Copy(false); 2041 SceneObjectGroup backup_group = Copy(false);
1380 backup_group.RootPart.Velocity = RootPart.Velocity; 2042 backup_group.RootPart.Velocity = RootPart.Velocity;
1381 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2043 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1389,6 +2051,11 @@ namespace OpenSim.Region.Framework.Scenes
1389 2051
1390 backup_group.ForEachPart(delegate(SceneObjectPart part) 2052 backup_group.ForEachPart(delegate(SceneObjectPart part)
1391 { 2053 {
2054 if (part.KeyframeMotion != null)
2055 {
2056 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2057 part.KeyframeMotion.UpdateSceneObject(this);
2058 }
1392 part.Inventory.ProcessInventoryBackup(datastore); 2059 part.Inventory.ProcessInventoryBackup(datastore);
1393 }); 2060 });
1394 2061
@@ -1441,10 +2108,14 @@ namespace OpenSim.Region.Framework.Scenes
1441 /// <returns></returns> 2108 /// <returns></returns>
1442 public SceneObjectGroup Copy(bool userExposed) 2109 public SceneObjectGroup Copy(bool userExposed)
1443 { 2110 {
2111 m_dupeInProgress = true;
1444 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2112 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1445 dupe.m_isBackedUp = false; 2113 dupe.m_isBackedUp = false;
1446 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2114 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1447 2115
2116 // new group as no sitting avatars
2117 dupe.m_linkedAvatars = new List<ScenePresence>();
2118
1448 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2119 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1449 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2120 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1450 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2121 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1455,7 +2126,7 @@ namespace OpenSim.Region.Framework.Scenes
1455 // This is only necessary when userExposed is false! 2126 // This is only necessary when userExposed is false!
1456 2127
1457 bool previousAttachmentStatus = dupe.IsAttachment; 2128 bool previousAttachmentStatus = dupe.IsAttachment;
1458 2129
1459 if (!userExposed) 2130 if (!userExposed)
1460 dupe.IsAttachment = true; 2131 dupe.IsAttachment = true;
1461 2132
@@ -1473,11 +2144,11 @@ namespace OpenSim.Region.Framework.Scenes
1473 dupe.m_rootPart.TrimPermissions(); 2144 dupe.m_rootPart.TrimPermissions();
1474 2145
1475 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2146 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1476 2147
1477 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2148 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1478 { 2149 {
1479 return p1.LinkNum.CompareTo(p2.LinkNum); 2150 return p1.LinkNum.CompareTo(p2.LinkNum);
1480 } 2151 }
1481 ); 2152 );
1482 2153
1483 foreach (SceneObjectPart part in partList) 2154 foreach (SceneObjectPart part in partList)
@@ -1487,41 +2158,53 @@ namespace OpenSim.Region.Framework.Scenes
1487 { 2158 {
1488 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2159 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1489 newPart.LinkNum = part.LinkNum; 2160 newPart.LinkNum = part.LinkNum;
1490 } 2161 if (userExposed)
2162 newPart.ParentID = dupe.m_rootPart.LocalId;
2163 }
1491 else 2164 else
1492 { 2165 {
1493 newPart = dupe.m_rootPart; 2166 newPart = dupe.m_rootPart;
1494 } 2167 }
2168/*
2169 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2170 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1495 2171
1496 // Need to duplicate the physics actor as well 2172 // Need to duplicate the physics actor as well
1497 PhysicsActor originalPartPa = part.PhysActor; 2173 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1498 if (originalPartPa != null && userExposed)
1499 { 2174 {
1500 PrimitiveBaseShape pbs = newPart.Shape; 2175 PrimitiveBaseShape pbs = newPart.Shape;
1501
1502 newPart.PhysActor 2176 newPart.PhysActor
1503 = m_scene.PhysicsScene.AddPrimShape( 2177 = m_scene.PhysicsScene.AddPrimShape(
1504 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2178 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1505 pbs, 2179 pbs,
1506 newPart.AbsolutePosition, 2180 newPart.AbsolutePosition,
1507 newPart.Scale, 2181 newPart.Scale,
1508 newPart.RotationOffset, 2182 newPart.GetWorldRotation(),
1509 originalPartPa.IsPhysical, 2183 isphys,
2184 isphan,
1510 newPart.LocalId); 2185 newPart.LocalId);
1511 2186
1512 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2187 newPart.DoPhysicsPropertyUpdate(isphys, true);
1513 } 2188 */
2189 if (userExposed)
2190 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2191// }
1514 } 2192 }
1515 2193
1516 if (userExposed) 2194 if (userExposed)
1517 { 2195 {
1518 dupe.UpdateParentIDs(); 2196// done above dupe.UpdateParentIDs();
2197
2198 if (dupe.m_rootPart.PhysActor != null)
2199 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2200
1519 dupe.HasGroupChanged = true; 2201 dupe.HasGroupChanged = true;
1520 dupe.AttachToBackup(); 2202 dupe.AttachToBackup();
1521 2203
1522 ScheduleGroupForFullUpdate(); 2204 ScheduleGroupForFullUpdate();
1523 } 2205 }
1524 2206
2207 m_dupeInProgress = false;
1525 return dupe; 2208 return dupe;
1526 } 2209 }
1527 2210
@@ -1533,11 +2216,24 @@ namespace OpenSim.Region.Framework.Scenes
1533 /// <param name="cGroupID"></param> 2216 /// <param name="cGroupID"></param>
1534 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2217 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1535 { 2218 {
1536 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2219 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2220 // give newpart a new local ID lettng old part keep same
2221 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2222 newpart.LocalId = m_scene.AllocateLocalId();
2223
2224 SetRootPart(newpart);
2225 if (userExposed)
2226 RootPart.Velocity = Vector3.Zero; // In case source is moving
1537 } 2227 }
1538 2228
1539 public void ScriptSetPhysicsStatus(bool usePhysics) 2229 public void ScriptSetPhysicsStatus(bool usePhysics)
1540 { 2230 {
2231 if (usePhysics)
2232 {
2233 if (RootPart.KeyframeMotion != null)
2234 RootPart.KeyframeMotion.Stop();
2235 RootPart.KeyframeMotion = null;
2236 }
1541 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2237 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1542 } 2238 }
1543 2239
@@ -1585,13 +2281,14 @@ namespace OpenSim.Region.Framework.Scenes
1585 2281
1586 if (pa != null) 2282 if (pa != null)
1587 { 2283 {
1588 pa.AddForce(impulse, true); 2284 // false to be applied as a impulse
2285 pa.AddForce(impulse, false);
1589 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2286 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1590 } 2287 }
1591 } 2288 }
1592 } 2289 }
1593 2290
1594 public void applyAngularImpulse(Vector3 impulse) 2291 public void ApplyAngularImpulse(Vector3 impulse)
1595 { 2292 {
1596 PhysicsActor pa = RootPart.PhysActor; 2293 PhysicsActor pa = RootPart.PhysActor;
1597 2294
@@ -1599,21 +2296,8 @@ namespace OpenSim.Region.Framework.Scenes
1599 { 2296 {
1600 if (!IsAttachment) 2297 if (!IsAttachment)
1601 { 2298 {
1602 pa.AddAngularForce(impulse, true); 2299 // false to be applied as a impulse
1603 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2300 pa.AddAngularForce(impulse, false);
1604 }
1605 }
1606 }
1607
1608 public void setAngularImpulse(Vector3 impulse)
1609 {
1610 PhysicsActor pa = RootPart.PhysActor;
1611
1612 if (pa != null)
1613 {
1614 if (!IsAttachment)
1615 {
1616 pa.Torque = impulse;
1617 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2301 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1618 } 2302 }
1619 } 2303 }
@@ -1621,20 +2305,10 @@ namespace OpenSim.Region.Framework.Scenes
1621 2305
1622 public Vector3 GetTorque() 2306 public Vector3 GetTorque()
1623 { 2307 {
1624 PhysicsActor pa = RootPart.PhysActor; 2308 return RootPart.Torque;
1625
1626 if (pa != null)
1627 {
1628 if (!IsAttachment)
1629 {
1630 Vector3 torque = pa.Torque;
1631 return torque;
1632 }
1633 }
1634
1635 return Vector3.Zero;
1636 } 2309 }
1637 2310
2311 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1638 public void moveToTarget(Vector3 target, float tau) 2312 public void moveToTarget(Vector3 target, float tau)
1639 { 2313 {
1640 if (IsAttachment) 2314 if (IsAttachment)
@@ -1666,6 +2340,46 @@ namespace OpenSim.Region.Framework.Scenes
1666 pa.PIDActive = false; 2340 pa.PIDActive = false;
1667 } 2341 }
1668 2342
2343 public void rotLookAt(Quaternion target, float strength, float damping)
2344 {
2345 SceneObjectPart rootpart = m_rootPart;
2346 if (rootpart != null)
2347 {
2348 if (IsAttachment)
2349 {
2350 /*
2351 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2352 if (avatar != null)
2353 {
2354 Rotate the Av?
2355 } */
2356 }
2357 else
2358 {
2359 if (rootpart.PhysActor != null)
2360 { // APID must be implemented in your physics system for this to function.
2361 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2362 rootpart.PhysActor.APIDStrength = strength;
2363 rootpart.PhysActor.APIDDamping = damping;
2364 rootpart.PhysActor.APIDActive = true;
2365 }
2366 }
2367 }
2368 }
2369
2370 public void stopLookAt()
2371 {
2372 SceneObjectPart rootpart = m_rootPart;
2373 if (rootpart != null)
2374 {
2375 if (rootpart.PhysActor != null)
2376 { // APID must be implemented in your physics system for this to function.
2377 rootpart.PhysActor.APIDActive = false;
2378 }
2379 }
2380
2381 }
2382
1669 /// <summary> 2383 /// <summary>
1670 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2384 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1671 /// </summary> 2385 /// </summary>
@@ -1682,7 +2396,7 @@ namespace OpenSim.Region.Framework.Scenes
1682 { 2396 {
1683 pa.PIDHoverHeight = height; 2397 pa.PIDHoverHeight = height;
1684 pa.PIDHoverType = hoverType; 2398 pa.PIDHoverType = hoverType;
1685 pa.PIDTau = tau; 2399 pa.PIDHoverTau = tau;
1686 pa.PIDHoverActive = true; 2400 pa.PIDHoverActive = true;
1687 } 2401 }
1688 else 2402 else
@@ -1722,7 +2436,12 @@ namespace OpenSim.Region.Framework.Scenes
1722 /// <param name="cGroupID"></param> 2436 /// <param name="cGroupID"></param>
1723 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2437 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1724 { 2438 {
1725 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2439 // give new ID to the new part, letting old keep original
2440 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2441 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2442 newPart.LocalId = m_scene.AllocateLocalId();
2443 newPart.SetParent(this);
2444
1726 AddPart(newPart); 2445 AddPart(newPart);
1727 2446
1728 SetPartAsNonRoot(newPart); 2447 SetPartAsNonRoot(newPart);
@@ -1851,11 +2570,11 @@ namespace OpenSim.Region.Framework.Scenes
1851 /// Immediately send a full update for this scene object. 2570 /// Immediately send a full update for this scene object.
1852 /// </summary> 2571 /// </summary>
1853 public void SendGroupFullUpdate() 2572 public void SendGroupFullUpdate()
1854 { 2573 {
1855 if (IsDeleted) 2574 if (IsDeleted)
1856 return; 2575 return;
1857 2576
1858// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2577// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1859 2578
1860 RootPart.SendFullUpdateToAllClients(); 2579 RootPart.SendFullUpdateToAllClients();
1861 2580
@@ -1989,6 +2708,11 @@ namespace OpenSim.Region.Framework.Scenes
1989 2708
1990 SceneObjectPart linkPart = objectGroup.m_rootPart; 2709 SceneObjectPart linkPart = objectGroup.m_rootPart;
1991 2710
2711 if (m_rootPart.PhysActor != null)
2712 m_rootPart.PhysActor.Building = true;
2713 if (linkPart.PhysActor != null)
2714 linkPart.PhysActor.Building = true;
2715
1992 // physics flags from group to be applied to linked parts 2716 // physics flags from group to be applied to linked parts
1993 bool grpusephys = UsesPhysics; 2717 bool grpusephys = UsesPhysics;
1994 bool grptemporary = IsTemporary; 2718 bool grptemporary = IsTemporary;
@@ -1997,19 +2721,21 @@ namespace OpenSim.Region.Framework.Scenes
1997 Quaternion oldRootRotation = linkPart.RotationOffset; 2721 Quaternion oldRootRotation = linkPart.RotationOffset;
1998 2722
1999 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2723 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2724
2000 linkPart.ParentID = m_rootPart.LocalId; 2725 linkPart.ParentID = m_rootPart.LocalId;
2001 linkPart.GroupPosition = AbsolutePosition; 2726
2002 Vector3 axPos = linkPart.OffsetPosition; 2727 linkPart.GroupPosition = AbsolutePosition;
2003 2728
2729 Vector3 axPos = linkPart.OffsetPosition;
2004 Quaternion parentRot = m_rootPart.RotationOffset; 2730 Quaternion parentRot = m_rootPart.RotationOffset;
2005 axPos *= Quaternion.Inverse(parentRot); 2731 axPos *= Quaternion.Conjugate(parentRot);
2006
2007 linkPart.OffsetPosition = axPos; 2732 linkPart.OffsetPosition = axPos;
2733
2008 Quaternion oldRot = linkPart.RotationOffset; 2734 Quaternion oldRot = linkPart.RotationOffset;
2009 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2735 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2010 linkPart.RotationOffset = newRot; 2736 linkPart.RotationOffset = newRot;
2011 2737
2012 linkPart.ParentID = m_rootPart.LocalId; 2738// linkPart.ParentID = m_rootPart.LocalId; done above
2013 2739
2014 if (m_rootPart.LinkNum == 0) 2740 if (m_rootPart.LinkNum == 0)
2015 m_rootPart.LinkNum = 1; 2741 m_rootPart.LinkNum = 1;
@@ -2037,7 +2763,7 @@ namespace OpenSim.Region.Framework.Scenes
2037 linkPart.CreateSelected = true; 2763 linkPart.CreateSelected = true;
2038 2764
2039 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2765 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2040 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2766 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2041 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2767 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2042 { 2768 {
2043 linkPart.PhysActor.link(m_rootPart.PhysActor); 2769 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2045,6 +2771,7 @@ namespace OpenSim.Region.Framework.Scenes
2045 } 2771 }
2046 2772
2047 linkPart.LinkNum = linkNum++; 2773 linkPart.LinkNum = linkNum++;
2774 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2048 2775
2049 SceneObjectPart[] ogParts = objectGroup.Parts; 2776 SceneObjectPart[] ogParts = objectGroup.Parts;
2050 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2777 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2059,7 +2786,7 @@ namespace OpenSim.Region.Framework.Scenes
2059 { 2786 {
2060 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2787 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2061 // let physics know 2788 // let physics know
2062 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2789 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2063 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2790 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2064 { 2791 {
2065 part.PhysActor.link(m_rootPart.PhysActor); 2792 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2074,7 +2801,7 @@ namespace OpenSim.Region.Framework.Scenes
2074 objectGroup.IsDeleted = true; 2801 objectGroup.IsDeleted = true;
2075 2802
2076 objectGroup.m_parts.Clear(); 2803 objectGroup.m_parts.Clear();
2077 2804
2078 // Can't do this yet since backup still makes use of the root part without any synchronization 2805 // Can't do this yet since backup still makes use of the root part without any synchronization
2079// objectGroup.m_rootPart = null; 2806// objectGroup.m_rootPart = null;
2080 2807
@@ -2085,6 +2812,9 @@ namespace OpenSim.Region.Framework.Scenes
2085 // unmoved prims! 2812 // unmoved prims!
2086 ResetChildPrimPhysicsPositions(); 2813 ResetChildPrimPhysicsPositions();
2087 2814
2815 if (m_rootPart.PhysActor != null)
2816 m_rootPart.PhysActor.Building = false;
2817
2088 //HasGroupChanged = true; 2818 //HasGroupChanged = true;
2089 //ScheduleGroupForFullUpdate(); 2819 //ScheduleGroupForFullUpdate();
2090 } 2820 }
@@ -2152,7 +2882,10 @@ namespace OpenSim.Region.Framework.Scenes
2152// m_log.DebugFormat( 2882// m_log.DebugFormat(
2153// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2883// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2154// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2884// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2155 2885
2886 if (m_rootPart.PhysActor != null)
2887 m_rootPart.PhysActor.Building = true;
2888
2156 linkPart.ClearUndoState(); 2889 linkPart.ClearUndoState();
2157 2890
2158 Quaternion worldRot = linkPart.GetWorldRotation(); 2891 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2212,6 +2945,14 @@ namespace OpenSim.Region.Framework.Scenes
2212 2945
2213 // When we delete a group, we currently have to force persist to the database if the object id has changed 2946 // When we delete a group, we currently have to force persist to the database if the object id has changed
2214 // (since delete works by deleting all rows which have a given object id) 2947 // (since delete works by deleting all rows which have a given object id)
2948
2949 // this is as it seems to be in sl now
2950 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2951 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2952
2953 if (m_rootPart.PhysActor != null)
2954 m_rootPart.PhysActor.Building = false;
2955
2215 objectGroup.HasGroupChangedDueToDelink = true; 2956 objectGroup.HasGroupChangedDueToDelink = true;
2216 2957
2217 return objectGroup; 2958 return objectGroup;
@@ -2223,6 +2964,7 @@ namespace OpenSim.Region.Framework.Scenes
2223 /// <param name="objectGroup"></param> 2964 /// <param name="objectGroup"></param>
2224 public virtual void DetachFromBackup() 2965 public virtual void DetachFromBackup()
2225 { 2966 {
2967 m_scene.SceneGraph.FireDetachFromBackup(this);
2226 if (m_isBackedUp && Scene != null) 2968 if (m_isBackedUp && Scene != null)
2227 m_scene.EventManager.OnBackup -= ProcessBackup; 2969 m_scene.EventManager.OnBackup -= ProcessBackup;
2228 2970
@@ -2241,7 +2983,8 @@ namespace OpenSim.Region.Framework.Scenes
2241 2983
2242 axPos *= parentRot; 2984 axPos *= parentRot;
2243 part.OffsetPosition = axPos; 2985 part.OffsetPosition = axPos;
2244 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2986 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2987 part.GroupPosition = newPos;
2245 part.OffsetPosition = Vector3.Zero; 2988 part.OffsetPosition = Vector3.Zero;
2246 part.RotationOffset = worldRot; 2989 part.RotationOffset = worldRot;
2247 2990
@@ -2252,20 +2995,20 @@ namespace OpenSim.Region.Framework.Scenes
2252 2995
2253 part.LinkNum = linkNum; 2996 part.LinkNum = linkNum;
2254 2997
2255 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2998 part.OffsetPosition = newPos - AbsolutePosition;
2256 2999
2257 Quaternion rootRotation = m_rootPart.RotationOffset; 3000 Quaternion rootRotation = m_rootPart.RotationOffset;
2258 3001
2259 Vector3 pos = part.OffsetPosition; 3002 Vector3 pos = part.OffsetPosition;
2260 pos *= Quaternion.Inverse(rootRotation); 3003 pos *= Quaternion.Conjugate(rootRotation);
2261 part.OffsetPosition = pos; 3004 part.OffsetPosition = pos;
2262 3005
2263 parentRot = m_rootPart.RotationOffset; 3006 parentRot = m_rootPart.RotationOffset;
2264 oldRot = part.RotationOffset; 3007 oldRot = part.RotationOffset;
2265 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3008 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2266 part.RotationOffset = newRot; 3009 part.RotationOffset = newRot;
2267 3010
2268 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3011 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2269 } 3012 }
2270 3013
2271 /// <summary> 3014 /// <summary>
@@ -2516,8 +3259,22 @@ namespace OpenSim.Region.Framework.Scenes
2516 } 3259 }
2517 } 3260 }
2518 3261
2519 for (int i = 0; i < parts.Length; i++) 3262 if (parts.Length > 1)
2520 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3263 {
3264 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3265
3266 for (int i = 0; i < parts.Length; i++)
3267 {
3268
3269 if (parts[i].UUID != m_rootPart.UUID)
3270 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3271 }
3272
3273 if (m_rootPart.PhysActor != null)
3274 m_rootPart.PhysActor.Building = false;
3275 }
3276 else
3277 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2521 } 3278 }
2522 } 3279 }
2523 3280
@@ -2530,6 +3287,17 @@ namespace OpenSim.Region.Framework.Scenes
2530 } 3287 }
2531 } 3288 }
2532 3289
3290
3291
3292 /// <summary>
3293 /// Gets the number of parts
3294 /// </summary>
3295 /// <returns></returns>
3296 public int GetPartCount()
3297 {
3298 return Parts.Count();
3299 }
3300
2533 /// <summary> 3301 /// <summary>
2534 /// Update the texture entry for this part 3302 /// Update the texture entry for this part
2535 /// </summary> 3303 /// </summary>
@@ -2591,11 +3359,6 @@ namespace OpenSim.Region.Framework.Scenes
2591 /// <param name="scale"></param> 3359 /// <param name="scale"></param>
2592 public void GroupResize(Vector3 scale) 3360 public void GroupResize(Vector3 scale)
2593 { 3361 {
2594// m_log.DebugFormat(
2595// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2596
2597 RootPart.StoreUndoState(true);
2598
2599 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3362 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2600 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3363 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2601 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3364 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2622,7 +3385,6 @@ namespace OpenSim.Region.Framework.Scenes
2622 SceneObjectPart obPart = parts[i]; 3385 SceneObjectPart obPart = parts[i];
2623 if (obPart.UUID != m_rootPart.UUID) 3386 if (obPart.UUID != m_rootPart.UUID)
2624 { 3387 {
2625// obPart.IgnoreUndoUpdate = true;
2626 Vector3 oldSize = new Vector3(obPart.Scale); 3388 Vector3 oldSize = new Vector3(obPart.Scale);
2627 3389
2628 float f = 1.0f; 3390 float f = 1.0f;
@@ -2686,8 +3448,6 @@ namespace OpenSim.Region.Framework.Scenes
2686 z *= a; 3448 z *= a;
2687 } 3449 }
2688 } 3450 }
2689
2690// obPart.IgnoreUndoUpdate = false;
2691 } 3451 }
2692 } 3452 }
2693 } 3453 }
@@ -2697,9 +3457,7 @@ namespace OpenSim.Region.Framework.Scenes
2697 prevScale.Y *= y; 3457 prevScale.Y *= y;
2698 prevScale.Z *= z; 3458 prevScale.Z *= z;
2699 3459
2700// RootPart.IgnoreUndoUpdate = true;
2701 RootPart.Resize(prevScale); 3460 RootPart.Resize(prevScale);
2702// RootPart.IgnoreUndoUpdate = false;
2703 3461
2704 parts = m_parts.GetArray(); 3462 parts = m_parts.GetArray();
2705 for (int i = 0; i < parts.Length; i++) 3463 for (int i = 0; i < parts.Length; i++)
@@ -2708,8 +3466,6 @@ namespace OpenSim.Region.Framework.Scenes
2708 3466
2709 if (obPart.UUID != m_rootPart.UUID) 3467 if (obPart.UUID != m_rootPart.UUID)
2710 { 3468 {
2711 obPart.IgnoreUndoUpdate = true;
2712
2713 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3469 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2714 currentpos.X *= x; 3470 currentpos.X *= x;
2715 currentpos.Y *= y; 3471 currentpos.Y *= y;
@@ -2722,16 +3478,12 @@ namespace OpenSim.Region.Framework.Scenes
2722 3478
2723 obPart.Resize(newSize); 3479 obPart.Resize(newSize);
2724 obPart.UpdateOffSet(currentpos); 3480 obPart.UpdateOffSet(currentpos);
2725
2726 obPart.IgnoreUndoUpdate = false;
2727 } 3481 }
2728 3482
2729// obPart.IgnoreUndoUpdate = false; 3483 HasGroupChanged = true;
2730// obPart.StoreUndoState(); 3484 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3485 ScheduleGroupForTerseUpdate();
2731 } 3486 }
2732
2733// m_log.DebugFormat(
2734// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2735 } 3487 }
2736 3488
2737 #endregion 3489 #endregion
@@ -2744,14 +3496,6 @@ namespace OpenSim.Region.Framework.Scenes
2744 /// <param name="pos"></param> 3496 /// <param name="pos"></param>
2745 public void UpdateGroupPosition(Vector3 pos) 3497 public void UpdateGroupPosition(Vector3 pos)
2746 { 3498 {
2747// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2748
2749 RootPart.StoreUndoState(true);
2750
2751// SceneObjectPart[] parts = m_parts.GetArray();
2752// for (int i = 0; i < parts.Length; i++)
2753// parts[i].StoreUndoState();
2754
2755 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3499 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2756 { 3500 {
2757 if (IsAttachment) 3501 if (IsAttachment)
@@ -2784,21 +3528,17 @@ namespace OpenSim.Region.Framework.Scenes
2784 /// </summary> 3528 /// </summary>
2785 /// <param name="pos"></param> 3529 /// <param name="pos"></param>
2786 /// <param name="localID"></param> 3530 /// <param name="localID"></param>
3531 ///
3532
2787 public void UpdateSinglePosition(Vector3 pos, uint localID) 3533 public void UpdateSinglePosition(Vector3 pos, uint localID)
2788 { 3534 {
2789 SceneObjectPart part = GetPart(localID); 3535 SceneObjectPart part = GetPart(localID);
2790 3536
2791// SceneObjectPart[] parts = m_parts.GetArray();
2792// for (int i = 0; i < parts.Length; i++)
2793// parts[i].StoreUndoState();
2794
2795 if (part != null) 3537 if (part != null)
2796 { 3538 {
2797// m_log.DebugFormat( 3539// unlock parts position change
2798// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3540 if (m_rootPart.PhysActor != null)
2799 3541 m_rootPart.PhysActor.Building = true;
2800 part.StoreUndoState(false);
2801 part.IgnoreUndoUpdate = true;
2802 3542
2803 if (part.UUID == m_rootPart.UUID) 3543 if (part.UUID == m_rootPart.UUID)
2804 { 3544 {
@@ -2809,8 +3549,10 @@ namespace OpenSim.Region.Framework.Scenes
2809 part.UpdateOffSet(pos); 3549 part.UpdateOffSet(pos);
2810 } 3550 }
2811 3551
3552 if (m_rootPart.PhysActor != null)
3553 m_rootPart.PhysActor.Building = false;
3554
2812 HasGroupChanged = true; 3555 HasGroupChanged = true;
2813 part.IgnoreUndoUpdate = false;
2814 } 3556 }
2815 } 3557 }
2816 3558
@@ -2820,13 +3562,7 @@ namespace OpenSim.Region.Framework.Scenes
2820 /// <param name="pos"></param> 3562 /// <param name="pos"></param>
2821 public void UpdateRootPosition(Vector3 pos) 3563 public void UpdateRootPosition(Vector3 pos)
2822 { 3564 {
2823// m_log.DebugFormat( 3565 // needs to be called with phys building true
2824// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2825
2826// SceneObjectPart[] parts = m_parts.GetArray();
2827// for (int i = 0; i < parts.Length; i++)
2828// parts[i].StoreUndoState();
2829
2830 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3566 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2831 Vector3 oldPos = 3567 Vector3 oldPos =
2832 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3568 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2849,7 +3585,14 @@ namespace OpenSim.Region.Framework.Scenes
2849 AbsolutePosition = newPos; 3585 AbsolutePosition = newPos;
2850 3586
2851 HasGroupChanged = true; 3587 HasGroupChanged = true;
2852 ScheduleGroupForTerseUpdate(); 3588 if (m_rootPart.Undoing)
3589 {
3590 ScheduleGroupForFullUpdate();
3591 }
3592 else
3593 {
3594 ScheduleGroupForTerseUpdate();
3595 }
2853 } 3596 }
2854 3597
2855 #endregion 3598 #endregion
@@ -2862,24 +3605,16 @@ namespace OpenSim.Region.Framework.Scenes
2862 /// <param name="rot"></param> 3605 /// <param name="rot"></param>
2863 public void UpdateGroupRotationR(Quaternion rot) 3606 public void UpdateGroupRotationR(Quaternion rot)
2864 { 3607 {
2865// m_log.DebugFormat(
2866// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2867
2868// SceneObjectPart[] parts = m_parts.GetArray();
2869// for (int i = 0; i < parts.Length; i++)
2870// parts[i].StoreUndoState();
2871
2872 m_rootPart.StoreUndoState(true);
2873
2874 m_rootPart.UpdateRotation(rot); 3608 m_rootPart.UpdateRotation(rot);
2875 3609
3610/* this is done by rootpart RotationOffset set called by UpdateRotation
2876 PhysicsActor actor = m_rootPart.PhysActor; 3611 PhysicsActor actor = m_rootPart.PhysActor;
2877 if (actor != null) 3612 if (actor != null)
2878 { 3613 {
2879 actor.Orientation = m_rootPart.RotationOffset; 3614 actor.Orientation = m_rootPart.RotationOffset;
2880 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3615 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2881 } 3616 }
2882 3617*/
2883 HasGroupChanged = true; 3618 HasGroupChanged = true;
2884 ScheduleGroupForTerseUpdate(); 3619 ScheduleGroupForTerseUpdate();
2885 } 3620 }
@@ -2891,16 +3626,6 @@ namespace OpenSim.Region.Framework.Scenes
2891 /// <param name="rot"></param> 3626 /// <param name="rot"></param>
2892 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3627 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2893 { 3628 {
2894// m_log.DebugFormat(
2895// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2896
2897// SceneObjectPart[] parts = m_parts.GetArray();
2898// for (int i = 0; i < parts.Length; i++)
2899// parts[i].StoreUndoState();
2900
2901 RootPart.StoreUndoState(true);
2902 RootPart.IgnoreUndoUpdate = true;
2903
2904 m_rootPart.UpdateRotation(rot); 3629 m_rootPart.UpdateRotation(rot);
2905 3630
2906 PhysicsActor actor = m_rootPart.PhysActor; 3631 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2914,8 +3639,6 @@ namespace OpenSim.Region.Framework.Scenes
2914 3639
2915 HasGroupChanged = true; 3640 HasGroupChanged = true;
2916 ScheduleGroupForTerseUpdate(); 3641 ScheduleGroupForTerseUpdate();
2917
2918 RootPart.IgnoreUndoUpdate = false;
2919 } 3642 }
2920 3643
2921 /// <summary> 3644 /// <summary>
@@ -2928,13 +3651,11 @@ namespace OpenSim.Region.Framework.Scenes
2928 SceneObjectPart part = GetPart(localID); 3651 SceneObjectPart part = GetPart(localID);
2929 3652
2930 SceneObjectPart[] parts = m_parts.GetArray(); 3653 SceneObjectPart[] parts = m_parts.GetArray();
2931 for (int i = 0; i < parts.Length; i++)
2932 parts[i].StoreUndoState();
2933 3654
2934 if (part != null) 3655 if (part != null)
2935 { 3656 {
2936// m_log.DebugFormat( 3657 if (m_rootPart.PhysActor != null)
2937// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3658 m_rootPart.PhysActor.Building = true;
2938 3659
2939 if (part.UUID == m_rootPart.UUID) 3660 if (part.UUID == m_rootPart.UUID)
2940 { 3661 {
@@ -2944,6 +3665,9 @@ namespace OpenSim.Region.Framework.Scenes
2944 { 3665 {
2945 part.UpdateRotation(rot); 3666 part.UpdateRotation(rot);
2946 } 3667 }
3668
3669 if (m_rootPart.PhysActor != null)
3670 m_rootPart.PhysActor.Building = false;
2947 } 3671 }
2948 } 3672 }
2949 3673
@@ -2957,12 +3681,8 @@ namespace OpenSim.Region.Framework.Scenes
2957 SceneObjectPart part = GetPart(localID); 3681 SceneObjectPart part = GetPart(localID);
2958 if (part != null) 3682 if (part != null)
2959 { 3683 {
2960// m_log.DebugFormat( 3684 if (m_rootPart.PhysActor != null)
2961// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3685 m_rootPart.PhysActor.Building = true;
2962// part.Name, part.LocalId, rot);
2963
2964 part.StoreUndoState();
2965 part.IgnoreUndoUpdate = true;
2966 3686
2967 if (part.UUID == m_rootPart.UUID) 3687 if (part.UUID == m_rootPart.UUID)
2968 { 3688 {
@@ -2975,7 +3695,8 @@ namespace OpenSim.Region.Framework.Scenes
2975 part.OffsetPosition = pos; 3695 part.OffsetPosition = pos;
2976 } 3696 }
2977 3697
2978 part.IgnoreUndoUpdate = false; 3698 if (m_rootPart.PhysActor != null)
3699 m_rootPart.PhysActor.Building = false;
2979 } 3700 }
2980 } 3701 }
2981 3702
@@ -2985,15 +3706,12 @@ namespace OpenSim.Region.Framework.Scenes
2985 /// <param name="rot"></param> 3706 /// <param name="rot"></param>
2986 public void UpdateRootRotation(Quaternion rot) 3707 public void UpdateRootRotation(Quaternion rot)
2987 { 3708 {
2988// m_log.DebugFormat( 3709 // needs to be called with phys building true
2989// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2990// Name, LocalId, rot);
2991
2992 Quaternion axRot = rot; 3710 Quaternion axRot = rot;
2993 Quaternion oldParentRot = m_rootPart.RotationOffset; 3711 Quaternion oldParentRot = m_rootPart.RotationOffset;
2994 3712
2995 m_rootPart.StoreUndoState(); 3713 //Don't use UpdateRotation because it schedules an update prematurely
2996 m_rootPart.UpdateRotation(rot); 3714 m_rootPart.RotationOffset = rot;
2997 3715
2998 PhysicsActor pa = m_rootPart.PhysActor; 3716 PhysicsActor pa = m_rootPart.PhysActor;
2999 3717
@@ -3009,35 +3727,145 @@ namespace OpenSim.Region.Framework.Scenes
3009 SceneObjectPart prim = parts[i]; 3727 SceneObjectPart prim = parts[i];
3010 if (prim.UUID != m_rootPart.UUID) 3728 if (prim.UUID != m_rootPart.UUID)
3011 { 3729 {
3012 prim.IgnoreUndoUpdate = true; 3730 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3731 NewRot = Quaternion.Inverse(axRot) * NewRot;
3732 prim.RotationOffset = NewRot;
3733
3013 Vector3 axPos = prim.OffsetPosition; 3734 Vector3 axPos = prim.OffsetPosition;
3735
3014 axPos *= oldParentRot; 3736 axPos *= oldParentRot;
3015 axPos *= Quaternion.Inverse(axRot); 3737 axPos *= Quaternion.Inverse(axRot);
3016 prim.OffsetPosition = axPos; 3738 prim.OffsetPosition = axPos;
3017 Quaternion primsRot = prim.RotationOffset; 3739 }
3018 Quaternion newRot = oldParentRot * primsRot; 3740 }
3019 newRot = Quaternion.Inverse(axRot) * newRot;
3020 prim.RotationOffset = newRot;
3021 prim.ScheduleTerseUpdate();
3022 prim.IgnoreUndoUpdate = false;
3023 }
3024 }
3025
3026// for (int i = 0; i < parts.Length; i++)
3027// {
3028// SceneObjectPart childpart = parts[i];
3029// if (childpart != m_rootPart)
3030// {
3031//// childpart.IgnoreUndoUpdate = false;
3032//// childpart.StoreUndoState();
3033// }
3034// }
3035 3741
3036 m_rootPart.ScheduleTerseUpdate(); 3742 HasGroupChanged = true;
3743 ScheduleGroupForFullUpdate();
3744 }
3037 3745
3038// m_log.DebugFormat( 3746 private enum updatetype :int
3039// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3747 {
3040// Name, LocalId, rot); 3748 none = 0,
3749 partterse = 1,
3750 partfull = 2,
3751 groupterse = 3,
3752 groupfull = 4
3753 }
3754
3755 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3756 {
3757 // TODO this still as excessive *.Schedule*Update()s
3758
3759 if (part != null && part.ParentGroup != null)
3760 {
3761 ObjectChangeType change = data.change;
3762 bool togroup = ((change & ObjectChangeType.Group) != 0);
3763 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3764
3765 SceneObjectGroup group = part.ParentGroup;
3766 PhysicsActor pha = group.RootPart.PhysActor;
3767
3768 updatetype updateType = updatetype.none;
3769
3770 if (togroup)
3771 {
3772 // related to group
3773 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3774 {
3775 if ((change & ObjectChangeType.Rotation) != 0)
3776 {
3777 group.RootPart.UpdateRotation(data.rotation);
3778 updateType = updatetype.none;
3779 }
3780 if ((change & ObjectChangeType.Position) != 0)
3781 {
3782 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3783 UpdateGroupPosition(data.position);
3784 updateType = updatetype.groupterse;
3785 }
3786 else
3787 // ugly rotation update of all parts
3788 {
3789 group.AbsolutePosition = AbsolutePosition;
3790 }
3791
3792 }
3793 if ((change & ObjectChangeType.Scale) != 0)
3794 {
3795 if (pha != null)
3796 pha.Building = true;
3797
3798 group.GroupResize(data.scale);
3799 updateType = updatetype.none;
3800
3801 if (pha != null)
3802 pha.Building = false;
3803 }
3804 }
3805 else
3806 {
3807 // related to single prim in a link-set ( ie group)
3808 if (pha != null)
3809 pha.Building = true;
3810
3811 // root part is special
3812 // parts offset positions or rotations need to change also
3813
3814 if (part == group.RootPart)
3815 {
3816 if ((change & ObjectChangeType.Rotation) != 0)
3817 group.UpdateRootRotation(data.rotation);
3818 if ((change & ObjectChangeType.Position) != 0)
3819 group.UpdateRootPosition(data.position);
3820 if ((change & ObjectChangeType.Scale) != 0)
3821 part.Resize(data.scale);
3822 }
3823 else
3824 {
3825 if ((change & ObjectChangeType.Position) != 0)
3826 {
3827 part.OffsetPosition = data.position;
3828 updateType = updatetype.partterse;
3829 }
3830 if ((change & ObjectChangeType.Rotation) != 0)
3831 {
3832 part.UpdateRotation(data.rotation);
3833 updateType = updatetype.none;
3834 }
3835 if ((change & ObjectChangeType.Scale) != 0)
3836 {
3837 part.Resize(data.scale);
3838 updateType = updatetype.none;
3839 }
3840 }
3841
3842 if (pha != null)
3843 pha.Building = false;
3844 }
3845
3846 if (updateType != updatetype.none)
3847 {
3848 group.HasGroupChanged = true;
3849
3850 switch (updateType)
3851 {
3852 case updatetype.partterse:
3853 part.ScheduleTerseUpdate();
3854 break;
3855 case updatetype.partfull:
3856 part.ScheduleFullUpdate();
3857 break;
3858 case updatetype.groupterse:
3859 group.ScheduleGroupForTerseUpdate();
3860 break;
3861 case updatetype.groupfull:
3862 group.ScheduleGroupForFullUpdate();
3863 break;
3864 default:
3865 break;
3866 }
3867 }
3868 }
3041 } 3869 }
3042 3870
3043 #endregion 3871 #endregion
@@ -3136,10 +3964,11 @@ namespace OpenSim.Region.Framework.Scenes
3136 scriptPosTarget target = m_targets[idx]; 3964 scriptPosTarget target = m_targets[idx];
3137 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 3965 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3138 { 3966 {
3967 at_target = true;
3968
3139 // trigger at_target 3969 // trigger at_target
3140 if (m_scriptListens_atTarget) 3970 if (m_scriptListens_atTarget)
3141 { 3971 {
3142 at_target = true;
3143 scriptPosTarget att = new scriptPosTarget(); 3972 scriptPosTarget att = new scriptPosTarget();
3144 att.targetPos = target.targetPos; 3973 att.targetPos = target.targetPos;
3145 att.tolerance = target.tolerance; 3974 att.tolerance = target.tolerance;
@@ -3257,11 +4086,50 @@ namespace OpenSim.Region.Framework.Scenes
3257 } 4086 }
3258 } 4087 }
3259 } 4088 }
3260 4089
4090 public Vector3 GetGeometricCenter()
4091 {
4092 // this is not real geometric center but a average of positions relative to root prim acording to
4093 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4094 // ignoring tortured prims details since sl also seems to ignore
4095 // so no real use in doing it on physics
4096
4097 Vector3 gc = Vector3.Zero;
4098
4099 int nparts = m_parts.Count;
4100 if (nparts <= 1)
4101 return gc;
4102
4103 SceneObjectPart[] parts = m_parts.GetArray();
4104 nparts = parts.Length; // just in case it changed
4105 if (nparts <= 1)
4106 return gc;
4107
4108 Quaternion parentRot = RootPart.RotationOffset;
4109 Vector3 pPos;
4110
4111 // average all parts positions
4112 for (int i = 0; i < nparts; i++)
4113 {
4114 // do it directly
4115 // gc += parts[i].GetWorldPosition();
4116 if (parts[i] != RootPart)
4117 {
4118 pPos = parts[i].OffsetPosition;
4119 gc += pPos;
4120 }
4121
4122 }
4123 gc /= nparts;
4124
4125 // relative to root:
4126// gc -= AbsolutePosition;
4127 return gc;
4128 }
4129
3261 public float GetMass() 4130 public float GetMass()
3262 { 4131 {
3263 float retmass = 0f; 4132 float retmass = 0f;
3264
3265 SceneObjectPart[] parts = m_parts.GetArray(); 4133 SceneObjectPart[] parts = m_parts.GetArray();
3266 for (int i = 0; i < parts.Length; i++) 4134 for (int i = 0; i < parts.Length; i++)
3267 retmass += parts[i].GetMass(); 4135 retmass += parts[i].GetMass();
@@ -3269,6 +4137,39 @@ namespace OpenSim.Region.Framework.Scenes
3269 return retmass; 4137 return retmass;
3270 } 4138 }
3271 4139
4140 // center of mass of full object
4141 public Vector3 GetCenterOfMass()
4142 {
4143 PhysicsActor pa = RootPart.PhysActor;
4144
4145 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4146 {
4147 // physics knows better about center of mass of physical prims
4148 Vector3 tmp = pa.CenterOfMass;
4149 return tmp;
4150 }
4151
4152 Vector3 Ptot = Vector3.Zero;
4153 float totmass = 0f;
4154 float m;
4155
4156 SceneObjectPart[] parts = m_parts.GetArray();
4157 for (int i = 0; i < parts.Length; i++)
4158 {
4159 m = parts[i].GetMass();
4160 Ptot += parts[i].GetPartCenterOfMass() * m;
4161 totmass += m;
4162 }
4163
4164 if (totmass == 0)
4165 totmass = 0;
4166 else
4167 totmass = 1 / totmass;
4168 Ptot *= totmass;
4169
4170 return Ptot;
4171 }
4172
3272 /// <summary> 4173 /// <summary>
3273 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4174 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3274 /// the physics engine can use it. 4175 /// the physics engine can use it.
@@ -3422,6 +4323,14 @@ namespace OpenSim.Region.Framework.Scenes
3422 FromItemID = uuid; 4323 FromItemID = uuid;
3423 } 4324 }
3424 4325
4326 public void ResetOwnerChangeFlag()
4327 {
4328 ForEachPart(delegate(SceneObjectPart part)
4329 {
4330 part.ResetOwnerChangeFlag();
4331 });
4332 }
4333
3425 #endregion 4334 #endregion
3426 } 4335 }
3427} 4336}