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.cs1289
1 files changed, 1072 insertions, 217 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 2686004..dce20c1 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,29 @@ 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 // agent.Reset();
639 //else // Not successful
640 // agent.RestoreInCurrentScene();
641
642 // In any case
643 agent.IsInTransit = false;
644
645 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
646 }
647
446 public override uint LocalId 648 public override uint LocalId
447 { 649 {
448 get { return m_rootPart.LocalId; } 650 get { return m_rootPart.LocalId; }
@@ -524,6 +726,11 @@ namespace OpenSim.Region.Framework.Scenes
524 m_isSelected = value; 726 m_isSelected = value;
525 // Tell physics engine that group is selected 727 // Tell physics engine that group is selected
526 728
729 // this is not right
730 // but ode engines should only really need to know about root part
731 // so they can put entire object simulation on hold and not colliding
732 // keep as was for now
733
527 PhysicsActor pa = m_rootPart.PhysActor; 734 PhysicsActor pa = m_rootPart.PhysActor;
528 if (pa != null) 735 if (pa != null)
529 { 736 {
@@ -540,6 +747,42 @@ namespace OpenSim.Region.Framework.Scenes
540 childPa.Selected = value; 747 childPa.Selected = value;
541 } 748 }
542 } 749 }
750 if (RootPart.KeyframeMotion != null)
751 RootPart.KeyframeMotion.Selected = value;
752 }
753 }
754
755 public void PartSelectChanged(bool partSelect)
756 {
757 // any part selected makes group selected
758 if (m_isSelected == partSelect)
759 return;
760
761 if (partSelect)
762 {
763 IsSelected = partSelect;
764// if (!IsAttachment)
765// ScheduleGroupForFullUpdate();
766 }
767 else
768 {
769 // bad bad bad 2 heavy for large linksets
770 // since viewer does send lot of (un)selects
771 // this needs to be replaced by a specific list or count ?
772 // but that will require extra code in several places
773
774 SceneObjectPart[] parts = m_parts.GetArray();
775 for (int i = 0; i < parts.Length; i++)
776 {
777 SceneObjectPart part = parts[i];
778 if (part.IsSelected)
779 return;
780 }
781 IsSelected = partSelect;
782 if (!IsAttachment)
783 {
784 ScheduleGroupForFullUpdate();
785 }
543 } 786 }
544 } 787 }
545 788
@@ -617,6 +860,7 @@ namespace OpenSim.Region.Framework.Scenes
617 /// </summary> 860 /// </summary>
618 public SceneObjectGroup() 861 public SceneObjectGroup()
619 { 862 {
863
620 } 864 }
621 865
622 /// <summary> 866 /// <summary>
@@ -633,7 +877,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// Constructor. This object is added to the scene later via AttachToScene() 877 /// Constructor. This object is added to the scene later via AttachToScene()
634 /// </summary> 878 /// </summary>
635 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 879 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
636 { 880 {
637 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 881 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
638 } 882 }
639 883
@@ -669,6 +913,9 @@ namespace OpenSim.Region.Framework.Scenes
669 /// </summary> 913 /// </summary>
670 public virtual void AttachToBackup() 914 public virtual void AttachToBackup()
671 { 915 {
916 if (IsAttachment) return;
917 m_scene.SceneGraph.FireAttachToBackup(this);
918
672 if (InSceneBackup) 919 if (InSceneBackup)
673 { 920 {
674 //m_log.DebugFormat( 921 //m_log.DebugFormat(
@@ -711,6 +958,13 @@ namespace OpenSim.Region.Framework.Scenes
711 958
712 ApplyPhysics(); 959 ApplyPhysics();
713 960
961 if (RootPart.PhysActor != null)
962 RootPart.Force = RootPart.Force;
963 if (RootPart.PhysActor != null)
964 RootPart.Torque = RootPart.Torque;
965 if (RootPart.PhysActor != null)
966 RootPart.Buoyancy = RootPart.Buoyancy;
967
714 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 968 // 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. 969 // for the same object with very different properties. The caller must schedule the update.
716 //ScheduleGroupForFullUpdate(); 970 //ScheduleGroupForFullUpdate();
@@ -726,6 +980,10 @@ namespace OpenSim.Region.Framework.Scenes
726 EntityIntersection result = new EntityIntersection(); 980 EntityIntersection result = new EntityIntersection();
727 981
728 SceneObjectPart[] parts = m_parts.GetArray(); 982 SceneObjectPart[] parts = m_parts.GetArray();
983
984 // Find closest hit here
985 float idist = float.MaxValue;
986
729 for (int i = 0; i < parts.Length; i++) 987 for (int i = 0; i < parts.Length; i++)
730 { 988 {
731 SceneObjectPart part = parts[i]; 989 SceneObjectPart part = parts[i];
@@ -740,11 +998,6 @@ namespace OpenSim.Region.Framework.Scenes
740 998
741 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 999 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
742 1000
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) 1001 if (inter.HitTF)
749 { 1002 {
750 // We need to find the closest prim to return to the testcaller along the ray 1003 // We need to find the closest prim to return to the testcaller along the ray
@@ -755,10 +1008,11 @@ namespace OpenSim.Region.Framework.Scenes
755 result.obj = part; 1008 result.obj = part;
756 result.normal = inter.normal; 1009 result.normal = inter.normal;
757 result.distance = inter.distance; 1010 result.distance = inter.distance;
1011
1012 idist = inter.distance;
758 } 1013 }
759 } 1014 }
760 } 1015 }
761
762 return result; 1016 return result;
763 } 1017 }
764 1018
@@ -770,25 +1024,27 @@ namespace OpenSim.Region.Framework.Scenes
770 /// <returns></returns> 1024 /// <returns></returns>
771 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1025 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
772 { 1026 {
773 maxX = -256f; 1027 maxX = float.MinValue;
774 maxY = -256f; 1028 maxY = float.MinValue;
775 maxZ = -256f; 1029 maxZ = float.MinValue;
776 minX = 256f; 1030 minX = float.MaxValue;
777 minY = 256f; 1031 minY = float.MaxValue;
778 minZ = 8192f; 1032 minZ = float.MaxValue;
779 1033
780 SceneObjectPart[] parts = m_parts.GetArray(); 1034 SceneObjectPart[] parts = m_parts.GetArray();
781 for (int i = 0; i < parts.Length; i++) 1035 foreach (SceneObjectPart part in parts)
782 { 1036 {
783 SceneObjectPart part = parts[i];
784
785 Vector3 worldPos = part.GetWorldPosition(); 1037 Vector3 worldPos = part.GetWorldPosition();
786 Vector3 offset = worldPos - AbsolutePosition; 1038 Vector3 offset = worldPos - AbsolutePosition;
787 Quaternion worldRot; 1039 Quaternion worldRot;
788 if (part.ParentID == 0) 1040 if (part.ParentID == 0)
1041 {
789 worldRot = part.RotationOffset; 1042 worldRot = part.RotationOffset;
1043 }
790 else 1044 else
1045 {
791 worldRot = part.GetWorldRotation(); 1046 worldRot = part.GetWorldRotation();
1047 }
792 1048
793 Vector3 frontTopLeft; 1049 Vector3 frontTopLeft;
794 Vector3 frontTopRight; 1050 Vector3 frontTopRight;
@@ -800,6 +1056,8 @@ namespace OpenSim.Region.Framework.Scenes
800 Vector3 backBottomLeft; 1056 Vector3 backBottomLeft;
801 Vector3 backBottomRight; 1057 Vector3 backBottomRight;
802 1058
1059 // Vector3[] corners = new Vector3[8];
1060
803 Vector3 orig = Vector3.Zero; 1061 Vector3 orig = Vector3.Zero;
804 1062
805 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1063 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -834,6 +1092,38 @@ namespace OpenSim.Region.Framework.Scenes
834 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1092 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
835 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1093 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
836 1094
1095
1096
1097 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1098 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1099 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1100 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1101 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1102 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1103 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1104 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1105
1106 //for (int i = 0; i < 8; i++)
1107 //{
1108 // corners[i] = corners[i] * worldRot;
1109 // corners[i] += offset;
1110
1111 // if (corners[i].X > maxX)
1112 // maxX = corners[i].X;
1113 // if (corners[i].X < minX)
1114 // minX = corners[i].X;
1115
1116 // if (corners[i].Y > maxY)
1117 // maxY = corners[i].Y;
1118 // if (corners[i].Y < minY)
1119 // minY = corners[i].Y;
1120
1121 // if (corners[i].Z > maxZ)
1122 // maxZ = corners[i].Y;
1123 // if (corners[i].Z < minZ)
1124 // minZ = corners[i].Z;
1125 //}
1126
837 frontTopLeft = frontTopLeft * worldRot; 1127 frontTopLeft = frontTopLeft * worldRot;
838 frontTopRight = frontTopRight * worldRot; 1128 frontTopRight = frontTopRight * worldRot;
839 frontBottomLeft = frontBottomLeft * worldRot; 1129 frontBottomLeft = frontBottomLeft * worldRot;
@@ -855,6 +1145,15 @@ namespace OpenSim.Region.Framework.Scenes
855 backTopLeft += offset; 1145 backTopLeft += offset;
856 backTopRight += offset; 1146 backTopRight += offset;
857 1147
1148 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1149 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1150 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1151 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1152 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1153 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1154 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1155 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1156
858 if (frontTopRight.X > maxX) 1157 if (frontTopRight.X > maxX)
859 maxX = frontTopRight.X; 1158 maxX = frontTopRight.X;
860 if (frontTopLeft.X > maxX) 1159 if (frontTopLeft.X > maxX)
@@ -998,17 +1297,118 @@ namespace OpenSim.Region.Framework.Scenes
998 1297
999 #endregion 1298 #endregion
1000 1299
1300 public void GetResourcesCosts(SceneObjectPart apart,
1301 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1302 {
1303 // this information may need to be cached
1304
1305 float cost;
1306 float tmpcost;
1307
1308 bool ComplexCost = false;
1309
1310 SceneObjectPart p;
1311 SceneObjectPart[] parts;
1312
1313 lock (m_parts)
1314 {
1315 parts = m_parts.GetArray();
1316 }
1317
1318 int nparts = parts.Length;
1319
1320
1321 for (int i = 0; i < nparts; i++)
1322 {
1323 p = parts[i];
1324
1325 if (p.UsesComplexCost)
1326 {
1327 ComplexCost = true;
1328 break;
1329 }
1330 }
1331
1332 if (ComplexCost)
1333 {
1334 linksetResCost = 0;
1335 linksetPhysCost = 0;
1336 partCost = 0;
1337 partPhysCost = 0;
1338
1339 for (int i = 0; i < nparts; i++)
1340 {
1341 p = parts[i];
1342
1343 cost = p.StreamingCost;
1344 tmpcost = p.SimulationCost;
1345 if (tmpcost > cost)
1346 cost = tmpcost;
1347 tmpcost = p.PhysicsCost;
1348 if (tmpcost > cost)
1349 cost = tmpcost;
1350
1351 linksetPhysCost += tmpcost;
1352 linksetResCost += cost;
1353
1354 if (p == apart)
1355 {
1356 partCost = cost;
1357 partPhysCost = tmpcost;
1358 }
1359 }
1360 }
1361 else
1362 {
1363 partPhysCost = 1.0f;
1364 partCost = 1.0f;
1365 linksetResCost = (float)nparts;
1366 linksetPhysCost = linksetResCost;
1367 }
1368 }
1369
1370 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1371 {
1372 SceneObjectPart p;
1373 SceneObjectPart[] parts;
1374
1375 lock (m_parts)
1376 {
1377 parts = m_parts.GetArray();
1378 }
1379
1380 int nparts = parts.Length;
1381
1382 PhysCost = 0;
1383 StreamCost = 0;
1384 SimulCost = 0;
1385
1386 for (int i = 0; i < nparts; i++)
1387 {
1388 p = parts[i];
1389
1390 StreamCost += p.StreamingCost;
1391 SimulCost += p.SimulationCost;
1392 PhysCost += p.PhysicsCost;
1393 }
1394 }
1395
1001 public void SaveScriptedState(XmlTextWriter writer) 1396 public void SaveScriptedState(XmlTextWriter writer)
1002 { 1397 {
1398 SaveScriptedState(writer, false);
1399 }
1400
1401 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1402 {
1003 XmlDocument doc = new XmlDocument(); 1403 XmlDocument doc = new XmlDocument();
1004 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1404 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1005 1405
1006 SceneObjectPart[] parts = m_parts.GetArray(); 1406 SceneObjectPart[] parts = m_parts.GetArray();
1007 for (int i = 0; i < parts.Length; i++) 1407 for (int i = 0; i < parts.Length; i++)
1008 { 1408 {
1009 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1409 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1010 foreach (KeyValuePair<UUID, string> kvp in pstates) 1410 foreach (KeyValuePair<UUID, string> kvp in pstates)
1011 states.Add(kvp.Key, kvp.Value); 1411 states[kvp.Key] = kvp.Value;
1012 } 1412 }
1013 1413
1014 if (states.Count > 0) 1414 if (states.Count > 0)
@@ -1028,6 +1428,169 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1428 }
1029 1429
1030 /// <summary> 1430 /// <summary>
1431 /// Add the avatar to this linkset (avatar is sat).
1432 /// </summary>
1433 /// <param name="agentID"></param>
1434 public void AddAvatar(UUID agentID)
1435 {
1436 ScenePresence presence;
1437 if (m_scene.TryGetScenePresence(agentID, out presence))
1438 {
1439 if (!m_linkedAvatars.Contains(presence))
1440 {
1441 m_linkedAvatars.Add(presence);
1442 }
1443 }
1444 }
1445
1446 /// <summary>
1447 /// Delete the avatar from this linkset (avatar is unsat).
1448 /// </summary>
1449 /// <param name="agentID"></param>
1450 public void DeleteAvatar(UUID agentID)
1451 {
1452 ScenePresence presence;
1453 if (m_scene.TryGetScenePresence(agentID, out presence))
1454 {
1455 if (m_linkedAvatars.Contains(presence))
1456 {
1457 m_linkedAvatars.Remove(presence);
1458 }
1459 }
1460 }
1461
1462 /// <summary>
1463 /// Returns the list of linked presences (avatars sat on this group)
1464 /// </summary>
1465 /// <param name="agentID"></param>
1466 public List<ScenePresence> GetLinkedAvatars()
1467 {
1468 return m_linkedAvatars;
1469 }
1470
1471 /// <summary>
1472 /// Attach this scene object to the given avatar.
1473 /// </summary>
1474 /// <param name="agentID"></param>
1475 /// <param name="attachmentpoint"></param>
1476 /// <param name="AttachOffset"></param>
1477 private void AttachToAgent(
1478 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1479 {
1480 if (avatar != null)
1481 {
1482 // don't attach attachments to child agents
1483 if (avatar.IsChildAgent) return;
1484
1485 // Remove from database and parcel prim count
1486 m_scene.DeleteFromStorage(so.UUID);
1487 m_scene.EventManager.TriggerParcelPrimCountTainted();
1488
1489 so.AttachedAvatar = avatar.UUID;
1490
1491 if (so.RootPart.PhysActor != null)
1492 {
1493 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1494 so.RootPart.PhysActor = null;
1495 }
1496
1497 so.AbsolutePosition = attachOffset;
1498 so.RootPart.AttachedPos = attachOffset;
1499 so.IsAttachment = true;
1500 so.RootPart.SetParentLocalId(avatar.LocalId);
1501 so.AttachmentPoint = attachmentpoint;
1502
1503 avatar.AddAttachment(this);
1504
1505 if (!silent)
1506 {
1507 // Killing it here will cause the client to deselect it
1508 // It then reappears on the avatar, deselected
1509 // through the full update below
1510 //
1511 if (IsSelected)
1512 {
1513 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1514 }
1515
1516 IsSelected = false; // fudge....
1517 ScheduleGroupForFullUpdate();
1518 }
1519 }
1520 else
1521 {
1522 m_log.WarnFormat(
1523 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1524 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1525 }
1526 }
1527
1528 public byte GetAttachmentPoint()
1529 {
1530 return m_rootPart.Shape.State;
1531 }
1532
1533 public void DetachToGround()
1534 {
1535 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1536 if (avatar == null)
1537 return;
1538
1539 avatar.RemoveAttachment(this);
1540
1541 Vector3 detachedpos = new Vector3(127f,127f,127f);
1542 if (avatar == null)
1543 return;
1544
1545 detachedpos = avatar.AbsolutePosition;
1546 FromItemID = UUID.Zero;
1547
1548 AbsolutePosition = detachedpos;
1549 AttachedAvatar = UUID.Zero;
1550
1551 //SceneObjectPart[] parts = m_parts.GetArray();
1552 //for (int i = 0; i < parts.Length; i++)
1553 // parts[i].AttachedAvatar = UUID.Zero;
1554
1555 m_rootPart.SetParentLocalId(0);
1556 AttachmentPoint = (byte)0;
1557 // must check if buildind should be true or false here
1558 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1559 HasGroupChanged = true;
1560 RootPart.Rezzed = DateTime.Now;
1561 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1562 AttachToBackup();
1563 m_scene.EventManager.TriggerParcelPrimCountTainted();
1564 m_rootPart.ScheduleFullUpdate();
1565 m_rootPart.ClearUndoState();
1566 }
1567
1568 public void DetachToInventoryPrep()
1569 {
1570 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1571 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1572 if (avatar != null)
1573 {
1574 //detachedpos = avatar.AbsolutePosition;
1575 avatar.RemoveAttachment(this);
1576 }
1577
1578 AttachedAvatar = UUID.Zero;
1579
1580 /*SceneObjectPart[] parts = m_parts.GetArray();
1581 for (int i = 0; i < parts.Length; i++)
1582 parts[i].AttachedAvatar = UUID.Zero;*/
1583
1584 m_rootPart.SetParentLocalId(0);
1585 //m_rootPart.SetAttachmentPoint((byte)0);
1586 IsAttachment = false;
1587 AbsolutePosition = m_rootPart.AttachedPos;
1588 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1589 //AttachToBackup();
1590 //m_rootPart.ScheduleFullUpdate();
1591 }
1592
1593 /// <summary>
1031 /// 1594 ///
1032 /// </summary> 1595 /// </summary>
1033 /// <param name="part"></param> 1596 /// <param name="part"></param>
@@ -1077,7 +1640,10 @@ namespace OpenSim.Region.Framework.Scenes
1077 public void AddPart(SceneObjectPart part) 1640 public void AddPart(SceneObjectPart part)
1078 { 1641 {
1079 part.SetParent(this); 1642 part.SetParent(this);
1080 part.LinkNum = m_parts.Add(part.UUID, part); 1643 m_parts.Add(part.UUID, part);
1644
1645 part.LinkNum = m_parts.Count;
1646
1081 if (part.LinkNum == 2) 1647 if (part.LinkNum == 2)
1082 RootPart.LinkNum = 1; 1648 RootPart.LinkNum = 1;
1083 } 1649 }
@@ -1165,7 +1731,7 @@ namespace OpenSim.Region.Framework.Scenes
1165// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1731// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1166// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1732// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1167 1733
1168 part.StoreUndoState(); 1734// part.StoreUndoState();
1169 part.OnGrab(offsetPos, remoteClient); 1735 part.OnGrab(offsetPos, remoteClient);
1170 } 1736 }
1171 1737
@@ -1185,6 +1751,11 @@ namespace OpenSim.Region.Framework.Scenes
1185 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1751 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1186 public void DeleteGroupFromScene(bool silent) 1752 public void DeleteGroupFromScene(bool silent)
1187 { 1753 {
1754 // We need to keep track of this state in case this group is still queued for backup.
1755 IsDeleted = true;
1756
1757 DetachFromBackup();
1758
1188 SceneObjectPart[] parts = m_parts.GetArray(); 1759 SceneObjectPart[] parts = m_parts.GetArray();
1189 for (int i = 0; i < parts.Length; i++) 1760 for (int i = 0; i < parts.Length; i++)
1190 { 1761 {
@@ -1207,6 +1778,8 @@ namespace OpenSim.Region.Framework.Scenes
1207 } 1778 }
1208 }); 1779 });
1209 } 1780 }
1781
1782
1210 } 1783 }
1211 1784
1212 public void AddScriptLPS(int count) 1785 public void AddScriptLPS(int count)
@@ -1276,28 +1849,43 @@ namespace OpenSim.Region.Framework.Scenes
1276 /// </summary> 1849 /// </summary>
1277 public void ApplyPhysics() 1850 public void ApplyPhysics()
1278 { 1851 {
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(); 1852 SceneObjectPart[] parts = m_parts.GetArray();
1284 if (parts.Length > 1) 1853 if (parts.Length > 1)
1285 { 1854 {
1855 ResetChildPrimPhysicsPositions();
1856
1857 // Apply physics to the root prim
1858 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1859
1860
1286 for (int i = 0; i < parts.Length; i++) 1861 for (int i = 0; i < parts.Length; i++)
1287 { 1862 {
1288 SceneObjectPart part = parts[i]; 1863 SceneObjectPart part = parts[i];
1289 if (part.LocalId != m_rootPart.LocalId) 1864 if (part.LocalId != m_rootPart.LocalId)
1290 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1865 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1291 } 1866 }
1292
1293 // Hack to get the physics scene geometries in the right spot 1867 // Hack to get the physics scene geometries in the right spot
1294 ResetChildPrimPhysicsPositions(); 1868// ResetChildPrimPhysicsPositions();
1869 if (m_rootPart.PhysActor != null)
1870 {
1871 m_rootPart.PhysActor.Building = false;
1872 }
1873 }
1874 else
1875 {
1876 // Apply physics to the root prim
1877 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1295 } 1878 }
1296 } 1879 }
1297 1880
1298 public void SetOwnerId(UUID userId) 1881 public void SetOwnerId(UUID userId)
1299 { 1882 {
1300 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1883 ForEachPart(delegate(SceneObjectPart part)
1884 {
1885
1886 part.OwnerID = userId;
1887
1888 });
1301 } 1889 }
1302 1890
1303 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1891 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1329,11 +1917,17 @@ namespace OpenSim.Region.Framework.Scenes
1329 return; 1917 return;
1330 } 1918 }
1331 1919
1920 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1921 return;
1922
1332 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1923 // 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. 1924 // any exception propogate upwards.
1334 try 1925 try
1335 { 1926 {
1336 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1927 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1928 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1929 m_scene.LoadingPrims) // Land may not be valid yet
1930
1337 { 1931 {
1338 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1932 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1339 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1933 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1360,6 +1954,7 @@ namespace OpenSim.Region.Framework.Scenes
1360 } 1954 }
1361 } 1955 }
1362 } 1956 }
1957
1363 } 1958 }
1364 1959
1365 if (m_scene.UseBackup && HasGroupChanged) 1960 if (m_scene.UseBackup && HasGroupChanged)
@@ -1367,10 +1962,30 @@ namespace OpenSim.Region.Framework.Scenes
1367 // don't backup while it's selected or you're asking for changes mid stream. 1962 // don't backup while it's selected or you're asking for changes mid stream.
1368 if (isTimeToPersist() || forcedBackup) 1963 if (isTimeToPersist() || forcedBackup)
1369 { 1964 {
1965 if (m_rootPart.PhysActor != null &&
1966 (!m_rootPart.PhysActor.IsPhysical))
1967 {
1968 // Possible ghost prim
1969 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1970 {
1971 foreach (SceneObjectPart part in m_parts.GetArray())
1972 {
1973 // Re-set physics actor positions and
1974 // orientations
1975 part.GroupPosition = m_rootPart.GroupPosition;
1976 }
1977 }
1978 }
1370// m_log.DebugFormat( 1979// m_log.DebugFormat(
1371// "[SCENE]: Storing {0}, {1} in {2}", 1980// "[SCENE]: Storing {0}, {1} in {2}",
1372// Name, UUID, m_scene.RegionInfo.RegionName); 1981// Name, UUID, m_scene.RegionInfo.RegionName);
1373 1982
1983 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
1984 {
1985 RootPart.Shape.State = 0;
1986 ScheduleGroupForFullUpdate();
1987 }
1988
1374 SceneObjectGroup backup_group = Copy(false); 1989 SceneObjectGroup backup_group = Copy(false);
1375 backup_group.RootPart.Velocity = RootPart.Velocity; 1990 backup_group.RootPart.Velocity = RootPart.Velocity;
1376 backup_group.RootPart.Acceleration = RootPart.Acceleration; 1991 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1384,6 +1999,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 1999
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 2000 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 2001 {
2002 if (part.KeyframeMotion != null)
2003 {
2004 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2005 part.KeyframeMotion.UpdateSceneObject(this);
2006 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 2007 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 2008 });
1389 2009
@@ -1436,6 +2056,7 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2056 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2057 public SceneObjectGroup Copy(bool userExposed)
1438 { 2058 {
2059 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2060 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2061 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2062 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1450,7 +2071,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2071 // This is only necessary when userExposed is false!
1451 2072
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2073 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2074
1454 if (!userExposed) 2075 if (!userExposed)
1455 dupe.IsAttachment = true; 2076 dupe.IsAttachment = true;
1456 2077
@@ -1468,11 +2089,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2089 dupe.m_rootPart.TrimPermissions();
1469 2090
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2091 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2092
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2093 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2094 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2095 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2096 }
1476 ); 2097 );
1477 2098
1478 foreach (SceneObjectPart part in partList) 2099 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2103,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2103 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2104 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2105 newPart.LinkNum = part.LinkNum;
1485 } 2106 if (userExposed)
2107 newPart.ParentID = dupe.m_rootPart.LocalId;
2108 }
1486 else 2109 else
1487 { 2110 {
1488 newPart = dupe.m_rootPart; 2111 newPart = dupe.m_rootPart;
1489 } 2112 }
2113/*
2114 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2115 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2116
1491 // Need to duplicate the physics actor as well 2117 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2118 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2119 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2120 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2121 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2122 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2123 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2124 pbs,
1501 newPart.AbsolutePosition, 2125 newPart.AbsolutePosition,
1502 newPart.Scale, 2126 newPart.Scale,
1503 newPart.RotationOffset, 2127 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2128 isphys,
2129 isphan,
1505 newPart.LocalId); 2130 newPart.LocalId);
1506 2131
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2132 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2133 */
2134 if (userExposed)
2135 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2136// }
1509 } 2137 }
1510 2138
1511 if (userExposed) 2139 if (userExposed)
1512 { 2140 {
1513 dupe.UpdateParentIDs(); 2141// done above dupe.UpdateParentIDs();
2142
2143 if (dupe.m_rootPart.PhysActor != null)
2144 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2145
1514 dupe.HasGroupChanged = true; 2146 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2147 dupe.AttachToBackup();
1516 2148
1517 ScheduleGroupForFullUpdate(); 2149 ScheduleGroupForFullUpdate();
1518 } 2150 }
1519 2151
2152 m_dupeInProgress = false;
1520 return dupe; 2153 return dupe;
1521 } 2154 }
1522 2155
@@ -1528,11 +2161,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2161 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2162 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2163 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2164 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2165 // give newpart a new local ID lettng old part keep same
2166 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2167 newpart.LocalId = m_scene.AllocateLocalId();
2168
2169 SetRootPart(newpart);
2170 if (userExposed)
2171 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2172 }
1533 2173
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2174 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2175 {
2176 if (usePhysics)
2177 {
2178 if (RootPart.KeyframeMotion != null)
2179 RootPart.KeyframeMotion.Stop();
2180 RootPart.KeyframeMotion = null;
2181 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2182 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2183 }
1538 2184
@@ -1586,7 +2232,7 @@ namespace OpenSim.Region.Framework.Scenes
1586 } 2232 }
1587 } 2233 }
1588 2234
1589 public void applyAngularImpulse(Vector3 impulse) 2235 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2236 {
1591 PhysicsActor pa = RootPart.PhysActor; 2237 PhysicsActor pa = RootPart.PhysActor;
1592 2238
@@ -1600,36 +2246,12 @@ namespace OpenSim.Region.Framework.Scenes
1600 } 2246 }
1601 } 2247 }
1602 2248
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() 2249 public Vector3 GetTorque()
1618 { 2250 {
1619 PhysicsActor pa = RootPart.PhysActor; 2251 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 } 2252 }
1632 2253
2254 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2255 public void moveToTarget(Vector3 target, float tau)
1634 { 2256 {
1635 if (IsAttachment) 2257 if (IsAttachment)
@@ -1661,6 +2283,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2283 pa.PIDActive = false;
1662 } 2284 }
1663 2285
2286 public void rotLookAt(Quaternion target, float strength, float damping)
2287 {
2288 SceneObjectPart rootpart = m_rootPart;
2289 if (rootpart != null)
2290 {
2291 if (IsAttachment)
2292 {
2293 /*
2294 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2295 if (avatar != null)
2296 {
2297 Rotate the Av?
2298 } */
2299 }
2300 else
2301 {
2302 if (rootpart.PhysActor != null)
2303 { // APID must be implemented in your physics system for this to function.
2304 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2305 rootpart.PhysActor.APIDStrength = strength;
2306 rootpart.PhysActor.APIDDamping = damping;
2307 rootpart.PhysActor.APIDActive = true;
2308 }
2309 }
2310 }
2311 }
2312
2313 public void stopLookAt()
2314 {
2315 SceneObjectPart rootpart = m_rootPart;
2316 if (rootpart != null)
2317 {
2318 if (rootpart.PhysActor != null)
2319 { // APID must be implemented in your physics system for this to function.
2320 rootpart.PhysActor.APIDActive = false;
2321 }
2322 }
2323
2324 }
2325
1664 /// <summary> 2326 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2327 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2328 /// </summary>
@@ -1677,7 +2339,7 @@ namespace OpenSim.Region.Framework.Scenes
1677 { 2339 {
1678 pa.PIDHoverHeight = height; 2340 pa.PIDHoverHeight = height;
1679 pa.PIDHoverType = hoverType; 2341 pa.PIDHoverType = hoverType;
1680 pa.PIDTau = tau; 2342 pa.PIDHoverTau = tau;
1681 pa.PIDHoverActive = true; 2343 pa.PIDHoverActive = true;
1682 } 2344 }
1683 else 2345 else
@@ -1717,7 +2379,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2379 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2380 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2381 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2382 // give new ID to the new part, letting old keep original
2383 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2384 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2385 newPart.LocalId = m_scene.AllocateLocalId();
2386 newPart.SetParent(this);
2387
1721 AddPart(newPart); 2388 AddPart(newPart);
1722 2389
1723 SetPartAsNonRoot(newPart); 2390 SetPartAsNonRoot(newPart);
@@ -1846,11 +2513,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2513 /// Immediately send a full update for this scene object.
1847 /// </summary> 2514 /// </summary>
1848 public void SendGroupFullUpdate() 2515 public void SendGroupFullUpdate()
1849 { 2516 {
1850 if (IsDeleted) 2517 if (IsDeleted)
1851 return; 2518 return;
1852 2519
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2520// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2521
1855 RootPart.SendFullUpdateToAllClients(); 2522 RootPart.SendFullUpdateToAllClients();
1856 2523
@@ -1984,6 +2651,11 @@ namespace OpenSim.Region.Framework.Scenes
1984 2651
1985 SceneObjectPart linkPart = objectGroup.m_rootPart; 2652 SceneObjectPart linkPart = objectGroup.m_rootPart;
1986 2653
2654 if (m_rootPart.PhysActor != null)
2655 m_rootPart.PhysActor.Building = true;
2656 if (linkPart.PhysActor != null)
2657 linkPart.PhysActor.Building = true;
2658
1987 // physics flags from group to be applied to linked parts 2659 // physics flags from group to be applied to linked parts
1988 bool grpusephys = UsesPhysics; 2660 bool grpusephys = UsesPhysics;
1989 bool grptemporary = IsTemporary; 2661 bool grptemporary = IsTemporary;
@@ -1992,19 +2664,21 @@ namespace OpenSim.Region.Framework.Scenes
1992 Quaternion oldRootRotation = linkPart.RotationOffset; 2664 Quaternion oldRootRotation = linkPart.RotationOffset;
1993 2665
1994 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2666 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2667
1995 linkPart.ParentID = m_rootPart.LocalId; 2668 linkPart.ParentID = m_rootPart.LocalId;
1996 linkPart.GroupPosition = AbsolutePosition; 2669
1997 Vector3 axPos = linkPart.OffsetPosition; 2670 linkPart.GroupPosition = AbsolutePosition;
1998 2671
2672 Vector3 axPos = linkPart.OffsetPosition;
1999 Quaternion parentRot = m_rootPart.RotationOffset; 2673 Quaternion parentRot = m_rootPart.RotationOffset;
2000 axPos *= Quaternion.Inverse(parentRot); 2674 axPos *= Quaternion.Conjugate(parentRot);
2001
2002 linkPart.OffsetPosition = axPos; 2675 linkPart.OffsetPosition = axPos;
2676
2003 Quaternion oldRot = linkPart.RotationOffset; 2677 Quaternion oldRot = linkPart.RotationOffset;
2004 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2678 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2005 linkPart.RotationOffset = newRot; 2679 linkPart.RotationOffset = newRot;
2006 2680
2007 linkPart.ParentID = m_rootPart.LocalId; 2681// linkPart.ParentID = m_rootPart.LocalId; done above
2008 2682
2009 if (m_rootPart.LinkNum == 0) 2683 if (m_rootPart.LinkNum == 0)
2010 m_rootPart.LinkNum = 1; 2684 m_rootPart.LinkNum = 1;
@@ -2032,7 +2706,7 @@ namespace OpenSim.Region.Framework.Scenes
2032 linkPart.CreateSelected = true; 2706 linkPart.CreateSelected = true;
2033 2707
2034 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2708 // 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); 2709 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) 2710 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2037 { 2711 {
2038 linkPart.PhysActor.link(m_rootPart.PhysActor); 2712 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2040,6 +2714,7 @@ namespace OpenSim.Region.Framework.Scenes
2040 } 2714 }
2041 2715
2042 linkPart.LinkNum = linkNum++; 2716 linkPart.LinkNum = linkNum++;
2717 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2043 2718
2044 SceneObjectPart[] ogParts = objectGroup.Parts; 2719 SceneObjectPart[] ogParts = objectGroup.Parts;
2045 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2720 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2054,7 +2729,7 @@ namespace OpenSim.Region.Framework.Scenes
2054 { 2729 {
2055 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2730 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2056 // let physics know 2731 // let physics know
2057 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2732 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) 2733 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2059 { 2734 {
2060 part.PhysActor.link(m_rootPart.PhysActor); 2735 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2069,7 +2744,7 @@ namespace OpenSim.Region.Framework.Scenes
2069 objectGroup.IsDeleted = true; 2744 objectGroup.IsDeleted = true;
2070 2745
2071 objectGroup.m_parts.Clear(); 2746 objectGroup.m_parts.Clear();
2072 2747
2073 // Can't do this yet since backup still makes use of the root part without any synchronization 2748 // Can't do this yet since backup still makes use of the root part without any synchronization
2074// objectGroup.m_rootPart = null; 2749// objectGroup.m_rootPart = null;
2075 2750
@@ -2080,6 +2755,9 @@ namespace OpenSim.Region.Framework.Scenes
2080 // unmoved prims! 2755 // unmoved prims!
2081 ResetChildPrimPhysicsPositions(); 2756 ResetChildPrimPhysicsPositions();
2082 2757
2758 if (m_rootPart.PhysActor != null)
2759 m_rootPart.PhysActor.Building = false;
2760
2083 //HasGroupChanged = true; 2761 //HasGroupChanged = true;
2084 //ScheduleGroupForFullUpdate(); 2762 //ScheduleGroupForFullUpdate();
2085 } 2763 }
@@ -2147,7 +2825,10 @@ namespace OpenSim.Region.Framework.Scenes
2147// m_log.DebugFormat( 2825// m_log.DebugFormat(
2148// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2826// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2149// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2827// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2150 2828
2829 if (m_rootPart.PhysActor != null)
2830 m_rootPart.PhysActor.Building = true;
2831
2151 linkPart.ClearUndoState(); 2832 linkPart.ClearUndoState();
2152 2833
2153 Quaternion worldRot = linkPart.GetWorldRotation(); 2834 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2207,6 +2888,14 @@ namespace OpenSim.Region.Framework.Scenes
2207 2888
2208 // When we delete a group, we currently have to force persist to the database if the object id has changed 2889 // 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) 2890 // (since delete works by deleting all rows which have a given object id)
2891
2892 // this is as it seems to be in sl now
2893 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2894 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2895
2896 if (m_rootPart.PhysActor != null)
2897 m_rootPart.PhysActor.Building = false;
2898
2210 objectGroup.HasGroupChangedDueToDelink = true; 2899 objectGroup.HasGroupChangedDueToDelink = true;
2211 2900
2212 return objectGroup; 2901 return objectGroup;
@@ -2218,6 +2907,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2907 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2908 public virtual void DetachFromBackup()
2220 { 2909 {
2910 m_scene.SceneGraph.FireDetachFromBackup(this);
2221 if (m_isBackedUp && Scene != null) 2911 if (m_isBackedUp && Scene != null)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2912 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2913
@@ -2236,7 +2926,8 @@ namespace OpenSim.Region.Framework.Scenes
2236 2926
2237 axPos *= parentRot; 2927 axPos *= parentRot;
2238 part.OffsetPosition = axPos; 2928 part.OffsetPosition = axPos;
2239 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2929 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2930 part.GroupPosition = newPos;
2240 part.OffsetPosition = Vector3.Zero; 2931 part.OffsetPosition = Vector3.Zero;
2241 part.RotationOffset = worldRot; 2932 part.RotationOffset = worldRot;
2242 2933
@@ -2247,20 +2938,20 @@ namespace OpenSim.Region.Framework.Scenes
2247 2938
2248 part.LinkNum = linkNum; 2939 part.LinkNum = linkNum;
2249 2940
2250 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2941 part.OffsetPosition = newPos - AbsolutePosition;
2251 2942
2252 Quaternion rootRotation = m_rootPart.RotationOffset; 2943 Quaternion rootRotation = m_rootPart.RotationOffset;
2253 2944
2254 Vector3 pos = part.OffsetPosition; 2945 Vector3 pos = part.OffsetPosition;
2255 pos *= Quaternion.Inverse(rootRotation); 2946 pos *= Quaternion.Conjugate(rootRotation);
2256 part.OffsetPosition = pos; 2947 part.OffsetPosition = pos;
2257 2948
2258 parentRot = m_rootPart.RotationOffset; 2949 parentRot = m_rootPart.RotationOffset;
2259 oldRot = part.RotationOffset; 2950 oldRot = part.RotationOffset;
2260 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2951 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2261 part.RotationOffset = newRot; 2952 part.RotationOffset = newRot;
2262 2953
2263 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2954 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2264 } 2955 }
2265 2956
2266 /// <summary> 2957 /// <summary>
@@ -2511,8 +3202,22 @@ namespace OpenSim.Region.Framework.Scenes
2511 } 3202 }
2512 } 3203 }
2513 3204
2514 for (int i = 0; i < parts.Length; i++) 3205 if (parts.Length > 1)
2515 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3206 {
3207 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3208
3209 for (int i = 0; i < parts.Length; i++)
3210 {
3211
3212 if (parts[i].UUID != m_rootPart.UUID)
3213 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3214 }
3215
3216 if (m_rootPart.PhysActor != null)
3217 m_rootPart.PhysActor.Building = false;
3218 }
3219 else
3220 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2516 } 3221 }
2517 } 3222 }
2518 3223
@@ -2525,6 +3230,17 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 3230 }
2526 } 3231 }
2527 3232
3233
3234
3235 /// <summary>
3236 /// Gets the number of parts
3237 /// </summary>
3238 /// <returns></returns>
3239 public int GetPartCount()
3240 {
3241 return Parts.Count();
3242 }
3243
2528 /// <summary> 3244 /// <summary>
2529 /// Update the texture entry for this part 3245 /// Update the texture entry for this part
2530 /// </summary> 3246 /// </summary>
@@ -2586,11 +3302,6 @@ namespace OpenSim.Region.Framework.Scenes
2586 /// <param name="scale"></param> 3302 /// <param name="scale"></param>
2587 public void GroupResize(Vector3 scale) 3303 public void GroupResize(Vector3 scale)
2588 { 3304 {
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); 3305 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2595 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3306 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2596 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3307 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2617,7 +3328,6 @@ namespace OpenSim.Region.Framework.Scenes
2617 SceneObjectPart obPart = parts[i]; 3328 SceneObjectPart obPart = parts[i];
2618 if (obPart.UUID != m_rootPart.UUID) 3329 if (obPart.UUID != m_rootPart.UUID)
2619 { 3330 {
2620// obPart.IgnoreUndoUpdate = true;
2621 Vector3 oldSize = new Vector3(obPart.Scale); 3331 Vector3 oldSize = new Vector3(obPart.Scale);
2622 3332
2623 float f = 1.0f; 3333 float f = 1.0f;
@@ -2681,8 +3391,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 z *= a; 3391 z *= a;
2682 } 3392 }
2683 } 3393 }
2684
2685// obPart.IgnoreUndoUpdate = false;
2686 } 3394 }
2687 } 3395 }
2688 } 3396 }
@@ -2692,9 +3400,7 @@ namespace OpenSim.Region.Framework.Scenes
2692 prevScale.Y *= y; 3400 prevScale.Y *= y;
2693 prevScale.Z *= z; 3401 prevScale.Z *= z;
2694 3402
2695// RootPart.IgnoreUndoUpdate = true;
2696 RootPart.Resize(prevScale); 3403 RootPart.Resize(prevScale);
2697// RootPart.IgnoreUndoUpdate = false;
2698 3404
2699 parts = m_parts.GetArray(); 3405 parts = m_parts.GetArray();
2700 for (int i = 0; i < parts.Length; i++) 3406 for (int i = 0; i < parts.Length; i++)
@@ -2703,8 +3409,6 @@ namespace OpenSim.Region.Framework.Scenes
2703 3409
2704 if (obPart.UUID != m_rootPart.UUID) 3410 if (obPart.UUID != m_rootPart.UUID)
2705 { 3411 {
2706 obPart.IgnoreUndoUpdate = true;
2707
2708 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3412 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2709 currentpos.X *= x; 3413 currentpos.X *= x;
2710 currentpos.Y *= y; 3414 currentpos.Y *= y;
@@ -2717,16 +3421,12 @@ namespace OpenSim.Region.Framework.Scenes
2717 3421
2718 obPart.Resize(newSize); 3422 obPart.Resize(newSize);
2719 obPart.UpdateOffSet(currentpos); 3423 obPart.UpdateOffSet(currentpos);
2720
2721 obPart.IgnoreUndoUpdate = false;
2722 } 3424 }
2723 3425
2724// obPart.IgnoreUndoUpdate = false; 3426 HasGroupChanged = true;
2725// obPart.StoreUndoState(); 3427 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3428 ScheduleGroupForTerseUpdate();
2726 } 3429 }
2727
2728// m_log.DebugFormat(
2729// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2730 } 3430 }
2731 3431
2732 #endregion 3432 #endregion
@@ -2739,14 +3439,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 /// <param name="pos"></param> 3439 /// <param name="pos"></param>
2740 public void UpdateGroupPosition(Vector3 pos) 3440 public void UpdateGroupPosition(Vector3 pos)
2741 { 3441 {
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)) 3442 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2751 { 3443 {
2752 if (IsAttachment) 3444 if (IsAttachment)
@@ -2779,21 +3471,17 @@ namespace OpenSim.Region.Framework.Scenes
2779 /// </summary> 3471 /// </summary>
2780 /// <param name="pos"></param> 3472 /// <param name="pos"></param>
2781 /// <param name="localID"></param> 3473 /// <param name="localID"></param>
3474 ///
3475
2782 public void UpdateSinglePosition(Vector3 pos, uint localID) 3476 public void UpdateSinglePosition(Vector3 pos, uint localID)
2783 { 3477 {
2784 SceneObjectPart part = GetPart(localID); 3478 SceneObjectPart part = GetPart(localID);
2785 3479
2786// SceneObjectPart[] parts = m_parts.GetArray();
2787// for (int i = 0; i < parts.Length; i++)
2788// parts[i].StoreUndoState();
2789
2790 if (part != null) 3480 if (part != null)
2791 { 3481 {
2792// m_log.DebugFormat( 3482// unlock parts position change
2793// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3483 if (m_rootPart.PhysActor != null)
2794 3484 m_rootPart.PhysActor.Building = true;
2795 part.StoreUndoState(false);
2796 part.IgnoreUndoUpdate = true;
2797 3485
2798 if (part.UUID == m_rootPart.UUID) 3486 if (part.UUID == m_rootPart.UUID)
2799 { 3487 {
@@ -2804,8 +3492,10 @@ namespace OpenSim.Region.Framework.Scenes
2804 part.UpdateOffSet(pos); 3492 part.UpdateOffSet(pos);
2805 } 3493 }
2806 3494
3495 if (m_rootPart.PhysActor != null)
3496 m_rootPart.PhysActor.Building = false;
3497
2807 HasGroupChanged = true; 3498 HasGroupChanged = true;
2808 part.IgnoreUndoUpdate = false;
2809 } 3499 }
2810 } 3500 }
2811 3501
@@ -2815,13 +3505,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 /// <param name="pos"></param> 3505 /// <param name="pos"></param>
2816 public void UpdateRootPosition(Vector3 pos) 3506 public void UpdateRootPosition(Vector3 pos)
2817 { 3507 {
2818// m_log.DebugFormat( 3508 // 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); 3509 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2826 Vector3 oldPos = 3510 Vector3 oldPos =
2827 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3511 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2844,7 +3528,14 @@ namespace OpenSim.Region.Framework.Scenes
2844 AbsolutePosition = newPos; 3528 AbsolutePosition = newPos;
2845 3529
2846 HasGroupChanged = true; 3530 HasGroupChanged = true;
2847 ScheduleGroupForTerseUpdate(); 3531 if (m_rootPart.Undoing)
3532 {
3533 ScheduleGroupForFullUpdate();
3534 }
3535 else
3536 {
3537 ScheduleGroupForTerseUpdate();
3538 }
2848 } 3539 }
2849 3540
2850 #endregion 3541 #endregion
@@ -2857,24 +3548,16 @@ namespace OpenSim.Region.Framework.Scenes
2857 /// <param name="rot"></param> 3548 /// <param name="rot"></param>
2858 public void UpdateGroupRotationR(Quaternion rot) 3549 public void UpdateGroupRotationR(Quaternion rot)
2859 { 3550 {
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); 3551 m_rootPart.UpdateRotation(rot);
2870 3552
3553/* this is done by rootpart RotationOffset set called by UpdateRotation
2871 PhysicsActor actor = m_rootPart.PhysActor; 3554 PhysicsActor actor = m_rootPart.PhysActor;
2872 if (actor != null) 3555 if (actor != null)
2873 { 3556 {
2874 actor.Orientation = m_rootPart.RotationOffset; 3557 actor.Orientation = m_rootPart.RotationOffset;
2875 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3558 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2876 } 3559 }
2877 3560*/
2878 HasGroupChanged = true; 3561 HasGroupChanged = true;
2879 ScheduleGroupForTerseUpdate(); 3562 ScheduleGroupForTerseUpdate();
2880 } 3563 }
@@ -2886,16 +3569,6 @@ namespace OpenSim.Region.Framework.Scenes
2886 /// <param name="rot"></param> 3569 /// <param name="rot"></param>
2887 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3570 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2888 { 3571 {
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); 3572 m_rootPart.UpdateRotation(rot);
2900 3573
2901 PhysicsActor actor = m_rootPart.PhysActor; 3574 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2909,8 +3582,6 @@ namespace OpenSim.Region.Framework.Scenes
2909 3582
2910 HasGroupChanged = true; 3583 HasGroupChanged = true;
2911 ScheduleGroupForTerseUpdate(); 3584 ScheduleGroupForTerseUpdate();
2912
2913 RootPart.IgnoreUndoUpdate = false;
2914 } 3585 }
2915 3586
2916 /// <summary> 3587 /// <summary>
@@ -2923,13 +3594,11 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart part = GetPart(localID); 3594 SceneObjectPart part = GetPart(localID);
2924 3595
2925 SceneObjectPart[] parts = m_parts.GetArray(); 3596 SceneObjectPart[] parts = m_parts.GetArray();
2926 for (int i = 0; i < parts.Length; i++)
2927 parts[i].StoreUndoState();
2928 3597
2929 if (part != null) 3598 if (part != null)
2930 { 3599 {
2931// m_log.DebugFormat( 3600 if (m_rootPart.PhysActor != null)
2932// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3601 m_rootPart.PhysActor.Building = true;
2933 3602
2934 if (part.UUID == m_rootPart.UUID) 3603 if (part.UUID == m_rootPart.UUID)
2935 { 3604 {
@@ -2939,6 +3608,9 @@ namespace OpenSim.Region.Framework.Scenes
2939 { 3608 {
2940 part.UpdateRotation(rot); 3609 part.UpdateRotation(rot);
2941 } 3610 }
3611
3612 if (m_rootPart.PhysActor != null)
3613 m_rootPart.PhysActor.Building = false;
2942 } 3614 }
2943 } 3615 }
2944 3616
@@ -2952,12 +3624,8 @@ namespace OpenSim.Region.Framework.Scenes
2952 SceneObjectPart part = GetPart(localID); 3624 SceneObjectPart part = GetPart(localID);
2953 if (part != null) 3625 if (part != null)
2954 { 3626 {
2955// m_log.DebugFormat( 3627 if (m_rootPart.PhysActor != null)
2956// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3628 m_rootPart.PhysActor.Building = true;
2957// part.Name, part.LocalId, rot);
2958
2959 part.StoreUndoState();
2960 part.IgnoreUndoUpdate = true;
2961 3629
2962 if (part.UUID == m_rootPart.UUID) 3630 if (part.UUID == m_rootPart.UUID)
2963 { 3631 {
@@ -2970,7 +3638,8 @@ namespace OpenSim.Region.Framework.Scenes
2970 part.OffsetPosition = pos; 3638 part.OffsetPosition = pos;
2971 } 3639 }
2972 3640
2973 part.IgnoreUndoUpdate = false; 3641 if (m_rootPart.PhysActor != null)
3642 m_rootPart.PhysActor.Building = false;
2974 } 3643 }
2975 } 3644 }
2976 3645
@@ -2980,15 +3649,12 @@ namespace OpenSim.Region.Framework.Scenes
2980 /// <param name="rot"></param> 3649 /// <param name="rot"></param>
2981 public void UpdateRootRotation(Quaternion rot) 3650 public void UpdateRootRotation(Quaternion rot)
2982 { 3651 {
2983// m_log.DebugFormat( 3652 // 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; 3653 Quaternion axRot = rot;
2988 Quaternion oldParentRot = m_rootPart.RotationOffset; 3654 Quaternion oldParentRot = m_rootPart.RotationOffset;
2989 3655
2990 m_rootPart.StoreUndoState(); 3656 //Don't use UpdateRotation because it schedules an update prematurely
2991 m_rootPart.UpdateRotation(rot); 3657 m_rootPart.RotationOffset = rot;
2992 3658
2993 PhysicsActor pa = m_rootPart.PhysActor; 3659 PhysicsActor pa = m_rootPart.PhysActor;
2994 3660
@@ -3004,35 +3670,144 @@ namespace OpenSim.Region.Framework.Scenes
3004 SceneObjectPart prim = parts[i]; 3670 SceneObjectPart prim = parts[i];
3005 if (prim.UUID != m_rootPart.UUID) 3671 if (prim.UUID != m_rootPart.UUID)
3006 { 3672 {
3007 prim.IgnoreUndoUpdate = true; 3673 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3674 NewRot = Quaternion.Inverse(axRot) * NewRot;
3675 prim.RotationOffset = NewRot;
3676
3008 Vector3 axPos = prim.OffsetPosition; 3677 Vector3 axPos = prim.OffsetPosition;
3678
3009 axPos *= oldParentRot; 3679 axPos *= oldParentRot;
3010 axPos *= Quaternion.Inverse(axRot); 3680 axPos *= Quaternion.Inverse(axRot);
3011 prim.OffsetPosition = axPos; 3681 prim.OffsetPosition = axPos;
3012 Quaternion primsRot = prim.RotationOffset; 3682 }
3013 Quaternion newRot = oldParentRot * primsRot; 3683 }
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 3684
3031 m_rootPart.ScheduleTerseUpdate(); 3685 HasGroupChanged = true;
3686 ScheduleGroupForFullUpdate();
3687 }
3032 3688
3033// m_log.DebugFormat( 3689 private enum updatetype :int
3034// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3690 {
3035// Name, LocalId, rot); 3691 none = 0,
3692 partterse = 1,
3693 partfull = 2,
3694 groupterse = 3,
3695 groupfull = 4
3696 }
3697
3698 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3699 {
3700 // TODO this still as excessive *.Schedule*Update()s
3701
3702 if (part != null && part.ParentGroup != null)
3703 {
3704 ObjectChangeType change = data.change;
3705 bool togroup = ((change & ObjectChangeType.Group) != 0);
3706 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3707
3708 SceneObjectGroup group = part.ParentGroup;
3709 PhysicsActor pha = group.RootPart.PhysActor;
3710
3711 updatetype updateType = updatetype.none;
3712
3713 if (togroup)
3714 {
3715 // related to group
3716 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3717 {
3718 if ((change & ObjectChangeType.Rotation) != 0)
3719 {
3720 group.RootPart.UpdateRotation(data.rotation);
3721 updateType = updatetype.none;
3722 }
3723 if ((change & ObjectChangeType.Position) != 0)
3724 {
3725 UpdateGroupPosition(data.position);
3726 updateType = updatetype.groupterse;
3727 }
3728 else
3729 // ugly rotation update of all parts
3730 {
3731 group.AbsolutePosition = AbsolutePosition;
3732 }
3733
3734 }
3735 if ((change & ObjectChangeType.Scale) != 0)
3736 {
3737 if (pha != null)
3738 pha.Building = true;
3739
3740 group.GroupResize(data.scale);
3741 updateType = updatetype.none;
3742
3743 if (pha != null)
3744 pha.Building = false;
3745 }
3746 }
3747 else
3748 {
3749 // related to single prim in a link-set ( ie group)
3750 if (pha != null)
3751 pha.Building = true;
3752
3753 // root part is special
3754 // parts offset positions or rotations need to change also
3755
3756 if (part == group.RootPart)
3757 {
3758 if ((change & ObjectChangeType.Rotation) != 0)
3759 group.UpdateRootRotation(data.rotation);
3760 if ((change & ObjectChangeType.Position) != 0)
3761 group.UpdateRootPosition(data.position);
3762 if ((change & ObjectChangeType.Scale) != 0)
3763 part.Resize(data.scale);
3764 }
3765 else
3766 {
3767 if ((change & ObjectChangeType.Position) != 0)
3768 {
3769 part.OffsetPosition = data.position;
3770 updateType = updatetype.partterse;
3771 }
3772 if ((change & ObjectChangeType.Rotation) != 0)
3773 {
3774 part.UpdateRotation(data.rotation);
3775 updateType = updatetype.none;
3776 }
3777 if ((change & ObjectChangeType.Scale) != 0)
3778 {
3779 part.Resize(data.scale);
3780 updateType = updatetype.none;
3781 }
3782 }
3783
3784 if (pha != null)
3785 pha.Building = false;
3786 }
3787
3788 if (updateType != updatetype.none)
3789 {
3790 group.HasGroupChanged = true;
3791
3792 switch (updateType)
3793 {
3794 case updatetype.partterse:
3795 part.ScheduleTerseUpdate();
3796 break;
3797 case updatetype.partfull:
3798 part.ScheduleFullUpdate();
3799 break;
3800 case updatetype.groupterse:
3801 group.ScheduleGroupForTerseUpdate();
3802 break;
3803 case updatetype.groupfull:
3804 group.ScheduleGroupForFullUpdate();
3805 break;
3806 default:
3807 break;
3808 }
3809 }
3810 }
3036 } 3811 }
3037 3812
3038 #endregion 3813 #endregion
@@ -3252,11 +4027,50 @@ namespace OpenSim.Region.Framework.Scenes
3252 } 4027 }
3253 } 4028 }
3254 } 4029 }
3255 4030
4031 public Vector3 GetGeometricCenter()
4032 {
4033 // this is not real geometric center but a average of positions relative to root prim acording to
4034 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4035 // ignoring tortured prims details since sl also seems to ignore
4036 // so no real use in doing it on physics
4037
4038 Vector3 gc = Vector3.Zero;
4039
4040 int nparts = m_parts.Count;
4041 if (nparts <= 1)
4042 return gc;
4043
4044 SceneObjectPart[] parts = m_parts.GetArray();
4045 nparts = parts.Length; // just in case it changed
4046 if (nparts <= 1)
4047 return gc;
4048
4049 Quaternion parentRot = RootPart.RotationOffset;
4050 Vector3 pPos;
4051
4052 // average all parts positions
4053 for (int i = 0; i < nparts; i++)
4054 {
4055 // do it directly
4056 // gc += parts[i].GetWorldPosition();
4057 if (parts[i] != RootPart)
4058 {
4059 pPos = parts[i].OffsetPosition;
4060 gc += pPos;
4061 }
4062
4063 }
4064 gc /= nparts;
4065
4066 // relative to root:
4067// gc -= AbsolutePosition;
4068 return gc;
4069 }
4070
3256 public float GetMass() 4071 public float GetMass()
3257 { 4072 {
3258 float retmass = 0f; 4073 float retmass = 0f;
3259
3260 SceneObjectPart[] parts = m_parts.GetArray(); 4074 SceneObjectPart[] parts = m_parts.GetArray();
3261 for (int i = 0; i < parts.Length; i++) 4075 for (int i = 0; i < parts.Length; i++)
3262 retmass += parts[i].GetMass(); 4076 retmass += parts[i].GetMass();
@@ -3264,6 +4078,39 @@ namespace OpenSim.Region.Framework.Scenes
3264 return retmass; 4078 return retmass;
3265 } 4079 }
3266 4080
4081 // center of mass of full object
4082 public Vector3 GetCenterOfMass()
4083 {
4084 PhysicsActor pa = RootPart.PhysActor;
4085
4086 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4087 {
4088 // physics knows better about center of mass of physical prims
4089 Vector3 tmp = pa.CenterOfMass;
4090 return tmp;
4091 }
4092
4093 Vector3 Ptot = Vector3.Zero;
4094 float totmass = 0f;
4095 float m;
4096
4097 SceneObjectPart[] parts = m_parts.GetArray();
4098 for (int i = 0; i < parts.Length; i++)
4099 {
4100 m = parts[i].GetMass();
4101 Ptot += parts[i].GetPartCenterOfMass() * m;
4102 totmass += m;
4103 }
4104
4105 if (totmass == 0)
4106 totmass = 0;
4107 else
4108 totmass = 1 / totmass;
4109 Ptot *= totmass;
4110
4111 return Ptot;
4112 }
4113
3267 /// <summary> 4114 /// <summary>
3268 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4115 /// 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. 4116 /// the physics engine can use it.
@@ -3417,6 +4264,14 @@ namespace OpenSim.Region.Framework.Scenes
3417 FromItemID = uuid; 4264 FromItemID = uuid;
3418 } 4265 }
3419 4266
4267 public void ResetOwnerChangeFlag()
4268 {
4269 ForEachPart(delegate(SceneObjectPart part)
4270 {
4271 part.ResetOwnerChangeFlag();
4272 });
4273 }
4274
3420 #endregion 4275 #endregion
3421 } 4276 }
3422} 4277}