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.cs656
1 files changed, 519 insertions, 137 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index f17fb28..896300f 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,89 @@ 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);
1441 1735
1442 // Need to duplicate the physics actor as well 1736 newPart.LinkNum = part.LinkNum;
1443 if (part.PhysActor != null && userExposed) 1737 }
1738
1739 // Need to duplicate the physics actor as well
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
1753 part.PhysActor.LocalID = part.LocalId;
1754 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1755 }
1756 }
1757 if (userExposed)
1444 { 1758 {
1445 PrimitiveBaseShape pbs = part.Shape; 1759 dupe.UpdateParentIDs();
1446 1760 dupe.HasGroupChanged = true;
1447 part.PhysActor 1761 dupe.AttachToBackup();
1448 = m_scene.PhysicsScene.AddPrimShape( 1762
1449 string.Format("{0}/{1}", part.Name, part.UUID), 1763 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 } 1764 }
1459 } 1765 }
1460 1766 finally
1461 if (userExposed)
1462 { 1767 {
1463 dupe.UpdateParentIDs(); 1768 m_dupeInProgress = false;
1464 dupe.HasGroupChanged = true;
1465 dupe.AttachToBackup();
1466
1467 ScheduleGroupForFullUpdate();
1468 } 1769 }
1469
1470 return dupe; 1770 return dupe;
1471 } 1771 }
1472 1772
@@ -1657,13 +1957,40 @@ namespace OpenSim.Region.Framework.Scenes
1657 } 1957 }
1658 } 1958 }
1659 1959
1960 public void rotLookAt(Quaternion target, float strength, float damping)
1961 {
1962 SceneObjectPart rootpart = m_rootPart;
1963 if (rootpart != null)
1964 {
1965 if (IsAttachment)
1966 {
1967 /*
1968 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1969 if (avatar != null)
1970 {
1971 Rotate the Av?
1972 } */
1973 }
1974 else
1975 {
1976 if (rootpart.PhysActor != null)
1977 { // APID must be implemented in your physics system for this to function.
1978 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1979 rootpart.PhysActor.APIDStrength = strength;
1980 rootpart.PhysActor.APIDDamping = damping;
1981 rootpart.PhysActor.APIDActive = true;
1982 }
1983 }
1984 }
1985 }
1986
1660 public void stopLookAt() 1987 public void stopLookAt()
1661 { 1988 {
1662 SceneObjectPart rootpart = m_rootPart; 1989 SceneObjectPart rootpart = m_rootPart;
1663 if (rootpart != null) 1990 if (rootpart != null)
1664 { 1991 {
1665 if (rootpart.PhysActor != null) 1992 if (rootpart.PhysActor != null)
1666 { 1993 { // APID must be implemented in your physics system for this to function.
1667 rootpart.PhysActor.APIDActive = false; 1994 rootpart.PhysActor.APIDActive = false;
1668 } 1995 }
1669 } 1996 }
@@ -1729,6 +2056,8 @@ namespace OpenSim.Region.Framework.Scenes
1729 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2056 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1730 { 2057 {
1731 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2058 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2059 newPart.SetParent(this);
2060
1732 AddPart(newPart); 2061 AddPart(newPart);
1733 2062
1734 SetPartAsNonRoot(newPart); 2063 SetPartAsNonRoot(newPart);
@@ -1875,11 +2204,11 @@ namespace OpenSim.Region.Framework.Scenes
1875 /// Immediately send a full update for this scene object. 2204 /// Immediately send a full update for this scene object.
1876 /// </summary> 2205 /// </summary>
1877 public void SendGroupFullUpdate() 2206 public void SendGroupFullUpdate()
1878 { 2207 {
1879 if (IsDeleted) 2208 if (IsDeleted)
1880 return; 2209 return;
1881 2210
1882// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2211// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1883 2212
1884 RootPart.SendFullUpdateToAllClients(); 2213 RootPart.SendFullUpdateToAllClients();
1885 2214
@@ -2068,12 +2397,15 @@ namespace OpenSim.Region.Framework.Scenes
2068 part.LinkNum += objectGroup.PrimCount; 2397 part.LinkNum += objectGroup.PrimCount;
2069 } 2398 }
2070 } 2399 }
2400 }
2071 2401
2072 linkPart.LinkNum = 2; 2402 linkPart.LinkNum = 2;
2073 2403
2074 linkPart.SetParent(this); 2404 linkPart.SetParent(this);
2075 linkPart.CreateSelected = true; 2405 linkPart.CreateSelected = true;
2076 2406
2407 lock (m_parts.SyncRoot)
2408 {
2077 //if (linkPart.PhysActor != null) 2409 //if (linkPart.PhysActor != null)
2078 //{ 2410 //{
2079 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2411 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2231,6 +2563,8 @@ namespace OpenSim.Region.Framework.Scenes
2231 /// <param name="objectGroup"></param> 2563 /// <param name="objectGroup"></param>
2232 public virtual void DetachFromBackup() 2564 public virtual void DetachFromBackup()
2233 { 2565 {
2566 m_scene.SceneGraph.FireDetachFromBackup(this);
2567
2234 if (m_isBackedUp) 2568 if (m_isBackedUp)
2235 m_scene.EventManager.OnBackup -= ProcessBackup; 2569 m_scene.EventManager.OnBackup -= ProcessBackup;
2236 2570
@@ -2535,6 +2869,17 @@ namespace OpenSim.Region.Framework.Scenes
2535 } 2869 }
2536 } 2870 }
2537 2871
2872
2873
2874 /// <summary>
2875 /// Gets the number of parts
2876 /// </summary>
2877 /// <returns></returns>
2878 public int GetPartCount()
2879 {
2880 return Parts.Count();
2881 }
2882
2538 /// <summary> 2883 /// <summary>
2539 /// Update the texture entry for this part 2884 /// Update the texture entry for this part
2540 /// </summary> 2885 /// </summary>
@@ -2596,11 +2941,9 @@ namespace OpenSim.Region.Framework.Scenes
2596 scale.Y = m_scene.m_maxNonphys; 2941 scale.Y = m_scene.m_maxNonphys;
2597 if (scale.Z > m_scene.m_maxNonphys) 2942 if (scale.Z > m_scene.m_maxNonphys)
2598 scale.Z = m_scene.m_maxNonphys; 2943 scale.Z = m_scene.m_maxNonphys;
2599
2600 SceneObjectPart part = GetChildPart(localID); 2944 SceneObjectPart part = GetChildPart(localID);
2601 if (part != null) 2945 if (part != null)
2602 { 2946 {
2603 part.Resize(scale);
2604 if (part.PhysActor != null) 2947 if (part.PhysActor != null)
2605 { 2948 {
2606 if (part.PhysActor.IsPhysical) 2949 if (part.PhysActor.IsPhysical)
@@ -2615,7 +2958,7 @@ namespace OpenSim.Region.Framework.Scenes
2615 part.PhysActor.Size = scale; 2958 part.PhysActor.Size = scale;
2616 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2959 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2617 } 2960 }
2618 //if (part.UUID != m_rootPart.UUID) 2961 part.Resize(scale);
2619 2962
2620 HasGroupChanged = true; 2963 HasGroupChanged = true;
2621 part.TriggerScriptChangedEvent(Changed.SCALE); 2964 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2638,7 +2981,6 @@ namespace OpenSim.Region.Framework.Scenes
2638 SceneObjectPart part = GetChildPart(localID); 2981 SceneObjectPart part = GetChildPart(localID);
2639 if (part != null) 2982 if (part != null)
2640 { 2983 {
2641 part.IgnoreUndoUpdate = true;
2642 if (scale.X > m_scene.m_maxNonphys) 2984 if (scale.X > m_scene.m_maxNonphys)
2643 scale.X = m_scene.m_maxNonphys; 2985 scale.X = m_scene.m_maxNonphys;
2644 if (scale.Y > m_scene.m_maxNonphys) 2986 if (scale.Y > m_scene.m_maxNonphys)
@@ -2675,7 +3017,7 @@ namespace OpenSim.Region.Framework.Scenes
2675 3017
2676 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3018 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2677 { 3019 {
2678 if (oldSize.X * x > m_scene.m_maxPhys) 3020 if (oldSize.X*x > m_scene.m_maxPhys)
2679 { 3021 {
2680 f = m_scene.m_maxPhys / oldSize.X; 3022 f = m_scene.m_maxPhys / oldSize.X;
2681 a = f / x; 3023 a = f / x;
@@ -2683,7 +3025,7 @@ namespace OpenSim.Region.Framework.Scenes
2683 y *= a; 3025 y *= a;
2684 z *= a; 3026 z *= a;
2685 } 3027 }
2686 if (oldSize.Y * y > m_scene.m_maxPhys) 3028 if (oldSize.Y*y > m_scene.m_maxPhys)
2687 { 3029 {
2688 f = m_scene.m_maxPhys / oldSize.Y; 3030 f = m_scene.m_maxPhys / oldSize.Y;
2689 a = f / y; 3031 a = f / y;
@@ -2691,7 +3033,7 @@ namespace OpenSim.Region.Framework.Scenes
2691 y *= a; 3033 y *= a;
2692 z *= a; 3034 z *= a;
2693 } 3035 }
2694 if (oldSize.Z * z > m_scene.m_maxPhys) 3036 if (oldSize.Z*z > m_scene.m_maxPhys)
2695 { 3037 {
2696 f = m_scene.m_maxPhys / oldSize.Z; 3038 f = m_scene.m_maxPhys / oldSize.Z;
2697 a = f / z; 3039 a = f / z;
@@ -2702,7 +3044,7 @@ namespace OpenSim.Region.Framework.Scenes
2702 } 3044 }
2703 else 3045 else
2704 { 3046 {
2705 if (oldSize.X * x > m_scene.m_maxNonphys) 3047 if (oldSize.X*x > m_scene.m_maxNonphys)
2706 { 3048 {
2707 f = m_scene.m_maxNonphys / oldSize.X; 3049 f = m_scene.m_maxNonphys / oldSize.X;
2708 a = f / x; 3050 a = f / x;
@@ -2710,7 +3052,7 @@ namespace OpenSim.Region.Framework.Scenes
2710 y *= a; 3052 y *= a;
2711 z *= a; 3053 z *= a;
2712 } 3054 }
2713 if (oldSize.Y * y > m_scene.m_maxNonphys) 3055 if (oldSize.Y*y > m_scene.m_maxNonphys)
2714 { 3056 {
2715 f = m_scene.m_maxNonphys / oldSize.Y; 3057 f = m_scene.m_maxNonphys / oldSize.Y;
2716 a = f / y; 3058 a = f / y;
@@ -2718,7 +3060,7 @@ namespace OpenSim.Region.Framework.Scenes
2718 y *= a; 3060 y *= a;
2719 z *= a; 3061 z *= a;
2720 } 3062 }
2721 if (oldSize.Z * z > m_scene.m_maxNonphys) 3063 if (oldSize.Z*z > m_scene.m_maxNonphys)
2722 { 3064 {
2723 f = m_scene.m_maxNonphys / oldSize.Z; 3065 f = m_scene.m_maxNonphys / oldSize.Z;
2724 a = f / z; 3066 a = f / z;
@@ -2728,7 +3070,6 @@ namespace OpenSim.Region.Framework.Scenes
2728 } 3070 }
2729 } 3071 }
2730 obPart.IgnoreUndoUpdate = false; 3072 obPart.IgnoreUndoUpdate = false;
2731 obPart.StoreUndoState();
2732 } 3073 }
2733 } 3074 }
2734 } 3075 }
@@ -2736,8 +3077,13 @@ namespace OpenSim.Region.Framework.Scenes
2736 Vector3 prevScale = part.Scale; 3077 Vector3 prevScale = part.Scale;
2737 prevScale.X *= x; 3078 prevScale.X *= x;
2738 prevScale.Y *= y; 3079 prevScale.Y *= y;
2739 prevScale.Z *= z; 3080 prevScale.Z *= z;;
3081
3082 part.IgnoreUndoUpdate = false;
3083 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3084 part.IgnoreUndoUpdate = true;
2740 part.Resize(prevScale); 3085 part.Resize(prevScale);
3086 part.IgnoreUndoUpdate = false;
2741 3087
2742 parts = m_parts.GetArray(); 3088 parts = m_parts.GetArray();
2743 for (int i = 0; i < parts.Length; i++) 3089 for (int i = 0; i < parts.Length; i++)
@@ -2746,19 +3092,26 @@ namespace OpenSim.Region.Framework.Scenes
2746 obPart.IgnoreUndoUpdate = true; 3092 obPart.IgnoreUndoUpdate = true;
2747 if (obPart.UUID != m_rootPart.UUID) 3093 if (obPart.UUID != m_rootPart.UUID)
2748 { 3094 {
2749 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3095 if (obPart.UUID != m_rootPart.UUID)
2750 currentpos.X *= x; 3096 {
2751 currentpos.Y *= y; 3097 obPart.IgnoreUndoUpdate = false;
2752 currentpos.Z *= z; 3098 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2753 Vector3 newSize = new Vector3(obPart.Scale); 3099 obPart.IgnoreUndoUpdate = true;
2754 newSize.X *= x; 3100
2755 newSize.Y *= y; 3101 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2756 newSize.Z *= z; 3102 currentpos.X *= x;
2757 obPart.Resize(newSize); 3103 currentpos.Y *= y;
2758 obPart.UpdateOffSet(currentpos); 3104 currentpos.Z *= z;
3105 Vector3 newSize = new Vector3(obPart.Scale);
3106 newSize.X *= x;
3107 newSize.Y *= y;
3108 newSize.Z *= z;
3109 obPart.Resize(newSize);
3110 obPart.UpdateOffSet(currentpos);
3111 }
3112 obPart.IgnoreUndoUpdate = false;
2759 } 3113 }
2760 obPart.IgnoreUndoUpdate = false; 3114 obPart.IgnoreUndoUpdate = false;
2761 obPart.StoreUndoState();
2762 } 3115 }
2763 3116
2764 if (part.PhysActor != null) 3117 if (part.PhysActor != null)
@@ -2768,7 +3121,6 @@ namespace OpenSim.Region.Framework.Scenes
2768 } 3121 }
2769 3122
2770 part.IgnoreUndoUpdate = false; 3123 part.IgnoreUndoUpdate = false;
2771 part.StoreUndoState();
2772 HasGroupChanged = true; 3124 HasGroupChanged = true;
2773 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3125 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2774 ScheduleGroupForTerseUpdate(); 3126 ScheduleGroupForTerseUpdate();
@@ -2785,14 +3137,11 @@ namespace OpenSim.Region.Framework.Scenes
2785 /// <param name="pos"></param> 3137 /// <param name="pos"></param>
2786 public void UpdateGroupPosition(Vector3 pos) 3138 public void UpdateGroupPosition(Vector3 pos)
2787 { 3139 {
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)) 3140 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2793 { 3141 {
2794 if (IsAttachment) 3142 if (IsAttachment)
2795 { 3143 {
3144 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2796 m_rootPart.AttachedPos = pos; 3145 m_rootPart.AttachedPos = pos;
2797 } 3146 }
2798 if (RootPart.GetStatusSandbox()) 3147 if (RootPart.GetStatusSandbox())
@@ -2826,7 +3175,7 @@ namespace OpenSim.Region.Framework.Scenes
2826 3175
2827 SceneObjectPart[] parts = m_parts.GetArray(); 3176 SceneObjectPart[] parts = m_parts.GetArray();
2828 for (int i = 0; i < parts.Length; i++) 3177 for (int i = 0; i < parts.Length; i++)
2829 parts[i].StoreUndoState(); 3178 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2830 3179
2831 if (part != null) 3180 if (part != null)
2832 { 3181 {
@@ -2851,7 +3200,7 @@ namespace OpenSim.Region.Framework.Scenes
2851 { 3200 {
2852 SceneObjectPart[] parts = m_parts.GetArray(); 3201 SceneObjectPart[] parts = m_parts.GetArray();
2853 for (int i = 0; i < parts.Length; i++) 3202 for (int i = 0; i < parts.Length; i++)
2854 parts[i].StoreUndoState(); 3203 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2855 3204
2856 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3205 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2857 Vector3 oldPos = 3206 Vector3 oldPos =
@@ -2872,10 +3221,27 @@ namespace OpenSim.Region.Framework.Scenes
2872 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3221 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2873 } 3222 }
2874 3223
2875 AbsolutePosition = newPos; 3224 //We have to set undoing here because otherwise an undo state will be saved
3225 if (!m_rootPart.Undoing)
3226 {
3227 m_rootPart.Undoing = true;
3228 AbsolutePosition = newPos;
3229 m_rootPart.Undoing = false;
3230 }
3231 else
3232 {
3233 AbsolutePosition = newPos;
3234 }
2876 3235
2877 HasGroupChanged = true; 3236 HasGroupChanged = true;
2878 ScheduleGroupForTerseUpdate(); 3237 if (m_rootPart.Undoing)
3238 {
3239 ScheduleGroupForFullUpdate();
3240 }
3241 else
3242 {
3243 ScheduleGroupForTerseUpdate();
3244 }
2879 } 3245 }
2880 3246
2881 public void OffsetForNewRegion(Vector3 offset) 3247 public void OffsetForNewRegion(Vector3 offset)
@@ -2895,7 +3261,7 @@ namespace OpenSim.Region.Framework.Scenes
2895 { 3261 {
2896 SceneObjectPart[] parts = m_parts.GetArray(); 3262 SceneObjectPart[] parts = m_parts.GetArray();
2897 for (int i = 0; i < parts.Length; i++) 3263 for (int i = 0; i < parts.Length; i++)
2898 parts[i].StoreUndoState(); 3264 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2899 3265
2900 m_rootPart.UpdateRotation(rot); 3266 m_rootPart.UpdateRotation(rot);
2901 3267
@@ -2919,7 +3285,7 @@ namespace OpenSim.Region.Framework.Scenes
2919 { 3285 {
2920 SceneObjectPart[] parts = m_parts.GetArray(); 3286 SceneObjectPart[] parts = m_parts.GetArray();
2921 for (int i = 0; i < parts.Length; i++) 3287 for (int i = 0; i < parts.Length; i++)
2922 parts[i].StoreUndoState(); 3288 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2923 3289
2924 m_rootPart.UpdateRotation(rot); 3290 m_rootPart.UpdateRotation(rot);
2925 3291
@@ -2944,10 +3310,9 @@ namespace OpenSim.Region.Framework.Scenes
2944 public void UpdateSingleRotation(Quaternion rot, uint localID) 3310 public void UpdateSingleRotation(Quaternion rot, uint localID)
2945 { 3311 {
2946 SceneObjectPart part = GetChildPart(localID); 3312 SceneObjectPart part = GetChildPart(localID);
2947
2948 SceneObjectPart[] parts = m_parts.GetArray(); 3313 SceneObjectPart[] parts = m_parts.GetArray();
2949 for (int i = 0; i < parts.Length; i++) 3314 for (int i = 0; i < parts.Length; i++)
2950 parts[i].StoreUndoState(); 3315 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2951 3316
2952 if (part != null) 3317 if (part != null)
2953 { 3318 {
@@ -2975,15 +3340,24 @@ namespace OpenSim.Region.Framework.Scenes
2975 if (part.UUID == m_rootPart.UUID) 3340 if (part.UUID == m_rootPart.UUID)
2976 { 3341 {
2977 UpdateRootRotation(rot); 3342 UpdateRootRotation(rot);
2978 AbsolutePosition = pos; 3343 if (!m_rootPart.Undoing)
3344 {
3345 m_rootPart.Undoing = true;
3346 AbsolutePosition = pos;
3347 m_rootPart.Undoing = false;
3348 }
3349 else
3350 {
3351 AbsolutePosition = pos;
3352 }
2979 } 3353 }
2980 else 3354 else
2981 { 3355 {
3356 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2982 part.IgnoreUndoUpdate = true; 3357 part.IgnoreUndoUpdate = true;
2983 part.UpdateRotation(rot); 3358 part.UpdateRotation(rot);
2984 part.OffsetPosition = pos; 3359 part.OffsetPosition = pos;
2985 part.IgnoreUndoUpdate = false; 3360 part.IgnoreUndoUpdate = false;
2986 part.StoreUndoState();
2987 } 3361 }
2988 } 3362 }
2989 } 3363 }
@@ -2997,7 +3371,13 @@ namespace OpenSim.Region.Framework.Scenes
2997 Quaternion axRot = rot; 3371 Quaternion axRot = rot;
2998 Quaternion oldParentRot = m_rootPart.RotationOffset; 3372 Quaternion oldParentRot = m_rootPart.RotationOffset;
2999 3373
3000 m_rootPart.StoreUndoState(); 3374 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3375 bool cancelUndo = false;
3376 if (!m_rootPart.Undoing)
3377 {
3378 m_rootPart.Undoing = true;
3379 cancelUndo = true;
3380 }
3001 m_rootPart.UpdateRotation(rot); 3381 m_rootPart.UpdateRotation(rot);
3002 if (m_rootPart.PhysActor != null) 3382 if (m_rootPart.PhysActor != null)
3003 { 3383 {
@@ -3021,17 +3401,12 @@ namespace OpenSim.Region.Framework.Scenes
3021 newRot *= Quaternion.Inverse(axRot); 3401 newRot *= Quaternion.Inverse(axRot);
3022 prim.RotationOffset = newRot; 3402 prim.RotationOffset = newRot;
3023 prim.ScheduleTerseUpdate(); 3403 prim.ScheduleTerseUpdate();
3404 prim.IgnoreUndoUpdate = false;
3024 } 3405 }
3025 } 3406 }
3026 3407 if (cancelUndo == true)
3027 for (int i = 0; i < parts.Length; i++)
3028 { 3408 {
3029 SceneObjectPart childpart = parts[i]; 3409 m_rootPart.Undoing = false;
3030 if (childpart != m_rootPart)
3031 {
3032 childpart.IgnoreUndoUpdate = false;
3033 childpart.StoreUndoState();
3034 }
3035 } 3410 }
3036 3411
3037 m_rootPart.ScheduleTerseUpdate(); 3412 m_rootPart.ScheduleTerseUpdate();
@@ -3257,7 +3632,6 @@ namespace OpenSim.Region.Framework.Scenes
3257 public float GetMass() 3632 public float GetMass()
3258 { 3633 {
3259 float retmass = 0f; 3634 float retmass = 0f;
3260
3261 SceneObjectPart[] parts = m_parts.GetArray(); 3635 SceneObjectPart[] parts = m_parts.GetArray();
3262 for (int i = 0; i < parts.Length; i++) 3636 for (int i = 0; i < parts.Length; i++)
3263 retmass += parts[i].GetMass(); 3637 retmass += parts[i].GetMass();
@@ -3373,6 +3747,14 @@ namespace OpenSim.Region.Framework.Scenes
3373 SetFromItemID(uuid); 3747 SetFromItemID(uuid);
3374 } 3748 }
3375 3749
3750 public void ResetOwnerChangeFlag()
3751 {
3752 ForEachPart(delegate(SceneObjectPart part)
3753 {
3754 part.ResetOwnerChangeFlag();
3755 });
3756 }
3757
3376 #endregion 3758 #endregion
3377 } 3759 }
3378} 3760}