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.cs1297
1 files changed, 1080 insertions, 217 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 2686004..42b6bc5 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 }
@@ -245,10 +309,10 @@ namespace OpenSim.Region.Framework.Scenes
245 309
246 private bool m_scriptListens_atTarget; 310 private bool m_scriptListens_atTarget;
247 private bool m_scriptListens_notAtTarget; 311 private bool m_scriptListens_notAtTarget;
248
249 private bool m_scriptListens_atRotTarget; 312 private bool m_scriptListens_atRotTarget;
250 private bool m_scriptListens_notAtRotTarget; 313 private bool m_scriptListens_notAtRotTarget;
251 314
315 public bool m_dupeInProgress = false;
252 internal Dictionary<UUID, string> m_savedScriptState; 316 internal Dictionary<UUID, string> m_savedScriptState;
253 317
254 #region Properties 318 #region Properties
@@ -285,6 +349,16 @@ namespace OpenSim.Region.Framework.Scenes
285 get { return m_parts.Count; } 349 get { return m_parts.Count; }
286 } 350 }
287 351
352// protected Quaternion m_rotation = Quaternion.Identity;
353//
354// public virtual Quaternion Rotation
355// {
356// get { return m_rotation; }
357// set {
358// m_rotation = value;
359// }
360// }
361
288 public Quaternion GroupRotation 362 public Quaternion GroupRotation
289 { 363 {
290 get { return m_rootPart.RotationOffset; } 364 get { return m_rootPart.RotationOffset; }
@@ -404,14 +478,99 @@ namespace OpenSim.Region.Framework.Scenes
404 478
405 if (Scene != null) 479 if (Scene != null)
406 { 480 {
407 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 481 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
408 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 482 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
483 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
484 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
485 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
409 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 486 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
410 { 487 {
411 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 488 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
489 uint x = 0;
490 uint y = 0;
491 string version = String.Empty;
492 Vector3 newpos = Vector3.Zero;
493 OpenSim.Services.Interfaces.GridRegion destination = null;
494
495 bool canCross = true;
496 foreach (ScenePresence av in m_linkedAvatars)
497 {
498 // We need to cross these agents. First, let's find
499 // out if any of them can't cross for some reason.
500 // We have to deny the crossing entirely if any
501 // of them are banned. Alternatively, we could
502 // unsit banned agents....
503
504
505 // We set the avatar position as being the object
506 // position to get the region to send to
507 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
508 {
509 canCross = false;
510 break;
511 }
512
513 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
514 }
515
516 if (canCross)
517 {
518 // We unparent the SP quietly so that it won't
519 // be made to stand up
520 foreach (ScenePresence av in m_linkedAvatars)
521 {
522 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
523 if (parentPart != null)
524 av.ParentUUID = parentPart.UUID;
525
526 av.ParentID = 0;
527 }
528
529 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
530
531 // Normalize
532 if (val.X >= Constants.RegionSize)
533 val.X -= Constants.RegionSize;
534 if (val.Y >= Constants.RegionSize)
535 val.Y -= Constants.RegionSize;
536 if (val.X < 0)
537 val.X += Constants.RegionSize;
538 if (val.Y < 0)
539 val.Y += Constants.RegionSize;
540
541 // If it's deleted, crossing was successful
542 if (IsDeleted)
543 {
544 foreach (ScenePresence av in m_linkedAvatars)
545 {
546 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
547
548 av.IsInTransit = true;
549
550 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
551 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
552 }
553
554 return;
555 }
556 }
557 else if (RootPart.PhysActor != null)
558 {
559 RootPart.PhysActor.CrossingFailure();
560 }
561
562 Vector3 oldp = AbsolutePosition;
563 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
564 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
565 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
412 } 566 }
413 } 567 }
414 568/* don't see the need but worse don't see where is restored to false if things stay in
569 foreach (SceneObjectPart part in m_parts.GetArray())
570 {
571 part.IgnoreUndoUpdate = true;
572 }
573 */
415 if (RootPart.GetStatusSandbox()) 574 if (RootPart.GetStatusSandbox())
416 { 575 {
417 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 576 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -425,10 +584,30 @@ namespace OpenSim.Region.Framework.Scenes
425 return; 584 return;
426 } 585 }
427 } 586 }
428
429 SceneObjectPart[] parts = m_parts.GetArray(); 587 SceneObjectPart[] parts = m_parts.GetArray();
430 for (int i = 0; i < parts.Length; i++) 588 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
431 parts[i].GroupPosition = val; 589 if (m_dupeInProgress)
590 triggerScriptEvent = false;
591 foreach (SceneObjectPart part in parts)
592 {
593 part.GroupPosition = val;
594 if (triggerScriptEvent)
595 part.TriggerScriptChangedEvent(Changed.POSITION);
596 }
597 if (!m_dupeInProgress)
598 {
599 foreach (ScenePresence av in m_linkedAvatars)
600 {
601 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
602 if (p != null && m_parts.TryGetValue(p.UUID, out p))
603 {
604 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
605 av.AbsolutePosition += offset;
606 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
607 av.SendAvatarDataToAllAgents();
608 }
609 }
610 }
432 611
433 //if (m_rootPart.PhysActor != null) 612 //if (m_rootPart.PhysActor != null)
434 //{ 613 //{
@@ -443,6 +622,37 @@ namespace OpenSim.Region.Framework.Scenes
443 } 622 }
444 } 623 }
445 624
625 public override Vector3 Velocity
626 {
627 get { return RootPart.Velocity; }
628 set { RootPart.Velocity = value; }
629 }
630
631 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
632 {
633 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
634 ScenePresence agent = icon.EndInvoke(iar);
635
636 //// If the cross was successful, this agent is a child agent
637 if (agent.IsChildAgent)
638 {
639 if (agent.ParentUUID != UUID.Zero)
640 {
641 agent.ParentPart = null;
642 agent.ParentPosition = Vector3.Zero;
643 }
644 }
645
646// agent.Reset();
647// else // Not successful
648// agent.RestoreInCurrentScene();
649
650 // In any case
651 agent.IsInTransit = false;
652
653 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
654 }
655
446 public override uint LocalId 656 public override uint LocalId
447 { 657 {
448 get { return m_rootPart.LocalId; } 658 get { return m_rootPart.LocalId; }
@@ -524,6 +734,11 @@ namespace OpenSim.Region.Framework.Scenes
524 m_isSelected = value; 734 m_isSelected = value;
525 // Tell physics engine that group is selected 735 // Tell physics engine that group is selected
526 736
737 // this is not right
738 // but ode engines should only really need to know about root part
739 // so they can put entire object simulation on hold and not colliding
740 // keep as was for now
741
527 PhysicsActor pa = m_rootPart.PhysActor; 742 PhysicsActor pa = m_rootPart.PhysActor;
528 if (pa != null) 743 if (pa != null)
529 { 744 {
@@ -540,6 +755,42 @@ namespace OpenSim.Region.Framework.Scenes
540 childPa.Selected = value; 755 childPa.Selected = value;
541 } 756 }
542 } 757 }
758 if (RootPart.KeyframeMotion != null)
759 RootPart.KeyframeMotion.Selected = value;
760 }
761 }
762
763 public void PartSelectChanged(bool partSelect)
764 {
765 // any part selected makes group selected
766 if (m_isSelected == partSelect)
767 return;
768
769 if (partSelect)
770 {
771 IsSelected = partSelect;
772// if (!IsAttachment)
773// ScheduleGroupForFullUpdate();
774 }
775 else
776 {
777 // bad bad bad 2 heavy for large linksets
778 // since viewer does send lot of (un)selects
779 // this needs to be replaced by a specific list or count ?
780 // but that will require extra code in several places
781
782 SceneObjectPart[] parts = m_parts.GetArray();
783 for (int i = 0; i < parts.Length; i++)
784 {
785 SceneObjectPart part = parts[i];
786 if (part.IsSelected)
787 return;
788 }
789 IsSelected = partSelect;
790 if (!IsAttachment)
791 {
792 ScheduleGroupForFullUpdate();
793 }
543 } 794 }
544 } 795 }
545 796
@@ -617,6 +868,7 @@ namespace OpenSim.Region.Framework.Scenes
617 /// </summary> 868 /// </summary>
618 public SceneObjectGroup() 869 public SceneObjectGroup()
619 { 870 {
871
620 } 872 }
621 873
622 /// <summary> 874 /// <summary>
@@ -633,7 +885,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// Constructor. This object is added to the scene later via AttachToScene() 885 /// Constructor. This object is added to the scene later via AttachToScene()
634 /// </summary> 886 /// </summary>
635 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 887 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
636 { 888 {
637 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 889 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
638 } 890 }
639 891
@@ -669,6 +921,9 @@ namespace OpenSim.Region.Framework.Scenes
669 /// </summary> 921 /// </summary>
670 public virtual void AttachToBackup() 922 public virtual void AttachToBackup()
671 { 923 {
924 if (IsAttachment) return;
925 m_scene.SceneGraph.FireAttachToBackup(this);
926
672 if (InSceneBackup) 927 if (InSceneBackup)
673 { 928 {
674 //m_log.DebugFormat( 929 //m_log.DebugFormat(
@@ -711,6 +966,13 @@ namespace OpenSim.Region.Framework.Scenes
711 966
712 ApplyPhysics(); 967 ApplyPhysics();
713 968
969 if (RootPart.PhysActor != null)
970 RootPart.Force = RootPart.Force;
971 if (RootPart.PhysActor != null)
972 RootPart.Torque = RootPart.Torque;
973 if (RootPart.PhysActor != null)
974 RootPart.Buoyancy = RootPart.Buoyancy;
975
714 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 976 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
715 // for the same object with very different properties. The caller must schedule the update. 977 // for the same object with very different properties. The caller must schedule the update.
716 //ScheduleGroupForFullUpdate(); 978 //ScheduleGroupForFullUpdate();
@@ -726,6 +988,10 @@ namespace OpenSim.Region.Framework.Scenes
726 EntityIntersection result = new EntityIntersection(); 988 EntityIntersection result = new EntityIntersection();
727 989
728 SceneObjectPart[] parts = m_parts.GetArray(); 990 SceneObjectPart[] parts = m_parts.GetArray();
991
992 // Find closest hit here
993 float idist = float.MaxValue;
994
729 for (int i = 0; i < parts.Length; i++) 995 for (int i = 0; i < parts.Length; i++)
730 { 996 {
731 SceneObjectPart part = parts[i]; 997 SceneObjectPart part = parts[i];
@@ -740,11 +1006,6 @@ namespace OpenSim.Region.Framework.Scenes
740 1006
741 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1007 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
742 1008
743 // This may need to be updated to the maximum draw distance possible..
744 // We might (and probably will) be checking for prim creation from other sims
745 // when the camera crosses the border.
746 float idist = Constants.RegionSize;
747
748 if (inter.HitTF) 1009 if (inter.HitTF)
749 { 1010 {
750 // We need to find the closest prim to return to the testcaller along the ray 1011 // We need to find the closest prim to return to the testcaller along the ray
@@ -755,10 +1016,11 @@ namespace OpenSim.Region.Framework.Scenes
755 result.obj = part; 1016 result.obj = part;
756 result.normal = inter.normal; 1017 result.normal = inter.normal;
757 result.distance = inter.distance; 1018 result.distance = inter.distance;
1019
1020 idist = inter.distance;
758 } 1021 }
759 } 1022 }
760 } 1023 }
761
762 return result; 1024 return result;
763 } 1025 }
764 1026
@@ -770,25 +1032,27 @@ namespace OpenSim.Region.Framework.Scenes
770 /// <returns></returns> 1032 /// <returns></returns>
771 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1033 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
772 { 1034 {
773 maxX = -256f; 1035 maxX = float.MinValue;
774 maxY = -256f; 1036 maxY = float.MinValue;
775 maxZ = -256f; 1037 maxZ = float.MinValue;
776 minX = 256f; 1038 minX = float.MaxValue;
777 minY = 256f; 1039 minY = float.MaxValue;
778 minZ = 8192f; 1040 minZ = float.MaxValue;
779 1041
780 SceneObjectPart[] parts = m_parts.GetArray(); 1042 SceneObjectPart[] parts = m_parts.GetArray();
781 for (int i = 0; i < parts.Length; i++) 1043 foreach (SceneObjectPart part in parts)
782 { 1044 {
783 SceneObjectPart part = parts[i];
784
785 Vector3 worldPos = part.GetWorldPosition(); 1045 Vector3 worldPos = part.GetWorldPosition();
786 Vector3 offset = worldPos - AbsolutePosition; 1046 Vector3 offset = worldPos - AbsolutePosition;
787 Quaternion worldRot; 1047 Quaternion worldRot;
788 if (part.ParentID == 0) 1048 if (part.ParentID == 0)
1049 {
789 worldRot = part.RotationOffset; 1050 worldRot = part.RotationOffset;
1051 }
790 else 1052 else
1053 {
791 worldRot = part.GetWorldRotation(); 1054 worldRot = part.GetWorldRotation();
1055 }
792 1056
793 Vector3 frontTopLeft; 1057 Vector3 frontTopLeft;
794 Vector3 frontTopRight; 1058 Vector3 frontTopRight;
@@ -800,6 +1064,8 @@ namespace OpenSim.Region.Framework.Scenes
800 Vector3 backBottomLeft; 1064 Vector3 backBottomLeft;
801 Vector3 backBottomRight; 1065 Vector3 backBottomRight;
802 1066
1067 // Vector3[] corners = new Vector3[8];
1068
803 Vector3 orig = Vector3.Zero; 1069 Vector3 orig = Vector3.Zero;
804 1070
805 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1071 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -834,6 +1100,38 @@ namespace OpenSim.Region.Framework.Scenes
834 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1100 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
835 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1101 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
836 1102
1103
1104
1105 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1106 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1107 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1108 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1109 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1110 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1111 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1112 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1113
1114 //for (int i = 0; i < 8; i++)
1115 //{
1116 // corners[i] = corners[i] * worldRot;
1117 // corners[i] += offset;
1118
1119 // if (corners[i].X > maxX)
1120 // maxX = corners[i].X;
1121 // if (corners[i].X < minX)
1122 // minX = corners[i].X;
1123
1124 // if (corners[i].Y > maxY)
1125 // maxY = corners[i].Y;
1126 // if (corners[i].Y < minY)
1127 // minY = corners[i].Y;
1128
1129 // if (corners[i].Z > maxZ)
1130 // maxZ = corners[i].Y;
1131 // if (corners[i].Z < minZ)
1132 // minZ = corners[i].Z;
1133 //}
1134
837 frontTopLeft = frontTopLeft * worldRot; 1135 frontTopLeft = frontTopLeft * worldRot;
838 frontTopRight = frontTopRight * worldRot; 1136 frontTopRight = frontTopRight * worldRot;
839 frontBottomLeft = frontBottomLeft * worldRot; 1137 frontBottomLeft = frontBottomLeft * worldRot;
@@ -855,6 +1153,15 @@ namespace OpenSim.Region.Framework.Scenes
855 backTopLeft += offset; 1153 backTopLeft += offset;
856 backTopRight += offset; 1154 backTopRight += offset;
857 1155
1156 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1157 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1158 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1159 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1160 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1161 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1162 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1163 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1164
858 if (frontTopRight.X > maxX) 1165 if (frontTopRight.X > maxX)
859 maxX = frontTopRight.X; 1166 maxX = frontTopRight.X;
860 if (frontTopLeft.X > maxX) 1167 if (frontTopLeft.X > maxX)
@@ -998,17 +1305,118 @@ namespace OpenSim.Region.Framework.Scenes
998 1305
999 #endregion 1306 #endregion
1000 1307
1308 public void GetResourcesCosts(SceneObjectPart apart,
1309 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1310 {
1311 // this information may need to be cached
1312
1313 float cost;
1314 float tmpcost;
1315
1316 bool ComplexCost = false;
1317
1318 SceneObjectPart p;
1319 SceneObjectPart[] parts;
1320
1321 lock (m_parts)
1322 {
1323 parts = m_parts.GetArray();
1324 }
1325
1326 int nparts = parts.Length;
1327
1328
1329 for (int i = 0; i < nparts; i++)
1330 {
1331 p = parts[i];
1332
1333 if (p.UsesComplexCost)
1334 {
1335 ComplexCost = true;
1336 break;
1337 }
1338 }
1339
1340 if (ComplexCost)
1341 {
1342 linksetResCost = 0;
1343 linksetPhysCost = 0;
1344 partCost = 0;
1345 partPhysCost = 0;
1346
1347 for (int i = 0; i < nparts; i++)
1348 {
1349 p = parts[i];
1350
1351 cost = p.StreamingCost;
1352 tmpcost = p.SimulationCost;
1353 if (tmpcost > cost)
1354 cost = tmpcost;
1355 tmpcost = p.PhysicsCost;
1356 if (tmpcost > cost)
1357 cost = tmpcost;
1358
1359 linksetPhysCost += tmpcost;
1360 linksetResCost += cost;
1361
1362 if (p == apart)
1363 {
1364 partCost = cost;
1365 partPhysCost = tmpcost;
1366 }
1367 }
1368 }
1369 else
1370 {
1371 partPhysCost = 1.0f;
1372 partCost = 1.0f;
1373 linksetResCost = (float)nparts;
1374 linksetPhysCost = linksetResCost;
1375 }
1376 }
1377
1378 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1379 {
1380 SceneObjectPart p;
1381 SceneObjectPart[] parts;
1382
1383 lock (m_parts)
1384 {
1385 parts = m_parts.GetArray();
1386 }
1387
1388 int nparts = parts.Length;
1389
1390 PhysCost = 0;
1391 StreamCost = 0;
1392 SimulCost = 0;
1393
1394 for (int i = 0; i < nparts; i++)
1395 {
1396 p = parts[i];
1397
1398 StreamCost += p.StreamingCost;
1399 SimulCost += p.SimulationCost;
1400 PhysCost += p.PhysicsCost;
1401 }
1402 }
1403
1001 public void SaveScriptedState(XmlTextWriter writer) 1404 public void SaveScriptedState(XmlTextWriter writer)
1002 { 1405 {
1406 SaveScriptedState(writer, false);
1407 }
1408
1409 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1410 {
1003 XmlDocument doc = new XmlDocument(); 1411 XmlDocument doc = new XmlDocument();
1004 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1412 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1005 1413
1006 SceneObjectPart[] parts = m_parts.GetArray(); 1414 SceneObjectPart[] parts = m_parts.GetArray();
1007 for (int i = 0; i < parts.Length; i++) 1415 for (int i = 0; i < parts.Length; i++)
1008 { 1416 {
1009 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1417 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1010 foreach (KeyValuePair<UUID, string> kvp in pstates) 1418 foreach (KeyValuePair<UUID, string> kvp in pstates)
1011 states.Add(kvp.Key, kvp.Value); 1419 states[kvp.Key] = kvp.Value;
1012 } 1420 }
1013 1421
1014 if (states.Count > 0) 1422 if (states.Count > 0)
@@ -1028,6 +1436,169 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1436 }
1029 1437
1030 /// <summary> 1438 /// <summary>
1439 /// Add the avatar to this linkset (avatar is sat).
1440 /// </summary>
1441 /// <param name="agentID"></param>
1442 public void AddAvatar(UUID agentID)
1443 {
1444 ScenePresence presence;
1445 if (m_scene.TryGetScenePresence(agentID, out presence))
1446 {
1447 if (!m_linkedAvatars.Contains(presence))
1448 {
1449 m_linkedAvatars.Add(presence);
1450 }
1451 }
1452 }
1453
1454 /// <summary>
1455 /// Delete the avatar from this linkset (avatar is unsat).
1456 /// </summary>
1457 /// <param name="agentID"></param>
1458 public void DeleteAvatar(UUID agentID)
1459 {
1460 ScenePresence presence;
1461 if (m_scene.TryGetScenePresence(agentID, out presence))
1462 {
1463 if (m_linkedAvatars.Contains(presence))
1464 {
1465 m_linkedAvatars.Remove(presence);
1466 }
1467 }
1468 }
1469
1470 /// <summary>
1471 /// Returns the list of linked presences (avatars sat on this group)
1472 /// </summary>
1473 /// <param name="agentID"></param>
1474 public List<ScenePresence> GetLinkedAvatars()
1475 {
1476 return m_linkedAvatars;
1477 }
1478
1479 /// <summary>
1480 /// Attach this scene object to the given avatar.
1481 /// </summary>
1482 /// <param name="agentID"></param>
1483 /// <param name="attachmentpoint"></param>
1484 /// <param name="AttachOffset"></param>
1485 private void AttachToAgent(
1486 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1487 {
1488 if (avatar != null)
1489 {
1490 // don't attach attachments to child agents
1491 if (avatar.IsChildAgent) return;
1492
1493 // Remove from database and parcel prim count
1494 m_scene.DeleteFromStorage(so.UUID);
1495 m_scene.EventManager.TriggerParcelPrimCountTainted();
1496
1497 so.AttachedAvatar = avatar.UUID;
1498
1499 if (so.RootPart.PhysActor != null)
1500 {
1501 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1502 so.RootPart.PhysActor = null;
1503 }
1504
1505 so.AbsolutePosition = attachOffset;
1506 so.RootPart.AttachedPos = attachOffset;
1507 so.IsAttachment = true;
1508 so.RootPart.SetParentLocalId(avatar.LocalId);
1509 so.AttachmentPoint = attachmentpoint;
1510
1511 avatar.AddAttachment(this);
1512
1513 if (!silent)
1514 {
1515 // Killing it here will cause the client to deselect it
1516 // It then reappears on the avatar, deselected
1517 // through the full update below
1518 //
1519 if (IsSelected)
1520 {
1521 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1522 }
1523
1524 IsSelected = false; // fudge....
1525 ScheduleGroupForFullUpdate();
1526 }
1527 }
1528 else
1529 {
1530 m_log.WarnFormat(
1531 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1532 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1533 }
1534 }
1535
1536 public byte GetAttachmentPoint()
1537 {
1538 return m_rootPart.Shape.State;
1539 }
1540
1541 public void DetachToGround()
1542 {
1543 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1544 if (avatar == null)
1545 return;
1546
1547 avatar.RemoveAttachment(this);
1548
1549 Vector3 detachedpos = new Vector3(127f,127f,127f);
1550 if (avatar == null)
1551 return;
1552
1553 detachedpos = avatar.AbsolutePosition;
1554 FromItemID = UUID.Zero;
1555
1556 AbsolutePosition = detachedpos;
1557 AttachedAvatar = UUID.Zero;
1558
1559 //SceneObjectPart[] parts = m_parts.GetArray();
1560 //for (int i = 0; i < parts.Length; i++)
1561 // parts[i].AttachedAvatar = UUID.Zero;
1562
1563 m_rootPart.SetParentLocalId(0);
1564 AttachmentPoint = (byte)0;
1565 // must check if buildind should be true or false here
1566 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1567 HasGroupChanged = true;
1568 RootPart.Rezzed = DateTime.Now;
1569 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1570 AttachToBackup();
1571 m_scene.EventManager.TriggerParcelPrimCountTainted();
1572 m_rootPart.ScheduleFullUpdate();
1573 m_rootPart.ClearUndoState();
1574 }
1575
1576 public void DetachToInventoryPrep()
1577 {
1578 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1579 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1580 if (avatar != null)
1581 {
1582 //detachedpos = avatar.AbsolutePosition;
1583 avatar.RemoveAttachment(this);
1584 }
1585
1586 AttachedAvatar = UUID.Zero;
1587
1588 /*SceneObjectPart[] parts = m_parts.GetArray();
1589 for (int i = 0; i < parts.Length; i++)
1590 parts[i].AttachedAvatar = UUID.Zero;*/
1591
1592 m_rootPart.SetParentLocalId(0);
1593 //m_rootPart.SetAttachmentPoint((byte)0);
1594 IsAttachment = false;
1595 AbsolutePosition = m_rootPart.AttachedPos;
1596 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1597 //AttachToBackup();
1598 //m_rootPart.ScheduleFullUpdate();
1599 }
1600
1601 /// <summary>
1031 /// 1602 ///
1032 /// </summary> 1603 /// </summary>
1033 /// <param name="part"></param> 1604 /// <param name="part"></param>
@@ -1077,7 +1648,10 @@ namespace OpenSim.Region.Framework.Scenes
1077 public void AddPart(SceneObjectPart part) 1648 public void AddPart(SceneObjectPart part)
1078 { 1649 {
1079 part.SetParent(this); 1650 part.SetParent(this);
1080 part.LinkNum = m_parts.Add(part.UUID, part); 1651 m_parts.Add(part.UUID, part);
1652
1653 part.LinkNum = m_parts.Count;
1654
1081 if (part.LinkNum == 2) 1655 if (part.LinkNum == 2)
1082 RootPart.LinkNum = 1; 1656 RootPart.LinkNum = 1;
1083 } 1657 }
@@ -1165,7 +1739,7 @@ namespace OpenSim.Region.Framework.Scenes
1165// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1739// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1166// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1740// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1167 1741
1168 part.StoreUndoState(); 1742// part.StoreUndoState();
1169 part.OnGrab(offsetPos, remoteClient); 1743 part.OnGrab(offsetPos, remoteClient);
1170 } 1744 }
1171 1745
@@ -1185,6 +1759,11 @@ namespace OpenSim.Region.Framework.Scenes
1185 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1759 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1186 public void DeleteGroupFromScene(bool silent) 1760 public void DeleteGroupFromScene(bool silent)
1187 { 1761 {
1762 // We need to keep track of this state in case this group is still queued for backup.
1763 IsDeleted = true;
1764
1765 DetachFromBackup();
1766
1188 SceneObjectPart[] parts = m_parts.GetArray(); 1767 SceneObjectPart[] parts = m_parts.GetArray();
1189 for (int i = 0; i < parts.Length; i++) 1768 for (int i = 0; i < parts.Length; i++)
1190 { 1769 {
@@ -1207,6 +1786,8 @@ namespace OpenSim.Region.Framework.Scenes
1207 } 1786 }
1208 }); 1787 });
1209 } 1788 }
1789
1790
1210 } 1791 }
1211 1792
1212 public void AddScriptLPS(int count) 1793 public void AddScriptLPS(int count)
@@ -1276,28 +1857,43 @@ namespace OpenSim.Region.Framework.Scenes
1276 /// </summary> 1857 /// </summary>
1277 public void ApplyPhysics() 1858 public void ApplyPhysics()
1278 { 1859 {
1279 // Apply physics to the root prim
1280 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1281
1282 // Apply physics to child prims
1283 SceneObjectPart[] parts = m_parts.GetArray(); 1860 SceneObjectPart[] parts = m_parts.GetArray();
1284 if (parts.Length > 1) 1861 if (parts.Length > 1)
1285 { 1862 {
1863 ResetChildPrimPhysicsPositions();
1864
1865 // Apply physics to the root prim
1866 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1867
1868
1286 for (int i = 0; i < parts.Length; i++) 1869 for (int i = 0; i < parts.Length; i++)
1287 { 1870 {
1288 SceneObjectPart part = parts[i]; 1871 SceneObjectPart part = parts[i];
1289 if (part.LocalId != m_rootPart.LocalId) 1872 if (part.LocalId != m_rootPart.LocalId)
1290 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1873 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1291 } 1874 }
1292
1293 // Hack to get the physics scene geometries in the right spot 1875 // Hack to get the physics scene geometries in the right spot
1294 ResetChildPrimPhysicsPositions(); 1876// ResetChildPrimPhysicsPositions();
1877 if (m_rootPart.PhysActor != null)
1878 {
1879 m_rootPart.PhysActor.Building = false;
1880 }
1881 }
1882 else
1883 {
1884 // Apply physics to the root prim
1885 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1295 } 1886 }
1296 } 1887 }
1297 1888
1298 public void SetOwnerId(UUID userId) 1889 public void SetOwnerId(UUID userId)
1299 { 1890 {
1300 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1891 ForEachPart(delegate(SceneObjectPart part)
1892 {
1893
1894 part.OwnerID = userId;
1895
1896 });
1301 } 1897 }
1302 1898
1303 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1899 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1329,11 +1925,17 @@ namespace OpenSim.Region.Framework.Scenes
1329 return; 1925 return;
1330 } 1926 }
1331 1927
1928 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1929 return;
1930
1332 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1931 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1333 // any exception propogate upwards. 1932 // any exception propogate upwards.
1334 try 1933 try
1335 { 1934 {
1336 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1935 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1936 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1937 m_scene.LoadingPrims) // Land may not be valid yet
1938
1337 { 1939 {
1338 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1940 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1339 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1941 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1360,6 +1962,7 @@ namespace OpenSim.Region.Framework.Scenes
1360 } 1962 }
1361 } 1963 }
1362 } 1964 }
1965
1363 } 1966 }
1364 1967
1365 if (m_scene.UseBackup && HasGroupChanged) 1968 if (m_scene.UseBackup && HasGroupChanged)
@@ -1367,10 +1970,30 @@ namespace OpenSim.Region.Framework.Scenes
1367 // don't backup while it's selected or you're asking for changes mid stream. 1970 // don't backup while it's selected or you're asking for changes mid stream.
1368 if (isTimeToPersist() || forcedBackup) 1971 if (isTimeToPersist() || forcedBackup)
1369 { 1972 {
1973 if (m_rootPart.PhysActor != null &&
1974 (!m_rootPart.PhysActor.IsPhysical))
1975 {
1976 // Possible ghost prim
1977 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1978 {
1979 foreach (SceneObjectPart part in m_parts.GetArray())
1980 {
1981 // Re-set physics actor positions and
1982 // orientations
1983 part.GroupPosition = m_rootPart.GroupPosition;
1984 }
1985 }
1986 }
1370// m_log.DebugFormat( 1987// m_log.DebugFormat(
1371// "[SCENE]: Storing {0}, {1} in {2}", 1988// "[SCENE]: Storing {0}, {1} in {2}",
1372// Name, UUID, m_scene.RegionInfo.RegionName); 1989// Name, UUID, m_scene.RegionInfo.RegionName);
1373 1990
1991 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
1992 {
1993 RootPart.Shape.State = 0;
1994 ScheduleGroupForFullUpdate();
1995 }
1996
1374 SceneObjectGroup backup_group = Copy(false); 1997 SceneObjectGroup backup_group = Copy(false);
1375 backup_group.RootPart.Velocity = RootPart.Velocity; 1998 backup_group.RootPart.Velocity = RootPart.Velocity;
1376 backup_group.RootPart.Acceleration = RootPart.Acceleration; 1999 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1384,6 +2007,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 2007
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 2008 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 2009 {
2010 if (part.KeyframeMotion != null)
2011 {
2012 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2013 part.KeyframeMotion.UpdateSceneObject(this);
2014 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 2015 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 2016 });
1389 2017
@@ -1436,6 +2064,7 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2064 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2065 public SceneObjectGroup Copy(bool userExposed)
1438 { 2066 {
2067 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2068 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2069 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2070 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1450,7 +2079,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2079 // This is only necessary when userExposed is false!
1451 2080
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2081 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2082
1454 if (!userExposed) 2083 if (!userExposed)
1455 dupe.IsAttachment = true; 2084 dupe.IsAttachment = true;
1456 2085
@@ -1468,11 +2097,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2097 dupe.m_rootPart.TrimPermissions();
1469 2098
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2099 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2100
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2101 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2102 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2103 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2104 }
1476 ); 2105 );
1477 2106
1478 foreach (SceneObjectPart part in partList) 2107 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2111,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2111 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2112 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2113 newPart.LinkNum = part.LinkNum;
1485 } 2114 if (userExposed)
2115 newPart.ParentID = dupe.m_rootPart.LocalId;
2116 }
1486 else 2117 else
1487 { 2118 {
1488 newPart = dupe.m_rootPart; 2119 newPart = dupe.m_rootPart;
1489 } 2120 }
2121/*
2122 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2123 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2124
1491 // Need to duplicate the physics actor as well 2125 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2126 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2127 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2128 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2129 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2130 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2131 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2132 pbs,
1501 newPart.AbsolutePosition, 2133 newPart.AbsolutePosition,
1502 newPart.Scale, 2134 newPart.Scale,
1503 newPart.RotationOffset, 2135 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2136 isphys,
2137 isphan,
1505 newPart.LocalId); 2138 newPart.LocalId);
1506 2139
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2140 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2141 */
2142 if (userExposed)
2143 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2144// }
1509 } 2145 }
1510 2146
1511 if (userExposed) 2147 if (userExposed)
1512 { 2148 {
1513 dupe.UpdateParentIDs(); 2149// done above dupe.UpdateParentIDs();
2150
2151 if (dupe.m_rootPart.PhysActor != null)
2152 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2153
1514 dupe.HasGroupChanged = true; 2154 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2155 dupe.AttachToBackup();
1516 2156
1517 ScheduleGroupForFullUpdate(); 2157 ScheduleGroupForFullUpdate();
1518 } 2158 }
1519 2159
2160 m_dupeInProgress = false;
1520 return dupe; 2161 return dupe;
1521 } 2162 }
1522 2163
@@ -1528,11 +2169,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2169 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2170 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2171 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2172 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2173 // give newpart a new local ID lettng old part keep same
2174 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2175 newpart.LocalId = m_scene.AllocateLocalId();
2176
2177 SetRootPart(newpart);
2178 if (userExposed)
2179 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2180 }
1533 2181
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2182 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2183 {
2184 if (usePhysics)
2185 {
2186 if (RootPart.KeyframeMotion != null)
2187 RootPart.KeyframeMotion.Stop();
2188 RootPart.KeyframeMotion = null;
2189 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2190 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2191 }
1538 2192
@@ -1586,7 +2240,7 @@ namespace OpenSim.Region.Framework.Scenes
1586 } 2240 }
1587 } 2241 }
1588 2242
1589 public void applyAngularImpulse(Vector3 impulse) 2243 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2244 {
1591 PhysicsActor pa = RootPart.PhysActor; 2245 PhysicsActor pa = RootPart.PhysActor;
1592 2246
@@ -1600,36 +2254,12 @@ namespace OpenSim.Region.Framework.Scenes
1600 } 2254 }
1601 } 2255 }
1602 2256
1603 public void setAngularImpulse(Vector3 impulse)
1604 {
1605 PhysicsActor pa = RootPart.PhysActor;
1606
1607 if (pa != null)
1608 {
1609 if (!IsAttachment)
1610 {
1611 pa.Torque = impulse;
1612 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1613 }
1614 }
1615 }
1616
1617 public Vector3 GetTorque() 2257 public Vector3 GetTorque()
1618 { 2258 {
1619 PhysicsActor pa = RootPart.PhysActor; 2259 return RootPart.Torque;
1620
1621 if (pa != null)
1622 {
1623 if (!IsAttachment)
1624 {
1625 Vector3 torque = pa.Torque;
1626 return torque;
1627 }
1628 }
1629
1630 return Vector3.Zero;
1631 } 2260 }
1632 2261
2262 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2263 public void moveToTarget(Vector3 target, float tau)
1634 { 2264 {
1635 if (IsAttachment) 2265 if (IsAttachment)
@@ -1661,6 +2291,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2291 pa.PIDActive = false;
1662 } 2292 }
1663 2293
2294 public void rotLookAt(Quaternion target, float strength, float damping)
2295 {
2296 SceneObjectPart rootpart = m_rootPart;
2297 if (rootpart != null)
2298 {
2299 if (IsAttachment)
2300 {
2301 /*
2302 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2303 if (avatar != null)
2304 {
2305 Rotate the Av?
2306 } */
2307 }
2308 else
2309 {
2310 if (rootpart.PhysActor != null)
2311 { // APID must be implemented in your physics system for this to function.
2312 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2313 rootpart.PhysActor.APIDStrength = strength;
2314 rootpart.PhysActor.APIDDamping = damping;
2315 rootpart.PhysActor.APIDActive = true;
2316 }
2317 }
2318 }
2319 }
2320
2321 public void stopLookAt()
2322 {
2323 SceneObjectPart rootpart = m_rootPart;
2324 if (rootpart != null)
2325 {
2326 if (rootpart.PhysActor != null)
2327 { // APID must be implemented in your physics system for this to function.
2328 rootpart.PhysActor.APIDActive = false;
2329 }
2330 }
2331
2332 }
2333
1664 /// <summary> 2334 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2335 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2336 /// </summary>
@@ -1677,7 +2347,7 @@ namespace OpenSim.Region.Framework.Scenes
1677 { 2347 {
1678 pa.PIDHoverHeight = height; 2348 pa.PIDHoverHeight = height;
1679 pa.PIDHoverType = hoverType; 2349 pa.PIDHoverType = hoverType;
1680 pa.PIDTau = tau; 2350 pa.PIDHoverTau = tau;
1681 pa.PIDHoverActive = true; 2351 pa.PIDHoverActive = true;
1682 } 2352 }
1683 else 2353 else
@@ -1717,7 +2387,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2387 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2388 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2389 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2390 // give new ID to the new part, letting old keep original
2391 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2392 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2393 newPart.LocalId = m_scene.AllocateLocalId();
2394 newPart.SetParent(this);
2395
1721 AddPart(newPart); 2396 AddPart(newPart);
1722 2397
1723 SetPartAsNonRoot(newPart); 2398 SetPartAsNonRoot(newPart);
@@ -1846,11 +2521,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2521 /// Immediately send a full update for this scene object.
1847 /// </summary> 2522 /// </summary>
1848 public void SendGroupFullUpdate() 2523 public void SendGroupFullUpdate()
1849 { 2524 {
1850 if (IsDeleted) 2525 if (IsDeleted)
1851 return; 2526 return;
1852 2527
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2528// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2529
1855 RootPart.SendFullUpdateToAllClients(); 2530 RootPart.SendFullUpdateToAllClients();
1856 2531
@@ -1984,6 +2659,11 @@ namespace OpenSim.Region.Framework.Scenes
1984 2659
1985 SceneObjectPart linkPart = objectGroup.m_rootPart; 2660 SceneObjectPart linkPart = objectGroup.m_rootPart;
1986 2661
2662 if (m_rootPart.PhysActor != null)
2663 m_rootPart.PhysActor.Building = true;
2664 if (linkPart.PhysActor != null)
2665 linkPart.PhysActor.Building = true;
2666
1987 // physics flags from group to be applied to linked parts 2667 // physics flags from group to be applied to linked parts
1988 bool grpusephys = UsesPhysics; 2668 bool grpusephys = UsesPhysics;
1989 bool grptemporary = IsTemporary; 2669 bool grptemporary = IsTemporary;
@@ -1992,19 +2672,21 @@ namespace OpenSim.Region.Framework.Scenes
1992 Quaternion oldRootRotation = linkPart.RotationOffset; 2672 Quaternion oldRootRotation = linkPart.RotationOffset;
1993 2673
1994 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2674 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2675
1995 linkPart.ParentID = m_rootPart.LocalId; 2676 linkPart.ParentID = m_rootPart.LocalId;
1996 linkPart.GroupPosition = AbsolutePosition; 2677
1997 Vector3 axPos = linkPart.OffsetPosition; 2678 linkPart.GroupPosition = AbsolutePosition;
1998 2679
2680 Vector3 axPos = linkPart.OffsetPosition;
1999 Quaternion parentRot = m_rootPart.RotationOffset; 2681 Quaternion parentRot = m_rootPart.RotationOffset;
2000 axPos *= Quaternion.Inverse(parentRot); 2682 axPos *= Quaternion.Conjugate(parentRot);
2001
2002 linkPart.OffsetPosition = axPos; 2683 linkPart.OffsetPosition = axPos;
2684
2003 Quaternion oldRot = linkPart.RotationOffset; 2685 Quaternion oldRot = linkPart.RotationOffset;
2004 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2686 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2005 linkPart.RotationOffset = newRot; 2687 linkPart.RotationOffset = newRot;
2006 2688
2007 linkPart.ParentID = m_rootPart.LocalId; 2689// linkPart.ParentID = m_rootPart.LocalId; done above
2008 2690
2009 if (m_rootPart.LinkNum == 0) 2691 if (m_rootPart.LinkNum == 0)
2010 m_rootPart.LinkNum = 1; 2692 m_rootPart.LinkNum = 1;
@@ -2032,7 +2714,7 @@ namespace OpenSim.Region.Framework.Scenes
2032 linkPart.CreateSelected = true; 2714 linkPart.CreateSelected = true;
2033 2715
2034 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2716 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2035 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2717 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2036 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2718 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2037 { 2719 {
2038 linkPart.PhysActor.link(m_rootPart.PhysActor); 2720 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2040,6 +2722,7 @@ namespace OpenSim.Region.Framework.Scenes
2040 } 2722 }
2041 2723
2042 linkPart.LinkNum = linkNum++; 2724 linkPart.LinkNum = linkNum++;
2725 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2043 2726
2044 SceneObjectPart[] ogParts = objectGroup.Parts; 2727 SceneObjectPart[] ogParts = objectGroup.Parts;
2045 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2728 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2054,7 +2737,7 @@ namespace OpenSim.Region.Framework.Scenes
2054 { 2737 {
2055 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2738 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2056 // let physics know 2739 // let physics know
2057 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2740 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2058 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2741 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2059 { 2742 {
2060 part.PhysActor.link(m_rootPart.PhysActor); 2743 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2069,7 +2752,7 @@ namespace OpenSim.Region.Framework.Scenes
2069 objectGroup.IsDeleted = true; 2752 objectGroup.IsDeleted = true;
2070 2753
2071 objectGroup.m_parts.Clear(); 2754 objectGroup.m_parts.Clear();
2072 2755
2073 // Can't do this yet since backup still makes use of the root part without any synchronization 2756 // Can't do this yet since backup still makes use of the root part without any synchronization
2074// objectGroup.m_rootPart = null; 2757// objectGroup.m_rootPart = null;
2075 2758
@@ -2080,6 +2763,9 @@ namespace OpenSim.Region.Framework.Scenes
2080 // unmoved prims! 2763 // unmoved prims!
2081 ResetChildPrimPhysicsPositions(); 2764 ResetChildPrimPhysicsPositions();
2082 2765
2766 if (m_rootPart.PhysActor != null)
2767 m_rootPart.PhysActor.Building = false;
2768
2083 //HasGroupChanged = true; 2769 //HasGroupChanged = true;
2084 //ScheduleGroupForFullUpdate(); 2770 //ScheduleGroupForFullUpdate();
2085 } 2771 }
@@ -2147,7 +2833,10 @@ namespace OpenSim.Region.Framework.Scenes
2147// m_log.DebugFormat( 2833// m_log.DebugFormat(
2148// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2834// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2149// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2835// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2150 2836
2837 if (m_rootPart.PhysActor != null)
2838 m_rootPart.PhysActor.Building = true;
2839
2151 linkPart.ClearUndoState(); 2840 linkPart.ClearUndoState();
2152 2841
2153 Quaternion worldRot = linkPart.GetWorldRotation(); 2842 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2207,6 +2896,14 @@ namespace OpenSim.Region.Framework.Scenes
2207 2896
2208 // When we delete a group, we currently have to force persist to the database if the object id has changed 2897 // When we delete a group, we currently have to force persist to the database if the object id has changed
2209 // (since delete works by deleting all rows which have a given object id) 2898 // (since delete works by deleting all rows which have a given object id)
2899
2900 // this is as it seems to be in sl now
2901 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2902 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2903
2904 if (m_rootPart.PhysActor != null)
2905 m_rootPart.PhysActor.Building = false;
2906
2210 objectGroup.HasGroupChangedDueToDelink = true; 2907 objectGroup.HasGroupChangedDueToDelink = true;
2211 2908
2212 return objectGroup; 2909 return objectGroup;
@@ -2218,6 +2915,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2915 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2916 public virtual void DetachFromBackup()
2220 { 2917 {
2918 m_scene.SceneGraph.FireDetachFromBackup(this);
2221 if (m_isBackedUp && Scene != null) 2919 if (m_isBackedUp && Scene != null)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2920 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2921
@@ -2236,7 +2934,8 @@ namespace OpenSim.Region.Framework.Scenes
2236 2934
2237 axPos *= parentRot; 2935 axPos *= parentRot;
2238 part.OffsetPosition = axPos; 2936 part.OffsetPosition = axPos;
2239 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2937 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2938 part.GroupPosition = newPos;
2240 part.OffsetPosition = Vector3.Zero; 2939 part.OffsetPosition = Vector3.Zero;
2241 part.RotationOffset = worldRot; 2940 part.RotationOffset = worldRot;
2242 2941
@@ -2247,20 +2946,20 @@ namespace OpenSim.Region.Framework.Scenes
2247 2946
2248 part.LinkNum = linkNum; 2947 part.LinkNum = linkNum;
2249 2948
2250 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2949 part.OffsetPosition = newPos - AbsolutePosition;
2251 2950
2252 Quaternion rootRotation = m_rootPart.RotationOffset; 2951 Quaternion rootRotation = m_rootPart.RotationOffset;
2253 2952
2254 Vector3 pos = part.OffsetPosition; 2953 Vector3 pos = part.OffsetPosition;
2255 pos *= Quaternion.Inverse(rootRotation); 2954 pos *= Quaternion.Conjugate(rootRotation);
2256 part.OffsetPosition = pos; 2955 part.OffsetPosition = pos;
2257 2956
2258 parentRot = m_rootPart.RotationOffset; 2957 parentRot = m_rootPart.RotationOffset;
2259 oldRot = part.RotationOffset; 2958 oldRot = part.RotationOffset;
2260 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2959 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2261 part.RotationOffset = newRot; 2960 part.RotationOffset = newRot;
2262 2961
2263 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2962 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2264 } 2963 }
2265 2964
2266 /// <summary> 2965 /// <summary>
@@ -2511,8 +3210,22 @@ namespace OpenSim.Region.Framework.Scenes
2511 } 3210 }
2512 } 3211 }
2513 3212
2514 for (int i = 0; i < parts.Length; i++) 3213 if (parts.Length > 1)
2515 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3214 {
3215 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3216
3217 for (int i = 0; i < parts.Length; i++)
3218 {
3219
3220 if (parts[i].UUID != m_rootPart.UUID)
3221 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3222 }
3223
3224 if (m_rootPart.PhysActor != null)
3225 m_rootPart.PhysActor.Building = false;
3226 }
3227 else
3228 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2516 } 3229 }
2517 } 3230 }
2518 3231
@@ -2525,6 +3238,17 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 3238 }
2526 } 3239 }
2527 3240
3241
3242
3243 /// <summary>
3244 /// Gets the number of parts
3245 /// </summary>
3246 /// <returns></returns>
3247 public int GetPartCount()
3248 {
3249 return Parts.Count();
3250 }
3251
2528 /// <summary> 3252 /// <summary>
2529 /// Update the texture entry for this part 3253 /// Update the texture entry for this part
2530 /// </summary> 3254 /// </summary>
@@ -2586,11 +3310,6 @@ namespace OpenSim.Region.Framework.Scenes
2586 /// <param name="scale"></param> 3310 /// <param name="scale"></param>
2587 public void GroupResize(Vector3 scale) 3311 public void GroupResize(Vector3 scale)
2588 { 3312 {
2589// m_log.DebugFormat(
2590// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2591
2592 RootPart.StoreUndoState(true);
2593
2594 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3313 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2595 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3314 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2596 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3315 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2617,7 +3336,6 @@ namespace OpenSim.Region.Framework.Scenes
2617 SceneObjectPart obPart = parts[i]; 3336 SceneObjectPart obPart = parts[i];
2618 if (obPart.UUID != m_rootPart.UUID) 3337 if (obPart.UUID != m_rootPart.UUID)
2619 { 3338 {
2620// obPart.IgnoreUndoUpdate = true;
2621 Vector3 oldSize = new Vector3(obPart.Scale); 3339 Vector3 oldSize = new Vector3(obPart.Scale);
2622 3340
2623 float f = 1.0f; 3341 float f = 1.0f;
@@ -2681,8 +3399,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 z *= a; 3399 z *= a;
2682 } 3400 }
2683 } 3401 }
2684
2685// obPart.IgnoreUndoUpdate = false;
2686 } 3402 }
2687 } 3403 }
2688 } 3404 }
@@ -2692,9 +3408,7 @@ namespace OpenSim.Region.Framework.Scenes
2692 prevScale.Y *= y; 3408 prevScale.Y *= y;
2693 prevScale.Z *= z; 3409 prevScale.Z *= z;
2694 3410
2695// RootPart.IgnoreUndoUpdate = true;
2696 RootPart.Resize(prevScale); 3411 RootPart.Resize(prevScale);
2697// RootPart.IgnoreUndoUpdate = false;
2698 3412
2699 parts = m_parts.GetArray(); 3413 parts = m_parts.GetArray();
2700 for (int i = 0; i < parts.Length; i++) 3414 for (int i = 0; i < parts.Length; i++)
@@ -2703,8 +3417,6 @@ namespace OpenSim.Region.Framework.Scenes
2703 3417
2704 if (obPart.UUID != m_rootPart.UUID) 3418 if (obPart.UUID != m_rootPart.UUID)
2705 { 3419 {
2706 obPart.IgnoreUndoUpdate = true;
2707
2708 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3420 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2709 currentpos.X *= x; 3421 currentpos.X *= x;
2710 currentpos.Y *= y; 3422 currentpos.Y *= y;
@@ -2717,16 +3429,12 @@ namespace OpenSim.Region.Framework.Scenes
2717 3429
2718 obPart.Resize(newSize); 3430 obPart.Resize(newSize);
2719 obPart.UpdateOffSet(currentpos); 3431 obPart.UpdateOffSet(currentpos);
2720
2721 obPart.IgnoreUndoUpdate = false;
2722 } 3432 }
2723 3433
2724// obPart.IgnoreUndoUpdate = false; 3434 HasGroupChanged = true;
2725// obPart.StoreUndoState(); 3435 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3436 ScheduleGroupForTerseUpdate();
2726 } 3437 }
2727
2728// m_log.DebugFormat(
2729// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2730 } 3438 }
2731 3439
2732 #endregion 3440 #endregion
@@ -2739,14 +3447,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 /// <param name="pos"></param> 3447 /// <param name="pos"></param>
2740 public void UpdateGroupPosition(Vector3 pos) 3448 public void UpdateGroupPosition(Vector3 pos)
2741 { 3449 {
2742// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2743
2744 RootPart.StoreUndoState(true);
2745
2746// SceneObjectPart[] parts = m_parts.GetArray();
2747// for (int i = 0; i < parts.Length; i++)
2748// parts[i].StoreUndoState();
2749
2750 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3450 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2751 { 3451 {
2752 if (IsAttachment) 3452 if (IsAttachment)
@@ -2779,21 +3479,17 @@ namespace OpenSim.Region.Framework.Scenes
2779 /// </summary> 3479 /// </summary>
2780 /// <param name="pos"></param> 3480 /// <param name="pos"></param>
2781 /// <param name="localID"></param> 3481 /// <param name="localID"></param>
3482 ///
3483
2782 public void UpdateSinglePosition(Vector3 pos, uint localID) 3484 public void UpdateSinglePosition(Vector3 pos, uint localID)
2783 { 3485 {
2784 SceneObjectPart part = GetPart(localID); 3486 SceneObjectPart part = GetPart(localID);
2785 3487
2786// SceneObjectPart[] parts = m_parts.GetArray();
2787// for (int i = 0; i < parts.Length; i++)
2788// parts[i].StoreUndoState();
2789
2790 if (part != null) 3488 if (part != null)
2791 { 3489 {
2792// m_log.DebugFormat( 3490// unlock parts position change
2793// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3491 if (m_rootPart.PhysActor != null)
2794 3492 m_rootPart.PhysActor.Building = true;
2795 part.StoreUndoState(false);
2796 part.IgnoreUndoUpdate = true;
2797 3493
2798 if (part.UUID == m_rootPart.UUID) 3494 if (part.UUID == m_rootPart.UUID)
2799 { 3495 {
@@ -2804,8 +3500,10 @@ namespace OpenSim.Region.Framework.Scenes
2804 part.UpdateOffSet(pos); 3500 part.UpdateOffSet(pos);
2805 } 3501 }
2806 3502
3503 if (m_rootPart.PhysActor != null)
3504 m_rootPart.PhysActor.Building = false;
3505
2807 HasGroupChanged = true; 3506 HasGroupChanged = true;
2808 part.IgnoreUndoUpdate = false;
2809 } 3507 }
2810 } 3508 }
2811 3509
@@ -2815,13 +3513,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 /// <param name="pos"></param> 3513 /// <param name="pos"></param>
2816 public void UpdateRootPosition(Vector3 pos) 3514 public void UpdateRootPosition(Vector3 pos)
2817 { 3515 {
2818// m_log.DebugFormat( 3516 // needs to be called with phys building true
2819// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2820
2821// SceneObjectPart[] parts = m_parts.GetArray();
2822// for (int i = 0; i < parts.Length; i++)
2823// parts[i].StoreUndoState();
2824
2825 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3517 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2826 Vector3 oldPos = 3518 Vector3 oldPos =
2827 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3519 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2844,7 +3536,14 @@ namespace OpenSim.Region.Framework.Scenes
2844 AbsolutePosition = newPos; 3536 AbsolutePosition = newPos;
2845 3537
2846 HasGroupChanged = true; 3538 HasGroupChanged = true;
2847 ScheduleGroupForTerseUpdate(); 3539 if (m_rootPart.Undoing)
3540 {
3541 ScheduleGroupForFullUpdate();
3542 }
3543 else
3544 {
3545 ScheduleGroupForTerseUpdate();
3546 }
2848 } 3547 }
2849 3548
2850 #endregion 3549 #endregion
@@ -2857,24 +3556,16 @@ namespace OpenSim.Region.Framework.Scenes
2857 /// <param name="rot"></param> 3556 /// <param name="rot"></param>
2858 public void UpdateGroupRotationR(Quaternion rot) 3557 public void UpdateGroupRotationR(Quaternion rot)
2859 { 3558 {
2860// m_log.DebugFormat(
2861// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2862
2863// SceneObjectPart[] parts = m_parts.GetArray();
2864// for (int i = 0; i < parts.Length; i++)
2865// parts[i].StoreUndoState();
2866
2867 m_rootPart.StoreUndoState(true);
2868
2869 m_rootPart.UpdateRotation(rot); 3559 m_rootPart.UpdateRotation(rot);
2870 3560
3561/* this is done by rootpart RotationOffset set called by UpdateRotation
2871 PhysicsActor actor = m_rootPart.PhysActor; 3562 PhysicsActor actor = m_rootPart.PhysActor;
2872 if (actor != null) 3563 if (actor != null)
2873 { 3564 {
2874 actor.Orientation = m_rootPart.RotationOffset; 3565 actor.Orientation = m_rootPart.RotationOffset;
2875 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3566 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2876 } 3567 }
2877 3568*/
2878 HasGroupChanged = true; 3569 HasGroupChanged = true;
2879 ScheduleGroupForTerseUpdate(); 3570 ScheduleGroupForTerseUpdate();
2880 } 3571 }
@@ -2886,16 +3577,6 @@ namespace OpenSim.Region.Framework.Scenes
2886 /// <param name="rot"></param> 3577 /// <param name="rot"></param>
2887 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3578 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2888 { 3579 {
2889// m_log.DebugFormat(
2890// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2891
2892// SceneObjectPart[] parts = m_parts.GetArray();
2893// for (int i = 0; i < parts.Length; i++)
2894// parts[i].StoreUndoState();
2895
2896 RootPart.StoreUndoState(true);
2897 RootPart.IgnoreUndoUpdate = true;
2898
2899 m_rootPart.UpdateRotation(rot); 3580 m_rootPart.UpdateRotation(rot);
2900 3581
2901 PhysicsActor actor = m_rootPart.PhysActor; 3582 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2909,8 +3590,6 @@ namespace OpenSim.Region.Framework.Scenes
2909 3590
2910 HasGroupChanged = true; 3591 HasGroupChanged = true;
2911 ScheduleGroupForTerseUpdate(); 3592 ScheduleGroupForTerseUpdate();
2912
2913 RootPart.IgnoreUndoUpdate = false;
2914 } 3593 }
2915 3594
2916 /// <summary> 3595 /// <summary>
@@ -2923,13 +3602,11 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart part = GetPart(localID); 3602 SceneObjectPart part = GetPart(localID);
2924 3603
2925 SceneObjectPart[] parts = m_parts.GetArray(); 3604 SceneObjectPart[] parts = m_parts.GetArray();
2926 for (int i = 0; i < parts.Length; i++)
2927 parts[i].StoreUndoState();
2928 3605
2929 if (part != null) 3606 if (part != null)
2930 { 3607 {
2931// m_log.DebugFormat( 3608 if (m_rootPart.PhysActor != null)
2932// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3609 m_rootPart.PhysActor.Building = true;
2933 3610
2934 if (part.UUID == m_rootPart.UUID) 3611 if (part.UUID == m_rootPart.UUID)
2935 { 3612 {
@@ -2939,6 +3616,9 @@ namespace OpenSim.Region.Framework.Scenes
2939 { 3616 {
2940 part.UpdateRotation(rot); 3617 part.UpdateRotation(rot);
2941 } 3618 }
3619
3620 if (m_rootPart.PhysActor != null)
3621 m_rootPart.PhysActor.Building = false;
2942 } 3622 }
2943 } 3623 }
2944 3624
@@ -2952,12 +3632,8 @@ namespace OpenSim.Region.Framework.Scenes
2952 SceneObjectPart part = GetPart(localID); 3632 SceneObjectPart part = GetPart(localID);
2953 if (part != null) 3633 if (part != null)
2954 { 3634 {
2955// m_log.DebugFormat( 3635 if (m_rootPart.PhysActor != null)
2956// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3636 m_rootPart.PhysActor.Building = true;
2957// part.Name, part.LocalId, rot);
2958
2959 part.StoreUndoState();
2960 part.IgnoreUndoUpdate = true;
2961 3637
2962 if (part.UUID == m_rootPart.UUID) 3638 if (part.UUID == m_rootPart.UUID)
2963 { 3639 {
@@ -2970,7 +3646,8 @@ namespace OpenSim.Region.Framework.Scenes
2970 part.OffsetPosition = pos; 3646 part.OffsetPosition = pos;
2971 } 3647 }
2972 3648
2973 part.IgnoreUndoUpdate = false; 3649 if (m_rootPart.PhysActor != null)
3650 m_rootPart.PhysActor.Building = false;
2974 } 3651 }
2975 } 3652 }
2976 3653
@@ -2980,15 +3657,12 @@ namespace OpenSim.Region.Framework.Scenes
2980 /// <param name="rot"></param> 3657 /// <param name="rot"></param>
2981 public void UpdateRootRotation(Quaternion rot) 3658 public void UpdateRootRotation(Quaternion rot)
2982 { 3659 {
2983// m_log.DebugFormat( 3660 // needs to be called with phys building true
2984// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2985// Name, LocalId, rot);
2986
2987 Quaternion axRot = rot; 3661 Quaternion axRot = rot;
2988 Quaternion oldParentRot = m_rootPart.RotationOffset; 3662 Quaternion oldParentRot = m_rootPart.RotationOffset;
2989 3663
2990 m_rootPart.StoreUndoState(); 3664 //Don't use UpdateRotation because it schedules an update prematurely
2991 m_rootPart.UpdateRotation(rot); 3665 m_rootPart.RotationOffset = rot;
2992 3666
2993 PhysicsActor pa = m_rootPart.PhysActor; 3667 PhysicsActor pa = m_rootPart.PhysActor;
2994 3668
@@ -3004,35 +3678,144 @@ namespace OpenSim.Region.Framework.Scenes
3004 SceneObjectPart prim = parts[i]; 3678 SceneObjectPart prim = parts[i];
3005 if (prim.UUID != m_rootPart.UUID) 3679 if (prim.UUID != m_rootPart.UUID)
3006 { 3680 {
3007 prim.IgnoreUndoUpdate = true; 3681 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3682 NewRot = Quaternion.Inverse(axRot) * NewRot;
3683 prim.RotationOffset = NewRot;
3684
3008 Vector3 axPos = prim.OffsetPosition; 3685 Vector3 axPos = prim.OffsetPosition;
3686
3009 axPos *= oldParentRot; 3687 axPos *= oldParentRot;
3010 axPos *= Quaternion.Inverse(axRot); 3688 axPos *= Quaternion.Inverse(axRot);
3011 prim.OffsetPosition = axPos; 3689 prim.OffsetPosition = axPos;
3012 Quaternion primsRot = prim.RotationOffset; 3690 }
3013 Quaternion newRot = oldParentRot * primsRot; 3691 }
3014 newRot = Quaternion.Inverse(axRot) * newRot;
3015 prim.RotationOffset = newRot;
3016 prim.ScheduleTerseUpdate();
3017 prim.IgnoreUndoUpdate = false;
3018 }
3019 }
3020
3021// for (int i = 0; i < parts.Length; i++)
3022// {
3023// SceneObjectPart childpart = parts[i];
3024// if (childpart != m_rootPart)
3025// {
3026//// childpart.IgnoreUndoUpdate = false;
3027//// childpart.StoreUndoState();
3028// }
3029// }
3030 3692
3031 m_rootPart.ScheduleTerseUpdate(); 3693 HasGroupChanged = true;
3694 ScheduleGroupForFullUpdate();
3695 }
3032 3696
3033// m_log.DebugFormat( 3697 private enum updatetype :int
3034// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3698 {
3035// Name, LocalId, rot); 3699 none = 0,
3700 partterse = 1,
3701 partfull = 2,
3702 groupterse = 3,
3703 groupfull = 4
3704 }
3705
3706 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3707 {
3708 // TODO this still as excessive *.Schedule*Update()s
3709
3710 if (part != null && part.ParentGroup != null)
3711 {
3712 ObjectChangeType change = data.change;
3713 bool togroup = ((change & ObjectChangeType.Group) != 0);
3714 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3715
3716 SceneObjectGroup group = part.ParentGroup;
3717 PhysicsActor pha = group.RootPart.PhysActor;
3718
3719 updatetype updateType = updatetype.none;
3720
3721 if (togroup)
3722 {
3723 // related to group
3724 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3725 {
3726 if ((change & ObjectChangeType.Rotation) != 0)
3727 {
3728 group.RootPart.UpdateRotation(data.rotation);
3729 updateType = updatetype.none;
3730 }
3731 if ((change & ObjectChangeType.Position) != 0)
3732 {
3733 UpdateGroupPosition(data.position);
3734 updateType = updatetype.groupterse;
3735 }
3736 else
3737 // ugly rotation update of all parts
3738 {
3739 group.AbsolutePosition = AbsolutePosition;
3740 }
3741
3742 }
3743 if ((change & ObjectChangeType.Scale) != 0)
3744 {
3745 if (pha != null)
3746 pha.Building = true;
3747
3748 group.GroupResize(data.scale);
3749 updateType = updatetype.none;
3750
3751 if (pha != null)
3752 pha.Building = false;
3753 }
3754 }
3755 else
3756 {
3757 // related to single prim in a link-set ( ie group)
3758 if (pha != null)
3759 pha.Building = true;
3760
3761 // root part is special
3762 // parts offset positions or rotations need to change also
3763
3764 if (part == group.RootPart)
3765 {
3766 if ((change & ObjectChangeType.Rotation) != 0)
3767 group.UpdateRootRotation(data.rotation);
3768 if ((change & ObjectChangeType.Position) != 0)
3769 group.UpdateRootPosition(data.position);
3770 if ((change & ObjectChangeType.Scale) != 0)
3771 part.Resize(data.scale);
3772 }
3773 else
3774 {
3775 if ((change & ObjectChangeType.Position) != 0)
3776 {
3777 part.OffsetPosition = data.position;
3778 updateType = updatetype.partterse;
3779 }
3780 if ((change & ObjectChangeType.Rotation) != 0)
3781 {
3782 part.UpdateRotation(data.rotation);
3783 updateType = updatetype.none;
3784 }
3785 if ((change & ObjectChangeType.Scale) != 0)
3786 {
3787 part.Resize(data.scale);
3788 updateType = updatetype.none;
3789 }
3790 }
3791
3792 if (pha != null)
3793 pha.Building = false;
3794 }
3795
3796 if (updateType != updatetype.none)
3797 {
3798 group.HasGroupChanged = true;
3799
3800 switch (updateType)
3801 {
3802 case updatetype.partterse:
3803 part.ScheduleTerseUpdate();
3804 break;
3805 case updatetype.partfull:
3806 part.ScheduleFullUpdate();
3807 break;
3808 case updatetype.groupterse:
3809 group.ScheduleGroupForTerseUpdate();
3810 break;
3811 case updatetype.groupfull:
3812 group.ScheduleGroupForFullUpdate();
3813 break;
3814 default:
3815 break;
3816 }
3817 }
3818 }
3036 } 3819 }
3037 3820
3038 #endregion 3821 #endregion
@@ -3252,11 +4035,50 @@ namespace OpenSim.Region.Framework.Scenes
3252 } 4035 }
3253 } 4036 }
3254 } 4037 }
3255 4038
4039 public Vector3 GetGeometricCenter()
4040 {
4041 // this is not real geometric center but a average of positions relative to root prim acording to
4042 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4043 // ignoring tortured prims details since sl also seems to ignore
4044 // so no real use in doing it on physics
4045
4046 Vector3 gc = Vector3.Zero;
4047
4048 int nparts = m_parts.Count;
4049 if (nparts <= 1)
4050 return gc;
4051
4052 SceneObjectPart[] parts = m_parts.GetArray();
4053 nparts = parts.Length; // just in case it changed
4054 if (nparts <= 1)
4055 return gc;
4056
4057 Quaternion parentRot = RootPart.RotationOffset;
4058 Vector3 pPos;
4059
4060 // average all parts positions
4061 for (int i = 0; i < nparts; i++)
4062 {
4063 // do it directly
4064 // gc += parts[i].GetWorldPosition();
4065 if (parts[i] != RootPart)
4066 {
4067 pPos = parts[i].OffsetPosition;
4068 gc += pPos;
4069 }
4070
4071 }
4072 gc /= nparts;
4073
4074 // relative to root:
4075// gc -= AbsolutePosition;
4076 return gc;
4077 }
4078
3256 public float GetMass() 4079 public float GetMass()
3257 { 4080 {
3258 float retmass = 0f; 4081 float retmass = 0f;
3259
3260 SceneObjectPart[] parts = m_parts.GetArray(); 4082 SceneObjectPart[] parts = m_parts.GetArray();
3261 for (int i = 0; i < parts.Length; i++) 4083 for (int i = 0; i < parts.Length; i++)
3262 retmass += parts[i].GetMass(); 4084 retmass += parts[i].GetMass();
@@ -3264,6 +4086,39 @@ namespace OpenSim.Region.Framework.Scenes
3264 return retmass; 4086 return retmass;
3265 } 4087 }
3266 4088
4089 // center of mass of full object
4090 public Vector3 GetCenterOfMass()
4091 {
4092 PhysicsActor pa = RootPart.PhysActor;
4093
4094 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4095 {
4096 // physics knows better about center of mass of physical prims
4097 Vector3 tmp = pa.CenterOfMass;
4098 return tmp;
4099 }
4100
4101 Vector3 Ptot = Vector3.Zero;
4102 float totmass = 0f;
4103 float m;
4104
4105 SceneObjectPart[] parts = m_parts.GetArray();
4106 for (int i = 0; i < parts.Length; i++)
4107 {
4108 m = parts[i].GetMass();
4109 Ptot += parts[i].GetPartCenterOfMass() * m;
4110 totmass += m;
4111 }
4112
4113 if (totmass == 0)
4114 totmass = 0;
4115 else
4116 totmass = 1 / totmass;
4117 Ptot *= totmass;
4118
4119 return Ptot;
4120 }
4121
3267 /// <summary> 4122 /// <summary>
3268 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4123 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3269 /// the physics engine can use it. 4124 /// the physics engine can use it.
@@ -3417,6 +4272,14 @@ namespace OpenSim.Region.Framework.Scenes
3417 FromItemID = uuid; 4272 FromItemID = uuid;
3418 } 4273 }
3419 4274
4275 public void ResetOwnerChangeFlag()
4276 {
4277 ForEachPart(delegate(SceneObjectPart part)
4278 {
4279 part.ResetOwnerChangeFlag();
4280 });
4281 }
4282
3420 #endregion 4283 #endregion
3421 } 4284 }
3422} 4285}