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.cs664
1 files changed, 524 insertions, 140 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index f17fb28..304de67 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 //{
@@ -467,6 +561,7 @@ namespace OpenSim.Region.Framework.Scenes
467 /// </summary> 561 /// </summary>
468 public SceneObjectGroup() 562 public SceneObjectGroup()
469 { 563 {
564
470 } 565 }
471 566
472 /// <summary> 567 /// <summary>
@@ -483,7 +578,7 @@ namespace OpenSim.Region.Framework.Scenes
483 /// Constructor. This object is added to the scene later via AttachToScene() 578 /// Constructor. This object is added to the scene later via AttachToScene()
484 /// </summary> 579 /// </summary>
485 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 580 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
486 { 581 {
487 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 582 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
488 } 583 }
489 584
@@ -531,6 +626,9 @@ namespace OpenSim.Region.Framework.Scenes
531 /// </summary> 626 /// </summary>
532 public virtual void AttachToBackup() 627 public virtual void AttachToBackup()
533 { 628 {
629 if (IsAttachment) return;
630 m_scene.SceneGraph.FireAttachToBackup(this);
631
534 if (InSceneBackup) 632 if (InSceneBackup)
535 { 633 {
536 //m_log.DebugFormat( 634 //m_log.DebugFormat(
@@ -646,9 +744,9 @@ namespace OpenSim.Region.Framework.Scenes
646 result.normal = inter.normal; 744 result.normal = inter.normal;
647 result.distance = inter.distance; 745 result.distance = inter.distance;
648 } 746 }
747
649 } 748 }
650 } 749 }
651
652 return result; 750 return result;
653 } 751 }
654 752
@@ -668,17 +766,19 @@ namespace OpenSim.Region.Framework.Scenes
668 minZ = 8192f; 766 minZ = 8192f;
669 767
670 SceneObjectPart[] parts = m_parts.GetArray(); 768 SceneObjectPart[] parts = m_parts.GetArray();
671 for (int i = 0; i < parts.Length; i++) 769 foreach (SceneObjectPart part in parts)
672 { 770 {
673 SceneObjectPart part = parts[i];
674
675 Vector3 worldPos = part.GetWorldPosition(); 771 Vector3 worldPos = part.GetWorldPosition();
676 Vector3 offset = worldPos - AbsolutePosition; 772 Vector3 offset = worldPos - AbsolutePosition;
677 Quaternion worldRot; 773 Quaternion worldRot;
678 if (part.ParentID == 0) 774 if (part.ParentID == 0)
775 {
679 worldRot = part.RotationOffset; 776 worldRot = part.RotationOffset;
777 }
680 else 778 else
779 {
681 worldRot = part.GetWorldRotation(); 780 worldRot = part.GetWorldRotation();
781 }
682 782
683 Vector3 frontTopLeft; 783 Vector3 frontTopLeft;
684 Vector3 frontTopRight; 784 Vector3 frontTopRight;
@@ -690,6 +790,8 @@ namespace OpenSim.Region.Framework.Scenes
690 Vector3 backBottomLeft; 790 Vector3 backBottomLeft;
691 Vector3 backBottomRight; 791 Vector3 backBottomRight;
692 792
793 // Vector3[] corners = new Vector3[8];
794
693 Vector3 orig = Vector3.Zero; 795 Vector3 orig = Vector3.Zero;
694 796
695 frontTopLeft.X = orig.X - (part.Scale.X / 2); 797 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -724,6 +826,38 @@ namespace OpenSim.Region.Framework.Scenes
724 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 826 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
725 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 827 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
726 828
829
830
831 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
832 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
833 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
834 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
835 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
836 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
837 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
838 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
839
840 //for (int i = 0; i < 8; i++)
841 //{
842 // corners[i] = corners[i] * worldRot;
843 // corners[i] += offset;
844
845 // if (corners[i].X > maxX)
846 // maxX = corners[i].X;
847 // if (corners[i].X < minX)
848 // minX = corners[i].X;
849
850 // if (corners[i].Y > maxY)
851 // maxY = corners[i].Y;
852 // if (corners[i].Y < minY)
853 // minY = corners[i].Y;
854
855 // if (corners[i].Z > maxZ)
856 // maxZ = corners[i].Y;
857 // if (corners[i].Z < minZ)
858 // minZ = corners[i].Z;
859 //}
860
727 frontTopLeft = frontTopLeft * worldRot; 861 frontTopLeft = frontTopLeft * worldRot;
728 frontTopRight = frontTopRight * worldRot; 862 frontTopRight = frontTopRight * worldRot;
729 frontBottomLeft = frontBottomLeft * worldRot; 863 frontBottomLeft = frontBottomLeft * worldRot;
@@ -745,6 +879,15 @@ namespace OpenSim.Region.Framework.Scenes
745 backTopLeft += offset; 879 backTopLeft += offset;
746 backTopRight += offset; 880 backTopRight += offset;
747 881
882 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
883 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
884 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
885 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
886 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
887 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
888 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
889 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
890
748 if (frontTopRight.X > maxX) 891 if (frontTopRight.X > maxX)
749 maxX = frontTopRight.X; 892 maxX = frontTopRight.X;
750 if (frontTopLeft.X > maxX) 893 if (frontTopLeft.X > maxX)
@@ -890,15 +1033,20 @@ namespace OpenSim.Region.Framework.Scenes
890 1033
891 public void SaveScriptedState(XmlTextWriter writer) 1034 public void SaveScriptedState(XmlTextWriter writer)
892 { 1035 {
1036 SaveScriptedState(writer, false);
1037 }
1038
1039 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1040 {
893 XmlDocument doc = new XmlDocument(); 1041 XmlDocument doc = new XmlDocument();
894 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1042 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
895 1043
896 SceneObjectPart[] parts = m_parts.GetArray(); 1044 SceneObjectPart[] parts = m_parts.GetArray();
897 for (int i = 0; i < parts.Length; i++) 1045 for (int i = 0; i < parts.Length; i++)
898 { 1046 {
899 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1047 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
900 foreach (KeyValuePair<UUID, string> kvp in pstates) 1048 foreach (KeyValuePair<UUID, string> kvp in pstates)
901 states.Add(kvp.Key, kvp.Value); 1049 states[kvp.Key] = kvp.Value;
902 } 1050 }
903 1051
904 if (states.Count > 0) 1052 if (states.Count > 0)
@@ -917,6 +1065,118 @@ namespace OpenSim.Region.Framework.Scenes
917 } 1065 }
918 } 1066 }
919 1067
1068 /// <summary>
1069 /// Add the avatar to this linkset (avatar is sat).
1070 /// </summary>
1071 /// <param name="agentID"></param>
1072 public void AddAvatar(UUID agentID)
1073 {
1074 ScenePresence presence;
1075 if (m_scene.TryGetScenePresence(agentID, out presence))
1076 {
1077 if (!m_linkedAvatars.Contains(presence))
1078 {
1079 m_linkedAvatars.Add(presence);
1080 }
1081 }
1082 }
1083
1084 /// <summary>
1085 /// Delete the avatar from this linkset (avatar is unsat).
1086 /// </summary>
1087 /// <param name="agentID"></param>
1088 public void DeleteAvatar(UUID agentID)
1089 {
1090 ScenePresence presence;
1091 if (m_scene.TryGetScenePresence(agentID, out presence))
1092 {
1093 if (m_linkedAvatars.Contains(presence))
1094 {
1095 m_linkedAvatars.Remove(presence);
1096 }
1097 }
1098 }
1099
1100 /// <summary>
1101 /// Returns the list of linked presences (avatars sat on this group)
1102 /// </summary>
1103 /// <param name="agentID"></param>
1104 public List<ScenePresence> GetLinkedAvatars()
1105 {
1106 return m_linkedAvatars;
1107 }
1108
1109 /// <summary>
1110 /// Attach this scene object to the given avatar.
1111 /// </summary>
1112 /// <param name="agentID"></param>
1113 /// <param name="attachmentpoint"></param>
1114 /// <param name="AttachOffset"></param>
1115 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1116 {
1117 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1118 if (avatar != null)
1119 {
1120 // don't attach attachments to child agents
1121 if (avatar.IsChildAgent) return;
1122
1123// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1124
1125 DetachFromBackup();
1126
1127 // Remove from database and parcel prim count
1128 m_scene.DeleteFromStorage(UUID);
1129 m_scene.EventManager.TriggerParcelPrimCountTainted();
1130
1131 m_rootPart.AttachedAvatar = agentID;
1132
1133 //Anakin Lohner bug #3839
1134 lock (m_parts)
1135 {
1136 foreach (SceneObjectPart p in m_parts.GetArray())
1137 {
1138 p.AttachedAvatar = agentID;
1139 }
1140 }
1141
1142 if (m_rootPart.PhysActor != null)
1143 {
1144 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1145 m_rootPart.PhysActor = null;
1146 }
1147
1148 AbsolutePosition = AttachOffset;
1149 m_rootPart.AttachedPos = AttachOffset;
1150 m_rootPart.IsAttachment = true;
1151
1152 m_rootPart.SetParentLocalId(avatar.LocalId);
1153 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1154
1155 avatar.AddAttachment(this);
1156
1157 if (!silent)
1158 {
1159 // Killing it here will cause the client to deselect it
1160 // It then reappears on the avatar, deselected
1161 // through the full update below
1162 //
1163 if (IsSelected)
1164 {
1165 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1166 }
1167
1168 IsSelected = false; // fudge....
1169 ScheduleGroupForFullUpdate();
1170 }
1171 }
1172 else
1173 {
1174 m_log.WarnFormat(
1175 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1176 UUID, agentID, Scene.RegionInfo.RegionName);
1177 }
1178 }
1179
920 public byte GetAttachmentPoint() 1180 public byte GetAttachmentPoint()
921 { 1181 {
922 return m_rootPart.Shape.State; 1182 return m_rootPart.Shape.State;
@@ -1043,7 +1303,10 @@ namespace OpenSim.Region.Framework.Scenes
1043 public void AddPart(SceneObjectPart part) 1303 public void AddPart(SceneObjectPart part)
1044 { 1304 {
1045 part.SetParent(this); 1305 part.SetParent(this);
1046 part.LinkNum = m_parts.Add(part.UUID, part); 1306 m_parts.Add(part.UUID, part);
1307
1308 part.LinkNum = m_parts.Count;
1309
1047 if (part.LinkNum == 2 && RootPart != null) 1310 if (part.LinkNum == 2 && RootPart != null)
1048 RootPart.LinkNum = 1; 1311 RootPart.LinkNum = 1;
1049 } 1312 }
@@ -1127,7 +1390,7 @@ namespace OpenSim.Region.Framework.Scenes
1127 1390
1128 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1391 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1129 { 1392 {
1130 part.StoreUndoState(); 1393 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1131 part.OnGrab(offsetPos, remoteClient); 1394 part.OnGrab(offsetPos, remoteClient);
1132 } 1395 }
1133 1396
@@ -1147,6 +1410,11 @@ namespace OpenSim.Region.Framework.Scenes
1147 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1410 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1148 public void DeleteGroupFromScene(bool silent) 1411 public void DeleteGroupFromScene(bool silent)
1149 { 1412 {
1413 // We need to keep track of this state in case this group is still queued for backup.
1414 m_isDeleted = true;
1415
1416 DetachFromBackup();
1417
1150 SceneObjectPart[] parts = m_parts.GetArray(); 1418 SceneObjectPart[] parts = m_parts.GetArray();
1151 for (int i = 0; i < parts.Length; i++) 1419 for (int i = 0; i < parts.Length; i++)
1152 { 1420 {
@@ -1158,13 +1426,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 avatar.StandUp(); 1426 avatar.StandUp();
1159 1427
1160 if (!silent) 1428 if (!silent)
1161 {
1162 part.UpdateFlag = 0; 1429 part.UpdateFlag = 0;
1163 if (part == m_rootPart)
1164 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1165 }
1166 }); 1430 });
1167 } 1431 }
1432
1433
1168 } 1434 }
1169 1435
1170 public void AddScriptLPS(int count) 1436 public void AddScriptLPS(int count)
@@ -1261,7 +1527,12 @@ namespace OpenSim.Region.Framework.Scenes
1261 1527
1262 public void SetOwnerId(UUID userId) 1528 public void SetOwnerId(UUID userId)
1263 { 1529 {
1264 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1530 ForEachPart(delegate(SceneObjectPart part)
1531 {
1532
1533 part.OwnerID = userId;
1534
1535 });
1265 } 1536 }
1266 1537
1267 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1538 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1293,11 +1564,17 @@ namespace OpenSim.Region.Framework.Scenes
1293 return; 1564 return;
1294 } 1565 }
1295 1566
1567 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1568 return;
1569
1296 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1570 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1297 // any exception propogate upwards. 1571 // any exception propogate upwards.
1298 try 1572 try
1299 { 1573 {
1300 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1574 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1575 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1576 m_scene.LoadingPrims) // Land may not be valid yet
1577
1301 { 1578 {
1302 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1579 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1303 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1580 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1322,6 +1599,7 @@ namespace OpenSim.Region.Framework.Scenes
1322 } 1599 }
1323 } 1600 }
1324 } 1601 }
1602
1325 } 1603 }
1326 1604
1327 if (HasGroupChanged) 1605 if (HasGroupChanged)
@@ -1329,6 +1607,20 @@ namespace OpenSim.Region.Framework.Scenes
1329 // don't backup while it's selected or you're asking for changes mid stream. 1607 // don't backup while it's selected or you're asking for changes mid stream.
1330 if (isTimeToPersist() || forcedBackup) 1608 if (isTimeToPersist() || forcedBackup)
1331 { 1609 {
1610 if (m_rootPart.PhysActor != null &&
1611 (!m_rootPart.PhysActor.IsPhysical))
1612 {
1613 // Possible ghost prim
1614 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1615 {
1616 foreach (SceneObjectPart part in m_parts.GetArray())
1617 {
1618 // Re-set physics actor positions and
1619 // orientations
1620 part.GroupPosition = m_rootPart.GroupPosition;
1621 }
1622 }
1623 }
1332// m_log.DebugFormat( 1624// m_log.DebugFormat(
1333// "[SCENE]: Storing {0}, {1} in {2}", 1625// "[SCENE]: Storing {0}, {1} in {2}",
1334// Name, UUID, m_scene.RegionInfo.RegionName); 1626// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1392,81 +1684,90 @@ namespace OpenSim.Region.Framework.Scenes
1392 /// <returns></returns> 1684 /// <returns></returns>
1393 public SceneObjectGroup Copy(bool userExposed) 1685 public SceneObjectGroup Copy(bool userExposed)
1394 { 1686 {
1395 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1687 SceneObjectGroup dupe;
1396 dupe.m_isBackedUp = false; 1688 try
1397 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1689 {
1398 1690 m_dupeInProgress = true;
1399 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1691 dupe = (SceneObjectGroup)MemberwiseClone();
1400 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1692 dupe.m_isBackedUp = false;
1401 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1693 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1402 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1403 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1404 // then restore it's attachment state
1405
1406 // This is only necessary when userExposed is false!
1407 1694
1408 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1695 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1409 1696 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1410 if (!userExposed) 1697 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1411 dupe.RootPart.IsAttachment = true; 1698 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1699 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1700 // then restore it's attachment state
1412 1701
1413 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1702 // This is only necessary when userExposed is false!
1414 1703
1415 if (!userExposed) 1704 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1416 {
1417 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1418 }
1419 1705
1420 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1706 if (!userExposed)
1421 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1707 dupe.RootPart.IsAttachment = true;
1422 1708
1423 if (userExposed) 1709 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1424 dupe.m_rootPart.TrimPermissions();
1425 1710
1426 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1711 if (!userExposed)
1427
1428 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1429 { 1712 {
1430 return p1.LinkNum.CompareTo(p2.LinkNum); 1713 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1431 } 1714 }
1432 );
1433 1715
1434 foreach (SceneObjectPart part in partList) 1716 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1435 { 1717 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1436 if (part.UUID != m_rootPart.UUID) 1718
1719 if (userExposed)
1720 dupe.m_rootPart.TrimPermissions();
1721
1722 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1723
1724 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1725 {
1726 return p1.LinkNum.CompareTo(p2.LinkNum);
1727 }
1728 );
1729
1730 foreach (SceneObjectPart part in partList)
1437 { 1731 {
1438 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1732 if (part.UUID != m_rootPart.UUID)
1439 newPart.LinkNum = part.LinkNum; 1733 {
1440 } 1734 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1735
1736 newPart.LinkNum = part.LinkNum;
1737 }
1441 1738
1442 // Need to duplicate the physics actor as well 1739 // Need to duplicate the physics actor as well
1443 if (part.PhysActor != null && userExposed) 1740 if (part.PhysActor != null && userExposed)
1741 {
1742 PrimitiveBaseShape pbs = part.Shape;
1743
1744 part.PhysActor
1745 = m_scene.PhysicsScene.AddPrimShape(
1746 string.Format("{0}/{1}", part.Name, part.UUID),
1747 pbs,
1748 part.AbsolutePosition,
1749 part.Scale,
1750 part.RotationOffset,
1751 part.PhysActor.IsPhysical);
1752 part.PhysActor.SetMaterial((int)part.Material);
1753
1754 part.PhysActor.LocalID = part.LocalId;
1755 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1756 }
1757 }
1758 if (userExposed)
1444 { 1759 {
1445 PrimitiveBaseShape pbs = part.Shape; 1760 dupe.UpdateParentIDs();
1446 1761 dupe.HasGroupChanged = true;
1447 part.PhysActor 1762 dupe.AttachToBackup();
1448 = m_scene.PhysicsScene.AddPrimShape( 1763
1449 string.Format("{0}/{1}", part.Name, part.UUID), 1764 ScheduleGroupForFullUpdate();
1450 pbs,
1451 part.AbsolutePosition,
1452 part.Scale,
1453 part.RotationOffset,
1454 part.PhysActor.IsPhysical);
1455
1456 part.PhysActor.LocalID = part.LocalId;
1457 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1458 } 1765 }
1459 } 1766 }
1460 1767 finally
1461 if (userExposed)
1462 { 1768 {
1463 dupe.UpdateParentIDs(); 1769 m_dupeInProgress = false;
1464 dupe.HasGroupChanged = true;
1465 dupe.AttachToBackup();
1466
1467 ScheduleGroupForFullUpdate();
1468 } 1770 }
1469
1470 return dupe; 1771 return dupe;
1471 } 1772 }
1472 1773
@@ -1657,13 +1958,40 @@ namespace OpenSim.Region.Framework.Scenes
1657 } 1958 }
1658 } 1959 }
1659 1960
1961 public void rotLookAt(Quaternion target, float strength, float damping)
1962 {
1963 SceneObjectPart rootpart = m_rootPart;
1964 if (rootpart != null)
1965 {
1966 if (IsAttachment)
1967 {
1968 /*
1969 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1970 if (avatar != null)
1971 {
1972 Rotate the Av?
1973 } */
1974 }
1975 else
1976 {
1977 if (rootpart.PhysActor != null)
1978 { // APID must be implemented in your physics system for this to function.
1979 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1980 rootpart.PhysActor.APIDStrength = strength;
1981 rootpart.PhysActor.APIDDamping = damping;
1982 rootpart.PhysActor.APIDActive = true;
1983 }
1984 }
1985 }
1986 }
1987
1660 public void stopLookAt() 1988 public void stopLookAt()
1661 { 1989 {
1662 SceneObjectPart rootpart = m_rootPart; 1990 SceneObjectPart rootpart = m_rootPart;
1663 if (rootpart != null) 1991 if (rootpart != null)
1664 { 1992 {
1665 if (rootpart.PhysActor != null) 1993 if (rootpart.PhysActor != null)
1666 { 1994 { // APID must be implemented in your physics system for this to function.
1667 rootpart.PhysActor.APIDActive = false; 1995 rootpart.PhysActor.APIDActive = false;
1668 } 1996 }
1669 } 1997 }
@@ -1729,6 +2057,8 @@ namespace OpenSim.Region.Framework.Scenes
1729 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2057 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1730 { 2058 {
1731 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2059 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2060 newPart.SetParent(this);
2061
1732 AddPart(newPart); 2062 AddPart(newPart);
1733 2063
1734 SetPartAsNonRoot(newPart); 2064 SetPartAsNonRoot(newPart);
@@ -1875,11 +2205,11 @@ namespace OpenSim.Region.Framework.Scenes
1875 /// Immediately send a full update for this scene object. 2205 /// Immediately send a full update for this scene object.
1876 /// </summary> 2206 /// </summary>
1877 public void SendGroupFullUpdate() 2207 public void SendGroupFullUpdate()
1878 { 2208 {
1879 if (IsDeleted) 2209 if (IsDeleted)
1880 return; 2210 return;
1881 2211
1882// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2212// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1883 2213
1884 RootPart.SendFullUpdateToAllClients(); 2214 RootPart.SendFullUpdateToAllClients();
1885 2215
@@ -2068,12 +2398,15 @@ namespace OpenSim.Region.Framework.Scenes
2068 part.LinkNum += objectGroup.PrimCount; 2398 part.LinkNum += objectGroup.PrimCount;
2069 } 2399 }
2070 } 2400 }
2401 }
2071 2402
2072 linkPart.LinkNum = 2; 2403 linkPart.LinkNum = 2;
2073 2404
2074 linkPart.SetParent(this); 2405 linkPart.SetParent(this);
2075 linkPart.CreateSelected = true; 2406 linkPart.CreateSelected = true;
2076 2407
2408 lock (m_parts.SyncRoot)
2409 {
2077 //if (linkPart.PhysActor != null) 2410 //if (linkPart.PhysActor != null)
2078 //{ 2411 //{
2079 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2412 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2231,6 +2564,8 @@ namespace OpenSim.Region.Framework.Scenes
2231 /// <param name="objectGroup"></param> 2564 /// <param name="objectGroup"></param>
2232 public virtual void DetachFromBackup() 2565 public virtual void DetachFromBackup()
2233 { 2566 {
2567 m_scene.SceneGraph.FireDetachFromBackup(this);
2568
2234 if (m_isBackedUp) 2569 if (m_isBackedUp)
2235 m_scene.EventManager.OnBackup -= ProcessBackup; 2570 m_scene.EventManager.OnBackup -= ProcessBackup;
2236 2571
@@ -2249,7 +2584,8 @@ namespace OpenSim.Region.Framework.Scenes
2249 2584
2250 axPos *= parentRot; 2585 axPos *= parentRot;
2251 part.OffsetPosition = axPos; 2586 part.OffsetPosition = axPos;
2252 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2587 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2588 part.GroupPosition = newPos;
2253 part.OffsetPosition = Vector3.Zero; 2589 part.OffsetPosition = Vector3.Zero;
2254 part.RotationOffset = worldRot; 2590 part.RotationOffset = worldRot;
2255 2591
@@ -2260,7 +2596,7 @@ namespace OpenSim.Region.Framework.Scenes
2260 2596
2261 part.LinkNum = linkNum; 2597 part.LinkNum = linkNum;
2262 2598
2263 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2599 part.OffsetPosition = newPos - AbsolutePosition;
2264 2600
2265 Quaternion rootRotation = m_rootPart.RotationOffset; 2601 Quaternion rootRotation = m_rootPart.RotationOffset;
2266 2602
@@ -2270,7 +2606,7 @@ namespace OpenSim.Region.Framework.Scenes
2270 2606
2271 parentRot = m_rootPart.RotationOffset; 2607 parentRot = m_rootPart.RotationOffset;
2272 oldRot = part.RotationOffset; 2608 oldRot = part.RotationOffset;
2273 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2609 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2274 part.RotationOffset = newRot; 2610 part.RotationOffset = newRot;
2275 } 2611 }
2276 2612
@@ -2535,6 +2871,17 @@ namespace OpenSim.Region.Framework.Scenes
2535 } 2871 }
2536 } 2872 }
2537 2873
2874
2875
2876 /// <summary>
2877 /// Gets the number of parts
2878 /// </summary>
2879 /// <returns></returns>
2880 public int GetPartCount()
2881 {
2882 return Parts.Count();
2883 }
2884
2538 /// <summary> 2885 /// <summary>
2539 /// Update the texture entry for this part 2886 /// Update the texture entry for this part
2540 /// </summary> 2887 /// </summary>
@@ -2596,11 +2943,9 @@ namespace OpenSim.Region.Framework.Scenes
2596 scale.Y = m_scene.m_maxNonphys; 2943 scale.Y = m_scene.m_maxNonphys;
2597 if (scale.Z > m_scene.m_maxNonphys) 2944 if (scale.Z > m_scene.m_maxNonphys)
2598 scale.Z = m_scene.m_maxNonphys; 2945 scale.Z = m_scene.m_maxNonphys;
2599
2600 SceneObjectPart part = GetChildPart(localID); 2946 SceneObjectPart part = GetChildPart(localID);
2601 if (part != null) 2947 if (part != null)
2602 { 2948 {
2603 part.Resize(scale);
2604 if (part.PhysActor != null) 2949 if (part.PhysActor != null)
2605 { 2950 {
2606 if (part.PhysActor.IsPhysical) 2951 if (part.PhysActor.IsPhysical)
@@ -2615,7 +2960,7 @@ namespace OpenSim.Region.Framework.Scenes
2615 part.PhysActor.Size = scale; 2960 part.PhysActor.Size = scale;
2616 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2961 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2617 } 2962 }
2618 //if (part.UUID != m_rootPart.UUID) 2963 part.Resize(scale);
2619 2964
2620 HasGroupChanged = true; 2965 HasGroupChanged = true;
2621 part.TriggerScriptChangedEvent(Changed.SCALE); 2966 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2638,7 +2983,6 @@ namespace OpenSim.Region.Framework.Scenes
2638 SceneObjectPart part = GetChildPart(localID); 2983 SceneObjectPart part = GetChildPart(localID);
2639 if (part != null) 2984 if (part != null)
2640 { 2985 {
2641 part.IgnoreUndoUpdate = true;
2642 if (scale.X > m_scene.m_maxNonphys) 2986 if (scale.X > m_scene.m_maxNonphys)
2643 scale.X = m_scene.m_maxNonphys; 2987 scale.X = m_scene.m_maxNonphys;
2644 if (scale.Y > m_scene.m_maxNonphys) 2988 if (scale.Y > m_scene.m_maxNonphys)
@@ -2675,7 +3019,7 @@ namespace OpenSim.Region.Framework.Scenes
2675 3019
2676 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3020 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2677 { 3021 {
2678 if (oldSize.X * x > m_scene.m_maxPhys) 3022 if (oldSize.X*x > m_scene.m_maxPhys)
2679 { 3023 {
2680 f = m_scene.m_maxPhys / oldSize.X; 3024 f = m_scene.m_maxPhys / oldSize.X;
2681 a = f / x; 3025 a = f / x;
@@ -2683,7 +3027,7 @@ namespace OpenSim.Region.Framework.Scenes
2683 y *= a; 3027 y *= a;
2684 z *= a; 3028 z *= a;
2685 } 3029 }
2686 if (oldSize.Y * y > m_scene.m_maxPhys) 3030 if (oldSize.Y*y > m_scene.m_maxPhys)
2687 { 3031 {
2688 f = m_scene.m_maxPhys / oldSize.Y; 3032 f = m_scene.m_maxPhys / oldSize.Y;
2689 a = f / y; 3033 a = f / y;
@@ -2691,7 +3035,7 @@ namespace OpenSim.Region.Framework.Scenes
2691 y *= a; 3035 y *= a;
2692 z *= a; 3036 z *= a;
2693 } 3037 }
2694 if (oldSize.Z * z > m_scene.m_maxPhys) 3038 if (oldSize.Z*z > m_scene.m_maxPhys)
2695 { 3039 {
2696 f = m_scene.m_maxPhys / oldSize.Z; 3040 f = m_scene.m_maxPhys / oldSize.Z;
2697 a = f / z; 3041 a = f / z;
@@ -2702,7 +3046,7 @@ namespace OpenSim.Region.Framework.Scenes
2702 } 3046 }
2703 else 3047 else
2704 { 3048 {
2705 if (oldSize.X * x > m_scene.m_maxNonphys) 3049 if (oldSize.X*x > m_scene.m_maxNonphys)
2706 { 3050 {
2707 f = m_scene.m_maxNonphys / oldSize.X; 3051 f = m_scene.m_maxNonphys / oldSize.X;
2708 a = f / x; 3052 a = f / x;
@@ -2710,7 +3054,7 @@ namespace OpenSim.Region.Framework.Scenes
2710 y *= a; 3054 y *= a;
2711 z *= a; 3055 z *= a;
2712 } 3056 }
2713 if (oldSize.Y * y > m_scene.m_maxNonphys) 3057 if (oldSize.Y*y > m_scene.m_maxNonphys)
2714 { 3058 {
2715 f = m_scene.m_maxNonphys / oldSize.Y; 3059 f = m_scene.m_maxNonphys / oldSize.Y;
2716 a = f / y; 3060 a = f / y;
@@ -2718,7 +3062,7 @@ namespace OpenSim.Region.Framework.Scenes
2718 y *= a; 3062 y *= a;
2719 z *= a; 3063 z *= a;
2720 } 3064 }
2721 if (oldSize.Z * z > m_scene.m_maxNonphys) 3065 if (oldSize.Z*z > m_scene.m_maxNonphys)
2722 { 3066 {
2723 f = m_scene.m_maxNonphys / oldSize.Z; 3067 f = m_scene.m_maxNonphys / oldSize.Z;
2724 a = f / z; 3068 a = f / z;
@@ -2728,7 +3072,6 @@ namespace OpenSim.Region.Framework.Scenes
2728 } 3072 }
2729 } 3073 }
2730 obPart.IgnoreUndoUpdate = false; 3074 obPart.IgnoreUndoUpdate = false;
2731 obPart.StoreUndoState();
2732 } 3075 }
2733 } 3076 }
2734 } 3077 }
@@ -2736,8 +3079,13 @@ namespace OpenSim.Region.Framework.Scenes
2736 Vector3 prevScale = part.Scale; 3079 Vector3 prevScale = part.Scale;
2737 prevScale.X *= x; 3080 prevScale.X *= x;
2738 prevScale.Y *= y; 3081 prevScale.Y *= y;
2739 prevScale.Z *= z; 3082 prevScale.Z *= z;;
3083
3084 part.IgnoreUndoUpdate = false;
3085 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3086 part.IgnoreUndoUpdate = true;
2740 part.Resize(prevScale); 3087 part.Resize(prevScale);
3088 part.IgnoreUndoUpdate = false;
2741 3089
2742 parts = m_parts.GetArray(); 3090 parts = m_parts.GetArray();
2743 for (int i = 0; i < parts.Length; i++) 3091 for (int i = 0; i < parts.Length; i++)
@@ -2746,19 +3094,26 @@ namespace OpenSim.Region.Framework.Scenes
2746 obPart.IgnoreUndoUpdate = true; 3094 obPart.IgnoreUndoUpdate = true;
2747 if (obPart.UUID != m_rootPart.UUID) 3095 if (obPart.UUID != m_rootPart.UUID)
2748 { 3096 {
2749 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3097 if (obPart.UUID != m_rootPart.UUID)
2750 currentpos.X *= x; 3098 {
2751 currentpos.Y *= y; 3099 obPart.IgnoreUndoUpdate = false;
2752 currentpos.Z *= z; 3100 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2753 Vector3 newSize = new Vector3(obPart.Scale); 3101 obPart.IgnoreUndoUpdate = true;
2754 newSize.X *= x; 3102
2755 newSize.Y *= y; 3103 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2756 newSize.Z *= z; 3104 currentpos.X *= x;
2757 obPart.Resize(newSize); 3105 currentpos.Y *= y;
2758 obPart.UpdateOffSet(currentpos); 3106 currentpos.Z *= z;
3107 Vector3 newSize = new Vector3(obPart.Scale);
3108 newSize.X *= x;
3109 newSize.Y *= y;
3110 newSize.Z *= z;
3111 obPart.Resize(newSize);
3112 obPart.UpdateOffSet(currentpos);
3113 }
3114 obPart.IgnoreUndoUpdate = false;
2759 } 3115 }
2760 obPart.IgnoreUndoUpdate = false; 3116 obPart.IgnoreUndoUpdate = false;
2761 obPart.StoreUndoState();
2762 } 3117 }
2763 3118
2764 if (part.PhysActor != null) 3119 if (part.PhysActor != null)
@@ -2768,7 +3123,6 @@ namespace OpenSim.Region.Framework.Scenes
2768 } 3123 }
2769 3124
2770 part.IgnoreUndoUpdate = false; 3125 part.IgnoreUndoUpdate = false;
2771 part.StoreUndoState();
2772 HasGroupChanged = true; 3126 HasGroupChanged = true;
2773 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3127 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2774 ScheduleGroupForTerseUpdate(); 3128 ScheduleGroupForTerseUpdate();
@@ -2785,14 +3139,11 @@ namespace OpenSim.Region.Framework.Scenes
2785 /// <param name="pos"></param> 3139 /// <param name="pos"></param>
2786 public void UpdateGroupPosition(Vector3 pos) 3140 public void UpdateGroupPosition(Vector3 pos)
2787 { 3141 {
2788 SceneObjectPart[] parts = m_parts.GetArray();
2789 for (int i = 0; i < parts.Length; i++)
2790 parts[i].StoreUndoState();
2791
2792 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3142 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2793 { 3143 {
2794 if (IsAttachment) 3144 if (IsAttachment)
2795 { 3145 {
3146 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2796 m_rootPart.AttachedPos = pos; 3147 m_rootPart.AttachedPos = pos;
2797 } 3148 }
2798 if (RootPart.GetStatusSandbox()) 3149 if (RootPart.GetStatusSandbox())
@@ -2826,7 +3177,7 @@ namespace OpenSim.Region.Framework.Scenes
2826 3177
2827 SceneObjectPart[] parts = m_parts.GetArray(); 3178 SceneObjectPart[] parts = m_parts.GetArray();
2828 for (int i = 0; i < parts.Length; i++) 3179 for (int i = 0; i < parts.Length; i++)
2829 parts[i].StoreUndoState(); 3180 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2830 3181
2831 if (part != null) 3182 if (part != null)
2832 { 3183 {
@@ -2851,7 +3202,7 @@ namespace OpenSim.Region.Framework.Scenes
2851 { 3202 {
2852 SceneObjectPart[] parts = m_parts.GetArray(); 3203 SceneObjectPart[] parts = m_parts.GetArray();
2853 for (int i = 0; i < parts.Length; i++) 3204 for (int i = 0; i < parts.Length; i++)
2854 parts[i].StoreUndoState(); 3205 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2855 3206
2856 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3207 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2857 Vector3 oldPos = 3208 Vector3 oldPos =
@@ -2872,10 +3223,27 @@ namespace OpenSim.Region.Framework.Scenes
2872 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3223 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2873 } 3224 }
2874 3225
2875 AbsolutePosition = newPos; 3226 //We have to set undoing here because otherwise an undo state will be saved
3227 if (!m_rootPart.Undoing)
3228 {
3229 m_rootPart.Undoing = true;
3230 AbsolutePosition = newPos;
3231 m_rootPart.Undoing = false;
3232 }
3233 else
3234 {
3235 AbsolutePosition = newPos;
3236 }
2876 3237
2877 HasGroupChanged = true; 3238 HasGroupChanged = true;
2878 ScheduleGroupForTerseUpdate(); 3239 if (m_rootPart.Undoing)
3240 {
3241 ScheduleGroupForFullUpdate();
3242 }
3243 else
3244 {
3245 ScheduleGroupForTerseUpdate();
3246 }
2879 } 3247 }
2880 3248
2881 public void OffsetForNewRegion(Vector3 offset) 3249 public void OffsetForNewRegion(Vector3 offset)
@@ -2895,7 +3263,7 @@ namespace OpenSim.Region.Framework.Scenes
2895 { 3263 {
2896 SceneObjectPart[] parts = m_parts.GetArray(); 3264 SceneObjectPart[] parts = m_parts.GetArray();
2897 for (int i = 0; i < parts.Length; i++) 3265 for (int i = 0; i < parts.Length; i++)
2898 parts[i].StoreUndoState(); 3266 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2899 3267
2900 m_rootPart.UpdateRotation(rot); 3268 m_rootPart.UpdateRotation(rot);
2901 3269
@@ -2919,7 +3287,7 @@ namespace OpenSim.Region.Framework.Scenes
2919 { 3287 {
2920 SceneObjectPart[] parts = m_parts.GetArray(); 3288 SceneObjectPart[] parts = m_parts.GetArray();
2921 for (int i = 0; i < parts.Length; i++) 3289 for (int i = 0; i < parts.Length; i++)
2922 parts[i].StoreUndoState(); 3290 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2923 3291
2924 m_rootPart.UpdateRotation(rot); 3292 m_rootPart.UpdateRotation(rot);
2925 3293
@@ -2944,10 +3312,9 @@ namespace OpenSim.Region.Framework.Scenes
2944 public void UpdateSingleRotation(Quaternion rot, uint localID) 3312 public void UpdateSingleRotation(Quaternion rot, uint localID)
2945 { 3313 {
2946 SceneObjectPart part = GetChildPart(localID); 3314 SceneObjectPart part = GetChildPart(localID);
2947
2948 SceneObjectPart[] parts = m_parts.GetArray(); 3315 SceneObjectPart[] parts = m_parts.GetArray();
2949 for (int i = 0; i < parts.Length; i++) 3316 for (int i = 0; i < parts.Length; i++)
2950 parts[i].StoreUndoState(); 3317 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2951 3318
2952 if (part != null) 3319 if (part != null)
2953 { 3320 {
@@ -2975,15 +3342,24 @@ namespace OpenSim.Region.Framework.Scenes
2975 if (part.UUID == m_rootPart.UUID) 3342 if (part.UUID == m_rootPart.UUID)
2976 { 3343 {
2977 UpdateRootRotation(rot); 3344 UpdateRootRotation(rot);
2978 AbsolutePosition = pos; 3345 if (!m_rootPart.Undoing)
3346 {
3347 m_rootPart.Undoing = true;
3348 AbsolutePosition = pos;
3349 m_rootPart.Undoing = false;
3350 }
3351 else
3352 {
3353 AbsolutePosition = pos;
3354 }
2979 } 3355 }
2980 else 3356 else
2981 { 3357 {
3358 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2982 part.IgnoreUndoUpdate = true; 3359 part.IgnoreUndoUpdate = true;
2983 part.UpdateRotation(rot); 3360 part.UpdateRotation(rot);
2984 part.OffsetPosition = pos; 3361 part.OffsetPosition = pos;
2985 part.IgnoreUndoUpdate = false; 3362 part.IgnoreUndoUpdate = false;
2986 part.StoreUndoState();
2987 } 3363 }
2988 } 3364 }
2989 } 3365 }
@@ -2997,7 +3373,13 @@ namespace OpenSim.Region.Framework.Scenes
2997 Quaternion axRot = rot; 3373 Quaternion axRot = rot;
2998 Quaternion oldParentRot = m_rootPart.RotationOffset; 3374 Quaternion oldParentRot = m_rootPart.RotationOffset;
2999 3375
3000 m_rootPart.StoreUndoState(); 3376 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3377 bool cancelUndo = false;
3378 if (!m_rootPart.Undoing)
3379 {
3380 m_rootPart.Undoing = true;
3381 cancelUndo = true;
3382 }
3001 m_rootPart.UpdateRotation(rot); 3383 m_rootPart.UpdateRotation(rot);
3002 if (m_rootPart.PhysActor != null) 3384 if (m_rootPart.PhysActor != null)
3003 { 3385 {
@@ -3021,17 +3403,12 @@ namespace OpenSim.Region.Framework.Scenes
3021 newRot *= Quaternion.Inverse(axRot); 3403 newRot *= Quaternion.Inverse(axRot);
3022 prim.RotationOffset = newRot; 3404 prim.RotationOffset = newRot;
3023 prim.ScheduleTerseUpdate(); 3405 prim.ScheduleTerseUpdate();
3406 prim.IgnoreUndoUpdate = false;
3024 } 3407 }
3025 } 3408 }
3026 3409 if (cancelUndo == true)
3027 for (int i = 0; i < parts.Length; i++)
3028 { 3410 {
3029 SceneObjectPart childpart = parts[i]; 3411 m_rootPart.Undoing = false;
3030 if (childpart != m_rootPart)
3031 {
3032 childpart.IgnoreUndoUpdate = false;
3033 childpart.StoreUndoState();
3034 }
3035 } 3412 }
3036 3413
3037 m_rootPart.ScheduleTerseUpdate(); 3414 m_rootPart.ScheduleTerseUpdate();
@@ -3257,7 +3634,6 @@ namespace OpenSim.Region.Framework.Scenes
3257 public float GetMass() 3634 public float GetMass()
3258 { 3635 {
3259 float retmass = 0f; 3636 float retmass = 0f;
3260
3261 SceneObjectPart[] parts = m_parts.GetArray(); 3637 SceneObjectPart[] parts = m_parts.GetArray();
3262 for (int i = 0; i < parts.Length; i++) 3638 for (int i = 0; i < parts.Length; i++)
3263 retmass += parts[i].GetMass(); 3639 retmass += parts[i].GetMass();
@@ -3373,6 +3749,14 @@ namespace OpenSim.Region.Framework.Scenes
3373 SetFromItemID(uuid); 3749 SetFromItemID(uuid);
3374 } 3750 }
3375 3751
3752 public void ResetOwnerChangeFlag()
3753 {
3754 ForEachPart(delegate(SceneObjectPart part)
3755 {
3756 part.ResetOwnerChangeFlag();
3757 });
3758 }
3759
3376 #endregion 3760 #endregion
3377 } 3761 }
3378} 3762}