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.cs1076
1 files changed, 875 insertions, 201 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 878476e..6feb333 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)
@@ -1460,40 +1940,53 @@ namespace OpenSim.Region.Framework.Scenes
1460 { 1940 {
1461 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1941 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1462 newPart.LinkNum = part.LinkNum; 1942 newPart.LinkNum = part.LinkNum;
1463 } 1943 if (userExposed)
1944 newPart.ParentID = dupe.m_rootPart.LocalId;
1945 }
1464 else 1946 else
1465 { 1947 {
1466 newPart = dupe.m_rootPart; 1948 newPart = dupe.m_rootPart;
1467 } 1949 }
1950/*
1951 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
1952 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1468 1953
1469 // Need to duplicate the physics actor as well 1954 // Need to duplicate the physics actor as well
1470 if (part.PhysActor != null && userExposed) 1955 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1471 { 1956 {
1472 PrimitiveBaseShape pbs = newPart.Shape; 1957 PrimitiveBaseShape pbs = newPart.Shape;
1473
1474 newPart.PhysActor 1958 newPart.PhysActor
1475 = m_scene.PhysicsScene.AddPrimShape( 1959 = m_scene.PhysicsScene.AddPrimShape(
1476 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1960 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1477 pbs, 1961 pbs,
1478 newPart.AbsolutePosition, 1962 newPart.AbsolutePosition,
1479 newPart.Scale, 1963 newPart.Scale,
1480 newPart.RotationOffset, 1964 newPart.GetWorldRotation(),
1481 part.PhysActor.IsPhysical, 1965 isphys,
1966 isphan,
1482 newPart.LocalId); 1967 newPart.LocalId);
1483 1968
1484 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1969 newPart.DoPhysicsPropertyUpdate(isphys, true);
1485 } 1970 */
1971 if (userExposed)
1972 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
1973// }
1486 } 1974 }
1487 1975
1488 if (userExposed) 1976 if (userExposed)
1489 { 1977 {
1490 dupe.UpdateParentIDs(); 1978// done above dupe.UpdateParentIDs();
1979
1980 if (dupe.m_rootPart.PhysActor != null)
1981 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
1982
1491 dupe.HasGroupChanged = true; 1983 dupe.HasGroupChanged = true;
1492 dupe.AttachToBackup(); 1984 dupe.AttachToBackup();
1493 1985
1494 ScheduleGroupForFullUpdate(); 1986 ScheduleGroupForFullUpdate();
1495 } 1987 }
1496 1988
1989 m_dupeInProgress = false;
1497 return dupe; 1990 return dupe;
1498 } 1991 }
1499 1992
@@ -1505,11 +1998,24 @@ namespace OpenSim.Region.Framework.Scenes
1505 /// <param name="cGroupID"></param> 1998 /// <param name="cGroupID"></param>
1506 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 1999 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1507 { 2000 {
1508 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2001 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2002 // give newpart a new local ID lettng old part keep same
2003 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2004 newpart.LocalId = m_scene.AllocateLocalId();
2005
2006 SetRootPart(newpart);
2007 if (userExposed)
2008 RootPart.Velocity = Vector3.Zero; // In case source is moving
1509 } 2009 }
1510 2010
1511 public void ScriptSetPhysicsStatus(bool usePhysics) 2011 public void ScriptSetPhysicsStatus(bool usePhysics)
1512 { 2012 {
2013 if (usePhysics)
2014 {
2015 if (RootPart.KeyframeMotion != null)
2016 RootPart.KeyframeMotion.Stop();
2017 RootPart.KeyframeMotion = null;
2018 }
1513 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2019 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1514 } 2020 }
1515 2021
@@ -1573,32 +2079,12 @@ namespace OpenSim.Region.Framework.Scenes
1573 } 2079 }
1574 } 2080 }
1575 2081
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() 2082 public Vector3 GetTorque()
1589 { 2083 {
1590 if (RootPart.PhysActor != null) 2084 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 } 2085 }
1601 2086
2087 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1602 public void moveToTarget(Vector3 target, float tau) 2088 public void moveToTarget(Vector3 target, float tau)
1603 { 2089 {
1604 if (IsAttachment) 2090 if (IsAttachment)
@@ -1626,6 +2112,46 @@ namespace OpenSim.Region.Framework.Scenes
1626 RootPart.PhysActor.PIDActive = false; 2112 RootPart.PhysActor.PIDActive = false;
1627 } 2113 }
1628 2114
2115 public void rotLookAt(Quaternion target, float strength, float damping)
2116 {
2117 SceneObjectPart rootpart = m_rootPart;
2118 if (rootpart != null)
2119 {
2120 if (IsAttachment)
2121 {
2122 /*
2123 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2124 if (avatar != null)
2125 {
2126 Rotate the Av?
2127 } */
2128 }
2129 else
2130 {
2131 if (rootpart.PhysActor != null)
2132 { // APID must be implemented in your physics system for this to function.
2133 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2134 rootpart.PhysActor.APIDStrength = strength;
2135 rootpart.PhysActor.APIDDamping = damping;
2136 rootpart.PhysActor.APIDActive = true;
2137 }
2138 }
2139 }
2140 }
2141
2142 public void stopLookAt()
2143 {
2144 SceneObjectPart rootpart = m_rootPart;
2145 if (rootpart != null)
2146 {
2147 if (rootpart.PhysActor != null)
2148 { // APID must be implemented in your physics system for this to function.
2149 rootpart.PhysActor.APIDActive = false;
2150 }
2151 }
2152
2153 }
2154
1629 /// <summary> 2155 /// <summary>
1630 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2156 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1631 /// </summary> 2157 /// </summary>
@@ -1680,7 +2206,12 @@ namespace OpenSim.Region.Framework.Scenes
1680 /// <param name="cGroupID"></param> 2206 /// <param name="cGroupID"></param>
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2207 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2208 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2209 // give new ID to the new part, letting old keep original
2210 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2211 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2212 newPart.LocalId = m_scene.AllocateLocalId();
2213 newPart.SetParent(this);
2214
1684 AddPart(newPart); 2215 AddPart(newPart);
1685 2216
1686 SetPartAsNonRoot(newPart); 2217 SetPartAsNonRoot(newPart);
@@ -1809,11 +2340,11 @@ namespace OpenSim.Region.Framework.Scenes
1809 /// Immediately send a full update for this scene object. 2340 /// Immediately send a full update for this scene object.
1810 /// </summary> 2341 /// </summary>
1811 public void SendGroupFullUpdate() 2342 public void SendGroupFullUpdate()
1812 { 2343 {
1813 if (IsDeleted) 2344 if (IsDeleted)
1814 return; 2345 return;
1815 2346
1816// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2347// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1817 2348
1818 RootPart.SendFullUpdateToAllClients(); 2349 RootPart.SendFullUpdateToAllClients();
1819 2350
@@ -1957,6 +2488,11 @@ namespace OpenSim.Region.Framework.Scenes
1957 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2488 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1958 public void LinkToGroup(SceneObjectGroup objectGroup) 2489 public void LinkToGroup(SceneObjectGroup objectGroup)
1959 { 2490 {
2491 LinkToGroup(objectGroup, false);
2492 }
2493
2494 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2495 {
1960// m_log.DebugFormat( 2496// m_log.DebugFormat(
1961// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2497// "[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); 2498// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1967,6 +2503,15 @@ namespace OpenSim.Region.Framework.Scenes
1967 2503
1968 SceneObjectPart linkPart = objectGroup.m_rootPart; 2504 SceneObjectPart linkPart = objectGroup.m_rootPart;
1969 2505
2506 if (m_rootPart.PhysActor != null)
2507 m_rootPart.PhysActor.Building = true;
2508 if (linkPart.PhysActor != null)
2509 linkPart.PhysActor.Building = true;
2510
2511 // physics flags from group to be applied to linked parts
2512 bool grpusephys = UsesPhysics;
2513 bool grptemporary = IsTemporary;
2514
1970 Vector3 oldGroupPosition = linkPart.GroupPosition; 2515 Vector3 oldGroupPosition = linkPart.GroupPosition;
1971 Quaternion oldRootRotation = linkPart.RotationOffset; 2516 Quaternion oldRootRotation = linkPart.RotationOffset;
1972 2517
@@ -1990,13 +2535,34 @@ namespace OpenSim.Region.Framework.Scenes
1990 2535
1991 lock (m_parts.SyncRoot) 2536 lock (m_parts.SyncRoot)
1992 { 2537 {
1993 int linkNum = PrimCount + 1; 2538 int linkNum;
2539 if (insert)
2540 {
2541 linkNum = 2;
2542 foreach (SceneObjectPart part in Parts)
2543 {
2544 if (part.LinkNum > 1)
2545 part.LinkNum++;
2546 }
2547 }
2548 else
2549 {
2550 linkNum = PrimCount + 1;
2551 }
1994 2552
1995 m_parts.Add(linkPart.UUID, linkPart); 2553 m_parts.Add(linkPart.UUID, linkPart);
1996 2554
1997 linkPart.SetParent(this); 2555 linkPart.SetParent(this);
1998 linkPart.CreateSelected = true; 2556 linkPart.CreateSelected = true;
1999 2557
2558 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2559 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2560 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2561 {
2562 linkPart.PhysActor.link(m_rootPart.PhysActor);
2563 this.Scene.PhysicsScene.AddPhysicsActorTaint(linkPart.PhysActor);
2564 }
2565
2000 linkPart.LinkNum = linkNum++; 2566 linkPart.LinkNum = linkNum++;
2001 2567
2002 SceneObjectPart[] ogParts = objectGroup.Parts; 2568 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2009,7 +2575,16 @@ namespace OpenSim.Region.Framework.Scenes
2009 { 2575 {
2010 SceneObjectPart part = ogParts[i]; 2576 SceneObjectPart part = ogParts[i];
2011 if (part.UUID != objectGroup.m_rootPart.UUID) 2577 if (part.UUID != objectGroup.m_rootPart.UUID)
2578 {
2012 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2579 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2580 // let physics know
2581 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2582 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2583 {
2584 part.PhysActor.link(m_rootPart.PhysActor);
2585 this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2586 }
2587 }
2013 part.ClearUndoState(); 2588 part.ClearUndoState();
2014 } 2589 }
2015 } 2590 }
@@ -2018,7 +2593,7 @@ namespace OpenSim.Region.Framework.Scenes
2018 objectGroup.IsDeleted = true; 2593 objectGroup.IsDeleted = true;
2019 2594
2020 objectGroup.m_parts.Clear(); 2595 objectGroup.m_parts.Clear();
2021 2596
2022 // Can't do this yet since backup still makes use of the root part without any synchronization 2597 // Can't do this yet since backup still makes use of the root part without any synchronization
2023// objectGroup.m_rootPart = null; 2598// objectGroup.m_rootPart = null;
2024 2599
@@ -2029,6 +2604,9 @@ namespace OpenSim.Region.Framework.Scenes
2029 // unmoved prims! 2604 // unmoved prims!
2030 ResetChildPrimPhysicsPositions(); 2605 ResetChildPrimPhysicsPositions();
2031 2606
2607 if (m_rootPart.PhysActor != null)
2608 m_rootPart.PhysActor.Building = false;
2609
2032 //HasGroupChanged = true; 2610 //HasGroupChanged = true;
2033 //ScheduleGroupForFullUpdate(); 2611 //ScheduleGroupForFullUpdate();
2034 } 2612 }
@@ -2081,7 +2659,10 @@ namespace OpenSim.Region.Framework.Scenes
2081// m_log.DebugFormat( 2659// m_log.DebugFormat(
2082// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2660// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2083// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2661// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2084 2662
2663 if (m_rootPart.PhysActor != null)
2664 m_rootPart.PhysActor.Building = true;
2665
2085 linkPart.ClearUndoState(); 2666 linkPart.ClearUndoState();
2086 2667
2087 Quaternion worldRot = linkPart.GetWorldRotation(); 2668 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2141,6 +2722,10 @@ namespace OpenSim.Region.Framework.Scenes
2141 2722
2142 // When we delete a group, we currently have to force persist to the database if the object id has changed 2723 // 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) 2724 // (since delete works by deleting all rows which have a given object id)
2725
2726 if (m_rootPart.PhysActor != null)
2727 m_rootPart.PhysActor.Building = false;
2728
2144 objectGroup.HasGroupChangedDueToDelink = true; 2729 objectGroup.HasGroupChangedDueToDelink = true;
2145 2730
2146 return objectGroup; 2731 return objectGroup;
@@ -2152,6 +2737,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 /// <param name="objectGroup"></param> 2737 /// <param name="objectGroup"></param>
2153 public virtual void DetachFromBackup() 2738 public virtual void DetachFromBackup()
2154 { 2739 {
2740 m_scene.SceneGraph.FireDetachFromBackup(this);
2155 if (m_isBackedUp && Scene != null) 2741 if (m_isBackedUp && Scene != null)
2156 m_scene.EventManager.OnBackup -= ProcessBackup; 2742 m_scene.EventManager.OnBackup -= ProcessBackup;
2157 2743
@@ -2170,7 +2756,8 @@ namespace OpenSim.Region.Framework.Scenes
2170 2756
2171 axPos *= parentRot; 2757 axPos *= parentRot;
2172 part.OffsetPosition = axPos; 2758 part.OffsetPosition = axPos;
2173 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2759 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2760 part.GroupPosition = newPos;
2174 part.OffsetPosition = Vector3.Zero; 2761 part.OffsetPosition = Vector3.Zero;
2175 part.RotationOffset = worldRot; 2762 part.RotationOffset = worldRot;
2176 2763
@@ -2181,7 +2768,7 @@ namespace OpenSim.Region.Framework.Scenes
2181 2768
2182 part.LinkNum = linkNum; 2769 part.LinkNum = linkNum;
2183 2770
2184 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2771 part.OffsetPosition = newPos - AbsolutePosition;
2185 2772
2186 Quaternion rootRotation = m_rootPart.RotationOffset; 2773 Quaternion rootRotation = m_rootPart.RotationOffset;
2187 2774
@@ -2191,7 +2778,7 @@ namespace OpenSim.Region.Framework.Scenes
2191 2778
2192 parentRot = m_rootPart.RotationOffset; 2779 parentRot = m_rootPart.RotationOffset;
2193 oldRot = part.RotationOffset; 2780 oldRot = part.RotationOffset;
2194 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2781 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2195 part.RotationOffset = newRot; 2782 part.RotationOffset = newRot;
2196 } 2783 }
2197 2784
@@ -2438,8 +3025,31 @@ namespace OpenSim.Region.Framework.Scenes
2438 } 3025 }
2439 } 3026 }
2440 3027
3028/*
3029 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2441 for (int i = 0; i < parts.Length; i++) 3030 for (int i = 0; i < parts.Length; i++)
2442 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3031 {
3032 if (parts[i] != RootPart)
3033 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
3034 }
3035*/
3036 if (parts.Length > 1)
3037 {
3038 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3039
3040 for (int i = 0; i < parts.Length; i++)
3041 {
3042
3043 if (parts[i].UUID != m_rootPart.UUID)
3044 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3045 }
3046
3047 if (m_rootPart.PhysActor != null)
3048 m_rootPart.PhysActor.Building = false;
3049 }
3050 else
3051 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3052
2443 } 3053 }
2444 } 3054 }
2445 3055
@@ -2452,6 +3062,17 @@ namespace OpenSim.Region.Framework.Scenes
2452 } 3062 }
2453 } 3063 }
2454 3064
3065
3066
3067 /// <summary>
3068 /// Gets the number of parts
3069 /// </summary>
3070 /// <returns></returns>
3071 public int GetPartCount()
3072 {
3073 return Parts.Count();
3074 }
3075
2455 /// <summary> 3076 /// <summary>
2456 /// Update the texture entry for this part 3077 /// Update the texture entry for this part
2457 /// </summary> 3078 /// </summary>
@@ -2511,11 +3132,6 @@ namespace OpenSim.Region.Framework.Scenes
2511 /// <param name="scale"></param> 3132 /// <param name="scale"></param>
2512 public void GroupResize(Vector3 scale) 3133 public void GroupResize(Vector3 scale)
2513 { 3134 {
2514// m_log.DebugFormat(
2515// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2516
2517 RootPart.StoreUndoState(true);
2518
2519 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3135 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2520 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3136 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2521 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3137 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2540,7 +3156,6 @@ namespace OpenSim.Region.Framework.Scenes
2540 SceneObjectPart obPart = parts[i]; 3156 SceneObjectPart obPart = parts[i];
2541 if (obPart.UUID != m_rootPart.UUID) 3157 if (obPart.UUID != m_rootPart.UUID)
2542 { 3158 {
2543// obPart.IgnoreUndoUpdate = true;
2544 Vector3 oldSize = new Vector3(obPart.Scale); 3159 Vector3 oldSize = new Vector3(obPart.Scale);
2545 3160
2546 float f = 1.0f; 3161 float f = 1.0f;
@@ -2604,8 +3219,6 @@ namespace OpenSim.Region.Framework.Scenes
2604 z *= a; 3219 z *= a;
2605 } 3220 }
2606 } 3221 }
2607
2608// obPart.IgnoreUndoUpdate = false;
2609 } 3222 }
2610 } 3223 }
2611 } 3224 }
@@ -2615,9 +3228,7 @@ namespace OpenSim.Region.Framework.Scenes
2615 prevScale.Y *= y; 3228 prevScale.Y *= y;
2616 prevScale.Z *= z; 3229 prevScale.Z *= z;
2617 3230
2618// RootPart.IgnoreUndoUpdate = true;
2619 RootPart.Resize(prevScale); 3231 RootPart.Resize(prevScale);
2620// RootPart.IgnoreUndoUpdate = false;
2621 3232
2622 parts = m_parts.GetArray(); 3233 parts = m_parts.GetArray();
2623 for (int i = 0; i < parts.Length; i++) 3234 for (int i = 0; i < parts.Length; i++)
@@ -2626,8 +3237,6 @@ namespace OpenSim.Region.Framework.Scenes
2626 3237
2627 if (obPart.UUID != m_rootPart.UUID) 3238 if (obPart.UUID != m_rootPart.UUID)
2628 { 3239 {
2629 obPart.IgnoreUndoUpdate = true;
2630
2631 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3240 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2632 currentpos.X *= x; 3241 currentpos.X *= x;
2633 currentpos.Y *= y; 3242 currentpos.Y *= y;
@@ -2640,16 +3249,12 @@ namespace OpenSim.Region.Framework.Scenes
2640 3249
2641 obPart.Resize(newSize); 3250 obPart.Resize(newSize);
2642 obPart.UpdateOffSet(currentpos); 3251 obPart.UpdateOffSet(currentpos);
2643
2644 obPart.IgnoreUndoUpdate = false;
2645 } 3252 }
2646 3253
2647// obPart.IgnoreUndoUpdate = false; 3254 HasGroupChanged = true;
2648// obPart.StoreUndoState(); 3255 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3256 ScheduleGroupForTerseUpdate();
2649 } 3257 }
2650
2651// m_log.DebugFormat(
2652// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2653 } 3258 }
2654 3259
2655 #endregion 3260 #endregion
@@ -2662,14 +3267,6 @@ namespace OpenSim.Region.Framework.Scenes
2662 /// <param name="pos"></param> 3267 /// <param name="pos"></param>
2663 public void UpdateGroupPosition(Vector3 pos) 3268 public void UpdateGroupPosition(Vector3 pos)
2664 { 3269 {
2665// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2666
2667 RootPart.StoreUndoState(true);
2668
2669// SceneObjectPart[] parts = m_parts.GetArray();
2670// for (int i = 0; i < parts.Length; i++)
2671// parts[i].StoreUndoState();
2672
2673 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3270 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2674 { 3271 {
2675 if (IsAttachment) 3272 if (IsAttachment)
@@ -2701,21 +3298,17 @@ namespace OpenSim.Region.Framework.Scenes
2701 /// </summary> 3298 /// </summary>
2702 /// <param name="pos"></param> 3299 /// <param name="pos"></param>
2703 /// <param name="localID"></param> 3300 /// <param name="localID"></param>
3301 ///
3302
2704 public void UpdateSinglePosition(Vector3 pos, uint localID) 3303 public void UpdateSinglePosition(Vector3 pos, uint localID)
2705 { 3304 {
2706 SceneObjectPart part = GetChildPart(localID); 3305 SceneObjectPart part = GetChildPart(localID);
2707 3306
2708// SceneObjectPart[] parts = m_parts.GetArray();
2709// for (int i = 0; i < parts.Length; i++)
2710// parts[i].StoreUndoState();
2711
2712 if (part != null) 3307 if (part != null)
2713 { 3308 {
2714// m_log.DebugFormat( 3309// unlock parts position change
2715// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3310 if (m_rootPart.PhysActor != null)
2716 3311 m_rootPart.PhysActor.Building = true;
2717 part.StoreUndoState(false);
2718 part.IgnoreUndoUpdate = true;
2719 3312
2720 if (part.UUID == m_rootPart.UUID) 3313 if (part.UUID == m_rootPart.UUID)
2721 { 3314 {
@@ -2726,8 +3319,10 @@ namespace OpenSim.Region.Framework.Scenes
2726 part.UpdateOffSet(pos); 3319 part.UpdateOffSet(pos);
2727 } 3320 }
2728 3321
3322 if (m_rootPart.PhysActor != null)
3323 m_rootPart.PhysActor.Building = false;
3324
2729 HasGroupChanged = true; 3325 HasGroupChanged = true;
2730 part.IgnoreUndoUpdate = false;
2731 } 3326 }
2732 } 3327 }
2733 3328
@@ -2737,13 +3332,7 @@ namespace OpenSim.Region.Framework.Scenes
2737 /// <param name="pos"></param> 3332 /// <param name="pos"></param>
2738 public void UpdateRootPosition(Vector3 pos) 3333 public void UpdateRootPosition(Vector3 pos)
2739 { 3334 {
2740// m_log.DebugFormat( 3335 // needs to be called with phys building true
2741// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2742
2743// SceneObjectPart[] parts = m_parts.GetArray();
2744// for (int i = 0; i < parts.Length; i++)
2745// parts[i].StoreUndoState();
2746
2747 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3336 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2748 Vector3 oldPos = 3337 Vector3 oldPos =
2749 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3338 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2766,7 +3355,14 @@ namespace OpenSim.Region.Framework.Scenes
2766 AbsolutePosition = newPos; 3355 AbsolutePosition = newPos;
2767 3356
2768 HasGroupChanged = true; 3357 HasGroupChanged = true;
2769 ScheduleGroupForTerseUpdate(); 3358 if (m_rootPart.Undoing)
3359 {
3360 ScheduleGroupForFullUpdate();
3361 }
3362 else
3363 {
3364 ScheduleGroupForTerseUpdate();
3365 }
2770 } 3366 }
2771 3367
2772 #endregion 3368 #endregion
@@ -2779,17 +3375,6 @@ namespace OpenSim.Region.Framework.Scenes
2779 /// <param name="rot"></param> 3375 /// <param name="rot"></param>
2780 public void UpdateGroupRotationR(Quaternion rot) 3376 public void UpdateGroupRotationR(Quaternion rot)
2781 { 3377 {
2782// m_log.DebugFormat(
2783// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2784
2785// SceneObjectPart[] parts = m_parts.GetArray();
2786// for (int i = 0; i < parts.Length; i++)
2787// parts[i].StoreUndoState();
2788
2789 m_rootPart.StoreUndoState(true);
2790
2791 m_rootPart.UpdateRotation(rot);
2792
2793 PhysicsActor actor = m_rootPart.PhysActor; 3378 PhysicsActor actor = m_rootPart.PhysActor;
2794 if (actor != null) 3379 if (actor != null)
2795 { 3380 {
@@ -2808,16 +3393,6 @@ namespace OpenSim.Region.Framework.Scenes
2808 /// <param name="rot"></param> 3393 /// <param name="rot"></param>
2809 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3394 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2810 { 3395 {
2811// m_log.DebugFormat(
2812// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2813
2814// SceneObjectPart[] parts = m_parts.GetArray();
2815// for (int i = 0; i < parts.Length; i++)
2816// parts[i].StoreUndoState();
2817
2818 RootPart.StoreUndoState(true);
2819 RootPart.IgnoreUndoUpdate = true;
2820
2821 m_rootPart.UpdateRotation(rot); 3396 m_rootPart.UpdateRotation(rot);
2822 3397
2823 PhysicsActor actor = m_rootPart.PhysActor; 3398 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2831,8 +3406,6 @@ namespace OpenSim.Region.Framework.Scenes
2831 3406
2832 HasGroupChanged = true; 3407 HasGroupChanged = true;
2833 ScheduleGroupForTerseUpdate(); 3408 ScheduleGroupForTerseUpdate();
2834
2835 RootPart.IgnoreUndoUpdate = false;
2836 } 3409 }
2837 3410
2838 /// <summary> 3411 /// <summary>
@@ -2843,15 +3416,12 @@ namespace OpenSim.Region.Framework.Scenes
2843 public void UpdateSingleRotation(Quaternion rot, uint localID) 3416 public void UpdateSingleRotation(Quaternion rot, uint localID)
2844 { 3417 {
2845 SceneObjectPart part = GetChildPart(localID); 3418 SceneObjectPart part = GetChildPart(localID);
2846
2847 SceneObjectPart[] parts = m_parts.GetArray(); 3419 SceneObjectPart[] parts = m_parts.GetArray();
2848 for (int i = 0; i < parts.Length; i++)
2849 parts[i].StoreUndoState();
2850 3420
2851 if (part != null) 3421 if (part != null)
2852 { 3422 {
2853// m_log.DebugFormat( 3423 if (m_rootPart.PhysActor != null)
2854// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3424 m_rootPart.PhysActor.Building = true;
2855 3425
2856 if (part.UUID == m_rootPart.UUID) 3426 if (part.UUID == m_rootPart.UUID)
2857 { 3427 {
@@ -2861,6 +3431,9 @@ namespace OpenSim.Region.Framework.Scenes
2861 { 3431 {
2862 part.UpdateRotation(rot); 3432 part.UpdateRotation(rot);
2863 } 3433 }
3434
3435 if (m_rootPart.PhysActor != null)
3436 m_rootPart.PhysActor.Building = false;
2864 } 3437 }
2865 } 3438 }
2866 3439
@@ -2874,12 +3447,8 @@ namespace OpenSim.Region.Framework.Scenes
2874 SceneObjectPart part = GetChildPart(localID); 3447 SceneObjectPart part = GetChildPart(localID);
2875 if (part != null) 3448 if (part != null)
2876 { 3449 {
2877// m_log.DebugFormat( 3450 if (m_rootPart.PhysActor != null)
2878// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3451 m_rootPart.PhysActor.Building = true;
2879// part.Name, part.LocalId, rot);
2880
2881 part.StoreUndoState();
2882 part.IgnoreUndoUpdate = true;
2883 3452
2884 if (part.UUID == m_rootPart.UUID) 3453 if (part.UUID == m_rootPart.UUID)
2885 { 3454 {
@@ -2892,7 +3461,8 @@ namespace OpenSim.Region.Framework.Scenes
2892 part.OffsetPosition = pos; 3461 part.OffsetPosition = pos;
2893 } 3462 }
2894 3463
2895 part.IgnoreUndoUpdate = false; 3464 if (m_rootPart.PhysActor != null)
3465 m_rootPart.PhysActor.Building = false;
2896 } 3466 }
2897 } 3467 }
2898 3468
@@ -2902,15 +3472,12 @@ namespace OpenSim.Region.Framework.Scenes
2902 /// <param name="rot"></param> 3472 /// <param name="rot"></param>
2903 public void UpdateRootRotation(Quaternion rot) 3473 public void UpdateRootRotation(Quaternion rot)
2904 { 3474 {
2905// m_log.DebugFormat( 3475 // needs to be called with phys building true
2906// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2907// Name, LocalId, rot);
2908
2909 Quaternion axRot = rot; 3476 Quaternion axRot = rot;
2910 Quaternion oldParentRot = m_rootPart.RotationOffset; 3477 Quaternion oldParentRot = m_rootPart.RotationOffset;
2911 3478
2912 m_rootPart.StoreUndoState(); 3479 //Don't use UpdateRotation because it schedules an update prematurely
2913 m_rootPart.UpdateRotation(rot); 3480 m_rootPart.RotationOffset = rot;
2914 if (m_rootPart.PhysActor != null) 3481 if (m_rootPart.PhysActor != null)
2915 { 3482 {
2916 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3483 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2923,35 +3490,135 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart prim = parts[i]; 3490 SceneObjectPart prim = parts[i];
2924 if (prim.UUID != m_rootPart.UUID) 3491 if (prim.UUID != m_rootPart.UUID)
2925 { 3492 {
2926 prim.IgnoreUndoUpdate = true; 3493 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3494 NewRot = Quaternion.Inverse(axRot) * NewRot;
3495 prim.RotationOffset = NewRot;
3496
2927 Vector3 axPos = prim.OffsetPosition; 3497 Vector3 axPos = prim.OffsetPosition;
3498
2928 axPos *= oldParentRot; 3499 axPos *= oldParentRot;
2929 axPos *= Quaternion.Inverse(axRot); 3500 axPos *= Quaternion.Inverse(axRot);
2930 prim.OffsetPosition = axPos; 3501 prim.OffsetPosition = axPos;
2931 Quaternion primsRot = prim.RotationOffset; 3502 }
2932 Quaternion newRot = oldParentRot * primsRot; 3503 }
2933 newRot = Quaternion.Inverse(axRot) * newRot;
2934 prim.RotationOffset = newRot;
2935 prim.ScheduleTerseUpdate();
2936 prim.IgnoreUndoUpdate = false;
2937 }
2938 }
2939
2940// for (int i = 0; i < parts.Length; i++)
2941// {
2942// SceneObjectPart childpart = parts[i];
2943// if (childpart != m_rootPart)
2944// {
2945//// childpart.IgnoreUndoUpdate = false;
2946//// childpart.StoreUndoState();
2947// }
2948// }
2949 3504
2950 m_rootPart.ScheduleTerseUpdate(); 3505 HasGroupChanged = true;
3506 ScheduleGroupForFullUpdate();
3507 }
2951 3508
2952// m_log.DebugFormat( 3509 private enum updatetype :int
2953// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3510 {
2954// Name, LocalId, rot); 3511 none = 0,
3512 partterse = 1,
3513 partfull = 2,
3514 groupterse = 3,
3515 groupfull = 4
3516 }
3517
3518 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3519 {
3520 // TODO this still as excessive *.Schedule*Update()s
3521
3522 if (part != null && part.ParentGroup != null)
3523 {
3524 ObjectChangeType change = data.change;
3525 bool togroup = ((change & ObjectChangeType.Group) != 0);
3526 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3527
3528 SceneObjectGroup group = part.ParentGroup;
3529 PhysicsActor pha = group.RootPart.PhysActor;
3530
3531 updatetype updateType = updatetype.none;
3532
3533 if (togroup)
3534 {
3535 // related to group
3536 if ((change & ObjectChangeType.Position) != 0)
3537 {
3538 group.AbsolutePosition = data.position;
3539 updateType = updatetype.groupterse;
3540 }
3541 if ((change & ObjectChangeType.Rotation) != 0)
3542 {
3543 group.RootPart.UpdateRotation(data.rotation);
3544 updateType = updatetype.none;
3545 }
3546 if ((change & ObjectChangeType.Scale) != 0)
3547 {
3548 if (pha != null)
3549 pha.Building = true;
3550
3551 group.GroupResize(data.scale);
3552 updateType = updatetype.none;
3553
3554 if (pha != null)
3555 pha.Building = false;
3556 }
3557 }
3558 else
3559 {
3560 // related to single prim in a link-set ( ie group)
3561 if (pha != null)
3562 pha.Building = true;
3563
3564 // root part is special
3565 // parts offset positions or rotations need to change also
3566
3567 if (part == group.RootPart)
3568 {
3569 if ((change & ObjectChangeType.Position) != 0)
3570 group.UpdateRootPosition(data.position);
3571 if ((change & ObjectChangeType.Rotation) != 0)
3572 group.UpdateRootRotation(data.rotation);
3573 if ((change & ObjectChangeType.Scale) != 0)
3574 part.Resize(data.scale);
3575 }
3576 else
3577 {
3578 if ((change & ObjectChangeType.Position) != 0)
3579 {
3580 part.OffsetPosition = data.position;
3581 updateType = updatetype.partterse;
3582 }
3583 if ((change & ObjectChangeType.Rotation) != 0)
3584 {
3585 part.UpdateRotation(data.rotation);
3586 updateType = updatetype.none;
3587 }
3588 if ((change & ObjectChangeType.Scale) != 0)
3589 {
3590 part.Resize(data.scale);
3591 updateType = updatetype.none;
3592 }
3593 }
3594
3595 if (pha != null)
3596 pha.Building = false;
3597 }
3598
3599 if (updateType != updatetype.none)
3600 {
3601 group.HasGroupChanged = true;
3602
3603 switch (updateType)
3604 {
3605 case updatetype.partterse:
3606 part.ScheduleTerseUpdate();
3607 break;
3608 case updatetype.partfull:
3609 part.ScheduleFullUpdate();
3610 break;
3611 case updatetype.groupterse:
3612 group.ScheduleGroupForTerseUpdate();
3613 break;
3614 case updatetype.groupfull:
3615 group.ScheduleGroupForFullUpdate();
3616 break;
3617 default:
3618 break;
3619 }
3620 }
3621 }
2955 } 3622 }
2956 3623
2957 #endregion 3624 #endregion
@@ -3175,7 +3842,6 @@ namespace OpenSim.Region.Framework.Scenes
3175 public float GetMass() 3842 public float GetMass()
3176 { 3843 {
3177 float retmass = 0f; 3844 float retmass = 0f;
3178
3179 SceneObjectPart[] parts = m_parts.GetArray(); 3845 SceneObjectPart[] parts = m_parts.GetArray();
3180 for (int i = 0; i < parts.Length; i++) 3846 for (int i = 0; i < parts.Length; i++)
3181 retmass += parts[i].GetMass(); 3847 retmass += parts[i].GetMass();
@@ -3271,6 +3937,14 @@ namespace OpenSim.Region.Framework.Scenes
3271 SetFromItemID(uuid); 3937 SetFromItemID(uuid);
3272 } 3938 }
3273 3939
3940 public void ResetOwnerChangeFlag()
3941 {
3942 ForEachPart(delegate(SceneObjectPart part)
3943 {
3944 part.ResetOwnerChangeFlag();
3945 });
3946 }
3947
3274 #endregion 3948 #endregion
3275 } 3949 }
3276} 3950}