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.cs705
1 files changed, 553 insertions, 152 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 79660a3..482597d 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -29,6 +29,7 @@ using 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;
@@ -105,8 +106,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 106 /// since the group's last persistent backup
106 /// </summary> 107 /// </summary>
107 private bool m_hasGroupChanged = false; 108 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 109 private long timeFirstChanged = 0;
109 private long timeLastChanged; 110 private long timeLastChanged = 0;
111 private long m_maxPersistTime = 0;
112 private long m_minPersistTime = 0;
113 private Random m_rand;
114 private bool m_suspendUpdates;
115 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
116
117 public bool areUpdatesSuspended
118 {
119 get
120 {
121 return m_suspendUpdates;
122 }
123 set
124 {
125 m_suspendUpdates = value;
126 if (!value)
127 {
128 QueueForUpdateCheck();
129 }
130 }
131 }
110 132
111 public bool HasGroupChanged 133 public bool HasGroupChanged
112 { 134 {
@@ -114,9 +136,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 136 {
115 if (value) 137 if (value)
116 { 138 {
139 if (m_isBackedUp)
140 {
141 m_scene.SceneGraph.FireChangeBackup(this);
142 }
117 timeLastChanged = DateTime.Now.Ticks; 143 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 144 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 145 timeFirstChanged = DateTime.Now.Ticks;
146 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
147 {
148 if (m_rand == null)
149 {
150 byte[] val = new byte[16];
151 m_rootPart.UUID.ToBytes(val, 0);
152 m_rand = new Random(BitConverter.ToInt32(val, 0));
153 }
154
155 if (m_scene.GetRootAgentCount() == 0)
156 {
157 //If the region is empty, this change has been made by an automated process
158 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
159
160 float factor = 1.5f + (float)(m_rand.NextDouble());
161 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
162 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
163 }
164 else
165 {
166 //If the region is not empty, we want to obey the minimum and maximum persist times
167 //but add a random factor so we stagger the object persistance a little
168 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
169 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
170 }
171 }
120 } 172 }
121 m_hasGroupChanged = value; 173 m_hasGroupChanged = value;
122 174
@@ -131,7 +183,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 183 /// 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. 184 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 185 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 186 public bool HasGroupChangedDueToDelink { get; set; }
135 187
136 private bool isTimeToPersist() 188 private bool isTimeToPersist()
137 { 189 {
@@ -141,8 +193,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 193 return false;
142 if (m_scene.ShuttingDown) 194 if (m_scene.ShuttingDown)
143 return true; 195 return true;
196
197 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
198 {
199 m_maxPersistTime = m_scene.m_persistAfter;
200 m_minPersistTime = m_scene.m_dontPersistBefore;
201 }
202
144 long currentTime = DateTime.Now.Ticks; 203 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 204
205 if (timeLastChanged == 0) timeLastChanged = currentTime;
206 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
207
208 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 209 return true;
147 return false; 210 return false;
148 } 211 }
@@ -185,10 +248,10 @@ namespace OpenSim.Region.Framework.Scenes
185 248
186 private bool m_scriptListens_atTarget; 249 private bool m_scriptListens_atTarget;
187 private bool m_scriptListens_notAtTarget; 250 private bool m_scriptListens_notAtTarget;
188
189 private bool m_scriptListens_atRotTarget; 251 private bool m_scriptListens_atRotTarget;
190 private bool m_scriptListens_notAtRotTarget; 252 private bool m_scriptListens_notAtRotTarget;
191 253
254 public bool m_dupeInProgress = false;
192 internal Dictionary<UUID, string> m_savedScriptState; 255 internal Dictionary<UUID, string> m_savedScriptState;
193 256
194 #region Properties 257 #region Properties
@@ -228,7 +291,13 @@ namespace OpenSim.Region.Framework.Scenes
228 public virtual Quaternion Rotation 291 public virtual Quaternion Rotation
229 { 292 {
230 get { return m_rotation; } 293 get { return m_rotation; }
231 set { m_rotation = value; } 294 set {
295 foreach(SceneObjectPart p in m_parts.GetArray())
296 {
297 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
298 }
299 m_rotation = value;
300 }
232 } 301 }
233 302
234 public Quaternion GroupRotation 303 public Quaternion GroupRotation
@@ -305,7 +374,11 @@ namespace OpenSim.Region.Framework.Scenes
305 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 374 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
306 } 375 }
307 } 376 }
308 377
378 foreach (SceneObjectPart part in m_parts.GetArray())
379 {
380 part.IgnoreUndoUpdate = true;
381 }
309 if (RootPart.GetStatusSandbox()) 382 if (RootPart.GetStatusSandbox())
310 { 383 {
311 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 384 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -319,10 +392,31 @@ namespace OpenSim.Region.Framework.Scenes
319 return; 392 return;
320 } 393 }
321 } 394 }
322
323 SceneObjectPart[] parts = m_parts.GetArray(); 395 SceneObjectPart[] parts = m_parts.GetArray();
324 for (int i = 0; i < parts.Length; i++) 396 foreach (SceneObjectPart part in parts)
325 parts[i].GroupPosition = val; 397 {
398 part.IgnoreUndoUpdate = false;
399 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
400 part.GroupPosition = val;
401 if (!m_dupeInProgress)
402 {
403 part.TriggerScriptChangedEvent(Changed.POSITION);
404 }
405 }
406 if (!m_dupeInProgress)
407 {
408 foreach (ScenePresence av in m_linkedAvatars)
409 {
410 SceneObjectPart p;
411 if (m_parts.TryGetValue(av.LinkedPrim, out p))
412 {
413 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
414 av.AbsolutePosition += offset;
415 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
416 av.SendAvatarDataToAllAgents();
417 }
418 }
419 }
326 420
327 //if (m_rootPart.PhysActor != null) 421 //if (m_rootPart.PhysActor != null)
328 //{ 422 //{
@@ -481,6 +575,7 @@ namespace OpenSim.Region.Framework.Scenes
481 /// </summary> 575 /// </summary>
482 public SceneObjectGroup() 576 public SceneObjectGroup()
483 { 577 {
578
484 } 579 }
485 580
486 /// <summary> 581 /// <summary>
@@ -497,7 +592,7 @@ namespace OpenSim.Region.Framework.Scenes
497 /// Constructor. This object is added to the scene later via AttachToScene() 592 /// Constructor. This object is added to the scene later via AttachToScene()
498 /// </summary> 593 /// </summary>
499 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 594 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
500 { 595 {
501 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 596 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
502 } 597 }
503 598
@@ -545,6 +640,9 @@ namespace OpenSim.Region.Framework.Scenes
545 /// </summary> 640 /// </summary>
546 public virtual void AttachToBackup() 641 public virtual void AttachToBackup()
547 { 642 {
643 if (IsAttachment) return;
644 m_scene.SceneGraph.FireAttachToBackup(this);
645
548 if (InSceneBackup) 646 if (InSceneBackup)
549 { 647 {
550 //m_log.DebugFormat( 648 //m_log.DebugFormat(
@@ -587,6 +685,9 @@ namespace OpenSim.Region.Framework.Scenes
587 685
588 ApplyPhysics(m_scene.m_physicalPrim); 686 ApplyPhysics(m_scene.m_physicalPrim);
589 687
688 if (RootPart.PhysActor != null)
689 RootPart.Buoyancy = RootPart.Buoyancy;
690
590 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 691 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
591 // for the same object with very different properties. The caller must schedule the update. 692 // for the same object with very different properties. The caller must schedule the update.
592 //ScheduleGroupForFullUpdate(); 693 //ScheduleGroupForFullUpdate();
@@ -660,9 +761,9 @@ namespace OpenSim.Region.Framework.Scenes
660 result.normal = inter.normal; 761 result.normal = inter.normal;
661 result.distance = inter.distance; 762 result.distance = inter.distance;
662 } 763 }
764
663 } 765 }
664 } 766 }
665
666 return result; 767 return result;
667 } 768 }
668 769
@@ -682,17 +783,19 @@ namespace OpenSim.Region.Framework.Scenes
682 minZ = 8192f; 783 minZ = 8192f;
683 784
684 SceneObjectPart[] parts = m_parts.GetArray(); 785 SceneObjectPart[] parts = m_parts.GetArray();
685 for (int i = 0; i < parts.Length; i++) 786 foreach (SceneObjectPart part in parts)
686 { 787 {
687 SceneObjectPart part = parts[i];
688
689 Vector3 worldPos = part.GetWorldPosition(); 788 Vector3 worldPos = part.GetWorldPosition();
690 Vector3 offset = worldPos - AbsolutePosition; 789 Vector3 offset = worldPos - AbsolutePosition;
691 Quaternion worldRot; 790 Quaternion worldRot;
692 if (part.ParentID == 0) 791 if (part.ParentID == 0)
792 {
693 worldRot = part.RotationOffset; 793 worldRot = part.RotationOffset;
794 }
694 else 795 else
796 {
695 worldRot = part.GetWorldRotation(); 797 worldRot = part.GetWorldRotation();
798 }
696 799
697 Vector3 frontTopLeft; 800 Vector3 frontTopLeft;
698 Vector3 frontTopRight; 801 Vector3 frontTopRight;
@@ -704,6 +807,8 @@ namespace OpenSim.Region.Framework.Scenes
704 Vector3 backBottomLeft; 807 Vector3 backBottomLeft;
705 Vector3 backBottomRight; 808 Vector3 backBottomRight;
706 809
810 // Vector3[] corners = new Vector3[8];
811
707 Vector3 orig = Vector3.Zero; 812 Vector3 orig = Vector3.Zero;
708 813
709 frontTopLeft.X = orig.X - (part.Scale.X / 2); 814 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -738,6 +843,38 @@ namespace OpenSim.Region.Framework.Scenes
738 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 843 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
739 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 844 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
740 845
846
847
848 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
849 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
850 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
851 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
852 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
853 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
854 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
855 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
856
857 //for (int i = 0; i < 8; i++)
858 //{
859 // corners[i] = corners[i] * worldRot;
860 // corners[i] += offset;
861
862 // if (corners[i].X > maxX)
863 // maxX = corners[i].X;
864 // if (corners[i].X < minX)
865 // minX = corners[i].X;
866
867 // if (corners[i].Y > maxY)
868 // maxY = corners[i].Y;
869 // if (corners[i].Y < minY)
870 // minY = corners[i].Y;
871
872 // if (corners[i].Z > maxZ)
873 // maxZ = corners[i].Y;
874 // if (corners[i].Z < minZ)
875 // minZ = corners[i].Z;
876 //}
877
741 frontTopLeft = frontTopLeft * worldRot; 878 frontTopLeft = frontTopLeft * worldRot;
742 frontTopRight = frontTopRight * worldRot; 879 frontTopRight = frontTopRight * worldRot;
743 frontBottomLeft = frontBottomLeft * worldRot; 880 frontBottomLeft = frontBottomLeft * worldRot;
@@ -759,6 +896,15 @@ namespace OpenSim.Region.Framework.Scenes
759 backTopLeft += offset; 896 backTopLeft += offset;
760 backTopRight += offset; 897 backTopRight += offset;
761 898
899 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
900 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
901 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
902 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
903 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
904 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
905 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
906 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
907
762 if (frontTopRight.X > maxX) 908 if (frontTopRight.X > maxX)
763 maxX = frontTopRight.X; 909 maxX = frontTopRight.X;
764 if (frontTopLeft.X > maxX) 910 if (frontTopLeft.X > maxX)
@@ -904,15 +1050,20 @@ namespace OpenSim.Region.Framework.Scenes
904 1050
905 public void SaveScriptedState(XmlTextWriter writer) 1051 public void SaveScriptedState(XmlTextWriter writer)
906 { 1052 {
1053 SaveScriptedState(writer, false);
1054 }
1055
1056 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1057 {
907 XmlDocument doc = new XmlDocument(); 1058 XmlDocument doc = new XmlDocument();
908 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1059 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
909 1060
910 SceneObjectPart[] parts = m_parts.GetArray(); 1061 SceneObjectPart[] parts = m_parts.GetArray();
911 for (int i = 0; i < parts.Length; i++) 1062 for (int i = 0; i < parts.Length; i++)
912 { 1063 {
913 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1064 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
914 foreach (KeyValuePair<UUID, string> kvp in pstates) 1065 foreach (KeyValuePair<UUID, string> kvp in pstates)
915 states.Add(kvp.Key, kvp.Value); 1066 states[kvp.Key] = kvp.Value;
916 } 1067 }
917 1068
918 if (states.Count > 0) 1069 if (states.Count > 0)
@@ -931,6 +1082,118 @@ namespace OpenSim.Region.Framework.Scenes
931 } 1082 }
932 } 1083 }
933 1084
1085 /// <summary>
1086 /// Add the avatar to this linkset (avatar is sat).
1087 /// </summary>
1088 /// <param name="agentID"></param>
1089 public void AddAvatar(UUID agentID)
1090 {
1091 ScenePresence presence;
1092 if (m_scene.TryGetScenePresence(agentID, out presence))
1093 {
1094 if (!m_linkedAvatars.Contains(presence))
1095 {
1096 m_linkedAvatars.Add(presence);
1097 }
1098 }
1099 }
1100
1101 /// <summary>
1102 /// Delete the avatar from this linkset (avatar is unsat).
1103 /// </summary>
1104 /// <param name="agentID"></param>
1105 public void DeleteAvatar(UUID agentID)
1106 {
1107 ScenePresence presence;
1108 if (m_scene.TryGetScenePresence(agentID, out presence))
1109 {
1110 if (m_linkedAvatars.Contains(presence))
1111 {
1112 m_linkedAvatars.Remove(presence);
1113 }
1114 }
1115 }
1116
1117 /// <summary>
1118 /// Returns the list of linked presences (avatars sat on this group)
1119 /// </summary>
1120 /// <param name="agentID"></param>
1121 public List<ScenePresence> GetLinkedAvatars()
1122 {
1123 return m_linkedAvatars;
1124 }
1125
1126 /// <summary>
1127 /// Attach this scene object to the given avatar.
1128 /// </summary>
1129 /// <param name="agentID"></param>
1130 /// <param name="attachmentpoint"></param>
1131 /// <param name="AttachOffset"></param>
1132 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1133 {
1134 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1135 if (avatar != null)
1136 {
1137 // don't attach attachments to child agents
1138 if (avatar.IsChildAgent) return;
1139
1140// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1141
1142 DetachFromBackup();
1143
1144 // Remove from database and parcel prim count
1145 m_scene.DeleteFromStorage(UUID);
1146 m_scene.EventManager.TriggerParcelPrimCountTainted();
1147
1148 m_rootPart.AttachedAvatar = agentID;
1149
1150 //Anakin Lohner bug #3839
1151 lock (m_parts)
1152 {
1153 foreach (SceneObjectPart p in m_parts.GetArray())
1154 {
1155 p.AttachedAvatar = agentID;
1156 }
1157 }
1158
1159 if (m_rootPart.PhysActor != null)
1160 {
1161 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1162 m_rootPart.PhysActor = null;
1163 }
1164
1165 AbsolutePosition = AttachOffset;
1166 m_rootPart.AttachedPos = AttachOffset;
1167 m_rootPart.IsAttachment = true;
1168
1169 m_rootPart.SetParentLocalId(avatar.LocalId);
1170 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1171
1172 avatar.AddAttachment(this);
1173
1174 if (!silent)
1175 {
1176 // Killing it here will cause the client to deselect it
1177 // It then reappears on the avatar, deselected
1178 // through the full update below
1179 //
1180 if (IsSelected)
1181 {
1182 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1183 }
1184
1185 IsSelected = false; // fudge....
1186 ScheduleGroupForFullUpdate();
1187 }
1188 }
1189 else
1190 {
1191 m_log.WarnFormat(
1192 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1193 UUID, agentID, Scene.RegionInfo.RegionName);
1194 }
1195 }
1196
934 public byte GetAttachmentPoint() 1197 public byte GetAttachmentPoint()
935 { 1198 {
936 return m_rootPart.Shape.State; 1199 return m_rootPart.Shape.State;
@@ -1057,7 +1320,10 @@ namespace OpenSim.Region.Framework.Scenes
1057 public void AddPart(SceneObjectPart part) 1320 public void AddPart(SceneObjectPart part)
1058 { 1321 {
1059 part.SetParent(this); 1322 part.SetParent(this);
1060 part.LinkNum = m_parts.Add(part.UUID, part); 1323 m_parts.Add(part.UUID, part);
1324
1325 part.LinkNum = m_parts.Count;
1326
1061 if (part.LinkNum == 2 && RootPart != null) 1327 if (part.LinkNum == 2 && RootPart != null)
1062 RootPart.LinkNum = 1; 1328 RootPart.LinkNum = 1;
1063 } 1329 }
@@ -1141,7 +1407,7 @@ namespace OpenSim.Region.Framework.Scenes
1141 1407
1142 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1408 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1143 { 1409 {
1144 part.StoreUndoState(); 1410 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1145 part.OnGrab(offsetPos, remoteClient); 1411 part.OnGrab(offsetPos, remoteClient);
1146 } 1412 }
1147 1413
@@ -1161,6 +1427,11 @@ namespace OpenSim.Region.Framework.Scenes
1161 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1427 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1162 public void DeleteGroupFromScene(bool silent) 1428 public void DeleteGroupFromScene(bool silent)
1163 { 1429 {
1430 // We need to keep track of this state in case this group is still queued for backup.
1431 m_isDeleted = true;
1432
1433 DetachFromBackup();
1434
1164 SceneObjectPart[] parts = m_parts.GetArray(); 1435 SceneObjectPart[] parts = m_parts.GetArray();
1165 for (int i = 0; i < parts.Length; i++) 1436 for (int i = 0; i < parts.Length; i++)
1166 { 1437 {
@@ -1172,13 +1443,11 @@ namespace OpenSim.Region.Framework.Scenes
1172 avatar.StandUp(); 1443 avatar.StandUp();
1173 1444
1174 if (!silent) 1445 if (!silent)
1175 {
1176 part.UpdateFlag = 0; 1446 part.UpdateFlag = 0;
1177 if (part == m_rootPart)
1178 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1179 }
1180 }); 1447 });
1181 } 1448 }
1449
1450
1182 } 1451 }
1183 1452
1184 public void AddScriptLPS(int count) 1453 public void AddScriptLPS(int count)
@@ -1275,7 +1544,12 @@ namespace OpenSim.Region.Framework.Scenes
1275 1544
1276 public void SetOwnerId(UUID userId) 1545 public void SetOwnerId(UUID userId)
1277 { 1546 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1547 ForEachPart(delegate(SceneObjectPart part)
1548 {
1549
1550 part.OwnerID = userId;
1551
1552 });
1279 } 1553 }
1280 1554
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1555 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1307,11 +1581,17 @@ namespace OpenSim.Region.Framework.Scenes
1307 return; 1581 return;
1308 } 1582 }
1309 1583
1584 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1585 return;
1586
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1587 // 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. 1588 // any exception propogate upwards.
1312 try 1589 try
1313 { 1590 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1591 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1592 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1593 m_scene.LoadingPrims) // Land may not be valid yet
1594
1315 { 1595 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1596 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1597 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1338,6 +1618,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1618 }
1339 } 1619 }
1340 } 1620 }
1621
1341 } 1622 }
1342 1623
1343 if (m_scene.UseBackup && HasGroupChanged) 1624 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,6 +1626,20 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1626 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1627 if (isTimeToPersist() || forcedBackup)
1347 { 1628 {
1629 if (m_rootPart.PhysActor != null &&
1630 (!m_rootPart.PhysActor.IsPhysical))
1631 {
1632 // Possible ghost prim
1633 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1634 {
1635 foreach (SceneObjectPart part in m_parts.GetArray())
1636 {
1637 // Re-set physics actor positions and
1638 // orientations
1639 part.GroupPosition = m_rootPart.GroupPosition;
1640 }
1641 }
1642 }
1348// m_log.DebugFormat( 1643// m_log.DebugFormat(
1349// "[SCENE]: Storing {0}, {1} in {2}", 1644// "[SCENE]: Storing {0}, {1} in {2}",
1350// Name, UUID, m_scene.RegionInfo.RegionName); 1645// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1408,81 +1703,90 @@ namespace OpenSim.Region.Framework.Scenes
1408 /// <returns></returns> 1703 /// <returns></returns>
1409 public SceneObjectGroup Copy(bool userExposed) 1704 public SceneObjectGroup Copy(bool userExposed)
1410 { 1705 {
1411 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1706 SceneObjectGroup dupe;
1412 dupe.m_isBackedUp = false; 1707 try
1413 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1708 {
1414 1709 m_dupeInProgress = true;
1415 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1710 dupe = (SceneObjectGroup)MemberwiseClone();
1416 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1711 dupe.m_isBackedUp = false;
1417 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1712 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1418 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1419 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1420 // then restore it's attachment state
1421
1422 // This is only necessary when userExposed is false!
1423 1713
1424 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1714 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1425 1715 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1426 if (!userExposed) 1716 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1427 dupe.RootPart.IsAttachment = true; 1717 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1718 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1719 // then restore it's attachment state
1428 1720
1429 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1721 // This is only necessary when userExposed is false!
1430 1722
1431 if (!userExposed) 1723 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1432 {
1433 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1434 }
1435 1724
1436 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1725 if (!userExposed)
1437 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1726 dupe.RootPart.IsAttachment = true;
1438 1727
1439 if (userExposed) 1728 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1440 dupe.m_rootPart.TrimPermissions();
1441 1729
1442 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1730 if (!userExposed)
1443
1444 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1445 { 1731 {
1446 return p1.LinkNum.CompareTo(p2.LinkNum); 1732 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1447 } 1733 }
1448 );
1449 1734
1450 foreach (SceneObjectPart part in partList) 1735 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1451 { 1736 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1452 if (part.UUID != m_rootPart.UUID) 1737
1738 if (userExposed)
1739 dupe.m_rootPart.TrimPermissions();
1740
1741 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1742
1743 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1744 {
1745 return p1.LinkNum.CompareTo(p2.LinkNum);
1746 }
1747 );
1748
1749 foreach (SceneObjectPart part in partList)
1453 { 1750 {
1454 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1751 if (part.UUID != m_rootPart.UUID)
1455 newPart.LinkNum = part.LinkNum; 1752 {
1456 } 1753 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1457 1754
1458 // Need to duplicate the physics actor as well 1755 newPart.LinkNum = part.LinkNum;
1459 if (part.PhysActor != null && userExposed) 1756 }
1757
1758 // Need to duplicate the physics actor as well
1759 if (part.PhysActor != null && userExposed)
1760 {
1761 PrimitiveBaseShape pbs = part.Shape;
1762
1763 part.PhysActor
1764 = m_scene.PhysicsScene.AddPrimShape(
1765 string.Format("{0}/{1}", part.Name, part.UUID),
1766 pbs,
1767 part.AbsolutePosition,
1768 part.Scale,
1769 part.RotationOffset,
1770 part.PhysActor.IsPhysical);
1771 part.PhysActor.SetMaterial((int)part.Material);
1772
1773 part.PhysActor.LocalID = part.LocalId;
1774 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1775 }
1776 }
1777 if (userExposed)
1460 { 1778 {
1461 PrimitiveBaseShape pbs = part.Shape; 1779 dupe.UpdateParentIDs();
1462 1780 dupe.HasGroupChanged = true;
1463 part.PhysActor 1781 dupe.AttachToBackup();
1464 = m_scene.PhysicsScene.AddPrimShape( 1782
1465 string.Format("{0}/{1}", part.Name, part.UUID), 1783 ScheduleGroupForFullUpdate();
1466 pbs,
1467 part.AbsolutePosition,
1468 part.Scale,
1469 part.RotationOffset,
1470 part.PhysActor.IsPhysical);
1471
1472 part.PhysActor.LocalID = part.LocalId;
1473 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1474 } 1784 }
1475 } 1785 }
1476 1786 finally
1477 if (userExposed)
1478 { 1787 {
1479 dupe.UpdateParentIDs(); 1788 m_dupeInProgress = false;
1480 dupe.HasGroupChanged = true;
1481 dupe.AttachToBackup();
1482
1483 ScheduleGroupForFullUpdate();
1484 } 1789 }
1485
1486 return dupe; 1790 return dupe;
1487 } 1791 }
1488 1792
@@ -1627,6 +1931,7 @@ namespace OpenSim.Region.Framework.Scenes
1627 return Vector3.Zero; 1931 return Vector3.Zero;
1628 } 1932 }
1629 1933
1934 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1630 public void moveToTarget(Vector3 target, float tau) 1935 public void moveToTarget(Vector3 target, float tau)
1631 { 1936 {
1632 SceneObjectPart rootpart = m_rootPart; 1937 SceneObjectPart rootpart = m_rootPart;
@@ -1666,20 +1971,55 @@ namespace OpenSim.Region.Framework.Scenes
1666 SceneObjectPart rootpart = m_rootPart; 1971 SceneObjectPart rootpart = m_rootPart;
1667 if (rootpart != null) 1972 if (rootpart != null)
1668 { 1973 {
1669 if (rootpart.PhysActor != null) 1974 if (IsAttachment)
1975 {
1976 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1977 if (avatar != null) avatar.StopMoveToPosition();
1978 }
1979 else
1670 { 1980 {
1671 rootpart.PhysActor.PIDActive = false; 1981 if (rootpart.PhysActor != null)
1982 {
1983 rootpart.PhysActor.PIDActive = false;
1984 }
1672 } 1985 }
1673 } 1986 }
1674 } 1987 }
1675 1988
1989 public void rotLookAt(Quaternion target, float strength, float damping)
1990 {
1991 SceneObjectPart rootpart = m_rootPart;
1992 if (rootpart != null)
1993 {
1994 if (IsAttachment)
1995 {
1996 /*
1997 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1998 if (avatar != null)
1999 {
2000 Rotate the Av?
2001 } */
2002 }
2003 else
2004 {
2005 if (rootpart.PhysActor != null)
2006 { // APID must be implemented in your physics system for this to function.
2007 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2008 rootpart.PhysActor.APIDStrength = strength;
2009 rootpart.PhysActor.APIDDamping = damping;
2010 rootpart.PhysActor.APIDActive = true;
2011 }
2012 }
2013 }
2014 }
2015
1676 public void stopLookAt() 2016 public void stopLookAt()
1677 { 2017 {
1678 SceneObjectPart rootpart = m_rootPart; 2018 SceneObjectPart rootpart = m_rootPart;
1679 if (rootpart != null) 2019 if (rootpart != null)
1680 { 2020 {
1681 if (rootpart.PhysActor != null) 2021 if (rootpart.PhysActor != null)
1682 { 2022 { // APID must be implemented in your physics system for this to function.
1683 rootpart.PhysActor.APIDActive = false; 2023 rootpart.PhysActor.APIDActive = false;
1684 } 2024 }
1685 } 2025 }
@@ -1745,6 +2085,8 @@ namespace OpenSim.Region.Framework.Scenes
1745 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2085 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1746 { 2086 {
1747 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2087 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2088 newPart.SetParent(this);
2089
1748 AddPart(newPart); 2090 AddPart(newPart);
1749 2091
1750 SetPartAsNonRoot(newPart); 2092 SetPartAsNonRoot(newPart);
@@ -1893,11 +2235,11 @@ namespace OpenSim.Region.Framework.Scenes
1893 /// Immediately send a full update for this scene object. 2235 /// Immediately send a full update for this scene object.
1894 /// </summary> 2236 /// </summary>
1895 public void SendGroupFullUpdate() 2237 public void SendGroupFullUpdate()
1896 { 2238 {
1897 if (IsDeleted) 2239 if (IsDeleted)
1898 return; 2240 return;
1899 2241
1900// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2242// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1901 2243
1902 RootPart.SendFullUpdateToAllClients(); 2244 RootPart.SendFullUpdateToAllClients();
1903 2245
@@ -2086,12 +2428,15 @@ namespace OpenSim.Region.Framework.Scenes
2086 part.LinkNum += objectGroup.PrimCount; 2428 part.LinkNum += objectGroup.PrimCount;
2087 } 2429 }
2088 } 2430 }
2431 }
2089 2432
2090 linkPart.LinkNum = 2; 2433 linkPart.LinkNum = 2;
2091 2434
2092 linkPart.SetParent(this); 2435 linkPart.SetParent(this);
2093 linkPart.CreateSelected = true; 2436 linkPart.CreateSelected = true;
2094 2437
2438 lock (m_parts.SyncRoot)
2439 {
2095 //if (linkPart.PhysActor != null) 2440 //if (linkPart.PhysActor != null)
2096 //{ 2441 //{
2097 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2442 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2249,6 +2594,8 @@ namespace OpenSim.Region.Framework.Scenes
2249 /// <param name="objectGroup"></param> 2594 /// <param name="objectGroup"></param>
2250 public virtual void DetachFromBackup() 2595 public virtual void DetachFromBackup()
2251 { 2596 {
2597 m_scene.SceneGraph.FireDetachFromBackup(this);
2598
2252 if (m_isBackedUp) 2599 if (m_isBackedUp)
2253 m_scene.EventManager.OnBackup -= ProcessBackup; 2600 m_scene.EventManager.OnBackup -= ProcessBackup;
2254 2601
@@ -2267,7 +2614,8 @@ namespace OpenSim.Region.Framework.Scenes
2267 2614
2268 axPos *= parentRot; 2615 axPos *= parentRot;
2269 part.OffsetPosition = axPos; 2616 part.OffsetPosition = axPos;
2270 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2617 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2618 part.GroupPosition = newPos;
2271 part.OffsetPosition = Vector3.Zero; 2619 part.OffsetPosition = Vector3.Zero;
2272 part.RotationOffset = worldRot; 2620 part.RotationOffset = worldRot;
2273 2621
@@ -2278,7 +2626,7 @@ namespace OpenSim.Region.Framework.Scenes
2278 2626
2279 part.LinkNum = linkNum; 2627 part.LinkNum = linkNum;
2280 2628
2281 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2629 part.OffsetPosition = newPos - AbsolutePosition;
2282 2630
2283 Quaternion rootRotation = m_rootPart.RotationOffset; 2631 Quaternion rootRotation = m_rootPart.RotationOffset;
2284 2632
@@ -2288,7 +2636,7 @@ namespace OpenSim.Region.Framework.Scenes
2288 2636
2289 parentRot = m_rootPart.RotationOffset; 2637 parentRot = m_rootPart.RotationOffset;
2290 oldRot = part.RotationOffset; 2638 oldRot = part.RotationOffset;
2291 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2639 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2292 part.RotationOffset = newRot; 2640 part.RotationOffset = newRot;
2293 } 2641 }
2294 2642
@@ -2539,8 +2887,12 @@ namespace OpenSim.Region.Framework.Scenes
2539 } 2887 }
2540 } 2888 }
2541 2889
2890 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2542 for (int i = 0; i < parts.Length; i++) 2891 for (int i = 0; i < parts.Length; i++)
2543 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2892 {
2893 if (parts[i] != RootPart)
2894 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2895 }
2544 } 2896 }
2545 } 2897 }
2546 2898
@@ -2553,6 +2905,17 @@ namespace OpenSim.Region.Framework.Scenes
2553 } 2905 }
2554 } 2906 }
2555 2907
2908
2909
2910 /// <summary>
2911 /// Gets the number of parts
2912 /// </summary>
2913 /// <returns></returns>
2914 public int GetPartCount()
2915 {
2916 return Parts.Count();
2917 }
2918
2556 /// <summary> 2919 /// <summary>
2557 /// Update the texture entry for this part 2920 /// Update the texture entry for this part
2558 /// </summary> 2921 /// </summary>
@@ -2614,11 +2977,9 @@ namespace OpenSim.Region.Framework.Scenes
2614 scale.Y = m_scene.m_maxNonphys; 2977 scale.Y = m_scene.m_maxNonphys;
2615 if (scale.Z > m_scene.m_maxNonphys) 2978 if (scale.Z > m_scene.m_maxNonphys)
2616 scale.Z = m_scene.m_maxNonphys; 2979 scale.Z = m_scene.m_maxNonphys;
2617
2618 SceneObjectPart part = GetChildPart(localID); 2980 SceneObjectPart part = GetChildPart(localID);
2619 if (part != null) 2981 if (part != null)
2620 { 2982 {
2621 part.Resize(scale);
2622 if (part.PhysActor != null) 2983 if (part.PhysActor != null)
2623 { 2984 {
2624 if (part.PhysActor.IsPhysical) 2985 if (part.PhysActor.IsPhysical)
@@ -2633,7 +2994,7 @@ namespace OpenSim.Region.Framework.Scenes
2633 part.PhysActor.Size = scale; 2994 part.PhysActor.Size = scale;
2634 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2995 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2635 } 2996 }
2636 //if (part.UUID != m_rootPart.UUID) 2997 part.Resize(scale);
2637 2998
2638 HasGroupChanged = true; 2999 HasGroupChanged = true;
2639 part.TriggerScriptChangedEvent(Changed.SCALE); 3000 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2656,7 +3017,6 @@ namespace OpenSim.Region.Framework.Scenes
2656 SceneObjectPart part = GetChildPart(localID); 3017 SceneObjectPart part = GetChildPart(localID);
2657 if (part != null) 3018 if (part != null)
2658 { 3019 {
2659 part.IgnoreUndoUpdate = true;
2660 if (scale.X > m_scene.m_maxNonphys) 3020 if (scale.X > m_scene.m_maxNonphys)
2661 scale.X = m_scene.m_maxNonphys; 3021 scale.X = m_scene.m_maxNonphys;
2662 if (scale.Y > m_scene.m_maxNonphys) 3022 if (scale.Y > m_scene.m_maxNonphys)
@@ -2693,7 +3053,7 @@ namespace OpenSim.Region.Framework.Scenes
2693 3053
2694 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3054 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2695 { 3055 {
2696 if (oldSize.X * x > m_scene.m_maxPhys) 3056 if (oldSize.X*x > m_scene.m_maxPhys)
2697 { 3057 {
2698 f = m_scene.m_maxPhys / oldSize.X; 3058 f = m_scene.m_maxPhys / oldSize.X;
2699 a = f / x; 3059 a = f / x;
@@ -2701,7 +3061,7 @@ namespace OpenSim.Region.Framework.Scenes
2701 y *= a; 3061 y *= a;
2702 z *= a; 3062 z *= a;
2703 } 3063 }
2704 if (oldSize.Y * y > m_scene.m_maxPhys) 3064 if (oldSize.Y*y > m_scene.m_maxPhys)
2705 { 3065 {
2706 f = m_scene.m_maxPhys / oldSize.Y; 3066 f = m_scene.m_maxPhys / oldSize.Y;
2707 a = f / y; 3067 a = f / y;
@@ -2709,7 +3069,7 @@ namespace OpenSim.Region.Framework.Scenes
2709 y *= a; 3069 y *= a;
2710 z *= a; 3070 z *= a;
2711 } 3071 }
2712 if (oldSize.Z * z > m_scene.m_maxPhys) 3072 if (oldSize.Z*z > m_scene.m_maxPhys)
2713 { 3073 {
2714 f = m_scene.m_maxPhys / oldSize.Z; 3074 f = m_scene.m_maxPhys / oldSize.Z;
2715 a = f / z; 3075 a = f / z;
@@ -2720,7 +3080,7 @@ namespace OpenSim.Region.Framework.Scenes
2720 } 3080 }
2721 else 3081 else
2722 { 3082 {
2723 if (oldSize.X * x > m_scene.m_maxNonphys) 3083 if (oldSize.X*x > m_scene.m_maxNonphys)
2724 { 3084 {
2725 f = m_scene.m_maxNonphys / oldSize.X; 3085 f = m_scene.m_maxNonphys / oldSize.X;
2726 a = f / x; 3086 a = f / x;
@@ -2728,7 +3088,7 @@ namespace OpenSim.Region.Framework.Scenes
2728 y *= a; 3088 y *= a;
2729 z *= a; 3089 z *= a;
2730 } 3090 }
2731 if (oldSize.Y * y > m_scene.m_maxNonphys) 3091 if (oldSize.Y*y > m_scene.m_maxNonphys)
2732 { 3092 {
2733 f = m_scene.m_maxNonphys / oldSize.Y; 3093 f = m_scene.m_maxNonphys / oldSize.Y;
2734 a = f / y; 3094 a = f / y;
@@ -2736,7 +3096,7 @@ namespace OpenSim.Region.Framework.Scenes
2736 y *= a; 3096 y *= a;
2737 z *= a; 3097 z *= a;
2738 } 3098 }
2739 if (oldSize.Z * z > m_scene.m_maxNonphys) 3099 if (oldSize.Z*z > m_scene.m_maxNonphys)
2740 { 3100 {
2741 f = m_scene.m_maxNonphys / oldSize.Z; 3101 f = m_scene.m_maxNonphys / oldSize.Z;
2742 a = f / z; 3102 a = f / z;
@@ -2746,7 +3106,6 @@ namespace OpenSim.Region.Framework.Scenes
2746 } 3106 }
2747 } 3107 }
2748 obPart.IgnoreUndoUpdate = false; 3108 obPart.IgnoreUndoUpdate = false;
2749 obPart.StoreUndoState();
2750 } 3109 }
2751 } 3110 }
2752 } 3111 }
@@ -2754,8 +3113,13 @@ namespace OpenSim.Region.Framework.Scenes
2754 Vector3 prevScale = part.Scale; 3113 Vector3 prevScale = part.Scale;
2755 prevScale.X *= x; 3114 prevScale.X *= x;
2756 prevScale.Y *= y; 3115 prevScale.Y *= y;
2757 prevScale.Z *= z; 3116 prevScale.Z *= z;;
3117
3118 part.IgnoreUndoUpdate = false;
3119 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3120 part.IgnoreUndoUpdate = true;
2758 part.Resize(prevScale); 3121 part.Resize(prevScale);
3122 part.IgnoreUndoUpdate = false;
2759 3123
2760 parts = m_parts.GetArray(); 3124 parts = m_parts.GetArray();
2761 for (int i = 0; i < parts.Length; i++) 3125 for (int i = 0; i < parts.Length; i++)
@@ -2764,19 +3128,26 @@ namespace OpenSim.Region.Framework.Scenes
2764 obPart.IgnoreUndoUpdate = true; 3128 obPart.IgnoreUndoUpdate = true;
2765 if (obPart.UUID != m_rootPart.UUID) 3129 if (obPart.UUID != m_rootPart.UUID)
2766 { 3130 {
2767 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3131 if (obPart.UUID != m_rootPart.UUID)
2768 currentpos.X *= x; 3132 {
2769 currentpos.Y *= y; 3133 obPart.IgnoreUndoUpdate = false;
2770 currentpos.Z *= z; 3134 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2771 Vector3 newSize = new Vector3(obPart.Scale); 3135 obPart.IgnoreUndoUpdate = true;
2772 newSize.X *= x; 3136
2773 newSize.Y *= y; 3137 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2774 newSize.Z *= z; 3138 currentpos.X *= x;
2775 obPart.Resize(newSize); 3139 currentpos.Y *= y;
2776 obPart.UpdateOffSet(currentpos); 3140 currentpos.Z *= z;
3141 Vector3 newSize = new Vector3(obPart.Scale);
3142 newSize.X *= x;
3143 newSize.Y *= y;
3144 newSize.Z *= z;
3145 obPart.Resize(newSize);
3146 obPart.UpdateOffSet(currentpos);
3147 }
3148 obPart.IgnoreUndoUpdate = false;
2777 } 3149 }
2778 obPart.IgnoreUndoUpdate = false; 3150 obPart.IgnoreUndoUpdate = false;
2779 obPart.StoreUndoState();
2780 } 3151 }
2781 3152
2782 if (part.PhysActor != null) 3153 if (part.PhysActor != null)
@@ -2786,7 +3157,6 @@ namespace OpenSim.Region.Framework.Scenes
2786 } 3157 }
2787 3158
2788 part.IgnoreUndoUpdate = false; 3159 part.IgnoreUndoUpdate = false;
2789 part.StoreUndoState();
2790 HasGroupChanged = true; 3160 HasGroupChanged = true;
2791 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3161 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2792 ScheduleGroupForTerseUpdate(); 3162 ScheduleGroupForTerseUpdate();
@@ -2803,14 +3173,11 @@ namespace OpenSim.Region.Framework.Scenes
2803 /// <param name="pos"></param> 3173 /// <param name="pos"></param>
2804 public void UpdateGroupPosition(Vector3 pos) 3174 public void UpdateGroupPosition(Vector3 pos)
2805 { 3175 {
2806 SceneObjectPart[] parts = m_parts.GetArray();
2807 for (int i = 0; i < parts.Length; i++)
2808 parts[i].StoreUndoState();
2809
2810 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3176 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2811 { 3177 {
2812 if (IsAttachment) 3178 if (IsAttachment)
2813 { 3179 {
3180 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2814 m_rootPart.AttachedPos = pos; 3181 m_rootPart.AttachedPos = pos;
2815 } 3182 }
2816 if (RootPart.GetStatusSandbox()) 3183 if (RootPart.GetStatusSandbox())
@@ -2844,7 +3211,7 @@ namespace OpenSim.Region.Framework.Scenes
2844 3211
2845 SceneObjectPart[] parts = m_parts.GetArray(); 3212 SceneObjectPart[] parts = m_parts.GetArray();
2846 for (int i = 0; i < parts.Length; i++) 3213 for (int i = 0; i < parts.Length; i++)
2847 parts[i].StoreUndoState(); 3214 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2848 3215
2849 if (part != null) 3216 if (part != null)
2850 { 3217 {
@@ -2869,7 +3236,7 @@ namespace OpenSim.Region.Framework.Scenes
2869 { 3236 {
2870 SceneObjectPart[] parts = m_parts.GetArray(); 3237 SceneObjectPart[] parts = m_parts.GetArray();
2871 for (int i = 0; i < parts.Length; i++) 3238 for (int i = 0; i < parts.Length; i++)
2872 parts[i].StoreUndoState(); 3239 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2873 3240
2874 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3241 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2875 Vector3 oldPos = 3242 Vector3 oldPos =
@@ -2890,10 +3257,27 @@ namespace OpenSim.Region.Framework.Scenes
2890 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3257 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2891 } 3258 }
2892 3259
2893 AbsolutePosition = newPos; 3260 //We have to set undoing here because otherwise an undo state will be saved
3261 if (!m_rootPart.Undoing)
3262 {
3263 m_rootPart.Undoing = true;
3264 AbsolutePosition = newPos;
3265 m_rootPart.Undoing = false;
3266 }
3267 else
3268 {
3269 AbsolutePosition = newPos;
3270 }
2894 3271
2895 HasGroupChanged = true; 3272 HasGroupChanged = true;
2896 ScheduleGroupForTerseUpdate(); 3273 if (m_rootPart.Undoing)
3274 {
3275 ScheduleGroupForFullUpdate();
3276 }
3277 else
3278 {
3279 ScheduleGroupForTerseUpdate();
3280 }
2897 } 3281 }
2898 3282
2899 public void OffsetForNewRegion(Vector3 offset) 3283 public void OffsetForNewRegion(Vector3 offset)
@@ -2913,7 +3297,7 @@ namespace OpenSim.Region.Framework.Scenes
2913 { 3297 {
2914 SceneObjectPart[] parts = m_parts.GetArray(); 3298 SceneObjectPart[] parts = m_parts.GetArray();
2915 for (int i = 0; i < parts.Length; i++) 3299 for (int i = 0; i < parts.Length; i++)
2916 parts[i].StoreUndoState(); 3300 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2917 3301
2918 m_rootPart.UpdateRotation(rot); 3302 m_rootPart.UpdateRotation(rot);
2919 3303
@@ -2937,7 +3321,7 @@ namespace OpenSim.Region.Framework.Scenes
2937 { 3321 {
2938 SceneObjectPart[] parts = m_parts.GetArray(); 3322 SceneObjectPart[] parts = m_parts.GetArray();
2939 for (int i = 0; i < parts.Length; i++) 3323 for (int i = 0; i < parts.Length; i++)
2940 parts[i].StoreUndoState(); 3324 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2941 3325
2942 m_rootPart.UpdateRotation(rot); 3326 m_rootPart.UpdateRotation(rot);
2943 3327
@@ -2962,10 +3346,9 @@ namespace OpenSim.Region.Framework.Scenes
2962 public void UpdateSingleRotation(Quaternion rot, uint localID) 3346 public void UpdateSingleRotation(Quaternion rot, uint localID)
2963 { 3347 {
2964 SceneObjectPart part = GetChildPart(localID); 3348 SceneObjectPart part = GetChildPart(localID);
2965
2966 SceneObjectPart[] parts = m_parts.GetArray(); 3349 SceneObjectPart[] parts = m_parts.GetArray();
2967 for (int i = 0; i < parts.Length; i++) 3350 for (int i = 0; i < parts.Length; i++)
2968 parts[i].StoreUndoState(); 3351 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2969 3352
2970 if (part != null) 3353 if (part != null)
2971 { 3354 {
@@ -2993,15 +3376,24 @@ namespace OpenSim.Region.Framework.Scenes
2993 if (part.UUID == m_rootPart.UUID) 3376 if (part.UUID == m_rootPart.UUID)
2994 { 3377 {
2995 UpdateRootRotation(rot); 3378 UpdateRootRotation(rot);
2996 AbsolutePosition = pos; 3379 if (!m_rootPart.Undoing)
3380 {
3381 m_rootPart.Undoing = true;
3382 AbsolutePosition = pos;
3383 m_rootPart.Undoing = false;
3384 }
3385 else
3386 {
3387 AbsolutePosition = pos;
3388 }
2997 } 3389 }
2998 else 3390 else
2999 { 3391 {
3392 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3000 part.IgnoreUndoUpdate = true; 3393 part.IgnoreUndoUpdate = true;
3001 part.UpdateRotation(rot); 3394 part.UpdateRotation(rot);
3002 part.OffsetPosition = pos; 3395 part.OffsetPosition = pos;
3003 part.IgnoreUndoUpdate = false; 3396 part.IgnoreUndoUpdate = false;
3004 part.StoreUndoState();
3005 } 3397 }
3006 } 3398 }
3007 } 3399 }
@@ -3015,8 +3407,16 @@ namespace OpenSim.Region.Framework.Scenes
3015 Quaternion axRot = rot; 3407 Quaternion axRot = rot;
3016 Quaternion oldParentRot = m_rootPart.RotationOffset; 3408 Quaternion oldParentRot = m_rootPart.RotationOffset;
3017 3409
3018 m_rootPart.StoreUndoState(); 3410 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3019 m_rootPart.UpdateRotation(rot); 3411 bool cancelUndo = false;
3412 if (!m_rootPart.Undoing)
3413 {
3414 m_rootPart.Undoing = true;
3415 cancelUndo = true;
3416 }
3417
3418 //Don't use UpdateRotation because it schedules an update prematurely
3419 m_rootPart.RotationOffset = rot;
3020 if (m_rootPart.PhysActor != null) 3420 if (m_rootPart.PhysActor != null)
3021 { 3421 {
3022 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3422 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -3031,28 +3431,22 @@ namespace OpenSim.Region.Framework.Scenes
3031 { 3431 {
3032 prim.IgnoreUndoUpdate = true; 3432 prim.IgnoreUndoUpdate = true;
3033 Vector3 axPos = prim.OffsetPosition; 3433 Vector3 axPos = prim.OffsetPosition;
3434
3034 axPos *= oldParentRot; 3435 axPos *= oldParentRot;
3035 axPos *= Quaternion.Inverse(axRot); 3436 axPos *= Quaternion.Inverse(axRot);
3036 prim.OffsetPosition = axPos; 3437 prim.OffsetPosition = axPos;
3037 Quaternion primsRot = prim.RotationOffset; 3438
3038 Quaternion newRot = primsRot * oldParentRot; 3439 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
3039 newRot *= Quaternion.Inverse(axRot); 3440
3040 prim.RotationOffset = newRot; 3441 prim.IgnoreUndoUpdate = false;
3041 prim.ScheduleTerseUpdate();
3042 } 3442 }
3043 } 3443 }
3044 3444 if (cancelUndo == true)
3045 for (int i = 0; i < parts.Length; i++)
3046 { 3445 {
3047 SceneObjectPart childpart = parts[i]; 3446 m_rootPart.Undoing = false;
3048 if (childpart != m_rootPart)
3049 {
3050 childpart.IgnoreUndoUpdate = false;
3051 childpart.StoreUndoState();
3052 }
3053 } 3447 }
3054 3448 HasGroupChanged = true;
3055 m_rootPart.ScheduleTerseUpdate(); 3449 ScheduleGroupForFullUpdate();
3056 } 3450 }
3057 3451
3058 #endregion 3452 #endregion
@@ -3275,7 +3669,6 @@ namespace OpenSim.Region.Framework.Scenes
3275 public float GetMass() 3669 public float GetMass()
3276 { 3670 {
3277 float retmass = 0f; 3671 float retmass = 0f;
3278
3279 SceneObjectPart[] parts = m_parts.GetArray(); 3672 SceneObjectPart[] parts = m_parts.GetArray();
3280 for (int i = 0; i < parts.Length; i++) 3673 for (int i = 0; i < parts.Length; i++)
3281 retmass += parts[i].GetMass(); 3674 retmass += parts[i].GetMass();
@@ -3391,6 +3784,14 @@ namespace OpenSim.Region.Framework.Scenes
3391 SetFromItemID(uuid); 3784 SetFromItemID(uuid);
3392 } 3785 }
3393 3786
3787 public void ResetOwnerChangeFlag()
3788 {
3789 ForEachPart(delegate(SceneObjectPart part)
3790 {
3791 part.ResetOwnerChangeFlag();
3792 });
3793 }
3794
3394 #endregion 3795 #endregion
3395 } 3796 }
3396} 3797}