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.cs700
1 files changed, 549 insertions, 151 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index ca7d9d9..759fc23 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
@@ -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
@@ -302,7 +371,11 @@ namespace OpenSim.Region.Framework.Scenes
302 { 371 {
303 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 372 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
304 } 373 }
305 374
375 foreach (SceneObjectPart part in m_parts.GetArray())
376 {
377 part.IgnoreUndoUpdate = true;
378 }
306 if (RootPart.GetStatusSandbox()) 379 if (RootPart.GetStatusSandbox())
307 { 380 {
308 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 381 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -313,10 +386,31 @@ namespace OpenSim.Region.Framework.Scenes
313 return; 386 return;
314 } 387 }
315 } 388 }
316
317 SceneObjectPart[] parts = m_parts.GetArray(); 389 SceneObjectPart[] parts = m_parts.GetArray();
318 for (int i = 0; i < parts.Length; i++) 390 foreach (SceneObjectPart part in parts)
319 parts[i].GroupPosition = val; 391 {
392 part.IgnoreUndoUpdate = false;
393 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
394 part.GroupPosition = val;
395 if (!m_dupeInProgress)
396 {
397 part.TriggerScriptChangedEvent(Changed.POSITION);
398 }
399 }
400 if (!m_dupeInProgress)
401 {
402 foreach (ScenePresence av in m_linkedAvatars)
403 {
404 SceneObjectPart p;
405 if (m_parts.TryGetValue(av.LinkedPrim, out p))
406 {
407 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
408 av.AbsolutePosition += offset;
409 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
410 av.SendAvatarDataToAllAgents();
411 }
412 }
413 }
320 414
321 //if (m_rootPart.PhysActor != null) 415 //if (m_rootPart.PhysActor != null)
322 //{ 416 //{
@@ -469,6 +563,7 @@ namespace OpenSim.Region.Framework.Scenes
469 /// </summary> 563 /// </summary>
470 public SceneObjectGroup() 564 public SceneObjectGroup()
471 { 565 {
566
472 } 567 }
473 568
474 /// <summary> 569 /// <summary>
@@ -485,7 +580,7 @@ namespace OpenSim.Region.Framework.Scenes
485 /// Constructor. This object is added to the scene later via AttachToScene() 580 /// Constructor. This object is added to the scene later via AttachToScene()
486 /// </summary> 581 /// </summary>
487 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 582 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
488 { 583 {
489 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 584 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
490 } 585 }
491 586
@@ -533,6 +628,9 @@ namespace OpenSim.Region.Framework.Scenes
533 /// </summary> 628 /// </summary>
534 public virtual void AttachToBackup() 629 public virtual void AttachToBackup()
535 { 630 {
631 if (IsAttachment) return;
632 m_scene.SceneGraph.FireAttachToBackup(this);
633
536 if (InSceneBackup) 634 if (InSceneBackup)
537 { 635 {
538 //m_log.DebugFormat( 636 //m_log.DebugFormat(
@@ -648,9 +746,9 @@ namespace OpenSim.Region.Framework.Scenes
648 result.normal = inter.normal; 746 result.normal = inter.normal;
649 result.distance = inter.distance; 747 result.distance = inter.distance;
650 } 748 }
749
651 } 750 }
652 } 751 }
653
654 return result; 752 return result;
655 } 753 }
656 754
@@ -670,17 +768,19 @@ namespace OpenSim.Region.Framework.Scenes
670 minZ = 8192f; 768 minZ = 8192f;
671 769
672 SceneObjectPart[] parts = m_parts.GetArray(); 770 SceneObjectPart[] parts = m_parts.GetArray();
673 for (int i = 0; i < parts.Length; i++) 771 foreach (SceneObjectPart part in parts)
674 { 772 {
675 SceneObjectPart part = parts[i];
676
677 Vector3 worldPos = part.GetWorldPosition(); 773 Vector3 worldPos = part.GetWorldPosition();
678 Vector3 offset = worldPos - AbsolutePosition; 774 Vector3 offset = worldPos - AbsolutePosition;
679 Quaternion worldRot; 775 Quaternion worldRot;
680 if (part.ParentID == 0) 776 if (part.ParentID == 0)
777 {
681 worldRot = part.RotationOffset; 778 worldRot = part.RotationOffset;
779 }
682 else 780 else
781 {
683 worldRot = part.GetWorldRotation(); 782 worldRot = part.GetWorldRotation();
783 }
684 784
685 Vector3 frontTopLeft; 785 Vector3 frontTopLeft;
686 Vector3 frontTopRight; 786 Vector3 frontTopRight;
@@ -692,6 +792,8 @@ namespace OpenSim.Region.Framework.Scenes
692 Vector3 backBottomLeft; 792 Vector3 backBottomLeft;
693 Vector3 backBottomRight; 793 Vector3 backBottomRight;
694 794
795 // Vector3[] corners = new Vector3[8];
796
695 Vector3 orig = Vector3.Zero; 797 Vector3 orig = Vector3.Zero;
696 798
697 frontTopLeft.X = orig.X - (part.Scale.X / 2); 799 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -726,6 +828,38 @@ namespace OpenSim.Region.Framework.Scenes
726 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 828 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
727 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 829 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
728 830
831
832
833 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
834 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
835 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
836 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
837 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
838 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
839 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
840 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
841
842 //for (int i = 0; i < 8; i++)
843 //{
844 // corners[i] = corners[i] * worldRot;
845 // corners[i] += offset;
846
847 // if (corners[i].X > maxX)
848 // maxX = corners[i].X;
849 // if (corners[i].X < minX)
850 // minX = corners[i].X;
851
852 // if (corners[i].Y > maxY)
853 // maxY = corners[i].Y;
854 // if (corners[i].Y < minY)
855 // minY = corners[i].Y;
856
857 // if (corners[i].Z > maxZ)
858 // maxZ = corners[i].Y;
859 // if (corners[i].Z < minZ)
860 // minZ = corners[i].Z;
861 //}
862
729 frontTopLeft = frontTopLeft * worldRot; 863 frontTopLeft = frontTopLeft * worldRot;
730 frontTopRight = frontTopRight * worldRot; 864 frontTopRight = frontTopRight * worldRot;
731 frontBottomLeft = frontBottomLeft * worldRot; 865 frontBottomLeft = frontBottomLeft * worldRot;
@@ -747,6 +881,15 @@ namespace OpenSim.Region.Framework.Scenes
747 backTopLeft += offset; 881 backTopLeft += offset;
748 backTopRight += offset; 882 backTopRight += offset;
749 883
884 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
885 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
886 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
887 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
888 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
889 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
890 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
891 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
892
750 if (frontTopRight.X > maxX) 893 if (frontTopRight.X > maxX)
751 maxX = frontTopRight.X; 894 maxX = frontTopRight.X;
752 if (frontTopLeft.X > maxX) 895 if (frontTopLeft.X > maxX)
@@ -892,15 +1035,20 @@ namespace OpenSim.Region.Framework.Scenes
892 1035
893 public void SaveScriptedState(XmlTextWriter writer) 1036 public void SaveScriptedState(XmlTextWriter writer)
894 { 1037 {
1038 SaveScriptedState(writer, false);
1039 }
1040
1041 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1042 {
895 XmlDocument doc = new XmlDocument(); 1043 XmlDocument doc = new XmlDocument();
896 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1044 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
897 1045
898 SceneObjectPart[] parts = m_parts.GetArray(); 1046 SceneObjectPart[] parts = m_parts.GetArray();
899 for (int i = 0; i < parts.Length; i++) 1047 for (int i = 0; i < parts.Length; i++)
900 { 1048 {
901 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1049 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
902 foreach (KeyValuePair<UUID, string> kvp in pstates) 1050 foreach (KeyValuePair<UUID, string> kvp in pstates)
903 states.Add(kvp.Key, kvp.Value); 1051 states[kvp.Key] = kvp.Value;
904 } 1052 }
905 1053
906 if (states.Count > 0) 1054 if (states.Count > 0)
@@ -919,6 +1067,118 @@ namespace OpenSim.Region.Framework.Scenes
919 } 1067 }
920 } 1068 }
921 1069
1070 /// <summary>
1071 /// Add the avatar to this linkset (avatar is sat).
1072 /// </summary>
1073 /// <param name="agentID"></param>
1074 public void AddAvatar(UUID agentID)
1075 {
1076 ScenePresence presence;
1077 if (m_scene.TryGetScenePresence(agentID, out presence))
1078 {
1079 if (!m_linkedAvatars.Contains(presence))
1080 {
1081 m_linkedAvatars.Add(presence);
1082 }
1083 }
1084 }
1085
1086 /// <summary>
1087 /// Delete the avatar from this linkset (avatar is unsat).
1088 /// </summary>
1089 /// <param name="agentID"></param>
1090 public void DeleteAvatar(UUID agentID)
1091 {
1092 ScenePresence presence;
1093 if (m_scene.TryGetScenePresence(agentID, out presence))
1094 {
1095 if (m_linkedAvatars.Contains(presence))
1096 {
1097 m_linkedAvatars.Remove(presence);
1098 }
1099 }
1100 }
1101
1102 /// <summary>
1103 /// Returns the list of linked presences (avatars sat on this group)
1104 /// </summary>
1105 /// <param name="agentID"></param>
1106 public List<ScenePresence> GetLinkedAvatars()
1107 {
1108 return m_linkedAvatars;
1109 }
1110
1111 /// <summary>
1112 /// Attach this scene object to the given avatar.
1113 /// </summary>
1114 /// <param name="agentID"></param>
1115 /// <param name="attachmentpoint"></param>
1116 /// <param name="AttachOffset"></param>
1117 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1118 {
1119 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1120 if (avatar != null)
1121 {
1122 // don't attach attachments to child agents
1123 if (avatar.IsChildAgent) return;
1124
1125// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1126
1127 DetachFromBackup();
1128
1129 // Remove from database and parcel prim count
1130 m_scene.DeleteFromStorage(UUID);
1131 m_scene.EventManager.TriggerParcelPrimCountTainted();
1132
1133 m_rootPart.AttachedAvatar = agentID;
1134
1135 //Anakin Lohner bug #3839
1136 lock (m_parts)
1137 {
1138 foreach (SceneObjectPart p in m_parts.GetArray())
1139 {
1140 p.AttachedAvatar = agentID;
1141 }
1142 }
1143
1144 if (m_rootPart.PhysActor != null)
1145 {
1146 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1147 m_rootPart.PhysActor = null;
1148 }
1149
1150 AbsolutePosition = AttachOffset;
1151 m_rootPart.AttachedPos = AttachOffset;
1152 m_rootPart.IsAttachment = true;
1153
1154 m_rootPart.SetParentLocalId(avatar.LocalId);
1155 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1156
1157 avatar.AddAttachment(this);
1158
1159 if (!silent)
1160 {
1161 // Killing it here will cause the client to deselect it
1162 // It then reappears on the avatar, deselected
1163 // through the full update below
1164 //
1165 if (IsSelected)
1166 {
1167 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1168 }
1169
1170 IsSelected = false; // fudge....
1171 ScheduleGroupForFullUpdate();
1172 }
1173 }
1174 else
1175 {
1176 m_log.WarnFormat(
1177 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1178 UUID, agentID, Scene.RegionInfo.RegionName);
1179 }
1180 }
1181
922 public byte GetAttachmentPoint() 1182 public byte GetAttachmentPoint()
923 { 1183 {
924 return m_rootPart.Shape.State; 1184 return m_rootPart.Shape.State;
@@ -1045,7 +1305,10 @@ namespace OpenSim.Region.Framework.Scenes
1045 public void AddPart(SceneObjectPart part) 1305 public void AddPart(SceneObjectPart part)
1046 { 1306 {
1047 part.SetParent(this); 1307 part.SetParent(this);
1048 part.LinkNum = m_parts.Add(part.UUID, part); 1308 m_parts.Add(part.UUID, part);
1309
1310 part.LinkNum = m_parts.Count;
1311
1049 if (part.LinkNum == 2 && RootPart != null) 1312 if (part.LinkNum == 2 && RootPart != null)
1050 RootPart.LinkNum = 1; 1313 RootPart.LinkNum = 1;
1051 } 1314 }
@@ -1129,7 +1392,7 @@ namespace OpenSim.Region.Framework.Scenes
1129 1392
1130 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1393 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1131 { 1394 {
1132 part.StoreUndoState(); 1395 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1133 part.OnGrab(offsetPos, remoteClient); 1396 part.OnGrab(offsetPos, remoteClient);
1134 } 1397 }
1135 1398
@@ -1149,6 +1412,11 @@ namespace OpenSim.Region.Framework.Scenes
1149 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1412 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1150 public void DeleteGroupFromScene(bool silent) 1413 public void DeleteGroupFromScene(bool silent)
1151 { 1414 {
1415 // We need to keep track of this state in case this group is still queued for backup.
1416 m_isDeleted = true;
1417
1418 DetachFromBackup();
1419
1152 SceneObjectPart[] parts = m_parts.GetArray(); 1420 SceneObjectPart[] parts = m_parts.GetArray();
1153 for (int i = 0; i < parts.Length; i++) 1421 for (int i = 0; i < parts.Length; i++)
1154 { 1422 {
@@ -1160,13 +1428,11 @@ namespace OpenSim.Region.Framework.Scenes
1160 avatar.StandUp(); 1428 avatar.StandUp();
1161 1429
1162 if (!silent) 1430 if (!silent)
1163 {
1164 part.UpdateFlag = 0; 1431 part.UpdateFlag = 0;
1165 if (part == m_rootPart)
1166 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1167 }
1168 }); 1432 });
1169 } 1433 }
1434
1435
1170 } 1436 }
1171 1437
1172 public void AddScriptLPS(int count) 1438 public void AddScriptLPS(int count)
@@ -1263,7 +1529,12 @@ namespace OpenSim.Region.Framework.Scenes
1263 1529
1264 public void SetOwnerId(UUID userId) 1530 public void SetOwnerId(UUID userId)
1265 { 1531 {
1266 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1532 ForEachPart(delegate(SceneObjectPart part)
1533 {
1534
1535 part.OwnerID = userId;
1536
1537 });
1267 } 1538 }
1268 1539
1269 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1540 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1295,11 +1566,17 @@ namespace OpenSim.Region.Framework.Scenes
1295 return; 1566 return;
1296 } 1567 }
1297 1568
1569 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1570 return;
1571
1298 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1572 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1299 // any exception propogate upwards. 1573 // any exception propogate upwards.
1300 try 1574 try
1301 { 1575 {
1302 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1576 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1577 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1578 m_scene.LoadingPrims) // Land may not be valid yet
1579
1303 { 1580 {
1304 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1581 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1305 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1582 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1326,6 +1603,7 @@ namespace OpenSim.Region.Framework.Scenes
1326 } 1603 }
1327 } 1604 }
1328 } 1605 }
1606
1329 } 1607 }
1330 1608
1331 if (HasGroupChanged) 1609 if (HasGroupChanged)
@@ -1333,6 +1611,20 @@ namespace OpenSim.Region.Framework.Scenes
1333 // don't backup while it's selected or you're asking for changes mid stream. 1611 // don't backup while it's selected or you're asking for changes mid stream.
1334 if (isTimeToPersist() || forcedBackup) 1612 if (isTimeToPersist() || forcedBackup)
1335 { 1613 {
1614 if (m_rootPart.PhysActor != null &&
1615 (!m_rootPart.PhysActor.IsPhysical))
1616 {
1617 // Possible ghost prim
1618 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1619 {
1620 foreach (SceneObjectPart part in m_parts.GetArray())
1621 {
1622 // Re-set physics actor positions and
1623 // orientations
1624 part.GroupPosition = m_rootPart.GroupPosition;
1625 }
1626 }
1627 }
1336// m_log.DebugFormat( 1628// m_log.DebugFormat(
1337// "[SCENE]: Storing {0}, {1} in {2}", 1629// "[SCENE]: Storing {0}, {1} in {2}",
1338// Name, UUID, m_scene.RegionInfo.RegionName); 1630// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1396,81 +1688,90 @@ namespace OpenSim.Region.Framework.Scenes
1396 /// <returns></returns> 1688 /// <returns></returns>
1397 public SceneObjectGroup Copy(bool userExposed) 1689 public SceneObjectGroup Copy(bool userExposed)
1398 { 1690 {
1399 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1691 SceneObjectGroup dupe;
1400 dupe.m_isBackedUp = false; 1692 try
1401 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1693 {
1402 1694 m_dupeInProgress = true;
1403 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1695 dupe = (SceneObjectGroup)MemberwiseClone();
1404 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1696 dupe.m_isBackedUp = false;
1405 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1697 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1406 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1407 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1408 // then restore it's attachment state
1409
1410 // This is only necessary when userExposed is false!
1411 1698
1412 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1699 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1413 1700 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1414 if (!userExposed) 1701 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1415 dupe.RootPart.IsAttachment = true; 1702 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1703 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1704 // then restore it's attachment state
1416 1705
1417 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1706 // This is only necessary when userExposed is false!
1418 1707
1419 if (!userExposed) 1708 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1420 {
1421 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1422 }
1423 1709
1424 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1710 if (!userExposed)
1425 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1711 dupe.RootPart.IsAttachment = true;
1426 1712
1427 if (userExposed) 1713 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1428 dupe.m_rootPart.TrimPermissions();
1429 1714
1430 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1715 if (!userExposed)
1431
1432 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1433 { 1716 {
1434 return p1.LinkNum.CompareTo(p2.LinkNum); 1717 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1435 } 1718 }
1436 );
1437 1719
1438 foreach (SceneObjectPart part in partList) 1720 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1439 { 1721 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1440 if (part.UUID != m_rootPart.UUID) 1722
1723 if (userExposed)
1724 dupe.m_rootPart.TrimPermissions();
1725
1726 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1727
1728 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1729 {
1730 return p1.LinkNum.CompareTo(p2.LinkNum);
1731 }
1732 );
1733
1734 foreach (SceneObjectPart part in partList)
1441 { 1735 {
1442 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1736 if (part.UUID != m_rootPart.UUID)
1443 newPart.LinkNum = part.LinkNum; 1737 {
1444 } 1738 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1445 1739
1446 // Need to duplicate the physics actor as well 1740 newPart.LinkNum = part.LinkNum;
1447 if (part.PhysActor != null && userExposed) 1741 }
1742
1743 // Need to duplicate the physics actor as well
1744 if (part.PhysActor != null && userExposed)
1745 {
1746 PrimitiveBaseShape pbs = part.Shape;
1747
1748 part.PhysActor
1749 = m_scene.PhysicsScene.AddPrimShape(
1750 string.Format("{0}/{1}", part.Name, part.UUID),
1751 pbs,
1752 part.AbsolutePosition,
1753 part.Scale,
1754 part.RotationOffset,
1755 part.PhysActor.IsPhysical);
1756 part.PhysActor.SetMaterial((int)part.Material);
1757
1758 part.PhysActor.LocalID = part.LocalId;
1759 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1760 }
1761 }
1762 if (userExposed)
1448 { 1763 {
1449 PrimitiveBaseShape pbs = part.Shape; 1764 dupe.UpdateParentIDs();
1450 1765 dupe.HasGroupChanged = true;
1451 part.PhysActor 1766 dupe.AttachToBackup();
1452 = m_scene.PhysicsScene.AddPrimShape( 1767
1453 string.Format("{0}/{1}", part.Name, part.UUID), 1768 ScheduleGroupForFullUpdate();
1454 pbs,
1455 part.AbsolutePosition,
1456 part.Scale,
1457 part.RotationOffset,
1458 part.PhysActor.IsPhysical);
1459
1460 part.PhysActor.LocalID = part.LocalId;
1461 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1462 } 1769 }
1463 } 1770 }
1464 1771 finally
1465 if (userExposed)
1466 { 1772 {
1467 dupe.UpdateParentIDs(); 1773 m_dupeInProgress = false;
1468 dupe.HasGroupChanged = true;
1469 dupe.AttachToBackup();
1470
1471 ScheduleGroupForFullUpdate();
1472 } 1774 }
1473
1474 return dupe; 1775 return dupe;
1475 } 1776 }
1476 1777
@@ -1615,6 +1916,7 @@ namespace OpenSim.Region.Framework.Scenes
1615 return Vector3.Zero; 1916 return Vector3.Zero;
1616 } 1917 }
1617 1918
1919 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1618 public void moveToTarget(Vector3 target, float tau) 1920 public void moveToTarget(Vector3 target, float tau)
1619 { 1921 {
1620 SceneObjectPart rootpart = m_rootPart; 1922 SceneObjectPart rootpart = m_rootPart;
@@ -1654,20 +1956,55 @@ namespace OpenSim.Region.Framework.Scenes
1654 SceneObjectPart rootpart = m_rootPart; 1956 SceneObjectPart rootpart = m_rootPart;
1655 if (rootpart != null) 1957 if (rootpart != null)
1656 { 1958 {
1657 if (rootpart.PhysActor != null) 1959 if (IsAttachment)
1960 {
1961 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1962 if (avatar != null) avatar.StopMoveToPosition();
1963 }
1964 else
1658 { 1965 {
1659 rootpart.PhysActor.PIDActive = false; 1966 if (rootpart.PhysActor != null)
1967 {
1968 rootpart.PhysActor.PIDActive = false;
1969 }
1660 } 1970 }
1661 } 1971 }
1662 } 1972 }
1663 1973
1974 public void rotLookAt(Quaternion target, float strength, float damping)
1975 {
1976 SceneObjectPart rootpart = m_rootPart;
1977 if (rootpart != null)
1978 {
1979 if (IsAttachment)
1980 {
1981 /*
1982 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1983 if (avatar != null)
1984 {
1985 Rotate the Av?
1986 } */
1987 }
1988 else
1989 {
1990 if (rootpart.PhysActor != null)
1991 { // APID must be implemented in your physics system for this to function.
1992 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1993 rootpart.PhysActor.APIDStrength = strength;
1994 rootpart.PhysActor.APIDDamping = damping;
1995 rootpart.PhysActor.APIDActive = true;
1996 }
1997 }
1998 }
1999 }
2000
1664 public void stopLookAt() 2001 public void stopLookAt()
1665 { 2002 {
1666 SceneObjectPart rootpart = m_rootPart; 2003 SceneObjectPart rootpart = m_rootPart;
1667 if (rootpart != null) 2004 if (rootpart != null)
1668 { 2005 {
1669 if (rootpart.PhysActor != null) 2006 if (rootpart.PhysActor != null)
1670 { 2007 { // APID must be implemented in your physics system for this to function.
1671 rootpart.PhysActor.APIDActive = false; 2008 rootpart.PhysActor.APIDActive = false;
1672 } 2009 }
1673 } 2010 }
@@ -1733,6 +2070,8 @@ namespace OpenSim.Region.Framework.Scenes
1733 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2070 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1734 { 2071 {
1735 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2072 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2073 newPart.SetParent(this);
2074
1736 AddPart(newPart); 2075 AddPart(newPart);
1737 2076
1738 SetPartAsNonRoot(newPart); 2077 SetPartAsNonRoot(newPart);
@@ -1879,11 +2218,11 @@ namespace OpenSim.Region.Framework.Scenes
1879 /// Immediately send a full update for this scene object. 2218 /// Immediately send a full update for this scene object.
1880 /// </summary> 2219 /// </summary>
1881 public void SendGroupFullUpdate() 2220 public void SendGroupFullUpdate()
1882 { 2221 {
1883 if (IsDeleted) 2222 if (IsDeleted)
1884 return; 2223 return;
1885 2224
1886// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2225// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1887 2226
1888 RootPart.SendFullUpdateToAllClients(); 2227 RootPart.SendFullUpdateToAllClients();
1889 2228
@@ -2072,12 +2411,15 @@ namespace OpenSim.Region.Framework.Scenes
2072 part.LinkNum += objectGroup.PrimCount; 2411 part.LinkNum += objectGroup.PrimCount;
2073 } 2412 }
2074 } 2413 }
2414 }
2075 2415
2076 linkPart.LinkNum = 2; 2416 linkPart.LinkNum = 2;
2077 2417
2078 linkPart.SetParent(this); 2418 linkPart.SetParent(this);
2079 linkPart.CreateSelected = true; 2419 linkPart.CreateSelected = true;
2080 2420
2421 lock (m_parts.SyncRoot)
2422 {
2081 //if (linkPart.PhysActor != null) 2423 //if (linkPart.PhysActor != null)
2082 //{ 2424 //{
2083 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2425 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2235,6 +2577,8 @@ namespace OpenSim.Region.Framework.Scenes
2235 /// <param name="objectGroup"></param> 2577 /// <param name="objectGroup"></param>
2236 public virtual void DetachFromBackup() 2578 public virtual void DetachFromBackup()
2237 { 2579 {
2580 m_scene.SceneGraph.FireDetachFromBackup(this);
2581
2238 if (m_isBackedUp) 2582 if (m_isBackedUp)
2239 m_scene.EventManager.OnBackup -= ProcessBackup; 2583 m_scene.EventManager.OnBackup -= ProcessBackup;
2240 2584
@@ -2253,7 +2597,8 @@ namespace OpenSim.Region.Framework.Scenes
2253 2597
2254 axPos *= parentRot; 2598 axPos *= parentRot;
2255 part.OffsetPosition = axPos; 2599 part.OffsetPosition = axPos;
2256 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2600 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2601 part.GroupPosition = newPos;
2257 part.OffsetPosition = Vector3.Zero; 2602 part.OffsetPosition = Vector3.Zero;
2258 part.RotationOffset = worldRot; 2603 part.RotationOffset = worldRot;
2259 2604
@@ -2264,7 +2609,7 @@ namespace OpenSim.Region.Framework.Scenes
2264 2609
2265 part.LinkNum = linkNum; 2610 part.LinkNum = linkNum;
2266 2611
2267 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2612 part.OffsetPosition = newPos - AbsolutePosition;
2268 2613
2269 Quaternion rootRotation = m_rootPart.RotationOffset; 2614 Quaternion rootRotation = m_rootPart.RotationOffset;
2270 2615
@@ -2274,7 +2619,7 @@ namespace OpenSim.Region.Framework.Scenes
2274 2619
2275 parentRot = m_rootPart.RotationOffset; 2620 parentRot = m_rootPart.RotationOffset;
2276 oldRot = part.RotationOffset; 2621 oldRot = part.RotationOffset;
2277 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2622 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2278 part.RotationOffset = newRot; 2623 part.RotationOffset = newRot;
2279 } 2624 }
2280 2625
@@ -2525,8 +2870,12 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 2870 }
2526 } 2871 }
2527 2872
2873 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2528 for (int i = 0; i < parts.Length; i++) 2874 for (int i = 0; i < parts.Length; i++)
2529 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2875 {
2876 if (parts[i] != RootPart)
2877 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2878 }
2530 } 2879 }
2531 } 2880 }
2532 2881
@@ -2539,6 +2888,17 @@ namespace OpenSim.Region.Framework.Scenes
2539 } 2888 }
2540 } 2889 }
2541 2890
2891
2892
2893 /// <summary>
2894 /// Gets the number of parts
2895 /// </summary>
2896 /// <returns></returns>
2897 public int GetPartCount()
2898 {
2899 return Parts.Count();
2900 }
2901
2542 /// <summary> 2902 /// <summary>
2543 /// Update the texture entry for this part 2903 /// Update the texture entry for this part
2544 /// </summary> 2904 /// </summary>
@@ -2600,11 +2960,9 @@ namespace OpenSim.Region.Framework.Scenes
2600 scale.Y = m_scene.m_maxNonphys; 2960 scale.Y = m_scene.m_maxNonphys;
2601 if (scale.Z > m_scene.m_maxNonphys) 2961 if (scale.Z > m_scene.m_maxNonphys)
2602 scale.Z = m_scene.m_maxNonphys; 2962 scale.Z = m_scene.m_maxNonphys;
2603
2604 SceneObjectPart part = GetChildPart(localID); 2963 SceneObjectPart part = GetChildPart(localID);
2605 if (part != null) 2964 if (part != null)
2606 { 2965 {
2607 part.Resize(scale);
2608 if (part.PhysActor != null) 2966 if (part.PhysActor != null)
2609 { 2967 {
2610 if (part.PhysActor.IsPhysical) 2968 if (part.PhysActor.IsPhysical)
@@ -2619,7 +2977,7 @@ namespace OpenSim.Region.Framework.Scenes
2619 part.PhysActor.Size = scale; 2977 part.PhysActor.Size = scale;
2620 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2978 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2621 } 2979 }
2622 //if (part.UUID != m_rootPart.UUID) 2980 part.Resize(scale);
2623 2981
2624 HasGroupChanged = true; 2982 HasGroupChanged = true;
2625 part.TriggerScriptChangedEvent(Changed.SCALE); 2983 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2642,7 +3000,6 @@ namespace OpenSim.Region.Framework.Scenes
2642 SceneObjectPart part = GetChildPart(localID); 3000 SceneObjectPart part = GetChildPart(localID);
2643 if (part != null) 3001 if (part != null)
2644 { 3002 {
2645 part.IgnoreUndoUpdate = true;
2646 if (scale.X > m_scene.m_maxNonphys) 3003 if (scale.X > m_scene.m_maxNonphys)
2647 scale.X = m_scene.m_maxNonphys; 3004 scale.X = m_scene.m_maxNonphys;
2648 if (scale.Y > m_scene.m_maxNonphys) 3005 if (scale.Y > m_scene.m_maxNonphys)
@@ -2679,7 +3036,7 @@ namespace OpenSim.Region.Framework.Scenes
2679 3036
2680 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3037 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2681 { 3038 {
2682 if (oldSize.X * x > m_scene.m_maxPhys) 3039 if (oldSize.X*x > m_scene.m_maxPhys)
2683 { 3040 {
2684 f = m_scene.m_maxPhys / oldSize.X; 3041 f = m_scene.m_maxPhys / oldSize.X;
2685 a = f / x; 3042 a = f / x;
@@ -2687,7 +3044,7 @@ namespace OpenSim.Region.Framework.Scenes
2687 y *= a; 3044 y *= a;
2688 z *= a; 3045 z *= a;
2689 } 3046 }
2690 if (oldSize.Y * y > m_scene.m_maxPhys) 3047 if (oldSize.Y*y > m_scene.m_maxPhys)
2691 { 3048 {
2692 f = m_scene.m_maxPhys / oldSize.Y; 3049 f = m_scene.m_maxPhys / oldSize.Y;
2693 a = f / y; 3050 a = f / y;
@@ -2695,7 +3052,7 @@ namespace OpenSim.Region.Framework.Scenes
2695 y *= a; 3052 y *= a;
2696 z *= a; 3053 z *= a;
2697 } 3054 }
2698 if (oldSize.Z * z > m_scene.m_maxPhys) 3055 if (oldSize.Z*z > m_scene.m_maxPhys)
2699 { 3056 {
2700 f = m_scene.m_maxPhys / oldSize.Z; 3057 f = m_scene.m_maxPhys / oldSize.Z;
2701 a = f / z; 3058 a = f / z;
@@ -2706,7 +3063,7 @@ namespace OpenSim.Region.Framework.Scenes
2706 } 3063 }
2707 else 3064 else
2708 { 3065 {
2709 if (oldSize.X * x > m_scene.m_maxNonphys) 3066 if (oldSize.X*x > m_scene.m_maxNonphys)
2710 { 3067 {
2711 f = m_scene.m_maxNonphys / oldSize.X; 3068 f = m_scene.m_maxNonphys / oldSize.X;
2712 a = f / x; 3069 a = f / x;
@@ -2714,7 +3071,7 @@ namespace OpenSim.Region.Framework.Scenes
2714 y *= a; 3071 y *= a;
2715 z *= a; 3072 z *= a;
2716 } 3073 }
2717 if (oldSize.Y * y > m_scene.m_maxNonphys) 3074 if (oldSize.Y*y > m_scene.m_maxNonphys)
2718 { 3075 {
2719 f = m_scene.m_maxNonphys / oldSize.Y; 3076 f = m_scene.m_maxNonphys / oldSize.Y;
2720 a = f / y; 3077 a = f / y;
@@ -2722,7 +3079,7 @@ namespace OpenSim.Region.Framework.Scenes
2722 y *= a; 3079 y *= a;
2723 z *= a; 3080 z *= a;
2724 } 3081 }
2725 if (oldSize.Z * z > m_scene.m_maxNonphys) 3082 if (oldSize.Z*z > m_scene.m_maxNonphys)
2726 { 3083 {
2727 f = m_scene.m_maxNonphys / oldSize.Z; 3084 f = m_scene.m_maxNonphys / oldSize.Z;
2728 a = f / z; 3085 a = f / z;
@@ -2732,7 +3089,6 @@ namespace OpenSim.Region.Framework.Scenes
2732 } 3089 }
2733 } 3090 }
2734 obPart.IgnoreUndoUpdate = false; 3091 obPart.IgnoreUndoUpdate = false;
2735 obPart.StoreUndoState();
2736 } 3092 }
2737 } 3093 }
2738 } 3094 }
@@ -2740,8 +3096,13 @@ namespace OpenSim.Region.Framework.Scenes
2740 Vector3 prevScale = part.Scale; 3096 Vector3 prevScale = part.Scale;
2741 prevScale.X *= x; 3097 prevScale.X *= x;
2742 prevScale.Y *= y; 3098 prevScale.Y *= y;
2743 prevScale.Z *= z; 3099 prevScale.Z *= z;;
3100
3101 part.IgnoreUndoUpdate = false;
3102 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3103 part.IgnoreUndoUpdate = true;
2744 part.Resize(prevScale); 3104 part.Resize(prevScale);
3105 part.IgnoreUndoUpdate = false;
2745 3106
2746 parts = m_parts.GetArray(); 3107 parts = m_parts.GetArray();
2747 for (int i = 0; i < parts.Length; i++) 3108 for (int i = 0; i < parts.Length; i++)
@@ -2750,19 +3111,26 @@ namespace OpenSim.Region.Framework.Scenes
2750 obPart.IgnoreUndoUpdate = true; 3111 obPart.IgnoreUndoUpdate = true;
2751 if (obPart.UUID != m_rootPart.UUID) 3112 if (obPart.UUID != m_rootPart.UUID)
2752 { 3113 {
2753 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3114 if (obPart.UUID != m_rootPart.UUID)
2754 currentpos.X *= x; 3115 {
2755 currentpos.Y *= y; 3116 obPart.IgnoreUndoUpdate = false;
2756 currentpos.Z *= z; 3117 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2757 Vector3 newSize = new Vector3(obPart.Scale); 3118 obPart.IgnoreUndoUpdate = true;
2758 newSize.X *= x; 3119
2759 newSize.Y *= y; 3120 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2760 newSize.Z *= z; 3121 currentpos.X *= x;
2761 obPart.Resize(newSize); 3122 currentpos.Y *= y;
2762 obPart.UpdateOffSet(currentpos); 3123 currentpos.Z *= z;
3124 Vector3 newSize = new Vector3(obPart.Scale);
3125 newSize.X *= x;
3126 newSize.Y *= y;
3127 newSize.Z *= z;
3128 obPart.Resize(newSize);
3129 obPart.UpdateOffSet(currentpos);
3130 }
3131 obPart.IgnoreUndoUpdate = false;
2763 } 3132 }
2764 obPart.IgnoreUndoUpdate = false; 3133 obPart.IgnoreUndoUpdate = false;
2765 obPart.StoreUndoState();
2766 } 3134 }
2767 3135
2768 if (part.PhysActor != null) 3136 if (part.PhysActor != null)
@@ -2772,7 +3140,6 @@ namespace OpenSim.Region.Framework.Scenes
2772 } 3140 }
2773 3141
2774 part.IgnoreUndoUpdate = false; 3142 part.IgnoreUndoUpdate = false;
2775 part.StoreUndoState();
2776 HasGroupChanged = true; 3143 HasGroupChanged = true;
2777 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3144 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2778 ScheduleGroupForTerseUpdate(); 3145 ScheduleGroupForTerseUpdate();
@@ -2789,14 +3156,11 @@ namespace OpenSim.Region.Framework.Scenes
2789 /// <param name="pos"></param> 3156 /// <param name="pos"></param>
2790 public void UpdateGroupPosition(Vector3 pos) 3157 public void UpdateGroupPosition(Vector3 pos)
2791 { 3158 {
2792 SceneObjectPart[] parts = m_parts.GetArray();
2793 for (int i = 0; i < parts.Length; i++)
2794 parts[i].StoreUndoState();
2795
2796 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3159 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2797 { 3160 {
2798 if (IsAttachment) 3161 if (IsAttachment)
2799 { 3162 {
3163 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2800 m_rootPart.AttachedPos = pos; 3164 m_rootPart.AttachedPos = pos;
2801 } 3165 }
2802 if (RootPart.GetStatusSandbox()) 3166 if (RootPart.GetStatusSandbox())
@@ -2830,7 +3194,7 @@ namespace OpenSim.Region.Framework.Scenes
2830 3194
2831 SceneObjectPart[] parts = m_parts.GetArray(); 3195 SceneObjectPart[] parts = m_parts.GetArray();
2832 for (int i = 0; i < parts.Length; i++) 3196 for (int i = 0; i < parts.Length; i++)
2833 parts[i].StoreUndoState(); 3197 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2834 3198
2835 if (part != null) 3199 if (part != null)
2836 { 3200 {
@@ -2855,7 +3219,7 @@ namespace OpenSim.Region.Framework.Scenes
2855 { 3219 {
2856 SceneObjectPart[] parts = m_parts.GetArray(); 3220 SceneObjectPart[] parts = m_parts.GetArray();
2857 for (int i = 0; i < parts.Length; i++) 3221 for (int i = 0; i < parts.Length; i++)
2858 parts[i].StoreUndoState(); 3222 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2859 3223
2860 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3224 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2861 Vector3 oldPos = 3225 Vector3 oldPos =
@@ -2876,10 +3240,27 @@ namespace OpenSim.Region.Framework.Scenes
2876 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3240 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2877 } 3241 }
2878 3242
2879 AbsolutePosition = newPos; 3243 //We have to set undoing here because otherwise an undo state will be saved
3244 if (!m_rootPart.Undoing)
3245 {
3246 m_rootPart.Undoing = true;
3247 AbsolutePosition = newPos;
3248 m_rootPart.Undoing = false;
3249 }
3250 else
3251 {
3252 AbsolutePosition = newPos;
3253 }
2880 3254
2881 HasGroupChanged = true; 3255 HasGroupChanged = true;
2882 ScheduleGroupForTerseUpdate(); 3256 if (m_rootPart.Undoing)
3257 {
3258 ScheduleGroupForFullUpdate();
3259 }
3260 else
3261 {
3262 ScheduleGroupForTerseUpdate();
3263 }
2883 } 3264 }
2884 3265
2885 public void OffsetForNewRegion(Vector3 offset) 3266 public void OffsetForNewRegion(Vector3 offset)
@@ -2899,7 +3280,7 @@ namespace OpenSim.Region.Framework.Scenes
2899 { 3280 {
2900 SceneObjectPart[] parts = m_parts.GetArray(); 3281 SceneObjectPart[] parts = m_parts.GetArray();
2901 for (int i = 0; i < parts.Length; i++) 3282 for (int i = 0; i < parts.Length; i++)
2902 parts[i].StoreUndoState(); 3283 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2903 3284
2904 m_rootPart.UpdateRotation(rot); 3285 m_rootPart.UpdateRotation(rot);
2905 3286
@@ -2923,7 +3304,7 @@ namespace OpenSim.Region.Framework.Scenes
2923 { 3304 {
2924 SceneObjectPart[] parts = m_parts.GetArray(); 3305 SceneObjectPart[] parts = m_parts.GetArray();
2925 for (int i = 0; i < parts.Length; i++) 3306 for (int i = 0; i < parts.Length; i++)
2926 parts[i].StoreUndoState(); 3307 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2927 3308
2928 m_rootPart.UpdateRotation(rot); 3309 m_rootPart.UpdateRotation(rot);
2929 3310
@@ -2948,10 +3329,9 @@ namespace OpenSim.Region.Framework.Scenes
2948 public void UpdateSingleRotation(Quaternion rot, uint localID) 3329 public void UpdateSingleRotation(Quaternion rot, uint localID)
2949 { 3330 {
2950 SceneObjectPart part = GetChildPart(localID); 3331 SceneObjectPart part = GetChildPart(localID);
2951
2952 SceneObjectPart[] parts = m_parts.GetArray(); 3332 SceneObjectPart[] parts = m_parts.GetArray();
2953 for (int i = 0; i < parts.Length; i++) 3333 for (int i = 0; i < parts.Length; i++)
2954 parts[i].StoreUndoState(); 3334 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2955 3335
2956 if (part != null) 3336 if (part != null)
2957 { 3337 {
@@ -2979,15 +3359,24 @@ namespace OpenSim.Region.Framework.Scenes
2979 if (part.UUID == m_rootPart.UUID) 3359 if (part.UUID == m_rootPart.UUID)
2980 { 3360 {
2981 UpdateRootRotation(rot); 3361 UpdateRootRotation(rot);
2982 AbsolutePosition = pos; 3362 if (!m_rootPart.Undoing)
3363 {
3364 m_rootPart.Undoing = true;
3365 AbsolutePosition = pos;
3366 m_rootPart.Undoing = false;
3367 }
3368 else
3369 {
3370 AbsolutePosition = pos;
3371 }
2983 } 3372 }
2984 else 3373 else
2985 { 3374 {
3375 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2986 part.IgnoreUndoUpdate = true; 3376 part.IgnoreUndoUpdate = true;
2987 part.UpdateRotation(rot); 3377 part.UpdateRotation(rot);
2988 part.OffsetPosition = pos; 3378 part.OffsetPosition = pos;
2989 part.IgnoreUndoUpdate = false; 3379 part.IgnoreUndoUpdate = false;
2990 part.StoreUndoState();
2991 } 3380 }
2992 } 3381 }
2993 } 3382 }
@@ -3001,8 +3390,16 @@ namespace OpenSim.Region.Framework.Scenes
3001 Quaternion axRot = rot; 3390 Quaternion axRot = rot;
3002 Quaternion oldParentRot = m_rootPart.RotationOffset; 3391 Quaternion oldParentRot = m_rootPart.RotationOffset;
3003 3392
3004 m_rootPart.StoreUndoState(); 3393 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3005 m_rootPart.UpdateRotation(rot); 3394 bool cancelUndo = false;
3395 if (!m_rootPart.Undoing)
3396 {
3397 m_rootPart.Undoing = true;
3398 cancelUndo = true;
3399 }
3400
3401 //Don't use UpdateRotation because it schedules an update prematurely
3402 m_rootPart.RotationOffset = rot;
3006 if (m_rootPart.PhysActor != null) 3403 if (m_rootPart.PhysActor != null)
3007 { 3404 {
3008 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3405 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -3017,28 +3414,22 @@ namespace OpenSim.Region.Framework.Scenes
3017 { 3414 {
3018 prim.IgnoreUndoUpdate = true; 3415 prim.IgnoreUndoUpdate = true;
3019 Vector3 axPos = prim.OffsetPosition; 3416 Vector3 axPos = prim.OffsetPosition;
3417
3020 axPos *= oldParentRot; 3418 axPos *= oldParentRot;
3021 axPos *= Quaternion.Inverse(axRot); 3419 axPos *= Quaternion.Inverse(axRot);
3022 prim.OffsetPosition = axPos; 3420 prim.OffsetPosition = axPos;
3023 Quaternion primsRot = prim.RotationOffset; 3421
3024 Quaternion newRot = primsRot * oldParentRot; 3422 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
3025 newRot *= Quaternion.Inverse(axRot); 3423
3026 prim.RotationOffset = newRot; 3424 prim.IgnoreUndoUpdate = false;
3027 prim.ScheduleTerseUpdate();
3028 } 3425 }
3029 } 3426 }
3030 3427 if (cancelUndo == true)
3031 for (int i = 0; i < parts.Length; i++)
3032 { 3428 {
3033 SceneObjectPart childpart = parts[i]; 3429 m_rootPart.Undoing = false;
3034 if (childpart != m_rootPart)
3035 {
3036 childpart.IgnoreUndoUpdate = false;
3037 childpart.StoreUndoState();
3038 }
3039 } 3430 }
3040 3431 HasGroupChanged = true;
3041 m_rootPart.ScheduleTerseUpdate(); 3432 ScheduleGroupForFullUpdate();
3042 } 3433 }
3043 3434
3044 #endregion 3435 #endregion
@@ -3261,7 +3652,6 @@ namespace OpenSim.Region.Framework.Scenes
3261 public float GetMass() 3652 public float GetMass()
3262 { 3653 {
3263 float retmass = 0f; 3654 float retmass = 0f;
3264
3265 SceneObjectPart[] parts = m_parts.GetArray(); 3655 SceneObjectPart[] parts = m_parts.GetArray();
3266 for (int i = 0; i < parts.Length; i++) 3656 for (int i = 0; i < parts.Length; i++)
3267 retmass += parts[i].GetMass(); 3657 retmass += parts[i].GetMass();
@@ -3377,6 +3767,14 @@ namespace OpenSim.Region.Framework.Scenes
3377 SetFromItemID(uuid); 3767 SetFromItemID(uuid);
3378 } 3768 }
3379 3769
3770 public void ResetOwnerChangeFlag()
3771 {
3772 ForEachPart(delegate(SceneObjectPart part)
3773 {
3774 part.ResetOwnerChangeFlag();
3775 });
3776 }
3777
3380 #endregion 3778 #endregion
3381 } 3779 }
3382} 3780}