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 5f00f84..79f7162 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 }
@@ -132,8 +184,19 @@ namespace OpenSim.Region.Framework.Scenes
132 return false; 184 return false;
133 if (m_scene.ShuttingDown) 185 if (m_scene.ShuttingDown)
134 return true; 186 return true;
187
188 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
189 {
190 m_maxPersistTime = m_scene.m_persistAfter;
191 m_minPersistTime = m_scene.m_dontPersistBefore;
192 }
193
135 long currentTime = DateTime.Now.Ticks; 194 long currentTime = DateTime.Now.Ticks;
136 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 195
196 if (timeLastChanged == 0) timeLastChanged = currentTime;
197 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
198
199 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
137 return true; 200 return true;
138 return false; 201 return false;
139 } 202 }
@@ -176,10 +239,10 @@ namespace OpenSim.Region.Framework.Scenes
176 239
177 private bool m_scriptListens_atTarget; 240 private bool m_scriptListens_atTarget;
178 private bool m_scriptListens_notAtTarget; 241 private bool m_scriptListens_notAtTarget;
179
180 private bool m_scriptListens_atRotTarget; 242 private bool m_scriptListens_atRotTarget;
181 private bool m_scriptListens_notAtRotTarget; 243 private bool m_scriptListens_notAtRotTarget;
182 244
245 public bool m_dupeInProgress = false;
183 internal Dictionary<UUID, string> m_savedScriptState; 246 internal Dictionary<UUID, string> m_savedScriptState;
184 247
185 #region Properties 248 #region Properties
@@ -219,7 +282,13 @@ namespace OpenSim.Region.Framework.Scenes
219 public virtual Quaternion Rotation 282 public virtual Quaternion Rotation
220 { 283 {
221 get { return m_rotation; } 284 get { return m_rotation; }
222 set { m_rotation = value; } 285 set {
286 foreach(SceneObjectPart p in m_parts.GetArray())
287 {
288 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
289 }
290 m_rotation = value;
291 }
223 } 292 }
224 293
225 public Quaternion GroupRotation 294 public Quaternion GroupRotation
@@ -293,7 +362,11 @@ namespace OpenSim.Region.Framework.Scenes
293 { 362 {
294 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 363 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
295 } 364 }
296 365
366 foreach (SceneObjectPart part in m_parts.GetArray())
367 {
368 part.IgnoreUndoUpdate = true;
369 }
297 if (RootPart.GetStatusSandbox()) 370 if (RootPart.GetStatusSandbox())
298 { 371 {
299 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 372 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -304,10 +377,31 @@ namespace OpenSim.Region.Framework.Scenes
304 return; 377 return;
305 } 378 }
306 } 379 }
307
308 SceneObjectPart[] parts = m_parts.GetArray(); 380 SceneObjectPart[] parts = m_parts.GetArray();
309 for (int i = 0; i < parts.Length; i++) 381 foreach (SceneObjectPart part in parts)
310 parts[i].GroupPosition = val; 382 {
383 part.IgnoreUndoUpdate = false;
384 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
385 part.GroupPosition = val;
386 if (!m_dupeInProgress)
387 {
388 part.TriggerScriptChangedEvent(Changed.POSITION);
389 }
390 }
391 if (!m_dupeInProgress)
392 {
393 foreach (ScenePresence av in m_linkedAvatars)
394 {
395 SceneObjectPart p;
396 if (m_parts.TryGetValue(av.LinkedPrim, out p))
397 {
398 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
399 av.AbsolutePosition += offset;
400 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
401 av.SendFullUpdateToAllClients();
402 }
403 }
404 }
311 405
312 //if (m_rootPart.PhysActor != null) 406 //if (m_rootPart.PhysActor != null)
313 //{ 407 //{
@@ -458,6 +552,7 @@ namespace OpenSim.Region.Framework.Scenes
458 /// </summary> 552 /// </summary>
459 public SceneObjectGroup() 553 public SceneObjectGroup()
460 { 554 {
555
461 } 556 }
462 557
463 /// <summary> 558 /// <summary>
@@ -474,7 +569,7 @@ namespace OpenSim.Region.Framework.Scenes
474 /// Constructor. This object is added to the scene later via AttachToScene() 569 /// Constructor. This object is added to the scene later via AttachToScene()
475 /// </summary> 570 /// </summary>
476 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 571 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
477 { 572 {
478 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 573 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
479 } 574 }
480 575
@@ -520,6 +615,9 @@ namespace OpenSim.Region.Framework.Scenes
520 /// </summary> 615 /// </summary>
521 public virtual void AttachToBackup() 616 public virtual void AttachToBackup()
522 { 617 {
618 if (IsAttachment) return;
619 m_scene.SceneGraph.FireAttachToBackup(this);
620
523 if (InSceneBackup) 621 if (InSceneBackup)
524 { 622 {
525 //m_log.DebugFormat( 623 //m_log.DebugFormat(
@@ -635,9 +733,9 @@ namespace OpenSim.Region.Framework.Scenes
635 result.normal = inter.normal; 733 result.normal = inter.normal;
636 result.distance = inter.distance; 734 result.distance = inter.distance;
637 } 735 }
736
638 } 737 }
639 } 738 }
640
641 return result; 739 return result;
642 } 740 }
643 741
@@ -657,17 +755,19 @@ namespace OpenSim.Region.Framework.Scenes
657 minZ = 8192f; 755 minZ = 8192f;
658 756
659 SceneObjectPart[] parts = m_parts.GetArray(); 757 SceneObjectPart[] parts = m_parts.GetArray();
660 for (int i = 0; i < parts.Length; i++) 758 foreach (SceneObjectPart part in parts)
661 { 759 {
662 SceneObjectPart part = parts[i];
663
664 Vector3 worldPos = part.GetWorldPosition(); 760 Vector3 worldPos = part.GetWorldPosition();
665 Vector3 offset = worldPos - AbsolutePosition; 761 Vector3 offset = worldPos - AbsolutePosition;
666 Quaternion worldRot; 762 Quaternion worldRot;
667 if (part.ParentID == 0) 763 if (part.ParentID == 0)
764 {
668 worldRot = part.RotationOffset; 765 worldRot = part.RotationOffset;
766 }
669 else 767 else
768 {
670 worldRot = part.GetWorldRotation(); 769 worldRot = part.GetWorldRotation();
770 }
671 771
672 Vector3 frontTopLeft; 772 Vector3 frontTopLeft;
673 Vector3 frontTopRight; 773 Vector3 frontTopRight;
@@ -679,6 +779,8 @@ namespace OpenSim.Region.Framework.Scenes
679 Vector3 backBottomLeft; 779 Vector3 backBottomLeft;
680 Vector3 backBottomRight; 780 Vector3 backBottomRight;
681 781
782 // Vector3[] corners = new Vector3[8];
783
682 Vector3 orig = Vector3.Zero; 784 Vector3 orig = Vector3.Zero;
683 785
684 frontTopLeft.X = orig.X - (part.Scale.X / 2); 786 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -713,6 +815,38 @@ namespace OpenSim.Region.Framework.Scenes
713 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 815 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
714 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 816 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
715 817
818
819
820 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
821 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
822 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
823 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
824 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
825 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
826 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
827 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
828
829 //for (int i = 0; i < 8; i++)
830 //{
831 // corners[i] = corners[i] * worldRot;
832 // corners[i] += offset;
833
834 // if (corners[i].X > maxX)
835 // maxX = corners[i].X;
836 // if (corners[i].X < minX)
837 // minX = corners[i].X;
838
839 // if (corners[i].Y > maxY)
840 // maxY = corners[i].Y;
841 // if (corners[i].Y < minY)
842 // minY = corners[i].Y;
843
844 // if (corners[i].Z > maxZ)
845 // maxZ = corners[i].Y;
846 // if (corners[i].Z < minZ)
847 // minZ = corners[i].Z;
848 //}
849
716 frontTopLeft = frontTopLeft * worldRot; 850 frontTopLeft = frontTopLeft * worldRot;
717 frontTopRight = frontTopRight * worldRot; 851 frontTopRight = frontTopRight * worldRot;
718 frontBottomLeft = frontBottomLeft * worldRot; 852 frontBottomLeft = frontBottomLeft * worldRot;
@@ -734,6 +868,15 @@ namespace OpenSim.Region.Framework.Scenes
734 backTopLeft += offset; 868 backTopLeft += offset;
735 backTopRight += offset; 869 backTopRight += offset;
736 870
871 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
872 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
873 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
874 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
875 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
876 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
877 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
878 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
879
737 if (frontTopRight.X > maxX) 880 if (frontTopRight.X > maxX)
738 maxX = frontTopRight.X; 881 maxX = frontTopRight.X;
739 if (frontTopLeft.X > maxX) 882 if (frontTopLeft.X > maxX)
@@ -879,15 +1022,20 @@ namespace OpenSim.Region.Framework.Scenes
879 1022
880 public void SaveScriptedState(XmlTextWriter writer) 1023 public void SaveScriptedState(XmlTextWriter writer)
881 { 1024 {
1025 SaveScriptedState(writer, false);
1026 }
1027
1028 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1029 {
882 XmlDocument doc = new XmlDocument(); 1030 XmlDocument doc = new XmlDocument();
883 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1031 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
884 1032
885 SceneObjectPart[] parts = m_parts.GetArray(); 1033 SceneObjectPart[] parts = m_parts.GetArray();
886 for (int i = 0; i < parts.Length; i++) 1034 for (int i = 0; i < parts.Length; i++)
887 { 1035 {
888 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1036 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
889 foreach (KeyValuePair<UUID, string> kvp in pstates) 1037 foreach (KeyValuePair<UUID, string> kvp in pstates)
890 states.Add(kvp.Key, kvp.Value); 1038 states[kvp.Key] = kvp.Value;
891 } 1039 }
892 1040
893 if (states.Count > 0) 1041 if (states.Count > 0)
@@ -906,6 +1054,118 @@ namespace OpenSim.Region.Framework.Scenes
906 } 1054 }
907 } 1055 }
908 1056
1057 /// <summary>
1058 /// Add the avatar to this linkset (avatar is sat).
1059 /// </summary>
1060 /// <param name="agentID"></param>
1061 public void AddAvatar(UUID agentID)
1062 {
1063 ScenePresence presence;
1064 if (m_scene.TryGetScenePresence(agentID, out presence))
1065 {
1066 if (!m_linkedAvatars.Contains(presence))
1067 {
1068 m_linkedAvatars.Add(presence);
1069 }
1070 }
1071 }
1072
1073 /// <summary>
1074 /// Delete the avatar from this linkset (avatar is unsat).
1075 /// </summary>
1076 /// <param name="agentID"></param>
1077 public void DeleteAvatar(UUID agentID)
1078 {
1079 ScenePresence presence;
1080 if (m_scene.TryGetScenePresence(agentID, out presence))
1081 {
1082 if (m_linkedAvatars.Contains(presence))
1083 {
1084 m_linkedAvatars.Remove(presence);
1085 }
1086 }
1087 }
1088
1089 /// <summary>
1090 /// Returns the list of linked presences (avatars sat on this group)
1091 /// </summary>
1092 /// <param name="agentID"></param>
1093 public List<ScenePresence> GetLinkedAvatars()
1094 {
1095 return m_linkedAvatars;
1096 }
1097
1098 /// <summary>
1099 /// Attach this scene object to the given avatar.
1100 /// </summary>
1101 /// <param name="agentID"></param>
1102 /// <param name="attachmentpoint"></param>
1103 /// <param name="AttachOffset"></param>
1104 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1105 {
1106 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1107 if (avatar != null)
1108 {
1109 // don't attach attachments to child agents
1110 if (avatar.IsChildAgent) return;
1111
1112// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1113
1114 DetachFromBackup();
1115
1116 // Remove from database and parcel prim count
1117 m_scene.DeleteFromStorage(UUID);
1118 m_scene.EventManager.TriggerParcelPrimCountTainted();
1119
1120 m_rootPart.AttachedAvatar = agentID;
1121
1122 //Anakin Lohner bug #3839
1123 lock (m_parts)
1124 {
1125 foreach (SceneObjectPart p in m_parts.GetArray())
1126 {
1127 p.AttachedAvatar = agentID;
1128 }
1129 }
1130
1131 if (m_rootPart.PhysActor != null)
1132 {
1133 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1134 m_rootPart.PhysActor = null;
1135 }
1136
1137 AbsolutePosition = AttachOffset;
1138 m_rootPart.AttachedPos = AttachOffset;
1139 m_rootPart.IsAttachment = true;
1140
1141 m_rootPart.SetParentLocalId(avatar.LocalId);
1142 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1143
1144 avatar.AddAttachment(this);
1145
1146 if (!silent)
1147 {
1148 // Killing it here will cause the client to deselect it
1149 // It then reappears on the avatar, deselected
1150 // through the full update below
1151 //
1152 if (IsSelected)
1153 {
1154 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1155 }
1156
1157 IsSelected = false; // fudge....
1158 ScheduleGroupForFullUpdate();
1159 }
1160 }
1161 else
1162 {
1163 m_log.WarnFormat(
1164 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1165 UUID, agentID, Scene.RegionInfo.RegionName);
1166 }
1167 }
1168
909 public byte GetAttachmentPoint() 1169 public byte GetAttachmentPoint()
910 { 1170 {
911 return m_rootPart.Shape.State; 1171 return m_rootPart.Shape.State;
@@ -1032,7 +1292,10 @@ namespace OpenSim.Region.Framework.Scenes
1032 public void AddPart(SceneObjectPart part) 1292 public void AddPart(SceneObjectPart part)
1033 { 1293 {
1034 part.SetParent(this); 1294 part.SetParent(this);
1035 part.LinkNum = m_parts.Add(part.UUID, part); 1295 m_parts.Add(part.UUID, part);
1296
1297 part.LinkNum = m_parts.Count;
1298
1036 if (part.LinkNum == 2 && RootPart != null) 1299 if (part.LinkNum == 2 && RootPart != null)
1037 RootPart.LinkNum = 1; 1300 RootPart.LinkNum = 1;
1038 } 1301 }
@@ -1116,7 +1379,7 @@ namespace OpenSim.Region.Framework.Scenes
1116 1379
1117 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1380 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1118 { 1381 {
1119 part.StoreUndoState(); 1382 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1120 part.OnGrab(offsetPos, remoteClient); 1383 part.OnGrab(offsetPos, remoteClient);
1121 } 1384 }
1122 1385
@@ -1136,6 +1399,11 @@ namespace OpenSim.Region.Framework.Scenes
1136 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1399 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1137 public void DeleteGroupFromScene(bool silent) 1400 public void DeleteGroupFromScene(bool silent)
1138 { 1401 {
1402 // We need to keep track of this state in case this group is still queued for backup.
1403 m_isDeleted = true;
1404
1405 DetachFromBackup();
1406
1139 SceneObjectPart[] parts = m_parts.GetArray(); 1407 SceneObjectPart[] parts = m_parts.GetArray();
1140 for (int i = 0; i < parts.Length; i++) 1408 for (int i = 0; i < parts.Length; i++)
1141 { 1409 {
@@ -1147,13 +1415,11 @@ namespace OpenSim.Region.Framework.Scenes
1147 avatar.StandUp(); 1415 avatar.StandUp();
1148 1416
1149 if (!silent) 1417 if (!silent)
1150 {
1151 part.UpdateFlag = 0; 1418 part.UpdateFlag = 0;
1152 if (part == m_rootPart)
1153 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1154 }
1155 }); 1419 });
1156 } 1420 }
1421
1422
1157 } 1423 }
1158 1424
1159 public void AddScriptLPS(int count) 1425 public void AddScriptLPS(int count)
@@ -1250,7 +1516,12 @@ namespace OpenSim.Region.Framework.Scenes
1250 1516
1251 public void SetOwnerId(UUID userId) 1517 public void SetOwnerId(UUID userId)
1252 { 1518 {
1253 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1519 ForEachPart(delegate(SceneObjectPart part)
1520 {
1521
1522 part.OwnerID = userId;
1523
1524 });
1254 } 1525 }
1255 1526
1256 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1527 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1282,11 +1553,17 @@ namespace OpenSim.Region.Framework.Scenes
1282 return; 1553 return;
1283 } 1554 }
1284 1555
1556 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1557 return;
1558
1285 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1559 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1286 // any exception propogate upwards. 1560 // any exception propogate upwards.
1287 try 1561 try
1288 { 1562 {
1289 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1563 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1564 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1565 m_scene.LoadingPrims) // Land may not be valid yet
1566
1290 { 1567 {
1291 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1568 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1292 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1569 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1311,6 +1588,7 @@ namespace OpenSim.Region.Framework.Scenes
1311 } 1588 }
1312 } 1589 }
1313 } 1590 }
1591
1314 } 1592 }
1315 1593
1316 if (HasGroupChanged) 1594 if (HasGroupChanged)
@@ -1318,6 +1596,20 @@ namespace OpenSim.Region.Framework.Scenes
1318 // don't backup while it's selected or you're asking for changes mid stream. 1596 // don't backup while it's selected or you're asking for changes mid stream.
1319 if (isTimeToPersist() || forcedBackup) 1597 if (isTimeToPersist() || forcedBackup)
1320 { 1598 {
1599 if (m_rootPart.PhysActor != null &&
1600 (!m_rootPart.PhysActor.IsPhysical))
1601 {
1602 // Possible ghost prim
1603 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1604 {
1605 foreach (SceneObjectPart part in m_parts.GetArray())
1606 {
1607 // Re-set physics actor positions and
1608 // orientations
1609 part.GroupPosition = m_rootPart.GroupPosition;
1610 }
1611 }
1612 }
1321// m_log.DebugFormat( 1613// m_log.DebugFormat(
1322// "[SCENE]: Storing {0}, {1} in {2}", 1614// "[SCENE]: Storing {0}, {1} in {2}",
1323// Name, UUID, m_scene.RegionInfo.RegionName); 1615// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1380,81 +1672,89 @@ namespace OpenSim.Region.Framework.Scenes
1380 /// <returns></returns> 1672 /// <returns></returns>
1381 public SceneObjectGroup Copy(bool userExposed) 1673 public SceneObjectGroup Copy(bool userExposed)
1382 { 1674 {
1383 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1675 SceneObjectGroup dupe;
1384 dupe.m_isBackedUp = false; 1676 try
1385 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1677 {
1386 1678 m_dupeInProgress = true;
1387 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1679 dupe = (SceneObjectGroup)MemberwiseClone();
1388 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1680 dupe.m_isBackedUp = false;
1389 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1681 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1390 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1391 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1392 // then restore it's attachment state
1393
1394 // This is only necessary when userExposed is false!
1395 1682
1396 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1683 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1397 1684 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1398 if (!userExposed) 1685 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1399 dupe.RootPart.IsAttachment = true; 1686 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1687 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1688 // then restore it's attachment state
1400 1689
1401 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1690 // This is only necessary when userExposed is false!
1402 1691
1403 if (!userExposed) 1692 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1404 {
1405 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1406 }
1407 1693
1408 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1694 if (!userExposed)
1409 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1695 dupe.RootPart.IsAttachment = true;
1410 1696
1411 if (userExposed) 1697 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1412 dupe.m_rootPart.TrimPermissions();
1413 1698
1414 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1699 if (!userExposed)
1415
1416 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1417 { 1700 {
1418 return p1.LinkNum.CompareTo(p2.LinkNum); 1701 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1419 } 1702 }
1420 );
1421 1703
1422 foreach (SceneObjectPart part in partList) 1704 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1423 { 1705 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1424 if (part.UUID != m_rootPart.UUID) 1706
1707 if (userExposed)
1708 dupe.m_rootPart.TrimPermissions();
1709
1710 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1711
1712 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1713 {
1714 return p1.LinkNum.CompareTo(p2.LinkNum);
1715 }
1716 );
1717
1718 foreach (SceneObjectPart part in partList)
1425 { 1719 {
1426 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1720 if (part.UUID != m_rootPart.UUID)
1427 newPart.LinkNum = part.LinkNum; 1721 {
1428 } 1722 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1429 1723
1430 // Need to duplicate the physics actor as well 1724 newPart.LinkNum = part.LinkNum;
1431 if (part.PhysActor != null && userExposed) 1725 }
1726
1727 // Need to duplicate the physics actor as well
1728 if (part.PhysActor != null && userExposed)
1729 {
1730 PrimitiveBaseShape pbs = part.Shape;
1731
1732 part.PhysActor
1733 = m_scene.PhysicsScene.AddPrimShape(
1734 string.Format("{0}/{1}", part.Name, part.UUID),
1735 pbs,
1736 part.AbsolutePosition,
1737 part.Scale,
1738 part.RotationOffset,
1739 part.PhysActor.IsPhysical);
1740
1741 part.PhysActor.LocalID = part.LocalId;
1742 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1743 }
1744 }
1745 if (userExposed)
1432 { 1746 {
1433 PrimitiveBaseShape pbs = part.Shape; 1747 dupe.UpdateParentIDs();
1434 1748 dupe.HasGroupChanged = true;
1435 part.PhysActor 1749 dupe.AttachToBackup();
1436 = m_scene.PhysicsScene.AddPrimShape( 1750
1437 string.Format("{0}/{1}", part.Name, part.UUID), 1751 ScheduleGroupForFullUpdate();
1438 pbs,
1439 part.AbsolutePosition,
1440 part.Scale,
1441 part.RotationOffset,
1442 part.PhysActor.IsPhysical);
1443
1444 part.PhysActor.LocalID = part.LocalId;
1445 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1446 } 1752 }
1447 } 1753 }
1448 1754 finally
1449 if (userExposed)
1450 { 1755 {
1451 dupe.UpdateParentIDs(); 1756 m_dupeInProgress = false;
1452 dupe.HasGroupChanged = true;
1453 dupe.AttachToBackup();
1454
1455 ScheduleGroupForFullUpdate();
1456 } 1757 }
1457
1458 return dupe; 1758 return dupe;
1459 } 1759 }
1460 1760
@@ -1645,13 +1945,40 @@ namespace OpenSim.Region.Framework.Scenes
1645 } 1945 }
1646 } 1946 }
1647 1947
1948 public void rotLookAt(Quaternion target, float strength, float damping)
1949 {
1950 SceneObjectPart rootpart = m_rootPart;
1951 if (rootpart != null)
1952 {
1953 if (IsAttachment)
1954 {
1955 /*
1956 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1957 if (avatar != null)
1958 {
1959 Rotate the Av?
1960 } */
1961 }
1962 else
1963 {
1964 if (rootpart.PhysActor != null)
1965 { // APID must be implemented in your physics system for this to function.
1966 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1967 rootpart.PhysActor.APIDStrength = strength;
1968 rootpart.PhysActor.APIDDamping = damping;
1969 rootpart.PhysActor.APIDActive = true;
1970 }
1971 }
1972 }
1973 }
1974
1648 public void stopLookAt() 1975 public void stopLookAt()
1649 { 1976 {
1650 SceneObjectPart rootpart = m_rootPart; 1977 SceneObjectPart rootpart = m_rootPart;
1651 if (rootpart != null) 1978 if (rootpart != null)
1652 { 1979 {
1653 if (rootpart.PhysActor != null) 1980 if (rootpart.PhysActor != null)
1654 { 1981 { // APID must be implemented in your physics system for this to function.
1655 rootpart.PhysActor.APIDActive = false; 1982 rootpart.PhysActor.APIDActive = false;
1656 } 1983 }
1657 } 1984 }
@@ -1717,6 +2044,8 @@ namespace OpenSim.Region.Framework.Scenes
1717 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2044 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1718 { 2045 {
1719 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2046 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2047 newPart.SetParent(this);
2048
1720 AddPart(newPart); 2049 AddPart(newPart);
1721 2050
1722 SetPartAsNonRoot(newPart); 2051 SetPartAsNonRoot(newPart);
@@ -1863,11 +2192,11 @@ namespace OpenSim.Region.Framework.Scenes
1863 /// Immediately send a full update for this scene object. 2192 /// Immediately send a full update for this scene object.
1864 /// </summary> 2193 /// </summary>
1865 public void SendGroupFullUpdate() 2194 public void SendGroupFullUpdate()
1866 { 2195 {
1867 if (IsDeleted) 2196 if (IsDeleted)
1868 return; 2197 return;
1869 2198
1870// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2199// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1871 2200
1872 RootPart.SendFullUpdateToAllClients(); 2201 RootPart.SendFullUpdateToAllClients();
1873 2202
@@ -2056,12 +2385,15 @@ namespace OpenSim.Region.Framework.Scenes
2056 part.LinkNum += objectGroup.PrimCount; 2385 part.LinkNum += objectGroup.PrimCount;
2057 } 2386 }
2058 } 2387 }
2388 }
2059 2389
2060 linkPart.LinkNum = 2; 2390 linkPart.LinkNum = 2;
2061 2391
2062 linkPart.SetParent(this); 2392 linkPart.SetParent(this);
2063 linkPart.CreateSelected = true; 2393 linkPart.CreateSelected = true;
2064 2394
2395 lock (m_parts.SyncRoot)
2396 {
2065 //if (linkPart.PhysActor != null) 2397 //if (linkPart.PhysActor != null)
2066 //{ 2398 //{
2067 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2399 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2218,6 +2550,8 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2550 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2551 public virtual void DetachFromBackup()
2220 { 2552 {
2553 m_scene.SceneGraph.FireDetachFromBackup(this);
2554
2221 if (m_isBackedUp) 2555 if (m_isBackedUp)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2556 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2557
@@ -2522,6 +2856,17 @@ namespace OpenSim.Region.Framework.Scenes
2522 } 2856 }
2523 } 2857 }
2524 2858
2859
2860
2861 /// <summary>
2862 /// Gets the number of parts
2863 /// </summary>
2864 /// <returns></returns>
2865 public int GetPartCount()
2866 {
2867 return Parts.Count();
2868 }
2869
2525 /// <summary> 2870 /// <summary>
2526 /// Update the texture entry for this part 2871 /// Update the texture entry for this part
2527 /// </summary> 2872 /// </summary>
@@ -2583,11 +2928,9 @@ namespace OpenSim.Region.Framework.Scenes
2583 scale.Y = m_scene.m_maxNonphys; 2928 scale.Y = m_scene.m_maxNonphys;
2584 if (scale.Z > m_scene.m_maxNonphys) 2929 if (scale.Z > m_scene.m_maxNonphys)
2585 scale.Z = m_scene.m_maxNonphys; 2930 scale.Z = m_scene.m_maxNonphys;
2586
2587 SceneObjectPart part = GetChildPart(localID); 2931 SceneObjectPart part = GetChildPart(localID);
2588 if (part != null) 2932 if (part != null)
2589 { 2933 {
2590 part.Resize(scale);
2591 if (part.PhysActor != null) 2934 if (part.PhysActor != null)
2592 { 2935 {
2593 if (part.PhysActor.IsPhysical) 2936 if (part.PhysActor.IsPhysical)
@@ -2602,7 +2945,7 @@ namespace OpenSim.Region.Framework.Scenes
2602 part.PhysActor.Size = scale; 2945 part.PhysActor.Size = scale;
2603 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2946 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2604 } 2947 }
2605 //if (part.UUID != m_rootPart.UUID) 2948 part.Resize(scale);
2606 2949
2607 HasGroupChanged = true; 2950 HasGroupChanged = true;
2608 ScheduleGroupForFullUpdate(); 2951 ScheduleGroupForFullUpdate();
@@ -2624,7 +2967,6 @@ namespace OpenSim.Region.Framework.Scenes
2624 SceneObjectPart part = GetChildPart(localID); 2967 SceneObjectPart part = GetChildPart(localID);
2625 if (part != null) 2968 if (part != null)
2626 { 2969 {
2627 part.IgnoreUndoUpdate = true;
2628 if (scale.X > m_scene.m_maxNonphys) 2970 if (scale.X > m_scene.m_maxNonphys)
2629 scale.X = m_scene.m_maxNonphys; 2971 scale.X = m_scene.m_maxNonphys;
2630 if (scale.Y > m_scene.m_maxNonphys) 2972 if (scale.Y > m_scene.m_maxNonphys)
@@ -2661,7 +3003,7 @@ namespace OpenSim.Region.Framework.Scenes
2661 3003
2662 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3004 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2663 { 3005 {
2664 if (oldSize.X * x > m_scene.m_maxPhys) 3006 if (oldSize.X*x > m_scene.m_maxPhys)
2665 { 3007 {
2666 f = m_scene.m_maxPhys / oldSize.X; 3008 f = m_scene.m_maxPhys / oldSize.X;
2667 a = f / x; 3009 a = f / x;
@@ -2669,7 +3011,7 @@ namespace OpenSim.Region.Framework.Scenes
2669 y *= a; 3011 y *= a;
2670 z *= a; 3012 z *= a;
2671 } 3013 }
2672 if (oldSize.Y * y > m_scene.m_maxPhys) 3014 if (oldSize.Y*y > m_scene.m_maxPhys)
2673 { 3015 {
2674 f = m_scene.m_maxPhys / oldSize.Y; 3016 f = m_scene.m_maxPhys / oldSize.Y;
2675 a = f / y; 3017 a = f / y;
@@ -2677,7 +3019,7 @@ namespace OpenSim.Region.Framework.Scenes
2677 y *= a; 3019 y *= a;
2678 z *= a; 3020 z *= a;
2679 } 3021 }
2680 if (oldSize.Z * z > m_scene.m_maxPhys) 3022 if (oldSize.Z*z > m_scene.m_maxPhys)
2681 { 3023 {
2682 f = m_scene.m_maxPhys / oldSize.Z; 3024 f = m_scene.m_maxPhys / oldSize.Z;
2683 a = f / z; 3025 a = f / z;
@@ -2688,7 +3030,7 @@ namespace OpenSim.Region.Framework.Scenes
2688 } 3030 }
2689 else 3031 else
2690 { 3032 {
2691 if (oldSize.X * x > m_scene.m_maxNonphys) 3033 if (oldSize.X*x > m_scene.m_maxNonphys)
2692 { 3034 {
2693 f = m_scene.m_maxNonphys / oldSize.X; 3035 f = m_scene.m_maxNonphys / oldSize.X;
2694 a = f / x; 3036 a = f / x;
@@ -2696,7 +3038,7 @@ namespace OpenSim.Region.Framework.Scenes
2696 y *= a; 3038 y *= a;
2697 z *= a; 3039 z *= a;
2698 } 3040 }
2699 if (oldSize.Y * y > m_scene.m_maxNonphys) 3041 if (oldSize.Y*y > m_scene.m_maxNonphys)
2700 { 3042 {
2701 f = m_scene.m_maxNonphys / oldSize.Y; 3043 f = m_scene.m_maxNonphys / oldSize.Y;
2702 a = f / y; 3044 a = f / y;
@@ -2704,7 +3046,7 @@ namespace OpenSim.Region.Framework.Scenes
2704 y *= a; 3046 y *= a;
2705 z *= a; 3047 z *= a;
2706 } 3048 }
2707 if (oldSize.Z * z > m_scene.m_maxNonphys) 3049 if (oldSize.Z*z > m_scene.m_maxNonphys)
2708 { 3050 {
2709 f = m_scene.m_maxNonphys / oldSize.Z; 3051 f = m_scene.m_maxNonphys / oldSize.Z;
2710 a = f / z; 3052 a = f / z;
@@ -2714,7 +3056,6 @@ namespace OpenSim.Region.Framework.Scenes
2714 } 3056 }
2715 } 3057 }
2716 obPart.IgnoreUndoUpdate = false; 3058 obPart.IgnoreUndoUpdate = false;
2717 obPart.StoreUndoState();
2718 } 3059 }
2719 } 3060 }
2720 } 3061 }
@@ -2722,8 +3063,13 @@ namespace OpenSim.Region.Framework.Scenes
2722 Vector3 prevScale = part.Scale; 3063 Vector3 prevScale = part.Scale;
2723 prevScale.X *= x; 3064 prevScale.X *= x;
2724 prevScale.Y *= y; 3065 prevScale.Y *= y;
2725 prevScale.Z *= z; 3066 prevScale.Z *= z;;
3067
3068 part.IgnoreUndoUpdate = false;
3069 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3070 part.IgnoreUndoUpdate = true;
2726 part.Resize(prevScale); 3071 part.Resize(prevScale);
3072 part.IgnoreUndoUpdate = false;
2727 3073
2728 parts = m_parts.GetArray(); 3074 parts = m_parts.GetArray();
2729 for (int i = 0; i < parts.Length; i++) 3075 for (int i = 0; i < parts.Length; i++)
@@ -2732,19 +3078,26 @@ namespace OpenSim.Region.Framework.Scenes
2732 obPart.IgnoreUndoUpdate = true; 3078 obPart.IgnoreUndoUpdate = true;
2733 if (obPart.UUID != m_rootPart.UUID) 3079 if (obPart.UUID != m_rootPart.UUID)
2734 { 3080 {
2735 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3081 if (obPart.UUID != m_rootPart.UUID)
2736 currentpos.X *= x; 3082 {
2737 currentpos.Y *= y; 3083 obPart.IgnoreUndoUpdate = false;
2738 currentpos.Z *= z; 3084 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2739 Vector3 newSize = new Vector3(obPart.Scale); 3085 obPart.IgnoreUndoUpdate = true;
2740 newSize.X *= x; 3086
2741 newSize.Y *= y; 3087 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2742 newSize.Z *= z; 3088 currentpos.X *= x;
2743 obPart.Resize(newSize); 3089 currentpos.Y *= y;
2744 obPart.UpdateOffSet(currentpos); 3090 currentpos.Z *= z;
3091 Vector3 newSize = new Vector3(obPart.Scale);
3092 newSize.X *= x;
3093 newSize.Y *= y;
3094 newSize.Z *= z;
3095 obPart.Resize(newSize);
3096 obPart.UpdateOffSet(currentpos);
3097 }
3098 obPart.IgnoreUndoUpdate = false;
2745 } 3099 }
2746 obPart.IgnoreUndoUpdate = false; 3100 obPart.IgnoreUndoUpdate = false;
2747 obPart.StoreUndoState();
2748 } 3101 }
2749 3102
2750 if (part.PhysActor != null) 3103 if (part.PhysActor != null)
@@ -2754,7 +3107,6 @@ namespace OpenSim.Region.Framework.Scenes
2754 } 3107 }
2755 3108
2756 part.IgnoreUndoUpdate = false; 3109 part.IgnoreUndoUpdate = false;
2757 part.StoreUndoState();
2758 HasGroupChanged = true; 3110 HasGroupChanged = true;
2759 ScheduleGroupForTerseUpdate(); 3111 ScheduleGroupForTerseUpdate();
2760 } 3112 }
@@ -2770,14 +3122,11 @@ namespace OpenSim.Region.Framework.Scenes
2770 /// <param name="pos"></param> 3122 /// <param name="pos"></param>
2771 public void UpdateGroupPosition(Vector3 pos) 3123 public void UpdateGroupPosition(Vector3 pos)
2772 { 3124 {
2773 SceneObjectPart[] parts = m_parts.GetArray();
2774 for (int i = 0; i < parts.Length; i++)
2775 parts[i].StoreUndoState();
2776
2777 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3125 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2778 { 3126 {
2779 if (IsAttachment) 3127 if (IsAttachment)
2780 { 3128 {
3129 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2781 m_rootPart.AttachedPos = pos; 3130 m_rootPart.AttachedPos = pos;
2782 } 3131 }
2783 if (RootPart.GetStatusSandbox()) 3132 if (RootPart.GetStatusSandbox())
@@ -2811,7 +3160,7 @@ namespace OpenSim.Region.Framework.Scenes
2811 3160
2812 SceneObjectPart[] parts = m_parts.GetArray(); 3161 SceneObjectPart[] parts = m_parts.GetArray();
2813 for (int i = 0; i < parts.Length; i++) 3162 for (int i = 0; i < parts.Length; i++)
2814 parts[i].StoreUndoState(); 3163 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2815 3164
2816 if (part != null) 3165 if (part != null)
2817 { 3166 {
@@ -2836,7 +3185,7 @@ namespace OpenSim.Region.Framework.Scenes
2836 { 3185 {
2837 SceneObjectPart[] parts = m_parts.GetArray(); 3186 SceneObjectPart[] parts = m_parts.GetArray();
2838 for (int i = 0; i < parts.Length; i++) 3187 for (int i = 0; i < parts.Length; i++)
2839 parts[i].StoreUndoState(); 3188 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2840 3189
2841 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3190 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2842 Vector3 oldPos = 3191 Vector3 oldPos =
@@ -2857,10 +3206,27 @@ namespace OpenSim.Region.Framework.Scenes
2857 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3206 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2858 } 3207 }
2859 3208
2860 AbsolutePosition = newPos; 3209 //We have to set undoing here because otherwise an undo state will be saved
3210 if (!m_rootPart.Undoing)
3211 {
3212 m_rootPart.Undoing = true;
3213 AbsolutePosition = newPos;
3214 m_rootPart.Undoing = false;
3215 }
3216 else
3217 {
3218 AbsolutePosition = newPos;
3219 }
2861 3220
2862 HasGroupChanged = true; 3221 HasGroupChanged = true;
2863 ScheduleGroupForTerseUpdate(); 3222 if (m_rootPart.Undoing)
3223 {
3224 ScheduleGroupForFullUpdate();
3225 }
3226 else
3227 {
3228 ScheduleGroupForTerseUpdate();
3229 }
2864 } 3230 }
2865 3231
2866 public void OffsetForNewRegion(Vector3 offset) 3232 public void OffsetForNewRegion(Vector3 offset)
@@ -2880,7 +3246,7 @@ namespace OpenSim.Region.Framework.Scenes
2880 { 3246 {
2881 SceneObjectPart[] parts = m_parts.GetArray(); 3247 SceneObjectPart[] parts = m_parts.GetArray();
2882 for (int i = 0; i < parts.Length; i++) 3248 for (int i = 0; i < parts.Length; i++)
2883 parts[i].StoreUndoState(); 3249 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2884 3250
2885 m_rootPart.UpdateRotation(rot); 3251 m_rootPart.UpdateRotation(rot);
2886 3252
@@ -2904,7 +3270,7 @@ namespace OpenSim.Region.Framework.Scenes
2904 { 3270 {
2905 SceneObjectPart[] parts = m_parts.GetArray(); 3271 SceneObjectPart[] parts = m_parts.GetArray();
2906 for (int i = 0; i < parts.Length; i++) 3272 for (int i = 0; i < parts.Length; i++)
2907 parts[i].StoreUndoState(); 3273 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2908 3274
2909 m_rootPart.UpdateRotation(rot); 3275 m_rootPart.UpdateRotation(rot);
2910 3276
@@ -2929,10 +3295,9 @@ namespace OpenSim.Region.Framework.Scenes
2929 public void UpdateSingleRotation(Quaternion rot, uint localID) 3295 public void UpdateSingleRotation(Quaternion rot, uint localID)
2930 { 3296 {
2931 SceneObjectPart part = GetChildPart(localID); 3297 SceneObjectPart part = GetChildPart(localID);
2932
2933 SceneObjectPart[] parts = m_parts.GetArray(); 3298 SceneObjectPart[] parts = m_parts.GetArray();
2934 for (int i = 0; i < parts.Length; i++) 3299 for (int i = 0; i < parts.Length; i++)
2935 parts[i].StoreUndoState(); 3300 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2936 3301
2937 if (part != null) 3302 if (part != null)
2938 { 3303 {
@@ -2960,15 +3325,24 @@ namespace OpenSim.Region.Framework.Scenes
2960 if (part.UUID == m_rootPart.UUID) 3325 if (part.UUID == m_rootPart.UUID)
2961 { 3326 {
2962 UpdateRootRotation(rot); 3327 UpdateRootRotation(rot);
2963 AbsolutePosition = pos; 3328 if (!m_rootPart.Undoing)
3329 {
3330 m_rootPart.Undoing = true;
3331 AbsolutePosition = pos;
3332 m_rootPart.Undoing = false;
3333 }
3334 else
3335 {
3336 AbsolutePosition = pos;
3337 }
2964 } 3338 }
2965 else 3339 else
2966 { 3340 {
3341 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2967 part.IgnoreUndoUpdate = true; 3342 part.IgnoreUndoUpdate = true;
2968 part.UpdateRotation(rot); 3343 part.UpdateRotation(rot);
2969 part.OffsetPosition = pos; 3344 part.OffsetPosition = pos;
2970 part.IgnoreUndoUpdate = false; 3345 part.IgnoreUndoUpdate = false;
2971 part.StoreUndoState();
2972 } 3346 }
2973 } 3347 }
2974 } 3348 }
@@ -2982,7 +3356,13 @@ namespace OpenSim.Region.Framework.Scenes
2982 Quaternion axRot = rot; 3356 Quaternion axRot = rot;
2983 Quaternion oldParentRot = m_rootPart.RotationOffset; 3357 Quaternion oldParentRot = m_rootPart.RotationOffset;
2984 3358
2985 m_rootPart.StoreUndoState(); 3359 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3360 bool cancelUndo = false;
3361 if (!m_rootPart.Undoing)
3362 {
3363 m_rootPart.Undoing = true;
3364 cancelUndo = true;
3365 }
2986 m_rootPart.UpdateRotation(rot); 3366 m_rootPart.UpdateRotation(rot);
2987 if (m_rootPart.PhysActor != null) 3367 if (m_rootPart.PhysActor != null)
2988 { 3368 {
@@ -3006,17 +3386,12 @@ namespace OpenSim.Region.Framework.Scenes
3006 newRot *= Quaternion.Inverse(axRot); 3386 newRot *= Quaternion.Inverse(axRot);
3007 prim.RotationOffset = newRot; 3387 prim.RotationOffset = newRot;
3008 prim.ScheduleTerseUpdate(); 3388 prim.ScheduleTerseUpdate();
3389 prim.IgnoreUndoUpdate = false;
3009 } 3390 }
3010 } 3391 }
3011 3392 if (cancelUndo == true)
3012 for (int i = 0; i < parts.Length; i++)
3013 { 3393 {
3014 SceneObjectPart childpart = parts[i]; 3394 m_rootPart.Undoing = false;
3015 if (childpart != m_rootPart)
3016 {
3017 childpart.IgnoreUndoUpdate = false;
3018 childpart.StoreUndoState();
3019 }
3020 } 3395 }
3021 3396
3022 m_rootPart.ScheduleTerseUpdate(); 3397 m_rootPart.ScheduleTerseUpdate();
@@ -3242,7 +3617,6 @@ namespace OpenSim.Region.Framework.Scenes
3242 public float GetMass() 3617 public float GetMass()
3243 { 3618 {
3244 float retmass = 0f; 3619 float retmass = 0f;
3245
3246 SceneObjectPart[] parts = m_parts.GetArray(); 3620 SceneObjectPart[] parts = m_parts.GetArray();
3247 for (int i = 0; i < parts.Length; i++) 3621 for (int i = 0; i < parts.Length; i++)
3248 retmass += parts[i].GetMass(); 3622 retmass += parts[i].GetMass();
@@ -3358,6 +3732,14 @@ namespace OpenSim.Region.Framework.Scenes
3358 SetFromItemID(uuid); 3732 SetFromItemID(uuid);
3359 } 3733 }
3360 3734
3735 public void ResetOwnerChangeFlag()
3736 {
3737 ForEachPart(delegate(SceneObjectPart part)
3738 {
3739 part.ResetOwnerChangeFlag();
3740 });
3741 }
3742
3361 #endregion 3743 #endregion
3362 } 3744 }
3363} 3745}