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.cs792
1 files changed, 696 insertions, 96 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 878476e..c9ea8e4 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,98 @@ 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
553 foreach (SceneObjectPart part in m_parts.GetArray())
554 {
555 part.IgnoreUndoUpdate = true;
556 }
399 if (RootPart.GetStatusSandbox()) 557 if (RootPart.GetStatusSandbox())
400 { 558 {
401 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 559 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -409,10 +567,30 @@ namespace OpenSim.Region.Framework.Scenes
409 return; 567 return;
410 } 568 }
411 } 569 }
412
413 SceneObjectPart[] parts = m_parts.GetArray(); 570 SceneObjectPart[] parts = m_parts.GetArray();
414 for (int i = 0; i < parts.Length; i++) 571 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
415 parts[i].GroupPosition = val; 572 if (m_dupeInProgress)
573 triggerScriptEvent = false;
574 foreach (SceneObjectPart part in parts)
575 {
576 part.GroupPosition = val;
577 if (triggerScriptEvent)
578 part.TriggerScriptChangedEvent(Changed.POSITION);
579 }
580 if (!m_dupeInProgress)
581 {
582 foreach (ScenePresence av in m_linkedAvatars)
583 {
584 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
585 if (p != null && m_parts.TryGetValue(p.UUID, out p))
586 {
587 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
588 av.AbsolutePosition += offset;
589 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
590 av.SendAvatarDataToAllAgents();
591 }
592 }
593 }
416 594
417 //if (m_rootPart.PhysActor != null) 595 //if (m_rootPart.PhysActor != null)
418 //{ 596 //{
@@ -427,6 +605,29 @@ namespace OpenSim.Region.Framework.Scenes
427 } 605 }
428 } 606 }
429 607
608 public override Vector3 Velocity
609 {
610 get { return RootPart.Velocity; }
611 set { RootPart.Velocity = value; }
612 }
613
614 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
615 {
616 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
617 ScenePresence agent = icon.EndInvoke(iar);
618
619 //// If the cross was successful, this agent is a child agent
620 //if (agent.IsChildAgent)
621 // agent.Reset();
622 //else // Not successful
623 // agent.RestoreInCurrentScene();
624
625 // In any case
626 agent.IsInTransit = false;
627
628 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
629 }
630
430 public override uint LocalId 631 public override uint LocalId
431 { 632 {
432 get { return m_rootPart.LocalId; } 633 get { return m_rootPart.LocalId; }
@@ -519,6 +720,8 @@ namespace OpenSim.Region.Framework.Scenes
519 child.PhysActor.Selected = value; 720 child.PhysActor.Selected = value;
520 } 721 }
521 } 722 }
723 if (RootPart.KeyframeMotion != null)
724 RootPart.KeyframeMotion.Selected = value;
522 } 725 }
523 } 726 }
524 727
@@ -578,6 +781,7 @@ namespace OpenSim.Region.Framework.Scenes
578 /// </summary> 781 /// </summary>
579 public SceneObjectGroup() 782 public SceneObjectGroup()
580 { 783 {
784
581 } 785 }
582 786
583 /// <summary> 787 /// <summary>
@@ -594,7 +798,7 @@ namespace OpenSim.Region.Framework.Scenes
594 /// Constructor. This object is added to the scene later via AttachToScene() 798 /// Constructor. This object is added to the scene later via AttachToScene()
595 /// </summary> 799 /// </summary>
596 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 800 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
597 { 801 {
598 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 802 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
599 } 803 }
600 804
@@ -642,6 +846,9 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 846 /// </summary>
643 public virtual void AttachToBackup() 847 public virtual void AttachToBackup()
644 { 848 {
849 if (IsAttachment) return;
850 m_scene.SceneGraph.FireAttachToBackup(this);
851
645 if (InSceneBackup) 852 if (InSceneBackup)
646 { 853 {
647 //m_log.DebugFormat( 854 //m_log.DebugFormat(
@@ -684,6 +891,13 @@ namespace OpenSim.Region.Framework.Scenes
684 891
685 ApplyPhysics(); 892 ApplyPhysics();
686 893
894 if (RootPart.PhysActor != null)
895 RootPart.Force = RootPart.Force;
896 if (RootPart.PhysActor != null)
897 RootPart.Torque = RootPart.Torque;
898 if (RootPart.PhysActor != null)
899 RootPart.Buoyancy = RootPart.Buoyancy;
900
687 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 901 // 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. 902 // for the same object with very different properties. The caller must schedule the update.
689 //ScheduleGroupForFullUpdate(); 903 //ScheduleGroupForFullUpdate();
@@ -699,6 +913,10 @@ namespace OpenSim.Region.Framework.Scenes
699 EntityIntersection result = new EntityIntersection(); 913 EntityIntersection result = new EntityIntersection();
700 914
701 SceneObjectPart[] parts = m_parts.GetArray(); 915 SceneObjectPart[] parts = m_parts.GetArray();
916
917 // Find closest hit here
918 float idist = float.MaxValue;
919
702 for (int i = 0; i < parts.Length; i++) 920 for (int i = 0; i < parts.Length; i++)
703 { 921 {
704 SceneObjectPart part = parts[i]; 922 SceneObjectPart part = parts[i];
@@ -713,11 +931,6 @@ namespace OpenSim.Region.Framework.Scenes
713 931
714 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 932 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
715 933
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) 934 if (inter.HitTF)
722 { 935 {
723 // We need to find the closest prim to return to the testcaller along the ray 936 // We need to find the closest prim to return to the testcaller along the ray
@@ -728,10 +941,11 @@ namespace OpenSim.Region.Framework.Scenes
728 result.obj = part; 941 result.obj = part;
729 result.normal = inter.normal; 942 result.normal = inter.normal;
730 result.distance = inter.distance; 943 result.distance = inter.distance;
944
945 idist = inter.distance;
731 } 946 }
732 } 947 }
733 } 948 }
734
735 return result; 949 return result;
736 } 950 }
737 951
@@ -751,17 +965,19 @@ namespace OpenSim.Region.Framework.Scenes
751 minZ = 8192f; 965 minZ = 8192f;
752 966
753 SceneObjectPart[] parts = m_parts.GetArray(); 967 SceneObjectPart[] parts = m_parts.GetArray();
754 for (int i = 0; i < parts.Length; i++) 968 foreach (SceneObjectPart part in parts)
755 { 969 {
756 SceneObjectPart part = parts[i];
757
758 Vector3 worldPos = part.GetWorldPosition(); 970 Vector3 worldPos = part.GetWorldPosition();
759 Vector3 offset = worldPos - AbsolutePosition; 971 Vector3 offset = worldPos - AbsolutePosition;
760 Quaternion worldRot; 972 Quaternion worldRot;
761 if (part.ParentID == 0) 973 if (part.ParentID == 0)
974 {
762 worldRot = part.RotationOffset; 975 worldRot = part.RotationOffset;
976 }
763 else 977 else
978 {
764 worldRot = part.GetWorldRotation(); 979 worldRot = part.GetWorldRotation();
980 }
765 981
766 Vector3 frontTopLeft; 982 Vector3 frontTopLeft;
767 Vector3 frontTopRight; 983 Vector3 frontTopRight;
@@ -773,6 +989,8 @@ namespace OpenSim.Region.Framework.Scenes
773 Vector3 backBottomLeft; 989 Vector3 backBottomLeft;
774 Vector3 backBottomRight; 990 Vector3 backBottomRight;
775 991
992 // Vector3[] corners = new Vector3[8];
993
776 Vector3 orig = Vector3.Zero; 994 Vector3 orig = Vector3.Zero;
777 995
778 frontTopLeft.X = orig.X - (part.Scale.X / 2); 996 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -807,6 +1025,38 @@ namespace OpenSim.Region.Framework.Scenes
807 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1025 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
808 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1026 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
809 1027
1028
1029
1030 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1031 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1032 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1033 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1034 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1035 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1036 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1037 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1038
1039 //for (int i = 0; i < 8; i++)
1040 //{
1041 // corners[i] = corners[i] * worldRot;
1042 // corners[i] += offset;
1043
1044 // if (corners[i].X > maxX)
1045 // maxX = corners[i].X;
1046 // if (corners[i].X < minX)
1047 // minX = corners[i].X;
1048
1049 // if (corners[i].Y > maxY)
1050 // maxY = corners[i].Y;
1051 // if (corners[i].Y < minY)
1052 // minY = corners[i].Y;
1053
1054 // if (corners[i].Z > maxZ)
1055 // maxZ = corners[i].Y;
1056 // if (corners[i].Z < minZ)
1057 // minZ = corners[i].Z;
1058 //}
1059
810 frontTopLeft = frontTopLeft * worldRot; 1060 frontTopLeft = frontTopLeft * worldRot;
811 frontTopRight = frontTopRight * worldRot; 1061 frontTopRight = frontTopRight * worldRot;
812 frontBottomLeft = frontBottomLeft * worldRot; 1062 frontBottomLeft = frontBottomLeft * worldRot;
@@ -828,6 +1078,15 @@ namespace OpenSim.Region.Framework.Scenes
828 backTopLeft += offset; 1078 backTopLeft += offset;
829 backTopRight += offset; 1079 backTopRight += offset;
830 1080
1081 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1082 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1083 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1084 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1085 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1086 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1087 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1088 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1089
831 if (frontTopRight.X > maxX) 1090 if (frontTopRight.X > maxX)
832 maxX = frontTopRight.X; 1091 maxX = frontTopRight.X;
833 if (frontTopLeft.X > maxX) 1092 if (frontTopLeft.X > maxX)
@@ -973,15 +1232,20 @@ namespace OpenSim.Region.Framework.Scenes
973 1232
974 public void SaveScriptedState(XmlTextWriter writer) 1233 public void SaveScriptedState(XmlTextWriter writer)
975 { 1234 {
1235 SaveScriptedState(writer, false);
1236 }
1237
1238 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1239 {
976 XmlDocument doc = new XmlDocument(); 1240 XmlDocument doc = new XmlDocument();
977 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1241 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
978 1242
979 SceneObjectPart[] parts = m_parts.GetArray(); 1243 SceneObjectPart[] parts = m_parts.GetArray();
980 for (int i = 0; i < parts.Length; i++) 1244 for (int i = 0; i < parts.Length; i++)
981 { 1245 {
982 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1246 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
983 foreach (KeyValuePair<UUID, string> kvp in pstates) 1247 foreach (KeyValuePair<UUID, string> kvp in pstates)
984 states.Add(kvp.Key, kvp.Value); 1248 states[kvp.Key] = kvp.Value;
985 } 1249 }
986 1250
987 if (states.Count > 0) 1251 if (states.Count > 0)
@@ -1001,6 +1265,169 @@ namespace OpenSim.Region.Framework.Scenes
1001 } 1265 }
1002 1266
1003 /// <summary> 1267 /// <summary>
1268 /// Add the avatar to this linkset (avatar is sat).
1269 /// </summary>
1270 /// <param name="agentID"></param>
1271 public void AddAvatar(UUID agentID)
1272 {
1273 ScenePresence presence;
1274 if (m_scene.TryGetScenePresence(agentID, out presence))
1275 {
1276 if (!m_linkedAvatars.Contains(presence))
1277 {
1278 m_linkedAvatars.Add(presence);
1279 }
1280 }
1281 }
1282
1283 /// <summary>
1284 /// Delete the avatar from this linkset (avatar is unsat).
1285 /// </summary>
1286 /// <param name="agentID"></param>
1287 public void DeleteAvatar(UUID agentID)
1288 {
1289 ScenePresence presence;
1290 if (m_scene.TryGetScenePresence(agentID, out presence))
1291 {
1292 if (m_linkedAvatars.Contains(presence))
1293 {
1294 m_linkedAvatars.Remove(presence);
1295 }
1296 }
1297 }
1298
1299 /// <summary>
1300 /// Returns the list of linked presences (avatars sat on this group)
1301 /// </summary>
1302 /// <param name="agentID"></param>
1303 public List<ScenePresence> GetLinkedAvatars()
1304 {
1305 return m_linkedAvatars;
1306 }
1307
1308 /// <summary>
1309 /// Attach this scene object to the given avatar.
1310 /// </summary>
1311 /// <param name="agentID"></param>
1312 /// <param name="attachmentpoint"></param>
1313 /// <param name="AttachOffset"></param>
1314 private void AttachToAgent(
1315 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1316 {
1317 if (avatar != null)
1318 {
1319 // don't attach attachments to child agents
1320 if (avatar.IsChildAgent) return;
1321
1322 // Remove from database and parcel prim count
1323 m_scene.DeleteFromStorage(so.UUID);
1324 m_scene.EventManager.TriggerParcelPrimCountTainted();
1325
1326 so.AttachedAvatar = avatar.UUID;
1327
1328 if (so.RootPart.PhysActor != null)
1329 {
1330 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1331 so.RootPart.PhysActor = null;
1332 }
1333
1334 so.AbsolutePosition = attachOffset;
1335 so.RootPart.AttachedPos = attachOffset;
1336 so.IsAttachment = true;
1337 so.RootPart.SetParentLocalId(avatar.LocalId);
1338 so.AttachmentPoint = attachmentpoint;
1339
1340 avatar.AddAttachment(this);
1341
1342 if (!silent)
1343 {
1344 // Killing it here will cause the client to deselect it
1345 // It then reappears on the avatar, deselected
1346 // through the full update below
1347 //
1348 if (IsSelected)
1349 {
1350 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1351 }
1352
1353 IsSelected = false; // fudge....
1354 ScheduleGroupForFullUpdate();
1355 }
1356 }
1357 else
1358 {
1359 m_log.WarnFormat(
1360 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1361 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1362 }
1363 }
1364
1365 public byte GetAttachmentPoint()
1366 {
1367 return m_rootPart.Shape.State;
1368 }
1369
1370 public void DetachToGround()
1371 {
1372 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1373 if (avatar == null)
1374 return;
1375
1376 avatar.RemoveAttachment(this);
1377
1378 Vector3 detachedpos = new Vector3(127f,127f,127f);
1379 if (avatar == null)
1380 return;
1381
1382 detachedpos = avatar.AbsolutePosition;
1383 RootPart.FromItemID = UUID.Zero;
1384
1385 AbsolutePosition = detachedpos;
1386 AttachedAvatar = UUID.Zero;
1387
1388 //SceneObjectPart[] parts = m_parts.GetArray();
1389 //for (int i = 0; i < parts.Length; i++)
1390 // parts[i].AttachedAvatar = UUID.Zero;
1391
1392 m_rootPart.SetParentLocalId(0);
1393 AttachmentPoint = (byte)0;
1394 // must check if buildind should be true or false here
1395 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1396 HasGroupChanged = true;
1397 RootPart.Rezzed = DateTime.Now;
1398 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1399 AttachToBackup();
1400 m_scene.EventManager.TriggerParcelPrimCountTainted();
1401 m_rootPart.ScheduleFullUpdate();
1402 m_rootPart.ClearUndoState();
1403 }
1404
1405 public void DetachToInventoryPrep()
1406 {
1407 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1408 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1409 if (avatar != null)
1410 {
1411 //detachedpos = avatar.AbsolutePosition;
1412 avatar.RemoveAttachment(this);
1413 }
1414
1415 AttachedAvatar = UUID.Zero;
1416
1417 /*SceneObjectPart[] parts = m_parts.GetArray();
1418 for (int i = 0; i < parts.Length; i++)
1419 parts[i].AttachedAvatar = UUID.Zero;*/
1420
1421 m_rootPart.SetParentLocalId(0);
1422 //m_rootPart.SetAttachmentPoint((byte)0);
1423 IsAttachment = false;
1424 AbsolutePosition = m_rootPart.AttachedPos;
1425 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1426 //AttachToBackup();
1427 //m_rootPart.ScheduleFullUpdate();
1428 }
1429
1430 /// <summary>
1004 /// 1431 ///
1005 /// </summary> 1432 /// </summary>
1006 /// <param name="part"></param> 1433 /// <param name="part"></param>
@@ -1050,7 +1477,10 @@ namespace OpenSim.Region.Framework.Scenes
1050 public void AddPart(SceneObjectPart part) 1477 public void AddPart(SceneObjectPart part)
1051 { 1478 {
1052 part.SetParent(this); 1479 part.SetParent(this);
1053 part.LinkNum = m_parts.Add(part.UUID, part); 1480 m_parts.Add(part.UUID, part);
1481
1482 part.LinkNum = m_parts.Count;
1483
1054 if (part.LinkNum == 2) 1484 if (part.LinkNum == 2)
1055 RootPart.LinkNum = 1; 1485 RootPart.LinkNum = 1;
1056 } 1486 }
@@ -1158,6 +1588,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1588 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1159 public void DeleteGroupFromScene(bool silent) 1589 public void DeleteGroupFromScene(bool silent)
1160 { 1590 {
1591 // We need to keep track of this state in case this group is still queued for backup.
1592 IsDeleted = true;
1593
1594 DetachFromBackup();
1595
1161 SceneObjectPart[] parts = m_parts.GetArray(); 1596 SceneObjectPart[] parts = m_parts.GetArray();
1162 for (int i = 0; i < parts.Length; i++) 1597 for (int i = 0; i < parts.Length; i++)
1163 { 1598 {
@@ -1180,6 +1615,8 @@ namespace OpenSim.Region.Framework.Scenes
1180 } 1615 }
1181 }); 1616 });
1182 } 1617 }
1618
1619
1183 } 1620 }
1184 1621
1185 public void AddScriptLPS(int count) 1622 public void AddScriptLPS(int count)
@@ -1254,28 +1691,43 @@ namespace OpenSim.Region.Framework.Scenes
1254 /// </summary> 1691 /// </summary>
1255 public void ApplyPhysics() 1692 public void ApplyPhysics()
1256 { 1693 {
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(); 1694 SceneObjectPart[] parts = m_parts.GetArray();
1262 if (parts.Length > 1) 1695 if (parts.Length > 1)
1263 { 1696 {
1697 ResetChildPrimPhysicsPositions();
1698
1699 // Apply physics to the root prim
1700 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1701
1702
1264 for (int i = 0; i < parts.Length; i++) 1703 for (int i = 0; i < parts.Length; i++)
1265 { 1704 {
1266 SceneObjectPart part = parts[i]; 1705 SceneObjectPart part = parts[i];
1267 if (part.LocalId != m_rootPart.LocalId) 1706 if (part.LocalId != m_rootPart.LocalId)
1268 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1707 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1269 } 1708 }
1270
1271 // Hack to get the physics scene geometries in the right spot 1709 // Hack to get the physics scene geometries in the right spot
1272 ResetChildPrimPhysicsPositions(); 1710// ResetChildPrimPhysicsPositions();
1711 if (m_rootPart.PhysActor != null)
1712 {
1713 m_rootPart.PhysActor.Building = false;
1714 }
1715 }
1716 else
1717 {
1718 // Apply physics to the root prim
1719 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1273 } 1720 }
1274 } 1721 }
1275 1722
1276 public void SetOwnerId(UUID userId) 1723 public void SetOwnerId(UUID userId)
1277 { 1724 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1725 ForEachPart(delegate(SceneObjectPart part)
1726 {
1727
1728 part.OwnerID = userId;
1729
1730 });
1279 } 1731 }
1280 1732
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1733 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1307,11 +1759,17 @@ namespace OpenSim.Region.Framework.Scenes
1307 return; 1759 return;
1308 } 1760 }
1309 1761
1762 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1763 return;
1764
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1765 // 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. 1766 // any exception propogate upwards.
1312 try 1767 try
1313 { 1768 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1769 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1770 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1771 m_scene.LoadingPrims) // Land may not be valid yet
1772
1315 { 1773 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1774 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1775 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1338,6 +1796,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1796 }
1339 } 1797 }
1340 } 1798 }
1799
1341 } 1800 }
1342 1801
1343 if (m_scene.UseBackup && HasGroupChanged) 1802 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,6 +1804,20 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1804 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1805 if (isTimeToPersist() || forcedBackup)
1347 { 1806 {
1807 if (m_rootPart.PhysActor != null &&
1808 (!m_rootPart.PhysActor.IsPhysical))
1809 {
1810 // Possible ghost prim
1811 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1812 {
1813 foreach (SceneObjectPart part in m_parts.GetArray())
1814 {
1815 // Re-set physics actor positions and
1816 // orientations
1817 part.GroupPosition = m_rootPart.GroupPosition;
1818 }
1819 }
1820 }
1348// m_log.DebugFormat( 1821// m_log.DebugFormat(
1349// "[SCENE]: Storing {0}, {1} in {2}", 1822// "[SCENE]: Storing {0}, {1} in {2}",
1350// Name, UUID, m_scene.RegionInfo.RegionName); 1823// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1362,6 +1835,11 @@ namespace OpenSim.Region.Framework.Scenes
1362 1835
1363 backup_group.ForEachPart(delegate(SceneObjectPart part) 1836 backup_group.ForEachPart(delegate(SceneObjectPart part)
1364 { 1837 {
1838 if (part.KeyframeMotion != null)
1839 {
1840 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
1841 part.KeyframeMotion.UpdateSceneObject(this);
1842 }
1365 part.Inventory.ProcessInventoryBackup(datastore); 1843 part.Inventory.ProcessInventoryBackup(datastore);
1366 }); 1844 });
1367 1845
@@ -1414,6 +1892,7 @@ namespace OpenSim.Region.Framework.Scenes
1414 /// <returns></returns> 1892 /// <returns></returns>
1415 public SceneObjectGroup Copy(bool userExposed) 1893 public SceneObjectGroup Copy(bool userExposed)
1416 { 1894 {
1895 m_dupeInProgress = true;
1417 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1896 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1418 dupe.m_isBackedUp = false; 1897 dupe.m_isBackedUp = false;
1419 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1898 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1428,7 +1907,7 @@ namespace OpenSim.Region.Framework.Scenes
1428 // This is only necessary when userExposed is false! 1907 // This is only necessary when userExposed is false!
1429 1908
1430 bool previousAttachmentStatus = dupe.IsAttachment; 1909 bool previousAttachmentStatus = dupe.IsAttachment;
1431 1910
1432 if (!userExposed) 1911 if (!userExposed)
1433 dupe.IsAttachment = true; 1912 dupe.IsAttachment = true;
1434 1913
@@ -1446,11 +1925,11 @@ namespace OpenSim.Region.Framework.Scenes
1446 dupe.m_rootPart.TrimPermissions(); 1925 dupe.m_rootPart.TrimPermissions();
1447 1926
1448 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1927 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1449 1928
1450 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1929 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1451 { 1930 {
1452 return p1.LinkNum.CompareTo(p2.LinkNum); 1931 return p1.LinkNum.CompareTo(p2.LinkNum);
1453 } 1932 }
1454 ); 1933 );
1455 1934
1456 foreach (SceneObjectPart part in partList) 1935 foreach (SceneObjectPart part in partList)
@@ -1470,21 +1949,24 @@ namespace OpenSim.Region.Framework.Scenes
1470 if (part.PhysActor != null && userExposed) 1949 if (part.PhysActor != null && userExposed)
1471 { 1950 {
1472 PrimitiveBaseShape pbs = newPart.Shape; 1951 PrimitiveBaseShape pbs = newPart.Shape;
1473 1952
1474 newPart.PhysActor 1953 newPart.PhysActor
1475 = m_scene.PhysicsScene.AddPrimShape( 1954 = m_scene.PhysicsScene.AddPrimShape(
1476 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1955 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1477 pbs, 1956 pbs,
1478 newPart.AbsolutePosition, 1957 newPart.AbsolutePosition,
1479 newPart.Scale, 1958 newPart.Scale,
1480 newPart.RotationOffset, 1959 //newPart.RotationOffset,
1960 newPart.GetWorldRotation(),
1481 part.PhysActor.IsPhysical, 1961 part.PhysActor.IsPhysical,
1482 newPart.LocalId); 1962 newPart.LocalId);
1483 1963
1484 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1964 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1485 } 1965 }
1486 } 1966 }
1487 1967 if (dupe.m_rootPart.PhysActor != null && userExposed)
1968 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
1969
1488 if (userExposed) 1970 if (userExposed)
1489 { 1971 {
1490 dupe.UpdateParentIDs(); 1972 dupe.UpdateParentIDs();
@@ -1494,6 +1976,7 @@ namespace OpenSim.Region.Framework.Scenes
1494 ScheduleGroupForFullUpdate(); 1976 ScheduleGroupForFullUpdate();
1495 } 1977 }
1496 1978
1979 m_dupeInProgress = false;
1497 return dupe; 1980 return dupe;
1498 } 1981 }
1499 1982
@@ -1506,10 +1989,18 @@ namespace OpenSim.Region.Framework.Scenes
1506 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 1989 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1507 { 1990 {
1508 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 1991 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
1992 if (userExposed)
1993 RootPart.Velocity = Vector3.Zero; // In case source is moving
1509 } 1994 }
1510 1995
1511 public void ScriptSetPhysicsStatus(bool usePhysics) 1996 public void ScriptSetPhysicsStatus(bool usePhysics)
1512 { 1997 {
1998 if (usePhysics)
1999 {
2000 if (RootPart.KeyframeMotion != null)
2001 RootPart.KeyframeMotion.Stop();
2002 RootPart.KeyframeMotion = null;
2003 }
1513 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2004 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1514 } 2005 }
1515 2006
@@ -1573,32 +2064,12 @@ namespace OpenSim.Region.Framework.Scenes
1573 } 2064 }
1574 } 2065 }
1575 2066
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() 2067 public Vector3 GetTorque()
1589 { 2068 {
1590 if (RootPart.PhysActor != null) 2069 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 } 2070 }
1601 2071
2072 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1602 public void moveToTarget(Vector3 target, float tau) 2073 public void moveToTarget(Vector3 target, float tau)
1603 { 2074 {
1604 if (IsAttachment) 2075 if (IsAttachment)
@@ -1626,6 +2097,46 @@ namespace OpenSim.Region.Framework.Scenes
1626 RootPart.PhysActor.PIDActive = false; 2097 RootPart.PhysActor.PIDActive = false;
1627 } 2098 }
1628 2099
2100 public void rotLookAt(Quaternion target, float strength, float damping)
2101 {
2102 SceneObjectPart rootpart = m_rootPart;
2103 if (rootpart != null)
2104 {
2105 if (IsAttachment)
2106 {
2107 /*
2108 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2109 if (avatar != null)
2110 {
2111 Rotate the Av?
2112 } */
2113 }
2114 else
2115 {
2116 if (rootpart.PhysActor != null)
2117 { // APID must be implemented in your physics system for this to function.
2118 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2119 rootpart.PhysActor.APIDStrength = strength;
2120 rootpart.PhysActor.APIDDamping = damping;
2121 rootpart.PhysActor.APIDActive = true;
2122 }
2123 }
2124 }
2125 }
2126
2127 public void stopLookAt()
2128 {
2129 SceneObjectPart rootpart = m_rootPart;
2130 if (rootpart != null)
2131 {
2132 if (rootpart.PhysActor != null)
2133 { // APID must be implemented in your physics system for this to function.
2134 rootpart.PhysActor.APIDActive = false;
2135 }
2136 }
2137
2138 }
2139
1629 /// <summary> 2140 /// <summary>
1630 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2141 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1631 /// </summary> 2142 /// </summary>
@@ -1681,6 +2192,8 @@ namespace OpenSim.Region.Framework.Scenes
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2192 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2193 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2194 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2195 newPart.SetParent(this);
2196
1684 AddPart(newPart); 2197 AddPart(newPart);
1685 2198
1686 SetPartAsNonRoot(newPart); 2199 SetPartAsNonRoot(newPart);
@@ -1809,11 +2322,11 @@ namespace OpenSim.Region.Framework.Scenes
1809 /// Immediately send a full update for this scene object. 2322 /// Immediately send a full update for this scene object.
1810 /// </summary> 2323 /// </summary>
1811 public void SendGroupFullUpdate() 2324 public void SendGroupFullUpdate()
1812 { 2325 {
1813 if (IsDeleted) 2326 if (IsDeleted)
1814 return; 2327 return;
1815 2328
1816// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2329// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1817 2330
1818 RootPart.SendFullUpdateToAllClients(); 2331 RootPart.SendFullUpdateToAllClients();
1819 2332
@@ -1957,6 +2470,11 @@ namespace OpenSim.Region.Framework.Scenes
1957 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2470 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1958 public void LinkToGroup(SceneObjectGroup objectGroup) 2471 public void LinkToGroup(SceneObjectGroup objectGroup)
1959 { 2472 {
2473 LinkToGroup(objectGroup, false);
2474 }
2475
2476 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2477 {
1960// m_log.DebugFormat( 2478// m_log.DebugFormat(
1961// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2479// "[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); 2480// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1990,7 +2508,20 @@ namespace OpenSim.Region.Framework.Scenes
1990 2508
1991 lock (m_parts.SyncRoot) 2509 lock (m_parts.SyncRoot)
1992 { 2510 {
1993 int linkNum = PrimCount + 1; 2511 int linkNum;
2512 if (insert)
2513 {
2514 linkNum = 2;
2515 foreach (SceneObjectPart part in Parts)
2516 {
2517 if (part.LinkNum > 1)
2518 part.LinkNum++;
2519 }
2520 }
2521 else
2522 {
2523 linkNum = PrimCount + 1;
2524 }
1994 2525
1995 m_parts.Add(linkPart.UUID, linkPart); 2526 m_parts.Add(linkPart.UUID, linkPart);
1996 2527
@@ -2018,7 +2549,7 @@ namespace OpenSim.Region.Framework.Scenes
2018 objectGroup.IsDeleted = true; 2549 objectGroup.IsDeleted = true;
2019 2550
2020 objectGroup.m_parts.Clear(); 2551 objectGroup.m_parts.Clear();
2021 2552
2022 // Can't do this yet since backup still makes use of the root part without any synchronization 2553 // Can't do this yet since backup still makes use of the root part without any synchronization
2023// objectGroup.m_rootPart = null; 2554// objectGroup.m_rootPart = null;
2024 2555
@@ -2152,6 +2683,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 /// <param name="objectGroup"></param> 2683 /// <param name="objectGroup"></param>
2153 public virtual void DetachFromBackup() 2684 public virtual void DetachFromBackup()
2154 { 2685 {
2686 m_scene.SceneGraph.FireDetachFromBackup(this);
2155 if (m_isBackedUp && Scene != null) 2687 if (m_isBackedUp && Scene != null)
2156 m_scene.EventManager.OnBackup -= ProcessBackup; 2688 m_scene.EventManager.OnBackup -= ProcessBackup;
2157 2689
@@ -2170,7 +2702,8 @@ namespace OpenSim.Region.Framework.Scenes
2170 2702
2171 axPos *= parentRot; 2703 axPos *= parentRot;
2172 part.OffsetPosition = axPos; 2704 part.OffsetPosition = axPos;
2173 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2705 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2706 part.GroupPosition = newPos;
2174 part.OffsetPosition = Vector3.Zero; 2707 part.OffsetPosition = Vector3.Zero;
2175 part.RotationOffset = worldRot; 2708 part.RotationOffset = worldRot;
2176 2709
@@ -2181,7 +2714,7 @@ namespace OpenSim.Region.Framework.Scenes
2181 2714
2182 part.LinkNum = linkNum; 2715 part.LinkNum = linkNum;
2183 2716
2184 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2717 part.OffsetPosition = newPos - AbsolutePosition;
2185 2718
2186 Quaternion rootRotation = m_rootPart.RotationOffset; 2719 Quaternion rootRotation = m_rootPart.RotationOffset;
2187 2720
@@ -2191,7 +2724,7 @@ namespace OpenSim.Region.Framework.Scenes
2191 2724
2192 parentRot = m_rootPart.RotationOffset; 2725 parentRot = m_rootPart.RotationOffset;
2193 oldRot = part.RotationOffset; 2726 oldRot = part.RotationOffset;
2194 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2727 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2195 part.RotationOffset = newRot; 2728 part.RotationOffset = newRot;
2196 } 2729 }
2197 2730
@@ -2438,8 +2971,31 @@ namespace OpenSim.Region.Framework.Scenes
2438 } 2971 }
2439 } 2972 }
2440 2973
2974/*
2975 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2441 for (int i = 0; i < parts.Length; i++) 2976 for (int i = 0; i < parts.Length; i++)
2442 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2977 {
2978 if (parts[i] != RootPart)
2979 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2980 }
2981*/
2982 if (parts.Length > 1)
2983 {
2984 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
2985
2986 for (int i = 0; i < parts.Length; i++)
2987 {
2988
2989 if (parts[i].UUID != m_rootPart.UUID)
2990 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
2991 }
2992
2993 if (m_rootPart.PhysActor != null)
2994 m_rootPart.PhysActor.Building = false;
2995 }
2996 else
2997 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2998
2443 } 2999 }
2444 } 3000 }
2445 3001
@@ -2452,6 +3008,17 @@ namespace OpenSim.Region.Framework.Scenes
2452 } 3008 }
2453 } 3009 }
2454 3010
3011
3012
3013 /// <summary>
3014 /// Gets the number of parts
3015 /// </summary>
3016 /// <returns></returns>
3017 public int GetPartCount()
3018 {
3019 return Parts.Count();
3020 }
3021
2455 /// <summary> 3022 /// <summary>
2456 /// Update the texture entry for this part 3023 /// Update the texture entry for this part
2457 /// </summary> 3024 /// </summary>
@@ -2513,7 +3080,6 @@ namespace OpenSim.Region.Framework.Scenes
2513 { 3080 {
2514// m_log.DebugFormat( 3081// m_log.DebugFormat(
2515// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 3082// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2516
2517 RootPart.StoreUndoState(true); 3083 RootPart.StoreUndoState(true);
2518 3084
2519 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3085 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2614,7 +3180,6 @@ namespace OpenSim.Region.Framework.Scenes
2614 prevScale.X *= x; 3180 prevScale.X *= x;
2615 prevScale.Y *= y; 3181 prevScale.Y *= y;
2616 prevScale.Z *= z; 3182 prevScale.Z *= z;
2617
2618// RootPart.IgnoreUndoUpdate = true; 3183// RootPart.IgnoreUndoUpdate = true;
2619 RootPart.Resize(prevScale); 3184 RootPart.Resize(prevScale);
2620// RootPart.IgnoreUndoUpdate = false; 3185// RootPart.IgnoreUndoUpdate = false;
@@ -2645,7 +3210,9 @@ namespace OpenSim.Region.Framework.Scenes
2645 } 3210 }
2646 3211
2647// obPart.IgnoreUndoUpdate = false; 3212// obPart.IgnoreUndoUpdate = false;
2648// obPart.StoreUndoState(); 3213 HasGroupChanged = true;
3214 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3215 ScheduleGroupForTerseUpdate();
2649 } 3216 }
2650 3217
2651// m_log.DebugFormat( 3218// m_log.DebugFormat(
@@ -2705,9 +3272,9 @@ namespace OpenSim.Region.Framework.Scenes
2705 { 3272 {
2706 SceneObjectPart part = GetChildPart(localID); 3273 SceneObjectPart part = GetChildPart(localID);
2707 3274
2708// SceneObjectPart[] parts = m_parts.GetArray(); 3275 SceneObjectPart[] parts = m_parts.GetArray();
2709// for (int i = 0; i < parts.Length; i++) 3276 for (int i = 0; i < parts.Length; i++)
2710// parts[i].StoreUndoState(); 3277 parts[i].StoreUndoState();
2711 3278
2712 if (part != null) 3279 if (part != null)
2713 { 3280 {
@@ -2763,10 +3330,27 @@ namespace OpenSim.Region.Framework.Scenes
2763 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3330 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2764 } 3331 }
2765 3332
2766 AbsolutePosition = newPos; 3333 //We have to set undoing here because otherwise an undo state will be saved
3334 if (!m_rootPart.Undoing)
3335 {
3336 m_rootPart.Undoing = true;
3337 AbsolutePosition = newPos;
3338 m_rootPart.Undoing = false;
3339 }
3340 else
3341 {
3342 AbsolutePosition = newPos;
3343 }
2767 3344
2768 HasGroupChanged = true; 3345 HasGroupChanged = true;
2769 ScheduleGroupForTerseUpdate(); 3346 if (m_rootPart.Undoing)
3347 {
3348 ScheduleGroupForFullUpdate();
3349 }
3350 else
3351 {
3352 ScheduleGroupForTerseUpdate();
3353 }
2770 } 3354 }
2771 3355
2772 #endregion 3356 #endregion
@@ -2843,10 +3427,7 @@ namespace OpenSim.Region.Framework.Scenes
2843 public void UpdateSingleRotation(Quaternion rot, uint localID) 3427 public void UpdateSingleRotation(Quaternion rot, uint localID)
2844 { 3428 {
2845 SceneObjectPart part = GetChildPart(localID); 3429 SceneObjectPart part = GetChildPart(localID);
2846
2847 SceneObjectPart[] parts = m_parts.GetArray(); 3430 SceneObjectPart[] parts = m_parts.GetArray();
2848 for (int i = 0; i < parts.Length; i++)
2849 parts[i].StoreUndoState();
2850 3431
2851 if (part != null) 3432 if (part != null)
2852 { 3433 {
@@ -2884,7 +3465,16 @@ namespace OpenSim.Region.Framework.Scenes
2884 if (part.UUID == m_rootPart.UUID) 3465 if (part.UUID == m_rootPart.UUID)
2885 { 3466 {
2886 UpdateRootRotation(rot); 3467 UpdateRootRotation(rot);
2887 AbsolutePosition = pos; 3468 if (!m_rootPart.Undoing)
3469 {
3470 m_rootPart.Undoing = true;
3471 AbsolutePosition = pos;
3472 m_rootPart.Undoing = false;
3473 }
3474 else
3475 {
3476 AbsolutePosition = pos;
3477 }
2888 } 3478 }
2889 else 3479 else
2890 { 3480 {
@@ -2908,9 +3498,10 @@ namespace OpenSim.Region.Framework.Scenes
2908 3498
2909 Quaternion axRot = rot; 3499 Quaternion axRot = rot;
2910 Quaternion oldParentRot = m_rootPart.RotationOffset; 3500 Quaternion oldParentRot = m_rootPart.RotationOffset;
2911
2912 m_rootPart.StoreUndoState(); 3501 m_rootPart.StoreUndoState();
2913 m_rootPart.UpdateRotation(rot); 3502
3503 //Don't use UpdateRotation because it schedules an update prematurely
3504 m_rootPart.RotationOffset = rot;
2914 if (m_rootPart.PhysActor != null) 3505 if (m_rootPart.PhysActor != null)
2915 { 3506 {
2916 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3507 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2924,15 +3515,17 @@ namespace OpenSim.Region.Framework.Scenes
2924 if (prim.UUID != m_rootPart.UUID) 3515 if (prim.UUID != m_rootPart.UUID)
2925 { 3516 {
2926 prim.IgnoreUndoUpdate = true; 3517 prim.IgnoreUndoUpdate = true;
3518
3519 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3520 NewRot = Quaternion.Inverse(axRot) * NewRot;
3521 prim.RotationOffset = NewRot;
3522
2927 Vector3 axPos = prim.OffsetPosition; 3523 Vector3 axPos = prim.OffsetPosition;
3524
2928 axPos *= oldParentRot; 3525 axPos *= oldParentRot;
2929 axPos *= Quaternion.Inverse(axRot); 3526 axPos *= Quaternion.Inverse(axRot);
2930 prim.OffsetPosition = axPos; 3527 prim.OffsetPosition = axPos;
2931 Quaternion primsRot = prim.RotationOffset; 3528
2932 Quaternion newRot = oldParentRot * primsRot;
2933 newRot = Quaternion.Inverse(axRot) * newRot;
2934 prim.RotationOffset = newRot;
2935 prim.ScheduleTerseUpdate();
2936 prim.IgnoreUndoUpdate = false; 3529 prim.IgnoreUndoUpdate = false;
2937 } 3530 }
2938 } 3531 }
@@ -2946,8 +3539,8 @@ namespace OpenSim.Region.Framework.Scenes
2946//// childpart.StoreUndoState(); 3539//// childpart.StoreUndoState();
2947// } 3540// }
2948// } 3541// }
2949 3542 HasGroupChanged = true;
2950 m_rootPart.ScheduleTerseUpdate(); 3543 ScheduleGroupForFullUpdate();
2951 3544
2952// m_log.DebugFormat( 3545// m_log.DebugFormat(
2953// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3546// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3175,7 +3768,6 @@ namespace OpenSim.Region.Framework.Scenes
3175 public float GetMass() 3768 public float GetMass()
3176 { 3769 {
3177 float retmass = 0f; 3770 float retmass = 0f;
3178
3179 SceneObjectPart[] parts = m_parts.GetArray(); 3771 SceneObjectPart[] parts = m_parts.GetArray();
3180 for (int i = 0; i < parts.Length; i++) 3772 for (int i = 0; i < parts.Length; i++)
3181 retmass += parts[i].GetMass(); 3773 retmass += parts[i].GetMass();
@@ -3271,6 +3863,14 @@ namespace OpenSim.Region.Framework.Scenes
3271 SetFromItemID(uuid); 3863 SetFromItemID(uuid);
3272 } 3864 }
3273 3865
3866 public void ResetOwnerChangeFlag()
3867 {
3868 ForEachPart(delegate(SceneObjectPart part)
3869 {
3870 part.ResetOwnerChangeFlag();
3871 });
3872 }
3873
3274 #endregion 3874 #endregion
3275 } 3875 }
3276} 3876}