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.cs901
1 files changed, 780 insertions, 121 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 878476e..2d71372 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 }
@@ -247,10 +311,10 @@ namespace OpenSim.Region.Framework.Scenes
247 311
248 private bool m_scriptListens_atTarget; 312 private bool m_scriptListens_atTarget;
249 private bool m_scriptListens_notAtTarget; 313 private bool m_scriptListens_notAtTarget;
250
251 private bool m_scriptListens_atRotTarget; 314 private bool m_scriptListens_atRotTarget;
252 private bool m_scriptListens_notAtRotTarget; 315 private bool m_scriptListens_notAtRotTarget;
253 316
317 public bool m_dupeInProgress = false;
254 internal Dictionary<UUID, string> m_savedScriptState; 318 internal Dictionary<UUID, string> m_savedScriptState;
255 319
256 #region Properties 320 #region Properties
@@ -287,6 +351,16 @@ namespace OpenSim.Region.Framework.Scenes
287 get { return m_parts.Count; } 351 get { return m_parts.Count; }
288 } 352 }
289 353
354// protected Quaternion m_rotation = Quaternion.Identity;
355//
356// public virtual Quaternion Rotation
357// {
358// get { return m_rotation; }
359// set {
360// m_rotation = value;
361// }
362// }
363
290 public Quaternion GroupRotation 364 public Quaternion GroupRotation
291 { 365 {
292 get { return m_rootPart.RotationOffset; } 366 get { return m_rootPart.RotationOffset; }
@@ -388,14 +462,99 @@ namespace OpenSim.Region.Framework.Scenes
388 462
389 if (Scene != null) 463 if (Scene != null)
390 { 464 {
391 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 465 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
392 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 466 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
467 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
468 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
469 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
393 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 470 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
394 { 471 {
395 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 472 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
473 uint x = 0;
474 uint y = 0;
475 string version = String.Empty;
476 Vector3 newpos = Vector3.Zero;
477 OpenSim.Services.Interfaces.GridRegion destination = null;
478
479 bool canCross = true;
480 foreach (ScenePresence av in m_linkedAvatars)
481 {
482 // We need to cross these agents. First, let's find
483 // out if any of them can't cross for some reason.
484 // We have to deny the crossing entirely if any
485 // of them are banned. Alternatively, we could
486 // unsit banned agents....
487
488
489 // We set the avatar position as being the object
490 // position to get the region to send to
491 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
492 {
493 canCross = false;
494 break;
495 }
496
497 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
498 }
499
500 if (canCross)
501 {
502 // We unparent the SP quietly so that it won't
503 // be made to stand up
504 foreach (ScenePresence av in m_linkedAvatars)
505 {
506 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
507 if (parentPart != null)
508 av.ParentUUID = parentPart.UUID;
509
510 av.ParentID = 0;
511 }
512
513 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
514
515 // Normalize
516 if (val.X >= Constants.RegionSize)
517 val.X -= Constants.RegionSize;
518 if (val.Y >= Constants.RegionSize)
519 val.Y -= Constants.RegionSize;
520 if (val.X < 0)
521 val.X += Constants.RegionSize;
522 if (val.Y < 0)
523 val.Y += Constants.RegionSize;
524
525 // If it's deleted, crossing was successful
526 if (IsDeleted)
527 {
528 foreach (ScenePresence av in m_linkedAvatars)
529 {
530 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
531
532 av.IsInTransit = true;
533
534 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
535 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
536 }
537
538 return;
539 }
540 }
541 else if (RootPart.PhysActor != null)
542 {
543 RootPart.PhysActor.CrossingFailure();
544 }
545
546 Vector3 oldp = AbsolutePosition;
547 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
548 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
549 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
396 } 550 }
397 } 551 }
398 552/* don't see the need but worse don't see where is restored to false if things stay in
553 foreach (SceneObjectPart part in m_parts.GetArray())
554 {
555 part.IgnoreUndoUpdate = true;
556 }
557 */
399 if (RootPart.GetStatusSandbox()) 558 if (RootPart.GetStatusSandbox())
400 { 559 {
401 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 560 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -409,10 +568,30 @@ namespace OpenSim.Region.Framework.Scenes
409 return; 568 return;
410 } 569 }
411 } 570 }
412
413 SceneObjectPart[] parts = m_parts.GetArray(); 571 SceneObjectPart[] parts = m_parts.GetArray();
414 for (int i = 0; i < parts.Length; i++) 572 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
415 parts[i].GroupPosition = val; 573 if (m_dupeInProgress)
574 triggerScriptEvent = false;
575 foreach (SceneObjectPart part in parts)
576 {
577 part.GroupPosition = val;
578 if (triggerScriptEvent)
579 part.TriggerScriptChangedEvent(Changed.POSITION);
580 }
581 if (!m_dupeInProgress)
582 {
583 foreach (ScenePresence av in m_linkedAvatars)
584 {
585 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
586 if (p != null && m_parts.TryGetValue(p.UUID, out p))
587 {
588 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
589 av.AbsolutePosition += offset;
590 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
591 av.SendAvatarDataToAllAgents();
592 }
593 }
594 }
416 595
417 //if (m_rootPart.PhysActor != null) 596 //if (m_rootPart.PhysActor != null)
418 //{ 597 //{
@@ -427,6 +606,29 @@ namespace OpenSim.Region.Framework.Scenes
427 } 606 }
428 } 607 }
429 608
609 public override Vector3 Velocity
610 {
611 get { return RootPart.Velocity; }
612 set { RootPart.Velocity = value; }
613 }
614
615 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
616 {
617 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
618 ScenePresence agent = icon.EndInvoke(iar);
619
620 //// If the cross was successful, this agent is a child agent
621 //if (agent.IsChildAgent)
622 // agent.Reset();
623 //else // Not successful
624 // agent.RestoreInCurrentScene();
625
626 // In any case
627 agent.IsInTransit = false;
628
629 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
630 }
631
430 public override uint LocalId 632 public override uint LocalId
431 { 633 {
432 get { return m_rootPart.LocalId; } 634 get { return m_rootPart.LocalId; }
@@ -519,6 +721,8 @@ namespace OpenSim.Region.Framework.Scenes
519 child.PhysActor.Selected = value; 721 child.PhysActor.Selected = value;
520 } 722 }
521 } 723 }
724 if (RootPart.KeyframeMotion != null)
725 RootPart.KeyframeMotion.Selected = value;
522 } 726 }
523 } 727 }
524 728
@@ -578,6 +782,7 @@ namespace OpenSim.Region.Framework.Scenes
578 /// </summary> 782 /// </summary>
579 public SceneObjectGroup() 783 public SceneObjectGroup()
580 { 784 {
785
581 } 786 }
582 787
583 /// <summary> 788 /// <summary>
@@ -594,7 +799,7 @@ namespace OpenSim.Region.Framework.Scenes
594 /// Constructor. This object is added to the scene later via AttachToScene() 799 /// Constructor. This object is added to the scene later via AttachToScene()
595 /// </summary> 800 /// </summary>
596 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 801 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
597 { 802 {
598 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 803 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
599 } 804 }
600 805
@@ -642,6 +847,9 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 847 /// </summary>
643 public virtual void AttachToBackup() 848 public virtual void AttachToBackup()
644 { 849 {
850 if (IsAttachment) return;
851 m_scene.SceneGraph.FireAttachToBackup(this);
852
645 if (InSceneBackup) 853 if (InSceneBackup)
646 { 854 {
647 //m_log.DebugFormat( 855 //m_log.DebugFormat(
@@ -684,6 +892,13 @@ namespace OpenSim.Region.Framework.Scenes
684 892
685 ApplyPhysics(); 893 ApplyPhysics();
686 894
895 if (RootPart.PhysActor != null)
896 RootPart.Force = RootPart.Force;
897 if (RootPart.PhysActor != null)
898 RootPart.Torque = RootPart.Torque;
899 if (RootPart.PhysActor != null)
900 RootPart.Buoyancy = RootPart.Buoyancy;
901
687 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 902 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
688 // for the same object with very different properties. The caller must schedule the update. 903 // for the same object with very different properties. The caller must schedule the update.
689 //ScheduleGroupForFullUpdate(); 904 //ScheduleGroupForFullUpdate();
@@ -699,6 +914,10 @@ namespace OpenSim.Region.Framework.Scenes
699 EntityIntersection result = new EntityIntersection(); 914 EntityIntersection result = new EntityIntersection();
700 915
701 SceneObjectPart[] parts = m_parts.GetArray(); 916 SceneObjectPart[] parts = m_parts.GetArray();
917
918 // Find closest hit here
919 float idist = float.MaxValue;
920
702 for (int i = 0; i < parts.Length; i++) 921 for (int i = 0; i < parts.Length; i++)
703 { 922 {
704 SceneObjectPart part = parts[i]; 923 SceneObjectPart part = parts[i];
@@ -713,11 +932,6 @@ namespace OpenSim.Region.Framework.Scenes
713 932
714 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 933 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
715 934
716 // This may need to be updated to the maximum draw distance possible..
717 // We might (and probably will) be checking for prim creation from other sims
718 // when the camera crosses the border.
719 float idist = Constants.RegionSize;
720
721 if (inter.HitTF) 935 if (inter.HitTF)
722 { 936 {
723 // We need to find the closest prim to return to the testcaller along the ray 937 // We need to find the closest prim to return to the testcaller along the ray
@@ -728,10 +942,11 @@ namespace OpenSim.Region.Framework.Scenes
728 result.obj = part; 942 result.obj = part;
729 result.normal = inter.normal; 943 result.normal = inter.normal;
730 result.distance = inter.distance; 944 result.distance = inter.distance;
945
946 idist = inter.distance;
731 } 947 }
732 } 948 }
733 } 949 }
734
735 return result; 950 return result;
736 } 951 }
737 952
@@ -743,25 +958,27 @@ namespace OpenSim.Region.Framework.Scenes
743 /// <returns></returns> 958 /// <returns></returns>
744 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 959 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
745 { 960 {
746 maxX = -256f; 961 maxX = float.MinValue;
747 maxY = -256f; 962 maxY = float.MinValue;
748 maxZ = -256f; 963 maxZ = float.MinValue;
749 minX = 256f; 964 minX = float.MaxValue;
750 minY = 256f; 965 minY = float.MaxValue;
751 minZ = 8192f; 966 minZ = float.MaxValue;
752 967
753 SceneObjectPart[] parts = m_parts.GetArray(); 968 SceneObjectPart[] parts = m_parts.GetArray();
754 for (int i = 0; i < parts.Length; i++) 969 foreach (SceneObjectPart part in parts)
755 { 970 {
756 SceneObjectPart part = parts[i];
757
758 Vector3 worldPos = part.GetWorldPosition(); 971 Vector3 worldPos = part.GetWorldPosition();
759 Vector3 offset = worldPos - AbsolutePosition; 972 Vector3 offset = worldPos - AbsolutePosition;
760 Quaternion worldRot; 973 Quaternion worldRot;
761 if (part.ParentID == 0) 974 if (part.ParentID == 0)
975 {
762 worldRot = part.RotationOffset; 976 worldRot = part.RotationOffset;
977 }
763 else 978 else
979 {
764 worldRot = part.GetWorldRotation(); 980 worldRot = part.GetWorldRotation();
981 }
765 982
766 Vector3 frontTopLeft; 983 Vector3 frontTopLeft;
767 Vector3 frontTopRight; 984 Vector3 frontTopRight;
@@ -773,6 +990,8 @@ namespace OpenSim.Region.Framework.Scenes
773 Vector3 backBottomLeft; 990 Vector3 backBottomLeft;
774 Vector3 backBottomRight; 991 Vector3 backBottomRight;
775 992
993 // Vector3[] corners = new Vector3[8];
994
776 Vector3 orig = Vector3.Zero; 995 Vector3 orig = Vector3.Zero;
777 996
778 frontTopLeft.X = orig.X - (part.Scale.X / 2); 997 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -807,6 +1026,38 @@ namespace OpenSim.Region.Framework.Scenes
807 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1026 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
808 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1027 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
809 1028
1029
1030
1031 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1032 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1033 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1034 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1035 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1036 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1037 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1038 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1039
1040 //for (int i = 0; i < 8; i++)
1041 //{
1042 // corners[i] = corners[i] * worldRot;
1043 // corners[i] += offset;
1044
1045 // if (corners[i].X > maxX)
1046 // maxX = corners[i].X;
1047 // if (corners[i].X < minX)
1048 // minX = corners[i].X;
1049
1050 // if (corners[i].Y > maxY)
1051 // maxY = corners[i].Y;
1052 // if (corners[i].Y < minY)
1053 // minY = corners[i].Y;
1054
1055 // if (corners[i].Z > maxZ)
1056 // maxZ = corners[i].Y;
1057 // if (corners[i].Z < minZ)
1058 // minZ = corners[i].Z;
1059 //}
1060
810 frontTopLeft = frontTopLeft * worldRot; 1061 frontTopLeft = frontTopLeft * worldRot;
811 frontTopRight = frontTopRight * worldRot; 1062 frontTopRight = frontTopRight * worldRot;
812 frontBottomLeft = frontBottomLeft * worldRot; 1063 frontBottomLeft = frontBottomLeft * worldRot;
@@ -828,6 +1079,15 @@ namespace OpenSim.Region.Framework.Scenes
828 backTopLeft += offset; 1079 backTopLeft += offset;
829 backTopRight += offset; 1080 backTopRight += offset;
830 1081
1082 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1083 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1084 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1085 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1086 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1087 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1088 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1089 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1090
831 if (frontTopRight.X > maxX) 1091 if (frontTopRight.X > maxX)
832 maxX = frontTopRight.X; 1092 maxX = frontTopRight.X;
833 if (frontTopLeft.X > maxX) 1093 if (frontTopLeft.X > maxX)
@@ -973,15 +1233,20 @@ namespace OpenSim.Region.Framework.Scenes
973 1233
974 public void SaveScriptedState(XmlTextWriter writer) 1234 public void SaveScriptedState(XmlTextWriter writer)
975 { 1235 {
1236 SaveScriptedState(writer, false);
1237 }
1238
1239 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1240 {
976 XmlDocument doc = new XmlDocument(); 1241 XmlDocument doc = new XmlDocument();
977 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1242 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
978 1243
979 SceneObjectPart[] parts = m_parts.GetArray(); 1244 SceneObjectPart[] parts = m_parts.GetArray();
980 for (int i = 0; i < parts.Length; i++) 1245 for (int i = 0; i < parts.Length; i++)
981 { 1246 {
982 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1247 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
983 foreach (KeyValuePair<UUID, string> kvp in pstates) 1248 foreach (KeyValuePair<UUID, string> kvp in pstates)
984 states.Add(kvp.Key, kvp.Value); 1249 states[kvp.Key] = kvp.Value;
985 } 1250 }
986 1251
987 if (states.Count > 0) 1252 if (states.Count > 0)
@@ -1001,6 +1266,169 @@ namespace OpenSim.Region.Framework.Scenes
1001 } 1266 }
1002 1267
1003 /// <summary> 1268 /// <summary>
1269 /// Add the avatar to this linkset (avatar is sat).
1270 /// </summary>
1271 /// <param name="agentID"></param>
1272 public void AddAvatar(UUID agentID)
1273 {
1274 ScenePresence presence;
1275 if (m_scene.TryGetScenePresence(agentID, out presence))
1276 {
1277 if (!m_linkedAvatars.Contains(presence))
1278 {
1279 m_linkedAvatars.Add(presence);
1280 }
1281 }
1282 }
1283
1284 /// <summary>
1285 /// Delete the avatar from this linkset (avatar is unsat).
1286 /// </summary>
1287 /// <param name="agentID"></param>
1288 public void DeleteAvatar(UUID agentID)
1289 {
1290 ScenePresence presence;
1291 if (m_scene.TryGetScenePresence(agentID, out presence))
1292 {
1293 if (m_linkedAvatars.Contains(presence))
1294 {
1295 m_linkedAvatars.Remove(presence);
1296 }
1297 }
1298 }
1299
1300 /// <summary>
1301 /// Returns the list of linked presences (avatars sat on this group)
1302 /// </summary>
1303 /// <param name="agentID"></param>
1304 public List<ScenePresence> GetLinkedAvatars()
1305 {
1306 return m_linkedAvatars;
1307 }
1308
1309 /// <summary>
1310 /// Attach this scene object to the given avatar.
1311 /// </summary>
1312 /// <param name="agentID"></param>
1313 /// <param name="attachmentpoint"></param>
1314 /// <param name="AttachOffset"></param>
1315 private void AttachToAgent(
1316 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1317 {
1318 if (avatar != null)
1319 {
1320 // don't attach attachments to child agents
1321 if (avatar.IsChildAgent) return;
1322
1323 // Remove from database and parcel prim count
1324 m_scene.DeleteFromStorage(so.UUID);
1325 m_scene.EventManager.TriggerParcelPrimCountTainted();
1326
1327 so.AttachedAvatar = avatar.UUID;
1328
1329 if (so.RootPart.PhysActor != null)
1330 {
1331 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1332 so.RootPart.PhysActor = null;
1333 }
1334
1335 so.AbsolutePosition = attachOffset;
1336 so.RootPart.AttachedPos = attachOffset;
1337 so.IsAttachment = true;
1338 so.RootPart.SetParentLocalId(avatar.LocalId);
1339 so.AttachmentPoint = attachmentpoint;
1340
1341 avatar.AddAttachment(this);
1342
1343 if (!silent)
1344 {
1345 // Killing it here will cause the client to deselect it
1346 // It then reappears on the avatar, deselected
1347 // through the full update below
1348 //
1349 if (IsSelected)
1350 {
1351 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1352 }
1353
1354 IsSelected = false; // fudge....
1355 ScheduleGroupForFullUpdate();
1356 }
1357 }
1358 else
1359 {
1360 m_log.WarnFormat(
1361 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1362 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1363 }
1364 }
1365
1366 public byte GetAttachmentPoint()
1367 {
1368 return m_rootPart.Shape.State;
1369 }
1370
1371 public void DetachToGround()
1372 {
1373 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1374 if (avatar == null)
1375 return;
1376
1377 avatar.RemoveAttachment(this);
1378
1379 Vector3 detachedpos = new Vector3(127f,127f,127f);
1380 if (avatar == null)
1381 return;
1382
1383 detachedpos = avatar.AbsolutePosition;
1384 RootPart.FromItemID = UUID.Zero;
1385
1386 AbsolutePosition = detachedpos;
1387 AttachedAvatar = UUID.Zero;
1388
1389 //SceneObjectPart[] parts = m_parts.GetArray();
1390 //for (int i = 0; i < parts.Length; i++)
1391 // parts[i].AttachedAvatar = UUID.Zero;
1392
1393 m_rootPart.SetParentLocalId(0);
1394 AttachmentPoint = (byte)0;
1395 // must check if buildind should be true or false here
1396 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1397 HasGroupChanged = true;
1398 RootPart.Rezzed = DateTime.Now;
1399 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1400 AttachToBackup();
1401 m_scene.EventManager.TriggerParcelPrimCountTainted();
1402 m_rootPart.ScheduleFullUpdate();
1403 m_rootPart.ClearUndoState();
1404 }
1405
1406 public void DetachToInventoryPrep()
1407 {
1408 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1409 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1410 if (avatar != null)
1411 {
1412 //detachedpos = avatar.AbsolutePosition;
1413 avatar.RemoveAttachment(this);
1414 }
1415
1416 AttachedAvatar = UUID.Zero;
1417
1418 /*SceneObjectPart[] parts = m_parts.GetArray();
1419 for (int i = 0; i < parts.Length; i++)
1420 parts[i].AttachedAvatar = UUID.Zero;*/
1421
1422 m_rootPart.SetParentLocalId(0);
1423 //m_rootPart.SetAttachmentPoint((byte)0);
1424 IsAttachment = false;
1425 AbsolutePosition = m_rootPart.AttachedPos;
1426 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1427 //AttachToBackup();
1428 //m_rootPart.ScheduleFullUpdate();
1429 }
1430
1431 /// <summary>
1004 /// 1432 ///
1005 /// </summary> 1433 /// </summary>
1006 /// <param name="part"></param> 1434 /// <param name="part"></param>
@@ -1050,7 +1478,10 @@ namespace OpenSim.Region.Framework.Scenes
1050 public void AddPart(SceneObjectPart part) 1478 public void AddPart(SceneObjectPart part)
1051 { 1479 {
1052 part.SetParent(this); 1480 part.SetParent(this);
1053 part.LinkNum = m_parts.Add(part.UUID, part); 1481 m_parts.Add(part.UUID, part);
1482
1483 part.LinkNum = m_parts.Count;
1484
1054 if (part.LinkNum == 2) 1485 if (part.LinkNum == 2)
1055 RootPart.LinkNum = 1; 1486 RootPart.LinkNum = 1;
1056 } 1487 }
@@ -1138,7 +1569,7 @@ namespace OpenSim.Region.Framework.Scenes
1138// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1569// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1139// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1570// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1140 1571
1141 part.StoreUndoState(); 1572// part.StoreUndoState();
1142 part.OnGrab(offsetPos, remoteClient); 1573 part.OnGrab(offsetPos, remoteClient);
1143 } 1574 }
1144 1575
@@ -1158,6 +1589,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1589 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1159 public void DeleteGroupFromScene(bool silent) 1590 public void DeleteGroupFromScene(bool silent)
1160 { 1591 {
1592 // We need to keep track of this state in case this group is still queued for backup.
1593 IsDeleted = true;
1594
1595 DetachFromBackup();
1596
1161 SceneObjectPart[] parts = m_parts.GetArray(); 1597 SceneObjectPart[] parts = m_parts.GetArray();
1162 for (int i = 0; i < parts.Length; i++) 1598 for (int i = 0; i < parts.Length; i++)
1163 { 1599 {
@@ -1180,6 +1616,8 @@ namespace OpenSim.Region.Framework.Scenes
1180 } 1616 }
1181 }); 1617 });
1182 } 1618 }
1619
1620
1183 } 1621 }
1184 1622
1185 public void AddScriptLPS(int count) 1623 public void AddScriptLPS(int count)
@@ -1254,28 +1692,43 @@ namespace OpenSim.Region.Framework.Scenes
1254 /// </summary> 1692 /// </summary>
1255 public void ApplyPhysics() 1693 public void ApplyPhysics()
1256 { 1694 {
1257 // Apply physics to the root prim
1258 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1259
1260 // Apply physics to child prims
1261 SceneObjectPart[] parts = m_parts.GetArray(); 1695 SceneObjectPart[] parts = m_parts.GetArray();
1262 if (parts.Length > 1) 1696 if (parts.Length > 1)
1263 { 1697 {
1698 ResetChildPrimPhysicsPositions();
1699
1700 // Apply physics to the root prim
1701 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1702
1703
1264 for (int i = 0; i < parts.Length; i++) 1704 for (int i = 0; i < parts.Length; i++)
1265 { 1705 {
1266 SceneObjectPart part = parts[i]; 1706 SceneObjectPart part = parts[i];
1267 if (part.LocalId != m_rootPart.LocalId) 1707 if (part.LocalId != m_rootPart.LocalId)
1268 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1708 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1269 } 1709 }
1270
1271 // Hack to get the physics scene geometries in the right spot 1710 // Hack to get the physics scene geometries in the right spot
1272 ResetChildPrimPhysicsPositions(); 1711// ResetChildPrimPhysicsPositions();
1712 if (m_rootPart.PhysActor != null)
1713 {
1714 m_rootPart.PhysActor.Building = false;
1715 }
1716 }
1717 else
1718 {
1719 // Apply physics to the root prim
1720 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1273 } 1721 }
1274 } 1722 }
1275 1723
1276 public void SetOwnerId(UUID userId) 1724 public void SetOwnerId(UUID userId)
1277 { 1725 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1726 ForEachPart(delegate(SceneObjectPart part)
1727 {
1728
1729 part.OwnerID = userId;
1730
1731 });
1279 } 1732 }
1280 1733
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1734 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1307,11 +1760,17 @@ namespace OpenSim.Region.Framework.Scenes
1307 return; 1760 return;
1308 } 1761 }
1309 1762
1763 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1764 return;
1765
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1766 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1311 // any exception propogate upwards. 1767 // any exception propogate upwards.
1312 try 1768 try
1313 { 1769 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1770 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1771 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1772 m_scene.LoadingPrims) // Land may not be valid yet
1773
1315 { 1774 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1775 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1776 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1338,6 +1797,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1797 }
1339 } 1798 }
1340 } 1799 }
1800
1341 } 1801 }
1342 1802
1343 if (m_scene.UseBackup && HasGroupChanged) 1803 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,6 +1805,20 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1805 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1806 if (isTimeToPersist() || forcedBackup)
1347 { 1807 {
1808 if (m_rootPart.PhysActor != null &&
1809 (!m_rootPart.PhysActor.IsPhysical))
1810 {
1811 // Possible ghost prim
1812 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1813 {
1814 foreach (SceneObjectPart part in m_parts.GetArray())
1815 {
1816 // Re-set physics actor positions and
1817 // orientations
1818 part.GroupPosition = m_rootPart.GroupPosition;
1819 }
1820 }
1821 }
1348// m_log.DebugFormat( 1822// m_log.DebugFormat(
1349// "[SCENE]: Storing {0}, {1} in {2}", 1823// "[SCENE]: Storing {0}, {1} in {2}",
1350// Name, UUID, m_scene.RegionInfo.RegionName); 1824// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1362,6 +1836,11 @@ namespace OpenSim.Region.Framework.Scenes
1362 1836
1363 backup_group.ForEachPart(delegate(SceneObjectPart part) 1837 backup_group.ForEachPart(delegate(SceneObjectPart part)
1364 { 1838 {
1839 if (part.KeyframeMotion != null)
1840 {
1841 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
1842 part.KeyframeMotion.UpdateSceneObject(this);
1843 }
1365 part.Inventory.ProcessInventoryBackup(datastore); 1844 part.Inventory.ProcessInventoryBackup(datastore);
1366 }); 1845 });
1367 1846
@@ -1414,6 +1893,7 @@ namespace OpenSim.Region.Framework.Scenes
1414 /// <returns></returns> 1893 /// <returns></returns>
1415 public SceneObjectGroup Copy(bool userExposed) 1894 public SceneObjectGroup Copy(bool userExposed)
1416 { 1895 {
1896 m_dupeInProgress = true;
1417 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1897 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1418 dupe.m_isBackedUp = false; 1898 dupe.m_isBackedUp = false;
1419 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1899 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1428,7 +1908,7 @@ namespace OpenSim.Region.Framework.Scenes
1428 // This is only necessary when userExposed is false! 1908 // This is only necessary when userExposed is false!
1429 1909
1430 bool previousAttachmentStatus = dupe.IsAttachment; 1910 bool previousAttachmentStatus = dupe.IsAttachment;
1431 1911
1432 if (!userExposed) 1912 if (!userExposed)
1433 dupe.IsAttachment = true; 1913 dupe.IsAttachment = true;
1434 1914
@@ -1446,11 +1926,11 @@ namespace OpenSim.Region.Framework.Scenes
1446 dupe.m_rootPart.TrimPermissions(); 1926 dupe.m_rootPart.TrimPermissions();
1447 1927
1448 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1928 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1449 1929
1450 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1930 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1451 { 1931 {
1452 return p1.LinkNum.CompareTo(p2.LinkNum); 1932 return p1.LinkNum.CompareTo(p2.LinkNum);
1453 } 1933 }
1454 ); 1934 );
1455 1935
1456 foreach (SceneObjectPart part in partList) 1936 foreach (SceneObjectPart part in partList)
@@ -1470,21 +1950,24 @@ namespace OpenSim.Region.Framework.Scenes
1470 if (part.PhysActor != null && userExposed) 1950 if (part.PhysActor != null && userExposed)
1471 { 1951 {
1472 PrimitiveBaseShape pbs = newPart.Shape; 1952 PrimitiveBaseShape pbs = newPart.Shape;
1473 1953
1474 newPart.PhysActor 1954 newPart.PhysActor
1475 = m_scene.PhysicsScene.AddPrimShape( 1955 = m_scene.PhysicsScene.AddPrimShape(
1476 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1956 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1477 pbs, 1957 pbs,
1478 newPart.AbsolutePosition, 1958 newPart.AbsolutePosition,
1479 newPart.Scale, 1959 newPart.Scale,
1480 newPart.RotationOffset, 1960 //newPart.RotationOffset,
1961 newPart.GetWorldRotation(),
1481 part.PhysActor.IsPhysical, 1962 part.PhysActor.IsPhysical,
1482 newPart.LocalId); 1963 newPart.LocalId);
1483 1964
1484 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1965 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1485 } 1966 }
1486 } 1967 }
1487 1968 if (dupe.m_rootPart.PhysActor != null && userExposed)
1969 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
1970
1488 if (userExposed) 1971 if (userExposed)
1489 { 1972 {
1490 dupe.UpdateParentIDs(); 1973 dupe.UpdateParentIDs();
@@ -1494,6 +1977,7 @@ namespace OpenSim.Region.Framework.Scenes
1494 ScheduleGroupForFullUpdate(); 1977 ScheduleGroupForFullUpdate();
1495 } 1978 }
1496 1979
1980 m_dupeInProgress = false;
1497 return dupe; 1981 return dupe;
1498 } 1982 }
1499 1983
@@ -1505,11 +1989,24 @@ namespace OpenSim.Region.Framework.Scenes
1505 /// <param name="cGroupID"></param> 1989 /// <param name="cGroupID"></param>
1506 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 1990 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1507 { 1991 {
1508 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 1992 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
1993 // give newpart a new local ID lettng old part keep same
1994 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
1995 newpart.LocalId = m_scene.AllocateLocalId();
1996
1997 SetRootPart(newpart);
1998 if (userExposed)
1999 RootPart.Velocity = Vector3.Zero; // In case source is moving
1509 } 2000 }
1510 2001
1511 public void ScriptSetPhysicsStatus(bool usePhysics) 2002 public void ScriptSetPhysicsStatus(bool usePhysics)
1512 { 2003 {
2004 if (usePhysics)
2005 {
2006 if (RootPart.KeyframeMotion != null)
2007 RootPart.KeyframeMotion.Stop();
2008 RootPart.KeyframeMotion = null;
2009 }
1513 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2010 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1514 } 2011 }
1515 2012
@@ -1573,32 +2070,12 @@ namespace OpenSim.Region.Framework.Scenes
1573 } 2070 }
1574 } 2071 }
1575 2072
1576 public void setAngularImpulse(Vector3 impulse)
1577 {
1578 if (RootPart.PhysActor != null)
1579 {
1580 if (!IsAttachment)
1581 {
1582 RootPart.PhysActor.Torque = impulse;
1583 m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor);
1584 }
1585 }
1586 }
1587
1588 public Vector3 GetTorque() 2073 public Vector3 GetTorque()
1589 { 2074 {
1590 if (RootPart.PhysActor != null) 2075 return RootPart.Torque;
1591 {
1592 if (!IsAttachment)
1593 {
1594 Vector3 torque = RootPart.PhysActor.Torque;
1595 return torque;
1596 }
1597 }
1598
1599 return Vector3.Zero;
1600 } 2076 }
1601 2077
2078 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1602 public void moveToTarget(Vector3 target, float tau) 2079 public void moveToTarget(Vector3 target, float tau)
1603 { 2080 {
1604 if (IsAttachment) 2081 if (IsAttachment)
@@ -1626,6 +2103,46 @@ namespace OpenSim.Region.Framework.Scenes
1626 RootPart.PhysActor.PIDActive = false; 2103 RootPart.PhysActor.PIDActive = false;
1627 } 2104 }
1628 2105
2106 public void rotLookAt(Quaternion target, float strength, float damping)
2107 {
2108 SceneObjectPart rootpart = m_rootPart;
2109 if (rootpart != null)
2110 {
2111 if (IsAttachment)
2112 {
2113 /*
2114 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2115 if (avatar != null)
2116 {
2117 Rotate the Av?
2118 } */
2119 }
2120 else
2121 {
2122 if (rootpart.PhysActor != null)
2123 { // APID must be implemented in your physics system for this to function.
2124 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2125 rootpart.PhysActor.APIDStrength = strength;
2126 rootpart.PhysActor.APIDDamping = damping;
2127 rootpart.PhysActor.APIDActive = true;
2128 }
2129 }
2130 }
2131 }
2132
2133 public void stopLookAt()
2134 {
2135 SceneObjectPart rootpart = m_rootPart;
2136 if (rootpart != null)
2137 {
2138 if (rootpart.PhysActor != null)
2139 { // APID must be implemented in your physics system for this to function.
2140 rootpart.PhysActor.APIDActive = false;
2141 }
2142 }
2143
2144 }
2145
1629 /// <summary> 2146 /// <summary>
1630 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2147 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1631 /// </summary> 2148 /// </summary>
@@ -1680,7 +2197,12 @@ namespace OpenSim.Region.Framework.Scenes
1680 /// <param name="cGroupID"></param> 2197 /// <param name="cGroupID"></param>
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2198 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2199 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2200 // give new ID to the new part, letting old keep original
2201 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2202 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2203 newPart.LocalId = m_scene.AllocateLocalId();
2204 newPart.SetParent(this);
2205
1684 AddPart(newPart); 2206 AddPart(newPart);
1685 2207
1686 SetPartAsNonRoot(newPart); 2208 SetPartAsNonRoot(newPart);
@@ -1809,11 +2331,11 @@ namespace OpenSim.Region.Framework.Scenes
1809 /// Immediately send a full update for this scene object. 2331 /// Immediately send a full update for this scene object.
1810 /// </summary> 2332 /// </summary>
1811 public void SendGroupFullUpdate() 2333 public void SendGroupFullUpdate()
1812 { 2334 {
1813 if (IsDeleted) 2335 if (IsDeleted)
1814 return; 2336 return;
1815 2337
1816// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2338// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1817 2339
1818 RootPart.SendFullUpdateToAllClients(); 2340 RootPart.SendFullUpdateToAllClients();
1819 2341
@@ -1957,6 +2479,11 @@ namespace OpenSim.Region.Framework.Scenes
1957 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2479 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1958 public void LinkToGroup(SceneObjectGroup objectGroup) 2480 public void LinkToGroup(SceneObjectGroup objectGroup)
1959 { 2481 {
2482 LinkToGroup(objectGroup, false);
2483 }
2484
2485 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2486 {
1960// m_log.DebugFormat( 2487// m_log.DebugFormat(
1961// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2488// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1962// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); 2489// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1967,6 +2494,11 @@ namespace OpenSim.Region.Framework.Scenes
1967 2494
1968 SceneObjectPart linkPart = objectGroup.m_rootPart; 2495 SceneObjectPart linkPart = objectGroup.m_rootPart;
1969 2496
2497 if (m_rootPart.PhysActor != null)
2498 m_rootPart.PhysActor.Building = true;
2499 if (linkPart.PhysActor != null)
2500 linkPart.PhysActor.Building = true;
2501
1970 Vector3 oldGroupPosition = linkPart.GroupPosition; 2502 Vector3 oldGroupPosition = linkPart.GroupPosition;
1971 Quaternion oldRootRotation = linkPart.RotationOffset; 2503 Quaternion oldRootRotation = linkPart.RotationOffset;
1972 2504
@@ -1990,13 +2522,33 @@ namespace OpenSim.Region.Framework.Scenes
1990 2522
1991 lock (m_parts.SyncRoot) 2523 lock (m_parts.SyncRoot)
1992 { 2524 {
1993 int linkNum = PrimCount + 1; 2525 int linkNum;
2526 if (insert)
2527 {
2528 linkNum = 2;
2529 foreach (SceneObjectPart part in Parts)
2530 {
2531 if (part.LinkNum > 1)
2532 part.LinkNum++;
2533 }
2534 }
2535 else
2536 {
2537 linkNum = PrimCount + 1;
2538 }
1994 2539
1995 m_parts.Add(linkPart.UUID, linkPart); 2540 m_parts.Add(linkPart.UUID, linkPart);
1996 2541
1997 linkPart.SetParent(this); 2542 linkPart.SetParent(this);
1998 linkPart.CreateSelected = true; 2543 linkPart.CreateSelected = true;
1999 2544
2545 // let physics know
2546 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2547 {
2548 linkPart.PhysActor.link(m_rootPart.PhysActor);
2549 this.Scene.PhysicsScene.AddPhysicsActorTaint(linkPart.PhysActor);
2550 }
2551
2000 linkPart.LinkNum = linkNum++; 2552 linkPart.LinkNum = linkNum++;
2001 2553
2002 SceneObjectPart[] ogParts = objectGroup.Parts; 2554 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2009,7 +2561,15 @@ namespace OpenSim.Region.Framework.Scenes
2009 { 2561 {
2010 SceneObjectPart part = ogParts[i]; 2562 SceneObjectPart part = ogParts[i];
2011 if (part.UUID != objectGroup.m_rootPart.UUID) 2563 if (part.UUID != objectGroup.m_rootPart.UUID)
2564 {
2012 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2565 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2566 // let physics know
2567 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2568 {
2569 part.PhysActor.link(m_rootPart.PhysActor);
2570 this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2571 }
2572 }
2013 part.ClearUndoState(); 2573 part.ClearUndoState();
2014 } 2574 }
2015 } 2575 }
@@ -2018,7 +2578,7 @@ namespace OpenSim.Region.Framework.Scenes
2018 objectGroup.IsDeleted = true; 2578 objectGroup.IsDeleted = true;
2019 2579
2020 objectGroup.m_parts.Clear(); 2580 objectGroup.m_parts.Clear();
2021 2581
2022 // Can't do this yet since backup still makes use of the root part without any synchronization 2582 // Can't do this yet since backup still makes use of the root part without any synchronization
2023// objectGroup.m_rootPart = null; 2583// objectGroup.m_rootPart = null;
2024 2584
@@ -2029,6 +2589,9 @@ namespace OpenSim.Region.Framework.Scenes
2029 // unmoved prims! 2589 // unmoved prims!
2030 ResetChildPrimPhysicsPositions(); 2590 ResetChildPrimPhysicsPositions();
2031 2591
2592 if (m_rootPart.PhysActor != null)
2593 m_rootPart.PhysActor.Building = false;
2594
2032 //HasGroupChanged = true; 2595 //HasGroupChanged = true;
2033 //ScheduleGroupForFullUpdate(); 2596 //ScheduleGroupForFullUpdate();
2034 } 2597 }
@@ -2081,7 +2644,10 @@ namespace OpenSim.Region.Framework.Scenes
2081// m_log.DebugFormat( 2644// m_log.DebugFormat(
2082// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2645// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2083// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2646// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2084 2647
2648 if (m_rootPart.PhysActor != null)
2649 m_rootPart.PhysActor.Building = true;
2650
2085 linkPart.ClearUndoState(); 2651 linkPart.ClearUndoState();
2086 2652
2087 Quaternion worldRot = linkPart.GetWorldRotation(); 2653 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2141,6 +2707,10 @@ namespace OpenSim.Region.Framework.Scenes
2141 2707
2142 // When we delete a group, we currently have to force persist to the database if the object id has changed 2708 // When we delete a group, we currently have to force persist to the database if the object id has changed
2143 // (since delete works by deleting all rows which have a given object id) 2709 // (since delete works by deleting all rows which have a given object id)
2710
2711 if (m_rootPart.PhysActor != null)
2712 m_rootPart.PhysActor.Building = false;
2713
2144 objectGroup.HasGroupChangedDueToDelink = true; 2714 objectGroup.HasGroupChangedDueToDelink = true;
2145 2715
2146 return objectGroup; 2716 return objectGroup;
@@ -2152,6 +2722,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 /// <param name="objectGroup"></param> 2722 /// <param name="objectGroup"></param>
2153 public virtual void DetachFromBackup() 2723 public virtual void DetachFromBackup()
2154 { 2724 {
2725 m_scene.SceneGraph.FireDetachFromBackup(this);
2155 if (m_isBackedUp && Scene != null) 2726 if (m_isBackedUp && Scene != null)
2156 m_scene.EventManager.OnBackup -= ProcessBackup; 2727 m_scene.EventManager.OnBackup -= ProcessBackup;
2157 2728
@@ -2170,7 +2741,8 @@ namespace OpenSim.Region.Framework.Scenes
2170 2741
2171 axPos *= parentRot; 2742 axPos *= parentRot;
2172 part.OffsetPosition = axPos; 2743 part.OffsetPosition = axPos;
2173 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2744 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2745 part.GroupPosition = newPos;
2174 part.OffsetPosition = Vector3.Zero; 2746 part.OffsetPosition = Vector3.Zero;
2175 part.RotationOffset = worldRot; 2747 part.RotationOffset = worldRot;
2176 2748
@@ -2181,7 +2753,7 @@ namespace OpenSim.Region.Framework.Scenes
2181 2753
2182 part.LinkNum = linkNum; 2754 part.LinkNum = linkNum;
2183 2755
2184 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2756 part.OffsetPosition = newPos - AbsolutePosition;
2185 2757
2186 Quaternion rootRotation = m_rootPart.RotationOffset; 2758 Quaternion rootRotation = m_rootPart.RotationOffset;
2187 2759
@@ -2191,7 +2763,7 @@ namespace OpenSim.Region.Framework.Scenes
2191 2763
2192 parentRot = m_rootPart.RotationOffset; 2764 parentRot = m_rootPart.RotationOffset;
2193 oldRot = part.RotationOffset; 2765 oldRot = part.RotationOffset;
2194 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2766 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2195 part.RotationOffset = newRot; 2767 part.RotationOffset = newRot;
2196 } 2768 }
2197 2769
@@ -2438,8 +3010,31 @@ namespace OpenSim.Region.Framework.Scenes
2438 } 3010 }
2439 } 3011 }
2440 3012
3013/*
3014 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2441 for (int i = 0; i < parts.Length; i++) 3015 for (int i = 0; i < parts.Length; i++)
2442 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3016 {
3017 if (parts[i] != RootPart)
3018 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
3019 }
3020*/
3021 if (parts.Length > 1)
3022 {
3023 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3024
3025 for (int i = 0; i < parts.Length; i++)
3026 {
3027
3028 if (parts[i].UUID != m_rootPart.UUID)
3029 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3030 }
3031
3032 if (m_rootPart.PhysActor != null)
3033 m_rootPart.PhysActor.Building = false;
3034 }
3035 else
3036 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3037
2443 } 3038 }
2444 } 3039 }
2445 3040
@@ -2452,6 +3047,17 @@ namespace OpenSim.Region.Framework.Scenes
2452 } 3047 }
2453 } 3048 }
2454 3049
3050
3051
3052 /// <summary>
3053 /// Gets the number of parts
3054 /// </summary>
3055 /// <returns></returns>
3056 public int GetPartCount()
3057 {
3058 return Parts.Count();
3059 }
3060
2455 /// <summary> 3061 /// <summary>
2456 /// Update the texture entry for this part 3062 /// Update the texture entry for this part
2457 /// </summary> 3063 /// </summary>
@@ -2513,8 +3119,7 @@ namespace OpenSim.Region.Framework.Scenes
2513 { 3119 {
2514// m_log.DebugFormat( 3120// m_log.DebugFormat(
2515// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 3121// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2516 3122// RootPart.StoreUndoState(true);
2517 RootPart.StoreUndoState(true);
2518 3123
2519 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3124 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2520 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3125 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
@@ -2614,7 +3219,6 @@ namespace OpenSim.Region.Framework.Scenes
2614 prevScale.X *= x; 3219 prevScale.X *= x;
2615 prevScale.Y *= y; 3220 prevScale.Y *= y;
2616 prevScale.Z *= z; 3221 prevScale.Z *= z;
2617
2618// RootPart.IgnoreUndoUpdate = true; 3222// RootPart.IgnoreUndoUpdate = true;
2619 RootPart.Resize(prevScale); 3223 RootPart.Resize(prevScale);
2620// RootPart.IgnoreUndoUpdate = false; 3224// RootPart.IgnoreUndoUpdate = false;
@@ -2626,7 +3230,7 @@ namespace OpenSim.Region.Framework.Scenes
2626 3230
2627 if (obPart.UUID != m_rootPart.UUID) 3231 if (obPart.UUID != m_rootPart.UUID)
2628 { 3232 {
2629 obPart.IgnoreUndoUpdate = true; 3233// obPart.IgnoreUndoUpdate = true;
2630 3234
2631 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3235 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2632 currentpos.X *= x; 3236 currentpos.X *= x;
@@ -2641,11 +3245,13 @@ namespace OpenSim.Region.Framework.Scenes
2641 obPart.Resize(newSize); 3245 obPart.Resize(newSize);
2642 obPart.UpdateOffSet(currentpos); 3246 obPart.UpdateOffSet(currentpos);
2643 3247
2644 obPart.IgnoreUndoUpdate = false; 3248// obPart.IgnoreUndoUpdate = false;
2645 } 3249 }
2646 3250
2647// obPart.IgnoreUndoUpdate = false; 3251// obPart.IgnoreUndoUpdate = false;
2648// obPart.StoreUndoState(); 3252 HasGroupChanged = true;
3253 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3254 ScheduleGroupForTerseUpdate();
2649 } 3255 }
2650 3256
2651// m_log.DebugFormat( 3257// m_log.DebugFormat(
@@ -2664,7 +3270,7 @@ namespace OpenSim.Region.Framework.Scenes
2664 { 3270 {
2665// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos); 3271// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2666 3272
2667 RootPart.StoreUndoState(true); 3273// RootPart.StoreUndoState(true);
2668 3274
2669// SceneObjectPart[] parts = m_parts.GetArray(); 3275// SceneObjectPart[] parts = m_parts.GetArray();
2670// for (int i = 0; i < parts.Length; i++) 3276// for (int i = 0; i < parts.Length; i++)
@@ -2714,8 +3320,12 @@ namespace OpenSim.Region.Framework.Scenes
2714// m_log.DebugFormat( 3320// m_log.DebugFormat(
2715// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3321// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos);
2716 3322
2717 part.StoreUndoState(false); 3323// part.StoreUndoState(false);
2718 part.IgnoreUndoUpdate = true; 3324// part.IgnoreUndoUpdate = true;
3325
3326// unlock parts position change
3327 if (m_rootPart.PhysActor != null)
3328 m_rootPart.PhysActor.Building = true;
2719 3329
2720 if (part.UUID == m_rootPart.UUID) 3330 if (part.UUID == m_rootPart.UUID)
2721 { 3331 {
@@ -2726,8 +3336,11 @@ namespace OpenSim.Region.Framework.Scenes
2726 part.UpdateOffSet(pos); 3336 part.UpdateOffSet(pos);
2727 } 3337 }
2728 3338
3339 if (m_rootPart.PhysActor != null)
3340 m_rootPart.PhysActor.Building = false;
3341
2729 HasGroupChanged = true; 3342 HasGroupChanged = true;
2730 part.IgnoreUndoUpdate = false; 3343// part.IgnoreUndoUpdate = false;
2731 } 3344 }
2732 } 3345 }
2733 3346
@@ -2763,10 +3376,27 @@ namespace OpenSim.Region.Framework.Scenes
2763 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3376 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2764 } 3377 }
2765 3378
2766 AbsolutePosition = newPos; 3379 //We have to set undoing here because otherwise an undo state will be saved
3380// if (!m_rootPart.Undoing)
3381// {
3382// m_rootPart.Undoing = true;
3383 AbsolutePosition = newPos;
3384// m_rootPart.Undoing = false;
3385// }
3386// else
3387// {
3388// AbsolutePosition = newPos;
3389// }
2767 3390
2768 HasGroupChanged = true; 3391 HasGroupChanged = true;
2769 ScheduleGroupForTerseUpdate(); 3392 if (m_rootPart.Undoing)
3393 {
3394 ScheduleGroupForFullUpdate();
3395 }
3396 else
3397 {
3398 ScheduleGroupForTerseUpdate();
3399 }
2770 } 3400 }
2771 3401
2772 #endregion 3402 #endregion
@@ -2786,9 +3416,9 @@ namespace OpenSim.Region.Framework.Scenes
2786// for (int i = 0; i < parts.Length; i++) 3416// for (int i = 0; i < parts.Length; i++)
2787// parts[i].StoreUndoState(); 3417// parts[i].StoreUndoState();
2788 3418
2789 m_rootPart.StoreUndoState(true); 3419// m_rootPart.StoreUndoState(true);
2790 3420
2791 m_rootPart.UpdateRotation(rot); 3421// m_rootPart.UpdateRotation(rot);
2792 3422
2793 PhysicsActor actor = m_rootPart.PhysActor; 3423 PhysicsActor actor = m_rootPart.PhysActor;
2794 if (actor != null) 3424 if (actor != null)
@@ -2815,8 +3445,8 @@ namespace OpenSim.Region.Framework.Scenes
2815// for (int i = 0; i < parts.Length; i++) 3445// for (int i = 0; i < parts.Length; i++)
2816// parts[i].StoreUndoState(); 3446// parts[i].StoreUndoState();
2817 3447
2818 RootPart.StoreUndoState(true); 3448// RootPart.StoreUndoState(true);
2819 RootPart.IgnoreUndoUpdate = true; 3449// RootPart.IgnoreUndoUpdate = true;
2820 3450
2821 m_rootPart.UpdateRotation(rot); 3451 m_rootPart.UpdateRotation(rot);
2822 3452
@@ -2832,7 +3462,7 @@ namespace OpenSim.Region.Framework.Scenes
2832 HasGroupChanged = true; 3462 HasGroupChanged = true;
2833 ScheduleGroupForTerseUpdate(); 3463 ScheduleGroupForTerseUpdate();
2834 3464
2835 RootPart.IgnoreUndoUpdate = false; 3465// RootPart.IgnoreUndoUpdate = false;
2836 } 3466 }
2837 3467
2838 /// <summary> 3468 /// <summary>
@@ -2843,16 +3473,16 @@ namespace OpenSim.Region.Framework.Scenes
2843 public void UpdateSingleRotation(Quaternion rot, uint localID) 3473 public void UpdateSingleRotation(Quaternion rot, uint localID)
2844 { 3474 {
2845 SceneObjectPart part = GetChildPart(localID); 3475 SceneObjectPart part = GetChildPart(localID);
2846
2847 SceneObjectPart[] parts = m_parts.GetArray(); 3476 SceneObjectPart[] parts = m_parts.GetArray();
2848 for (int i = 0; i < parts.Length; i++)
2849 parts[i].StoreUndoState();
2850 3477
2851 if (part != null) 3478 if (part != null)
2852 { 3479 {
2853// m_log.DebugFormat( 3480// m_log.DebugFormat(
2854// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3481// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot);
2855 3482
3483 if (m_rootPart.PhysActor != null)
3484 m_rootPart.PhysActor.Building = true;
3485
2856 if (part.UUID == m_rootPart.UUID) 3486 if (part.UUID == m_rootPart.UUID)
2857 { 3487 {
2858 UpdateRootRotation(rot); 3488 UpdateRootRotation(rot);
@@ -2861,6 +3491,9 @@ namespace OpenSim.Region.Framework.Scenes
2861 { 3491 {
2862 part.UpdateRotation(rot); 3492 part.UpdateRotation(rot);
2863 } 3493 }
3494
3495 if (m_rootPart.PhysActor != null)
3496 m_rootPart.PhysActor.Building = false;
2864 } 3497 }
2865 } 3498 }
2866 3499
@@ -2878,13 +3511,26 @@ namespace OpenSim.Region.Framework.Scenes
2878// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3511// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}",
2879// part.Name, part.LocalId, rot); 3512// part.Name, part.LocalId, rot);
2880 3513
2881 part.StoreUndoState(); 3514// part.StoreUndoState();
2882 part.IgnoreUndoUpdate = true; 3515// part.IgnoreUndoUpdate = true;
3516
3517 if (m_rootPart.PhysActor != null)
3518 m_rootPart.PhysActor.Building = true;
2883 3519
2884 if (part.UUID == m_rootPart.UUID) 3520 if (part.UUID == m_rootPart.UUID)
2885 { 3521 {
2886 UpdateRootRotation(rot); 3522 UpdateRootRotation(rot);
2887 AbsolutePosition = pos; 3523/* if (!m_rootPart.Undoing)
3524 {
3525 m_rootPart.Undoing = true;
3526 AbsolutePosition = pos;
3527 m_rootPart.Undoing = false;
3528 }
3529 else
3530 {
3531 */
3532 AbsolutePosition = pos;
3533// }
2888 } 3534 }
2889 else 3535 else
2890 { 3536 {
@@ -2892,7 +3538,10 @@ namespace OpenSim.Region.Framework.Scenes
2892 part.OffsetPosition = pos; 3538 part.OffsetPosition = pos;
2893 } 3539 }
2894 3540
2895 part.IgnoreUndoUpdate = false; 3541 if (m_rootPart.PhysActor != null)
3542 m_rootPart.PhysActor.Building = false;
3543
3544// part.IgnoreUndoUpdate = false;
2896 } 3545 }
2897 } 3546 }
2898 3547
@@ -2908,9 +3557,10 @@ namespace OpenSim.Region.Framework.Scenes
2908 3557
2909 Quaternion axRot = rot; 3558 Quaternion axRot = rot;
2910 Quaternion oldParentRot = m_rootPart.RotationOffset; 3559 Quaternion oldParentRot = m_rootPart.RotationOffset;
2911 3560// m_rootPart.StoreUndoState();
2912 m_rootPart.StoreUndoState(); 3561
2913 m_rootPart.UpdateRotation(rot); 3562 //Don't use UpdateRotation because it schedules an update prematurely
3563 m_rootPart.RotationOffset = rot;
2914 if (m_rootPart.PhysActor != null) 3564 if (m_rootPart.PhysActor != null)
2915 { 3565 {
2916 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3566 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2923,17 +3573,19 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart prim = parts[i]; 3573 SceneObjectPart prim = parts[i];
2924 if (prim.UUID != m_rootPart.UUID) 3574 if (prim.UUID != m_rootPart.UUID)
2925 { 3575 {
2926 prim.IgnoreUndoUpdate = true; 3576// prim.IgnoreUndoUpdate = true;
3577
3578 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3579 NewRot = Quaternion.Inverse(axRot) * NewRot;
3580 prim.RotationOffset = NewRot;
3581
2927 Vector3 axPos = prim.OffsetPosition; 3582 Vector3 axPos = prim.OffsetPosition;
3583
2928 axPos *= oldParentRot; 3584 axPos *= oldParentRot;
2929 axPos *= Quaternion.Inverse(axRot); 3585 axPos *= Quaternion.Inverse(axRot);
2930 prim.OffsetPosition = axPos; 3586 prim.OffsetPosition = axPos;
2931 Quaternion primsRot = prim.RotationOffset; 3587
2932 Quaternion newRot = oldParentRot * primsRot; 3588// prim.IgnoreUndoUpdate = false;
2933 newRot = Quaternion.Inverse(axRot) * newRot;
2934 prim.RotationOffset = newRot;
2935 prim.ScheduleTerseUpdate();
2936 prim.IgnoreUndoUpdate = false;
2937 } 3589 }
2938 } 3590 }
2939 3591
@@ -2946,8 +3598,8 @@ namespace OpenSim.Region.Framework.Scenes
2946//// childpart.StoreUndoState(); 3598//// childpart.StoreUndoState();
2947// } 3599// }
2948// } 3600// }
2949 3601 HasGroupChanged = true;
2950 m_rootPart.ScheduleTerseUpdate(); 3602 ScheduleGroupForFullUpdate();
2951 3603
2952// m_log.DebugFormat( 3604// m_log.DebugFormat(
2953// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3605// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3175,7 +3827,6 @@ namespace OpenSim.Region.Framework.Scenes
3175 public float GetMass() 3827 public float GetMass()
3176 { 3828 {
3177 float retmass = 0f; 3829 float retmass = 0f;
3178
3179 SceneObjectPart[] parts = m_parts.GetArray(); 3830 SceneObjectPart[] parts = m_parts.GetArray();
3180 for (int i = 0; i < parts.Length; i++) 3831 for (int i = 0; i < parts.Length; i++)
3181 retmass += parts[i].GetMass(); 3832 retmass += parts[i].GetMass();
@@ -3271,6 +3922,14 @@ namespace OpenSim.Region.Framework.Scenes
3271 SetFromItemID(uuid); 3922 SetFromItemID(uuid);
3272 } 3923 }
3273 3924
3925 public void ResetOwnerChangeFlag()
3926 {
3927 ForEachPart(delegate(SceneObjectPart part)
3928 {
3929 part.ResetOwnerChangeFlag();
3930 });
3931 }
3932
3274 #endregion 3933 #endregion
3275 } 3934 }
3276} 3935}