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.cs750
1 files changed, 676 insertions, 74 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 878476e..cf8637f 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 (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; }
@@ -578,6 +779,7 @@ namespace OpenSim.Region.Framework.Scenes
578 /// </summary> 779 /// </summary>
579 public SceneObjectGroup() 780 public SceneObjectGroup()
580 { 781 {
782
581 } 783 }
582 784
583 /// <summary> 785 /// <summary>
@@ -594,7 +796,7 @@ namespace OpenSim.Region.Framework.Scenes
594 /// Constructor. This object is added to the scene later via AttachToScene() 796 /// Constructor. This object is added to the scene later via AttachToScene()
595 /// </summary> 797 /// </summary>
596 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 798 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
597 { 799 {
598 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 800 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
599 } 801 }
600 802
@@ -642,6 +844,9 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 844 /// </summary>
643 public virtual void AttachToBackup() 845 public virtual void AttachToBackup()
644 { 846 {
847 if (IsAttachment) return;
848 m_scene.SceneGraph.FireAttachToBackup(this);
849
645 if (InSceneBackup) 850 if (InSceneBackup)
646 { 851 {
647 //m_log.DebugFormat( 852 //m_log.DebugFormat(
@@ -684,6 +889,9 @@ namespace OpenSim.Region.Framework.Scenes
684 889
685 ApplyPhysics(); 890 ApplyPhysics();
686 891
892 if (RootPart.PhysActor != null)
893 RootPart.Buoyancy = RootPart.Buoyancy;
894
687 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 895 // 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. 896 // for the same object with very different properties. The caller must schedule the update.
689 //ScheduleGroupForFullUpdate(); 897 //ScheduleGroupForFullUpdate();
@@ -699,6 +907,10 @@ namespace OpenSim.Region.Framework.Scenes
699 EntityIntersection result = new EntityIntersection(); 907 EntityIntersection result = new EntityIntersection();
700 908
701 SceneObjectPart[] parts = m_parts.GetArray(); 909 SceneObjectPart[] parts = m_parts.GetArray();
910
911 // Find closest hit here
912 float idist = float.MaxValue;
913
702 for (int i = 0; i < parts.Length; i++) 914 for (int i = 0; i < parts.Length; i++)
703 { 915 {
704 SceneObjectPart part = parts[i]; 916 SceneObjectPart part = parts[i];
@@ -713,11 +925,6 @@ namespace OpenSim.Region.Framework.Scenes
713 925
714 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 926 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
715 927
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) 928 if (inter.HitTF)
722 { 929 {
723 // We need to find the closest prim to return to the testcaller along the ray 930 // We need to find the closest prim to return to the testcaller along the ray
@@ -728,10 +935,11 @@ namespace OpenSim.Region.Framework.Scenes
728 result.obj = part; 935 result.obj = part;
729 result.normal = inter.normal; 936 result.normal = inter.normal;
730 result.distance = inter.distance; 937 result.distance = inter.distance;
938
939 idist = inter.distance;
731 } 940 }
732 } 941 }
733 } 942 }
734
735 return result; 943 return result;
736 } 944 }
737 945
@@ -751,17 +959,19 @@ namespace OpenSim.Region.Framework.Scenes
751 minZ = 8192f; 959 minZ = 8192f;
752 960
753 SceneObjectPart[] parts = m_parts.GetArray(); 961 SceneObjectPart[] parts = m_parts.GetArray();
754 for (int i = 0; i < parts.Length; i++) 962 foreach (SceneObjectPart part in parts)
755 { 963 {
756 SceneObjectPart part = parts[i];
757
758 Vector3 worldPos = part.GetWorldPosition(); 964 Vector3 worldPos = part.GetWorldPosition();
759 Vector3 offset = worldPos - AbsolutePosition; 965 Vector3 offset = worldPos - AbsolutePosition;
760 Quaternion worldRot; 966 Quaternion worldRot;
761 if (part.ParentID == 0) 967 if (part.ParentID == 0)
968 {
762 worldRot = part.RotationOffset; 969 worldRot = part.RotationOffset;
970 }
763 else 971 else
972 {
764 worldRot = part.GetWorldRotation(); 973 worldRot = part.GetWorldRotation();
974 }
765 975
766 Vector3 frontTopLeft; 976 Vector3 frontTopLeft;
767 Vector3 frontTopRight; 977 Vector3 frontTopRight;
@@ -773,6 +983,8 @@ namespace OpenSim.Region.Framework.Scenes
773 Vector3 backBottomLeft; 983 Vector3 backBottomLeft;
774 Vector3 backBottomRight; 984 Vector3 backBottomRight;
775 985
986 // Vector3[] corners = new Vector3[8];
987
776 Vector3 orig = Vector3.Zero; 988 Vector3 orig = Vector3.Zero;
777 989
778 frontTopLeft.X = orig.X - (part.Scale.X / 2); 990 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -807,6 +1019,38 @@ namespace OpenSim.Region.Framework.Scenes
807 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1019 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
808 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1020 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
809 1021
1022
1023
1024 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1025 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1026 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1027 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1028 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1029 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1030 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1031 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1032
1033 //for (int i = 0; i < 8; i++)
1034 //{
1035 // corners[i] = corners[i] * worldRot;
1036 // corners[i] += offset;
1037
1038 // if (corners[i].X > maxX)
1039 // maxX = corners[i].X;
1040 // if (corners[i].X < minX)
1041 // minX = corners[i].X;
1042
1043 // if (corners[i].Y > maxY)
1044 // maxY = corners[i].Y;
1045 // if (corners[i].Y < minY)
1046 // minY = corners[i].Y;
1047
1048 // if (corners[i].Z > maxZ)
1049 // maxZ = corners[i].Y;
1050 // if (corners[i].Z < minZ)
1051 // minZ = corners[i].Z;
1052 //}
1053
810 frontTopLeft = frontTopLeft * worldRot; 1054 frontTopLeft = frontTopLeft * worldRot;
811 frontTopRight = frontTopRight * worldRot; 1055 frontTopRight = frontTopRight * worldRot;
812 frontBottomLeft = frontBottomLeft * worldRot; 1056 frontBottomLeft = frontBottomLeft * worldRot;
@@ -828,6 +1072,15 @@ namespace OpenSim.Region.Framework.Scenes
828 backTopLeft += offset; 1072 backTopLeft += offset;
829 backTopRight += offset; 1073 backTopRight += offset;
830 1074
1075 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1076 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1077 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1078 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1079 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1080 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1081 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1082 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1083
831 if (frontTopRight.X > maxX) 1084 if (frontTopRight.X > maxX)
832 maxX = frontTopRight.X; 1085 maxX = frontTopRight.X;
833 if (frontTopLeft.X > maxX) 1086 if (frontTopLeft.X > maxX)
@@ -973,15 +1226,20 @@ namespace OpenSim.Region.Framework.Scenes
973 1226
974 public void SaveScriptedState(XmlTextWriter writer) 1227 public void SaveScriptedState(XmlTextWriter writer)
975 { 1228 {
1229 SaveScriptedState(writer, false);
1230 }
1231
1232 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1233 {
976 XmlDocument doc = new XmlDocument(); 1234 XmlDocument doc = new XmlDocument();
977 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1235 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
978 1236
979 SceneObjectPart[] parts = m_parts.GetArray(); 1237 SceneObjectPart[] parts = m_parts.GetArray();
980 for (int i = 0; i < parts.Length; i++) 1238 for (int i = 0; i < parts.Length; i++)
981 { 1239 {
982 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1240 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
983 foreach (KeyValuePair<UUID, string> kvp in pstates) 1241 foreach (KeyValuePair<UUID, string> kvp in pstates)
984 states.Add(kvp.Key, kvp.Value); 1242 states[kvp.Key] = kvp.Value;
985 } 1243 }
986 1244
987 if (states.Count > 0) 1245 if (states.Count > 0)
@@ -1001,6 +1259,169 @@ namespace OpenSim.Region.Framework.Scenes
1001 } 1259 }
1002 1260
1003 /// <summary> 1261 /// <summary>
1262 /// Add the avatar to this linkset (avatar is sat).
1263 /// </summary>
1264 /// <param name="agentID"></param>
1265 public void AddAvatar(UUID agentID)
1266 {
1267 ScenePresence presence;
1268 if (m_scene.TryGetScenePresence(agentID, out presence))
1269 {
1270 if (!m_linkedAvatars.Contains(presence))
1271 {
1272 m_linkedAvatars.Add(presence);
1273 }
1274 }
1275 }
1276
1277 /// <summary>
1278 /// Delete the avatar from this linkset (avatar is unsat).
1279 /// </summary>
1280 /// <param name="agentID"></param>
1281 public void DeleteAvatar(UUID agentID)
1282 {
1283 ScenePresence presence;
1284 if (m_scene.TryGetScenePresence(agentID, out presence))
1285 {
1286 if (m_linkedAvatars.Contains(presence))
1287 {
1288 m_linkedAvatars.Remove(presence);
1289 }
1290 }
1291 }
1292
1293 /// <summary>
1294 /// Returns the list of linked presences (avatars sat on this group)
1295 /// </summary>
1296 /// <param name="agentID"></param>
1297 public List<ScenePresence> GetLinkedAvatars()
1298 {
1299 return m_linkedAvatars;
1300 }
1301
1302 /// <summary>
1303 /// Attach this scene object to the given avatar.
1304 /// </summary>
1305 /// <param name="agentID"></param>
1306 /// <param name="attachmentpoint"></param>
1307 /// <param name="AttachOffset"></param>
1308 private void AttachToAgent(
1309 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1310 {
1311 if (avatar != null)
1312 {
1313 // don't attach attachments to child agents
1314 if (avatar.IsChildAgent) return;
1315
1316 // Remove from database and parcel prim count
1317 m_scene.DeleteFromStorage(so.UUID);
1318 m_scene.EventManager.TriggerParcelPrimCountTainted();
1319
1320 so.AttachedAvatar = avatar.UUID;
1321
1322 if (so.RootPart.PhysActor != null)
1323 {
1324 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1325 so.RootPart.PhysActor = null;
1326 }
1327
1328 so.AbsolutePosition = attachOffset;
1329 so.RootPart.AttachedPos = attachOffset;
1330 so.IsAttachment = true;
1331 so.RootPart.SetParentLocalId(avatar.LocalId);
1332 so.AttachmentPoint = attachmentpoint;
1333
1334 avatar.AddAttachment(this);
1335
1336 if (!silent)
1337 {
1338 // Killing it here will cause the client to deselect it
1339 // It then reappears on the avatar, deselected
1340 // through the full update below
1341 //
1342 if (IsSelected)
1343 {
1344 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1345 }
1346
1347 IsSelected = false; // fudge....
1348 ScheduleGroupForFullUpdate();
1349 }
1350 }
1351 else
1352 {
1353 m_log.WarnFormat(
1354 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1355 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1356 }
1357 }
1358
1359 public byte GetAttachmentPoint()
1360 {
1361 return m_rootPart.Shape.State;
1362 }
1363
1364 public void DetachToGround()
1365 {
1366 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1367 if (avatar == null)
1368 return;
1369
1370 avatar.RemoveAttachment(this);
1371
1372 Vector3 detachedpos = new Vector3(127f,127f,127f);
1373 if (avatar == null)
1374 return;
1375
1376 detachedpos = avatar.AbsolutePosition;
1377 RootPart.FromItemID = UUID.Zero;
1378
1379 AbsolutePosition = detachedpos;
1380 AttachedAvatar = UUID.Zero;
1381
1382 //SceneObjectPart[] parts = m_parts.GetArray();
1383 //for (int i = 0; i < parts.Length; i++)
1384 // parts[i].AttachedAvatar = UUID.Zero;
1385
1386 m_rootPart.SetParentLocalId(0);
1387 AttachmentPoint = (byte)0;
1388 // must check if buildind should be true or false here
1389 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1390 HasGroupChanged = true;
1391 RootPart.Rezzed = DateTime.Now;
1392 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1393 AttachToBackup();
1394 m_scene.EventManager.TriggerParcelPrimCountTainted();
1395 m_rootPart.ScheduleFullUpdate();
1396 m_rootPart.ClearUndoState();
1397 }
1398
1399 public void DetachToInventoryPrep()
1400 {
1401 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1402 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1403 if (avatar != null)
1404 {
1405 //detachedpos = avatar.AbsolutePosition;
1406 avatar.RemoveAttachment(this);
1407 }
1408
1409 AttachedAvatar = UUID.Zero;
1410
1411 /*SceneObjectPart[] parts = m_parts.GetArray();
1412 for (int i = 0; i < parts.Length; i++)
1413 parts[i].AttachedAvatar = UUID.Zero;*/
1414
1415 m_rootPart.SetParentLocalId(0);
1416 //m_rootPart.SetAttachmentPoint((byte)0);
1417 IsAttachment = false;
1418 AbsolutePosition = m_rootPart.AttachedPos;
1419 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1420 //AttachToBackup();
1421 //m_rootPart.ScheduleFullUpdate();
1422 }
1423
1424 /// <summary>
1004 /// 1425 ///
1005 /// </summary> 1426 /// </summary>
1006 /// <param name="part"></param> 1427 /// <param name="part"></param>
@@ -1050,7 +1471,10 @@ namespace OpenSim.Region.Framework.Scenes
1050 public void AddPart(SceneObjectPart part) 1471 public void AddPart(SceneObjectPart part)
1051 { 1472 {
1052 part.SetParent(this); 1473 part.SetParent(this);
1053 part.LinkNum = m_parts.Add(part.UUID, part); 1474 m_parts.Add(part.UUID, part);
1475
1476 part.LinkNum = m_parts.Count;
1477
1054 if (part.LinkNum == 2) 1478 if (part.LinkNum == 2)
1055 RootPart.LinkNum = 1; 1479 RootPart.LinkNum = 1;
1056 } 1480 }
@@ -1158,6 +1582,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1582 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1159 public void DeleteGroupFromScene(bool silent) 1583 public void DeleteGroupFromScene(bool silent)
1160 { 1584 {
1585 // We need to keep track of this state in case this group is still queued for backup.
1586 IsDeleted = true;
1587
1588 DetachFromBackup();
1589
1161 SceneObjectPart[] parts = m_parts.GetArray(); 1590 SceneObjectPart[] parts = m_parts.GetArray();
1162 for (int i = 0; i < parts.Length; i++) 1591 for (int i = 0; i < parts.Length; i++)
1163 { 1592 {
@@ -1180,6 +1609,8 @@ namespace OpenSim.Region.Framework.Scenes
1180 } 1609 }
1181 }); 1610 });
1182 } 1611 }
1612
1613
1183 } 1614 }
1184 1615
1185 public void AddScriptLPS(int count) 1616 public void AddScriptLPS(int count)
@@ -1254,28 +1685,43 @@ namespace OpenSim.Region.Framework.Scenes
1254 /// </summary> 1685 /// </summary>
1255 public void ApplyPhysics() 1686 public void ApplyPhysics()
1256 { 1687 {
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(); 1688 SceneObjectPart[] parts = m_parts.GetArray();
1262 if (parts.Length > 1) 1689 if (parts.Length > 1)
1263 { 1690 {
1691 ResetChildPrimPhysicsPositions();
1692
1693 // Apply physics to the root prim
1694 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1695
1696
1264 for (int i = 0; i < parts.Length; i++) 1697 for (int i = 0; i < parts.Length; i++)
1265 { 1698 {
1266 SceneObjectPart part = parts[i]; 1699 SceneObjectPart part = parts[i];
1267 if (part.LocalId != m_rootPart.LocalId) 1700 if (part.LocalId != m_rootPart.LocalId)
1268 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1701 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1269 } 1702 }
1270
1271 // Hack to get the physics scene geometries in the right spot 1703 // Hack to get the physics scene geometries in the right spot
1272 ResetChildPrimPhysicsPositions(); 1704// ResetChildPrimPhysicsPositions();
1705 if (m_rootPart.PhysActor != null)
1706 {
1707 m_rootPart.PhysActor.Building = false;
1708 }
1709 }
1710 else
1711 {
1712 // Apply physics to the root prim
1713 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1273 } 1714 }
1274 } 1715 }
1275 1716
1276 public void SetOwnerId(UUID userId) 1717 public void SetOwnerId(UUID userId)
1277 { 1718 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1719 ForEachPart(delegate(SceneObjectPart part)
1720 {
1721
1722 part.OwnerID = userId;
1723
1724 });
1279 } 1725 }
1280 1726
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1727 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1307,11 +1753,17 @@ namespace OpenSim.Region.Framework.Scenes
1307 return; 1753 return;
1308 } 1754 }
1309 1755
1756 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1757 return;
1758
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1759 // 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. 1760 // any exception propogate upwards.
1312 try 1761 try
1313 { 1762 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1763 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1764 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1765 m_scene.LoadingPrims) // Land may not be valid yet
1766
1315 { 1767 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1768 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1769 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1338,6 +1790,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1790 }
1339 } 1791 }
1340 } 1792 }
1793
1341 } 1794 }
1342 1795
1343 if (m_scene.UseBackup && HasGroupChanged) 1796 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,6 +1798,20 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1798 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1799 if (isTimeToPersist() || forcedBackup)
1347 { 1800 {
1801 if (m_rootPart.PhysActor != null &&
1802 (!m_rootPart.PhysActor.IsPhysical))
1803 {
1804 // Possible ghost prim
1805 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1806 {
1807 foreach (SceneObjectPart part in m_parts.GetArray())
1808 {
1809 // Re-set physics actor positions and
1810 // orientations
1811 part.GroupPosition = m_rootPart.GroupPosition;
1812 }
1813 }
1814 }
1348// m_log.DebugFormat( 1815// m_log.DebugFormat(
1349// "[SCENE]: Storing {0}, {1} in {2}", 1816// "[SCENE]: Storing {0}, {1} in {2}",
1350// Name, UUID, m_scene.RegionInfo.RegionName); 1817// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1414,6 +1881,7 @@ namespace OpenSim.Region.Framework.Scenes
1414 /// <returns></returns> 1881 /// <returns></returns>
1415 public SceneObjectGroup Copy(bool userExposed) 1882 public SceneObjectGroup Copy(bool userExposed)
1416 { 1883 {
1884 m_dupeInProgress = true;
1417 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1885 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1418 dupe.m_isBackedUp = false; 1886 dupe.m_isBackedUp = false;
1419 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1887 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1428,7 +1896,7 @@ namespace OpenSim.Region.Framework.Scenes
1428 // This is only necessary when userExposed is false! 1896 // This is only necessary when userExposed is false!
1429 1897
1430 bool previousAttachmentStatus = dupe.IsAttachment; 1898 bool previousAttachmentStatus = dupe.IsAttachment;
1431 1899
1432 if (!userExposed) 1900 if (!userExposed)
1433 dupe.IsAttachment = true; 1901 dupe.IsAttachment = true;
1434 1902
@@ -1446,11 +1914,11 @@ namespace OpenSim.Region.Framework.Scenes
1446 dupe.m_rootPart.TrimPermissions(); 1914 dupe.m_rootPart.TrimPermissions();
1447 1915
1448 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1916 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1449 1917
1450 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1918 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1451 { 1919 {
1452 return p1.LinkNum.CompareTo(p2.LinkNum); 1920 return p1.LinkNum.CompareTo(p2.LinkNum);
1453 } 1921 }
1454 ); 1922 );
1455 1923
1456 foreach (SceneObjectPart part in partList) 1924 foreach (SceneObjectPart part in partList)
@@ -1470,21 +1938,24 @@ namespace OpenSim.Region.Framework.Scenes
1470 if (part.PhysActor != null && userExposed) 1938 if (part.PhysActor != null && userExposed)
1471 { 1939 {
1472 PrimitiveBaseShape pbs = newPart.Shape; 1940 PrimitiveBaseShape pbs = newPart.Shape;
1473 1941
1474 newPart.PhysActor 1942 newPart.PhysActor
1475 = m_scene.PhysicsScene.AddPrimShape( 1943 = m_scene.PhysicsScene.AddPrimShape(
1476 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1944 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1477 pbs, 1945 pbs,
1478 newPart.AbsolutePosition, 1946 newPart.AbsolutePosition,
1479 newPart.Scale, 1947 newPart.Scale,
1480 newPart.RotationOffset, 1948 //newPart.RotationOffset,
1949 newPart.GetWorldRotation(),
1481 part.PhysActor.IsPhysical, 1950 part.PhysActor.IsPhysical,
1482 newPart.LocalId); 1951 newPart.LocalId);
1483 1952
1484 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1953 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1485 } 1954 }
1486 } 1955 }
1487 1956 if (dupe.m_rootPart.PhysActor != null && userExposed)
1957 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
1958
1488 if (userExposed) 1959 if (userExposed)
1489 { 1960 {
1490 dupe.UpdateParentIDs(); 1961 dupe.UpdateParentIDs();
@@ -1494,6 +1965,7 @@ namespace OpenSim.Region.Framework.Scenes
1494 ScheduleGroupForFullUpdate(); 1965 ScheduleGroupForFullUpdate();
1495 } 1966 }
1496 1967
1968 m_dupeInProgress = false;
1497 return dupe; 1969 return dupe;
1498 } 1970 }
1499 1971
@@ -1599,6 +2071,7 @@ namespace OpenSim.Region.Framework.Scenes
1599 return Vector3.Zero; 2071 return Vector3.Zero;
1600 } 2072 }
1601 2073
2074 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1602 public void moveToTarget(Vector3 target, float tau) 2075 public void moveToTarget(Vector3 target, float tau)
1603 { 2076 {
1604 if (IsAttachment) 2077 if (IsAttachment)
@@ -1626,6 +2099,46 @@ namespace OpenSim.Region.Framework.Scenes
1626 RootPart.PhysActor.PIDActive = false; 2099 RootPart.PhysActor.PIDActive = false;
1627 } 2100 }
1628 2101
2102 public void rotLookAt(Quaternion target, float strength, float damping)
2103 {
2104 SceneObjectPart rootpart = m_rootPart;
2105 if (rootpart != null)
2106 {
2107 if (IsAttachment)
2108 {
2109 /*
2110 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2111 if (avatar != null)
2112 {
2113 Rotate the Av?
2114 } */
2115 }
2116 else
2117 {
2118 if (rootpart.PhysActor != null)
2119 { // APID must be implemented in your physics system for this to function.
2120 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2121 rootpart.PhysActor.APIDStrength = strength;
2122 rootpart.PhysActor.APIDDamping = damping;
2123 rootpart.PhysActor.APIDActive = true;
2124 }
2125 }
2126 }
2127 }
2128
2129 public void stopLookAt()
2130 {
2131 SceneObjectPart rootpart = m_rootPart;
2132 if (rootpart != null)
2133 {
2134 if (rootpart.PhysActor != null)
2135 { // APID must be implemented in your physics system for this to function.
2136 rootpart.PhysActor.APIDActive = false;
2137 }
2138 }
2139
2140 }
2141
1629 /// <summary> 2142 /// <summary>
1630 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2143 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1631 /// </summary> 2144 /// </summary>
@@ -1681,6 +2194,8 @@ namespace OpenSim.Region.Framework.Scenes
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2194 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2195 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2196 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2197 newPart.SetParent(this);
2198
1684 AddPart(newPart); 2199 AddPart(newPart);
1685 2200
1686 SetPartAsNonRoot(newPart); 2201 SetPartAsNonRoot(newPart);
@@ -1809,11 +2324,11 @@ namespace OpenSim.Region.Framework.Scenes
1809 /// Immediately send a full update for this scene object. 2324 /// Immediately send a full update for this scene object.
1810 /// </summary> 2325 /// </summary>
1811 public void SendGroupFullUpdate() 2326 public void SendGroupFullUpdate()
1812 { 2327 {
1813 if (IsDeleted) 2328 if (IsDeleted)
1814 return; 2329 return;
1815 2330
1816// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2331// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1817 2332
1818 RootPart.SendFullUpdateToAllClients(); 2333 RootPart.SendFullUpdateToAllClients();
1819 2334
@@ -1957,6 +2472,11 @@ namespace OpenSim.Region.Framework.Scenes
1957 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2472 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1958 public void LinkToGroup(SceneObjectGroup objectGroup) 2473 public void LinkToGroup(SceneObjectGroup objectGroup)
1959 { 2474 {
2475 LinkToGroup(objectGroup, false);
2476 }
2477
2478 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2479 {
1960// m_log.DebugFormat( 2480// m_log.DebugFormat(
1961// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2481// "[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); 2482// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1990,7 +2510,20 @@ namespace OpenSim.Region.Framework.Scenes
1990 2510
1991 lock (m_parts.SyncRoot) 2511 lock (m_parts.SyncRoot)
1992 { 2512 {
1993 int linkNum = PrimCount + 1; 2513 int linkNum;
2514 if (insert)
2515 {
2516 linkNum = 2;
2517 foreach (SceneObjectPart part in Parts)
2518 {
2519 if (part.LinkNum > 1)
2520 part.LinkNum++;
2521 }
2522 }
2523 else
2524 {
2525 linkNum = PrimCount + 1;
2526 }
1994 2527
1995 m_parts.Add(linkPart.UUID, linkPart); 2528 m_parts.Add(linkPart.UUID, linkPart);
1996 2529
@@ -2018,7 +2551,7 @@ namespace OpenSim.Region.Framework.Scenes
2018 objectGroup.IsDeleted = true; 2551 objectGroup.IsDeleted = true;
2019 2552
2020 objectGroup.m_parts.Clear(); 2553 objectGroup.m_parts.Clear();
2021 2554
2022 // Can't do this yet since backup still makes use of the root part without any synchronization 2555 // Can't do this yet since backup still makes use of the root part without any synchronization
2023// objectGroup.m_rootPart = null; 2556// objectGroup.m_rootPart = null;
2024 2557
@@ -2152,6 +2685,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 /// <param name="objectGroup"></param> 2685 /// <param name="objectGroup"></param>
2153 public virtual void DetachFromBackup() 2686 public virtual void DetachFromBackup()
2154 { 2687 {
2688 m_scene.SceneGraph.FireDetachFromBackup(this);
2155 if (m_isBackedUp && Scene != null) 2689 if (m_isBackedUp && Scene != null)
2156 m_scene.EventManager.OnBackup -= ProcessBackup; 2690 m_scene.EventManager.OnBackup -= ProcessBackup;
2157 2691
@@ -2170,7 +2704,8 @@ namespace OpenSim.Region.Framework.Scenes
2170 2704
2171 axPos *= parentRot; 2705 axPos *= parentRot;
2172 part.OffsetPosition = axPos; 2706 part.OffsetPosition = axPos;
2173 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2707 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2708 part.GroupPosition = newPos;
2174 part.OffsetPosition = Vector3.Zero; 2709 part.OffsetPosition = Vector3.Zero;
2175 part.RotationOffset = worldRot; 2710 part.RotationOffset = worldRot;
2176 2711
@@ -2181,7 +2716,7 @@ namespace OpenSim.Region.Framework.Scenes
2181 2716
2182 part.LinkNum = linkNum; 2717 part.LinkNum = linkNum;
2183 2718
2184 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2719 part.OffsetPosition = newPos - AbsolutePosition;
2185 2720
2186 Quaternion rootRotation = m_rootPart.RotationOffset; 2721 Quaternion rootRotation = m_rootPart.RotationOffset;
2187 2722
@@ -2191,7 +2726,7 @@ namespace OpenSim.Region.Framework.Scenes
2191 2726
2192 parentRot = m_rootPart.RotationOffset; 2727 parentRot = m_rootPart.RotationOffset;
2193 oldRot = part.RotationOffset; 2728 oldRot = part.RotationOffset;
2194 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2729 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2195 part.RotationOffset = newRot; 2730 part.RotationOffset = newRot;
2196 } 2731 }
2197 2732
@@ -2438,8 +2973,31 @@ namespace OpenSim.Region.Framework.Scenes
2438 } 2973 }
2439 } 2974 }
2440 2975
2976/*
2977 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2441 for (int i = 0; i < parts.Length; i++) 2978 for (int i = 0; i < parts.Length; i++)
2442 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2979 {
2980 if (parts[i] != RootPart)
2981 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2982 }
2983*/
2984 if (parts.Length > 1)
2985 {
2986 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
2987
2988 for (int i = 0; i < parts.Length; i++)
2989 {
2990
2991 if (parts[i].UUID != m_rootPart.UUID)
2992 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
2993 }
2994
2995 if (m_rootPart.PhysActor != null)
2996 m_rootPart.PhysActor.Building = false;
2997 }
2998 else
2999 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3000
2443 } 3001 }
2444 } 3002 }
2445 3003
@@ -2452,6 +3010,17 @@ namespace OpenSim.Region.Framework.Scenes
2452 } 3010 }
2453 } 3011 }
2454 3012
3013
3014
3015 /// <summary>
3016 /// Gets the number of parts
3017 /// </summary>
3018 /// <returns></returns>
3019 public int GetPartCount()
3020 {
3021 return Parts.Count();
3022 }
3023
2455 /// <summary> 3024 /// <summary>
2456 /// Update the texture entry for this part 3025 /// Update the texture entry for this part
2457 /// </summary> 3026 /// </summary>
@@ -2513,7 +3082,6 @@ namespace OpenSim.Region.Framework.Scenes
2513 { 3082 {
2514// m_log.DebugFormat( 3083// m_log.DebugFormat(
2515// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 3084// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2516
2517 RootPart.StoreUndoState(true); 3085 RootPart.StoreUndoState(true);
2518 3086
2519 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3087 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2614,7 +3182,6 @@ namespace OpenSim.Region.Framework.Scenes
2614 prevScale.X *= x; 3182 prevScale.X *= x;
2615 prevScale.Y *= y; 3183 prevScale.Y *= y;
2616 prevScale.Z *= z; 3184 prevScale.Z *= z;
2617
2618// RootPart.IgnoreUndoUpdate = true; 3185// RootPart.IgnoreUndoUpdate = true;
2619 RootPart.Resize(prevScale); 3186 RootPart.Resize(prevScale);
2620// RootPart.IgnoreUndoUpdate = false; 3187// RootPart.IgnoreUndoUpdate = false;
@@ -2645,7 +3212,9 @@ namespace OpenSim.Region.Framework.Scenes
2645 } 3212 }
2646 3213
2647// obPart.IgnoreUndoUpdate = false; 3214// obPart.IgnoreUndoUpdate = false;
2648// obPart.StoreUndoState(); 3215 HasGroupChanged = true;
3216 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3217 ScheduleGroupForTerseUpdate();
2649 } 3218 }
2650 3219
2651// m_log.DebugFormat( 3220// m_log.DebugFormat(
@@ -2705,9 +3274,9 @@ namespace OpenSim.Region.Framework.Scenes
2705 { 3274 {
2706 SceneObjectPart part = GetChildPart(localID); 3275 SceneObjectPart part = GetChildPart(localID);
2707 3276
2708// SceneObjectPart[] parts = m_parts.GetArray(); 3277 SceneObjectPart[] parts = m_parts.GetArray();
2709// for (int i = 0; i < parts.Length; i++) 3278 for (int i = 0; i < parts.Length; i++)
2710// parts[i].StoreUndoState(); 3279 parts[i].StoreUndoState();
2711 3280
2712 if (part != null) 3281 if (part != null)
2713 { 3282 {
@@ -2763,10 +3332,27 @@ namespace OpenSim.Region.Framework.Scenes
2763 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3332 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2764 } 3333 }
2765 3334
2766 AbsolutePosition = newPos; 3335 //We have to set undoing here because otherwise an undo state will be saved
3336 if (!m_rootPart.Undoing)
3337 {
3338 m_rootPart.Undoing = true;
3339 AbsolutePosition = newPos;
3340 m_rootPart.Undoing = false;
3341 }
3342 else
3343 {
3344 AbsolutePosition = newPos;
3345 }
2767 3346
2768 HasGroupChanged = true; 3347 HasGroupChanged = true;
2769 ScheduleGroupForTerseUpdate(); 3348 if (m_rootPart.Undoing)
3349 {
3350 ScheduleGroupForFullUpdate();
3351 }
3352 else
3353 {
3354 ScheduleGroupForTerseUpdate();
3355 }
2770 } 3356 }
2771 3357
2772 #endregion 3358 #endregion
@@ -2843,10 +3429,7 @@ namespace OpenSim.Region.Framework.Scenes
2843 public void UpdateSingleRotation(Quaternion rot, uint localID) 3429 public void UpdateSingleRotation(Quaternion rot, uint localID)
2844 { 3430 {
2845 SceneObjectPart part = GetChildPart(localID); 3431 SceneObjectPart part = GetChildPart(localID);
2846
2847 SceneObjectPart[] parts = m_parts.GetArray(); 3432 SceneObjectPart[] parts = m_parts.GetArray();
2848 for (int i = 0; i < parts.Length; i++)
2849 parts[i].StoreUndoState();
2850 3433
2851 if (part != null) 3434 if (part != null)
2852 { 3435 {
@@ -2884,7 +3467,16 @@ namespace OpenSim.Region.Framework.Scenes
2884 if (part.UUID == m_rootPart.UUID) 3467 if (part.UUID == m_rootPart.UUID)
2885 { 3468 {
2886 UpdateRootRotation(rot); 3469 UpdateRootRotation(rot);
2887 AbsolutePosition = pos; 3470 if (!m_rootPart.Undoing)
3471 {
3472 m_rootPart.Undoing = true;
3473 AbsolutePosition = pos;
3474 m_rootPart.Undoing = false;
3475 }
3476 else
3477 {
3478 AbsolutePosition = pos;
3479 }
2888 } 3480 }
2889 else 3481 else
2890 { 3482 {
@@ -2908,9 +3500,10 @@ namespace OpenSim.Region.Framework.Scenes
2908 3500
2909 Quaternion axRot = rot; 3501 Quaternion axRot = rot;
2910 Quaternion oldParentRot = m_rootPart.RotationOffset; 3502 Quaternion oldParentRot = m_rootPart.RotationOffset;
2911
2912 m_rootPart.StoreUndoState(); 3503 m_rootPart.StoreUndoState();
2913 m_rootPart.UpdateRotation(rot); 3504
3505 //Don't use UpdateRotation because it schedules an update prematurely
3506 m_rootPart.RotationOffset = rot;
2914 if (m_rootPart.PhysActor != null) 3507 if (m_rootPart.PhysActor != null)
2915 { 3508 {
2916 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3509 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2924,15 +3517,17 @@ namespace OpenSim.Region.Framework.Scenes
2924 if (prim.UUID != m_rootPart.UUID) 3517 if (prim.UUID != m_rootPart.UUID)
2925 { 3518 {
2926 prim.IgnoreUndoUpdate = true; 3519 prim.IgnoreUndoUpdate = true;
3520
3521 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3522 NewRot = Quaternion.Inverse(axRot) * NewRot;
3523 prim.RotationOffset = NewRot;
3524
2927 Vector3 axPos = prim.OffsetPosition; 3525 Vector3 axPos = prim.OffsetPosition;
3526
2928 axPos *= oldParentRot; 3527 axPos *= oldParentRot;
2929 axPos *= Quaternion.Inverse(axRot); 3528 axPos *= Quaternion.Inverse(axRot);
2930 prim.OffsetPosition = axPos; 3529 prim.OffsetPosition = axPos;
2931 Quaternion primsRot = prim.RotationOffset; 3530
2932 Quaternion newRot = oldParentRot * primsRot;
2933 newRot = Quaternion.Inverse(axRot) * newRot;
2934 prim.RotationOffset = newRot;
2935 prim.ScheduleTerseUpdate();
2936 prim.IgnoreUndoUpdate = false; 3531 prim.IgnoreUndoUpdate = false;
2937 } 3532 }
2938 } 3533 }
@@ -2946,8 +3541,8 @@ namespace OpenSim.Region.Framework.Scenes
2946//// childpart.StoreUndoState(); 3541//// childpart.StoreUndoState();
2947// } 3542// }
2948// } 3543// }
2949 3544 HasGroupChanged = true;
2950 m_rootPart.ScheduleTerseUpdate(); 3545 ScheduleGroupForFullUpdate();
2951 3546
2952// m_log.DebugFormat( 3547// m_log.DebugFormat(
2953// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3548// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3175,7 +3770,6 @@ namespace OpenSim.Region.Framework.Scenes
3175 public float GetMass() 3770 public float GetMass()
3176 { 3771 {
3177 float retmass = 0f; 3772 float retmass = 0f;
3178
3179 SceneObjectPart[] parts = m_parts.GetArray(); 3773 SceneObjectPart[] parts = m_parts.GetArray();
3180 for (int i = 0; i < parts.Length; i++) 3774 for (int i = 0; i < parts.Length; i++)
3181 retmass += parts[i].GetMass(); 3775 retmass += parts[i].GetMass();
@@ -3271,6 +3865,14 @@ namespace OpenSim.Region.Framework.Scenes
3271 SetFromItemID(uuid); 3865 SetFromItemID(uuid);
3272 } 3866 }
3273 3867
3868 public void ResetOwnerChangeFlag()
3869 {
3870 ForEachPart(delegate(SceneObjectPart part)
3871 {
3872 part.ResetOwnerChangeFlag();
3873 });
3874 }
3875
3274 #endregion 3876 #endregion
3275 } 3877 }
3276} 3878}