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.cs666
1 files changed, 531 insertions, 135 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 5f00f84..c870797 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)
@@ -1286,7 +1557,10 @@ namespace OpenSim.Region.Framework.Scenes
1286 // any exception propogate upwards. 1557 // any exception propogate upwards.
1287 try 1558 try
1288 { 1559 {
1289 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1560 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1561 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1562 m_scene.LoadingPrims) // Land may not be valid yet
1563
1290 { 1564 {
1291 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1565 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1292 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1566 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1311,6 +1585,7 @@ namespace OpenSim.Region.Framework.Scenes
1311 } 1585 }
1312 } 1586 }
1313 } 1587 }
1588
1314 } 1589 }
1315 1590
1316 if (HasGroupChanged) 1591 if (HasGroupChanged)
@@ -1318,6 +1593,20 @@ namespace OpenSim.Region.Framework.Scenes
1318 // don't backup while it's selected or you're asking for changes mid stream. 1593 // don't backup while it's selected or you're asking for changes mid stream.
1319 if (isTimeToPersist() || forcedBackup) 1594 if (isTimeToPersist() || forcedBackup)
1320 { 1595 {
1596 if (m_rootPart.PhysActor != null &&
1597 (!m_rootPart.PhysActor.IsPhysical))
1598 {
1599 // Possible ghost prim
1600 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1601 {
1602 foreach (SceneObjectPart part in m_parts.GetArray())
1603 {
1604 // Re-set physics actor positions and
1605 // orientations
1606 part.GroupPosition = m_rootPart.GroupPosition;
1607 }
1608 }
1609 }
1321// m_log.DebugFormat( 1610// m_log.DebugFormat(
1322// "[SCENE]: Storing {0}, {1} in {2}", 1611// "[SCENE]: Storing {0}, {1} in {2}",
1323// Name, UUID, m_scene.RegionInfo.RegionName); 1612// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1380,81 +1669,106 @@ namespace OpenSim.Region.Framework.Scenes
1380 /// <returns></returns> 1669 /// <returns></returns>
1381 public SceneObjectGroup Copy(bool userExposed) 1670 public SceneObjectGroup Copy(bool userExposed)
1382 { 1671 {
1383 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1672 SceneObjectGroup dupe;
1384 dupe.m_isBackedUp = false; 1673 try
1385 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1674 {
1675 m_dupeInProgress = true;
1676 dupe = (SceneObjectGroup)MemberwiseClone();
1677 dupe.m_isBackedUp = false;
1678 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1386 1679
1387 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1680 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1388 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1681 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1389 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1682 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1390 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1683 // 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, 1684 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1392 // then restore it's attachment state 1685 // then restore it's attachment state
1393 1686
1394 // This is only necessary when userExposed is false! 1687 // This is only necessary when userExposed is false!
1395 1688
1396 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1689 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1397
1398 if (!userExposed)
1399 dupe.RootPart.IsAttachment = true;
1400 1690
1401 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1691 if (!userExposed)
1692 dupe.RootPart.IsAttachment = true;
1402 1693
1403 if (!userExposed) 1694 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1404 { 1695
1405 dupe.RootPart.IsAttachment = previousAttachmentStatus; 1696 if (!userExposed)
1406 } 1697 {
1698 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1699 }
1407 1700
1408 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1701 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1409 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1702 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1410 1703
1411 if (userExposed) 1704 if (userExposed)
1412 dupe.m_rootPart.TrimPermissions(); 1705 dupe.m_rootPart.TrimPermissions();
1413 1706
1414 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1707 /// may need to create a new Physics actor.
1415 1708 if (dupe.RootPart.PhysActor != null && userExposed)
1416 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1417 { 1709 {
1418 return p1.LinkNum.CompareTo(p2.LinkNum); 1710 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1711
1712 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1713 dupe.RootPart.Name,
1714 pbs,
1715 dupe.RootPart.AbsolutePosition,
1716 dupe.RootPart.Scale,
1717 dupe.RootPart.RotationOffset,
1718 dupe.RootPart.PhysActor.IsPhysical);
1719
1720 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1721 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1419 } 1722 }
1420 );
1421 1723
1422 foreach (SceneObjectPart part in partList) 1724 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1423 { 1725
1424 if (part.UUID != m_rootPart.UUID) 1726 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1727 {
1728 return p1.LinkNum.CompareTo(p2.LinkNum);
1729 }
1730 );
1731
1732 foreach (SceneObjectPart part in partList)
1425 { 1733 {
1426 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1734 if (part.UUID != m_rootPart.UUID)
1427 newPart.LinkNum = part.LinkNum; 1735 {
1428 } 1736 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1737
1738 newPart.LinkNum = part.LinkNum;
1739 }
1429 1740
1430 // Need to duplicate the physics actor as well 1741 // Need to duplicate the physics actor as well
1431 if (part.PhysActor != null && userExposed) 1742 if (part.PhysActor != null && userExposed)
1743 {
1744 PrimitiveBaseShape pbs = part.Shape;
1745
1746 part.PhysActor
1747 = m_scene.PhysicsScene.AddPrimShape(
1748 string.Format("{0}/{1}", part.Name, part.UUID),
1749 pbs,
1750 part.AbsolutePosition,
1751 part.Scale,
1752 part.RotationOffset,
1753 part.PhysActor.IsPhysical);
1754
1755 part.PhysActor.LocalID = part.LocalId;
1756 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1757 }
1758 }
1759 if (userExposed)
1432 { 1760 {
1433 PrimitiveBaseShape pbs = part.Shape; 1761 dupe.UpdateParentIDs();
1434 1762 dupe.HasGroupChanged = true;
1435 part.PhysActor 1763 dupe.AttachToBackup();
1436 = m_scene.PhysicsScene.AddPrimShape( 1764
1437 string.Format("{0}/{1}", part.Name, part.UUID), 1765 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 } 1766 }
1447 } 1767 }
1448 1768 finally
1449 if (userExposed)
1450 { 1769 {
1451 dupe.UpdateParentIDs(); 1770 m_dupeInProgress = false;
1452 dupe.HasGroupChanged = true;
1453 dupe.AttachToBackup();
1454
1455 ScheduleGroupForFullUpdate();
1456 } 1771 }
1457
1458 return dupe; 1772 return dupe;
1459 } 1773 }
1460 1774
@@ -1645,13 +1959,40 @@ namespace OpenSim.Region.Framework.Scenes
1645 } 1959 }
1646 } 1960 }
1647 1961
1962 public void rotLookAt(Quaternion target, float strength, float damping)
1963 {
1964 SceneObjectPart rootpart = m_rootPart;
1965 if (rootpart != null)
1966 {
1967 if (IsAttachment)
1968 {
1969 /*
1970 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1971 if (avatar != null)
1972 {
1973 Rotate the Av?
1974 } */
1975 }
1976 else
1977 {
1978 if (rootpart.PhysActor != null)
1979 { // APID must be implemented in your physics system for this to function.
1980 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1981 rootpart.PhysActor.APIDStrength = strength;
1982 rootpart.PhysActor.APIDDamping = damping;
1983 rootpart.PhysActor.APIDActive = true;
1984 }
1985 }
1986 }
1987 }
1988
1648 public void stopLookAt() 1989 public void stopLookAt()
1649 { 1990 {
1650 SceneObjectPart rootpart = m_rootPart; 1991 SceneObjectPart rootpart = m_rootPart;
1651 if (rootpart != null) 1992 if (rootpart != null)
1652 { 1993 {
1653 if (rootpart.PhysActor != null) 1994 if (rootpart.PhysActor != null)
1654 { 1995 { // APID must be implemented in your physics system for this to function.
1655 rootpart.PhysActor.APIDActive = false; 1996 rootpart.PhysActor.APIDActive = false;
1656 } 1997 }
1657 } 1998 }
@@ -1717,6 +2058,8 @@ namespace OpenSim.Region.Framework.Scenes
1717 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2058 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1718 { 2059 {
1719 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2060 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2061 newPart.SetParent(this);
2062
1720 AddPart(newPart); 2063 AddPart(newPart);
1721 2064
1722 SetPartAsNonRoot(newPart); 2065 SetPartAsNonRoot(newPart);
@@ -1863,11 +2206,11 @@ namespace OpenSim.Region.Framework.Scenes
1863 /// Immediately send a full update for this scene object. 2206 /// Immediately send a full update for this scene object.
1864 /// </summary> 2207 /// </summary>
1865 public void SendGroupFullUpdate() 2208 public void SendGroupFullUpdate()
1866 { 2209 {
1867 if (IsDeleted) 2210 if (IsDeleted)
1868 return; 2211 return;
1869 2212
1870// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2213// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1871 2214
1872 RootPart.SendFullUpdateToAllClients(); 2215 RootPart.SendFullUpdateToAllClients();
1873 2216
@@ -2056,12 +2399,15 @@ namespace OpenSim.Region.Framework.Scenes
2056 part.LinkNum += objectGroup.PrimCount; 2399 part.LinkNum += objectGroup.PrimCount;
2057 } 2400 }
2058 } 2401 }
2402 }
2059 2403
2060 linkPart.LinkNum = 2; 2404 linkPart.LinkNum = 2;
2061 2405
2062 linkPart.SetParent(this); 2406 linkPart.SetParent(this);
2063 linkPart.CreateSelected = true; 2407 linkPart.CreateSelected = true;
2064 2408
2409 lock (m_parts.SyncRoot)
2410 {
2065 //if (linkPart.PhysActor != null) 2411 //if (linkPart.PhysActor != null)
2066 //{ 2412 //{
2067 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2413 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2218,6 +2564,8 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2564 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2565 public virtual void DetachFromBackup()
2220 { 2566 {
2567 m_scene.SceneGraph.FireDetachFromBackup(this);
2568
2221 if (m_isBackedUp) 2569 if (m_isBackedUp)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2570 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2571
@@ -2522,6 +2870,17 @@ namespace OpenSim.Region.Framework.Scenes
2522 } 2870 }
2523 } 2871 }
2524 2872
2873
2874
2875 /// <summary>
2876 /// Gets the number of parts
2877 /// </summary>
2878 /// <returns></returns>
2879 public int GetPartCount()
2880 {
2881 return Parts.Count();
2882 }
2883
2525 /// <summary> 2884 /// <summary>
2526 /// Update the texture entry for this part 2885 /// Update the texture entry for this part
2527 /// </summary> 2886 /// </summary>
@@ -2583,11 +2942,9 @@ namespace OpenSim.Region.Framework.Scenes
2583 scale.Y = m_scene.m_maxNonphys; 2942 scale.Y = m_scene.m_maxNonphys;
2584 if (scale.Z > m_scene.m_maxNonphys) 2943 if (scale.Z > m_scene.m_maxNonphys)
2585 scale.Z = m_scene.m_maxNonphys; 2944 scale.Z = m_scene.m_maxNonphys;
2586
2587 SceneObjectPart part = GetChildPart(localID); 2945 SceneObjectPart part = GetChildPart(localID);
2588 if (part != null) 2946 if (part != null)
2589 { 2947 {
2590 part.Resize(scale);
2591 if (part.PhysActor != null) 2948 if (part.PhysActor != null)
2592 { 2949 {
2593 if (part.PhysActor.IsPhysical) 2950 if (part.PhysActor.IsPhysical)
@@ -2602,7 +2959,7 @@ namespace OpenSim.Region.Framework.Scenes
2602 part.PhysActor.Size = scale; 2959 part.PhysActor.Size = scale;
2603 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2960 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2604 } 2961 }
2605 //if (part.UUID != m_rootPart.UUID) 2962 part.Resize(scale);
2606 2963
2607 HasGroupChanged = true; 2964 HasGroupChanged = true;
2608 ScheduleGroupForFullUpdate(); 2965 ScheduleGroupForFullUpdate();
@@ -2624,7 +2981,6 @@ namespace OpenSim.Region.Framework.Scenes
2624 SceneObjectPart part = GetChildPart(localID); 2981 SceneObjectPart part = GetChildPart(localID);
2625 if (part != null) 2982 if (part != null)
2626 { 2983 {
2627 part.IgnoreUndoUpdate = true;
2628 if (scale.X > m_scene.m_maxNonphys) 2984 if (scale.X > m_scene.m_maxNonphys)
2629 scale.X = m_scene.m_maxNonphys; 2985 scale.X = m_scene.m_maxNonphys;
2630 if (scale.Y > m_scene.m_maxNonphys) 2986 if (scale.Y > m_scene.m_maxNonphys)
@@ -2661,7 +3017,7 @@ namespace OpenSim.Region.Framework.Scenes
2661 3017
2662 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3018 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2663 { 3019 {
2664 if (oldSize.X * x > m_scene.m_maxPhys) 3020 if (oldSize.X*x > m_scene.m_maxPhys)
2665 { 3021 {
2666 f = m_scene.m_maxPhys / oldSize.X; 3022 f = m_scene.m_maxPhys / oldSize.X;
2667 a = f / x; 3023 a = f / x;
@@ -2669,7 +3025,7 @@ namespace OpenSim.Region.Framework.Scenes
2669 y *= a; 3025 y *= a;
2670 z *= a; 3026 z *= a;
2671 } 3027 }
2672 if (oldSize.Y * y > m_scene.m_maxPhys) 3028 if (oldSize.Y*y > m_scene.m_maxPhys)
2673 { 3029 {
2674 f = m_scene.m_maxPhys / oldSize.Y; 3030 f = m_scene.m_maxPhys / oldSize.Y;
2675 a = f / y; 3031 a = f / y;
@@ -2677,7 +3033,7 @@ namespace OpenSim.Region.Framework.Scenes
2677 y *= a; 3033 y *= a;
2678 z *= a; 3034 z *= a;
2679 } 3035 }
2680 if (oldSize.Z * z > m_scene.m_maxPhys) 3036 if (oldSize.Z*z > m_scene.m_maxPhys)
2681 { 3037 {
2682 f = m_scene.m_maxPhys / oldSize.Z; 3038 f = m_scene.m_maxPhys / oldSize.Z;
2683 a = f / z; 3039 a = f / z;
@@ -2688,7 +3044,7 @@ namespace OpenSim.Region.Framework.Scenes
2688 } 3044 }
2689 else 3045 else
2690 { 3046 {
2691 if (oldSize.X * x > m_scene.m_maxNonphys) 3047 if (oldSize.X*x > m_scene.m_maxNonphys)
2692 { 3048 {
2693 f = m_scene.m_maxNonphys / oldSize.X; 3049 f = m_scene.m_maxNonphys / oldSize.X;
2694 a = f / x; 3050 a = f / x;
@@ -2696,7 +3052,7 @@ namespace OpenSim.Region.Framework.Scenes
2696 y *= a; 3052 y *= a;
2697 z *= a; 3053 z *= a;
2698 } 3054 }
2699 if (oldSize.Y * y > m_scene.m_maxNonphys) 3055 if (oldSize.Y*y > m_scene.m_maxNonphys)
2700 { 3056 {
2701 f = m_scene.m_maxNonphys / oldSize.Y; 3057 f = m_scene.m_maxNonphys / oldSize.Y;
2702 a = f / y; 3058 a = f / y;
@@ -2704,7 +3060,7 @@ namespace OpenSim.Region.Framework.Scenes
2704 y *= a; 3060 y *= a;
2705 z *= a; 3061 z *= a;
2706 } 3062 }
2707 if (oldSize.Z * z > m_scene.m_maxNonphys) 3063 if (oldSize.Z*z > m_scene.m_maxNonphys)
2708 { 3064 {
2709 f = m_scene.m_maxNonphys / oldSize.Z; 3065 f = m_scene.m_maxNonphys / oldSize.Z;
2710 a = f / z; 3066 a = f / z;
@@ -2714,7 +3070,6 @@ namespace OpenSim.Region.Framework.Scenes
2714 } 3070 }
2715 } 3071 }
2716 obPart.IgnoreUndoUpdate = false; 3072 obPart.IgnoreUndoUpdate = false;
2717 obPart.StoreUndoState();
2718 } 3073 }
2719 } 3074 }
2720 } 3075 }
@@ -2722,8 +3077,13 @@ namespace OpenSim.Region.Framework.Scenes
2722 Vector3 prevScale = part.Scale; 3077 Vector3 prevScale = part.Scale;
2723 prevScale.X *= x; 3078 prevScale.X *= x;
2724 prevScale.Y *= y; 3079 prevScale.Y *= y;
2725 prevScale.Z *= z; 3080 prevScale.Z *= z;;
3081
3082 part.IgnoreUndoUpdate = false;
3083 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3084 part.IgnoreUndoUpdate = true;
2726 part.Resize(prevScale); 3085 part.Resize(prevScale);
3086 part.IgnoreUndoUpdate = false;
2727 3087
2728 parts = m_parts.GetArray(); 3088 parts = m_parts.GetArray();
2729 for (int i = 0; i < parts.Length; i++) 3089 for (int i = 0; i < parts.Length; i++)
@@ -2732,19 +3092,26 @@ namespace OpenSim.Region.Framework.Scenes
2732 obPart.IgnoreUndoUpdate = true; 3092 obPart.IgnoreUndoUpdate = true;
2733 if (obPart.UUID != m_rootPart.UUID) 3093 if (obPart.UUID != m_rootPart.UUID)
2734 { 3094 {
2735 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3095 if (obPart.UUID != m_rootPart.UUID)
2736 currentpos.X *= x; 3096 {
2737 currentpos.Y *= y; 3097 obPart.IgnoreUndoUpdate = false;
2738 currentpos.Z *= z; 3098 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2739 Vector3 newSize = new Vector3(obPart.Scale); 3099 obPart.IgnoreUndoUpdate = true;
2740 newSize.X *= x; 3100
2741 newSize.Y *= y; 3101 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2742 newSize.Z *= z; 3102 currentpos.X *= x;
2743 obPart.Resize(newSize); 3103 currentpos.Y *= y;
2744 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;
2745 } 3113 }
2746 obPart.IgnoreUndoUpdate = false; 3114 obPart.IgnoreUndoUpdate = false;
2747 obPart.StoreUndoState();
2748 } 3115 }
2749 3116
2750 if (part.PhysActor != null) 3117 if (part.PhysActor != null)
@@ -2754,7 +3121,6 @@ namespace OpenSim.Region.Framework.Scenes
2754 } 3121 }
2755 3122
2756 part.IgnoreUndoUpdate = false; 3123 part.IgnoreUndoUpdate = false;
2757 part.StoreUndoState();
2758 HasGroupChanged = true; 3124 HasGroupChanged = true;
2759 ScheduleGroupForTerseUpdate(); 3125 ScheduleGroupForTerseUpdate();
2760 } 3126 }
@@ -2770,14 +3136,11 @@ namespace OpenSim.Region.Framework.Scenes
2770 /// <param name="pos"></param> 3136 /// <param name="pos"></param>
2771 public void UpdateGroupPosition(Vector3 pos) 3137 public void UpdateGroupPosition(Vector3 pos)
2772 { 3138 {
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)) 3139 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2778 { 3140 {
2779 if (IsAttachment) 3141 if (IsAttachment)
2780 { 3142 {
3143 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2781 m_rootPart.AttachedPos = pos; 3144 m_rootPart.AttachedPos = pos;
2782 } 3145 }
2783 if (RootPart.GetStatusSandbox()) 3146 if (RootPart.GetStatusSandbox())
@@ -2811,7 +3174,7 @@ namespace OpenSim.Region.Framework.Scenes
2811 3174
2812 SceneObjectPart[] parts = m_parts.GetArray(); 3175 SceneObjectPart[] parts = m_parts.GetArray();
2813 for (int i = 0; i < parts.Length; i++) 3176 for (int i = 0; i < parts.Length; i++)
2814 parts[i].StoreUndoState(); 3177 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2815 3178
2816 if (part != null) 3179 if (part != null)
2817 { 3180 {
@@ -2836,7 +3199,7 @@ namespace OpenSim.Region.Framework.Scenes
2836 { 3199 {
2837 SceneObjectPart[] parts = m_parts.GetArray(); 3200 SceneObjectPart[] parts = m_parts.GetArray();
2838 for (int i = 0; i < parts.Length; i++) 3201 for (int i = 0; i < parts.Length; i++)
2839 parts[i].StoreUndoState(); 3202 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2840 3203
2841 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3204 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2842 Vector3 oldPos = 3205 Vector3 oldPos =
@@ -2857,10 +3220,27 @@ namespace OpenSim.Region.Framework.Scenes
2857 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3220 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2858 } 3221 }
2859 3222
2860 AbsolutePosition = newPos; 3223 //We have to set undoing here because otherwise an undo state will be saved
3224 if (!m_rootPart.Undoing)
3225 {
3226 m_rootPart.Undoing = true;
3227 AbsolutePosition = newPos;
3228 m_rootPart.Undoing = false;
3229 }
3230 else
3231 {
3232 AbsolutePosition = newPos;
3233 }
2861 3234
2862 HasGroupChanged = true; 3235 HasGroupChanged = true;
2863 ScheduleGroupForTerseUpdate(); 3236 if (m_rootPart.Undoing)
3237 {
3238 ScheduleGroupForFullUpdate();
3239 }
3240 else
3241 {
3242 ScheduleGroupForTerseUpdate();
3243 }
2864 } 3244 }
2865 3245
2866 public void OffsetForNewRegion(Vector3 offset) 3246 public void OffsetForNewRegion(Vector3 offset)
@@ -2880,7 +3260,7 @@ namespace OpenSim.Region.Framework.Scenes
2880 { 3260 {
2881 SceneObjectPart[] parts = m_parts.GetArray(); 3261 SceneObjectPart[] parts = m_parts.GetArray();
2882 for (int i = 0; i < parts.Length; i++) 3262 for (int i = 0; i < parts.Length; i++)
2883 parts[i].StoreUndoState(); 3263 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2884 3264
2885 m_rootPart.UpdateRotation(rot); 3265 m_rootPart.UpdateRotation(rot);
2886 3266
@@ -2904,7 +3284,7 @@ namespace OpenSim.Region.Framework.Scenes
2904 { 3284 {
2905 SceneObjectPart[] parts = m_parts.GetArray(); 3285 SceneObjectPart[] parts = m_parts.GetArray();
2906 for (int i = 0; i < parts.Length; i++) 3286 for (int i = 0; i < parts.Length; i++)
2907 parts[i].StoreUndoState(); 3287 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2908 3288
2909 m_rootPart.UpdateRotation(rot); 3289 m_rootPart.UpdateRotation(rot);
2910 3290
@@ -2929,10 +3309,9 @@ namespace OpenSim.Region.Framework.Scenes
2929 public void UpdateSingleRotation(Quaternion rot, uint localID) 3309 public void UpdateSingleRotation(Quaternion rot, uint localID)
2930 { 3310 {
2931 SceneObjectPart part = GetChildPart(localID); 3311 SceneObjectPart part = GetChildPart(localID);
2932
2933 SceneObjectPart[] parts = m_parts.GetArray(); 3312 SceneObjectPart[] parts = m_parts.GetArray();
2934 for (int i = 0; i < parts.Length; i++) 3313 for (int i = 0; i < parts.Length; i++)
2935 parts[i].StoreUndoState(); 3314 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2936 3315
2937 if (part != null) 3316 if (part != null)
2938 { 3317 {
@@ -2960,15 +3339,24 @@ namespace OpenSim.Region.Framework.Scenes
2960 if (part.UUID == m_rootPart.UUID) 3339 if (part.UUID == m_rootPart.UUID)
2961 { 3340 {
2962 UpdateRootRotation(rot); 3341 UpdateRootRotation(rot);
2963 AbsolutePosition = pos; 3342 if (!m_rootPart.Undoing)
3343 {
3344 m_rootPart.Undoing = true;
3345 AbsolutePosition = pos;
3346 m_rootPart.Undoing = false;
3347 }
3348 else
3349 {
3350 AbsolutePosition = pos;
3351 }
2964 } 3352 }
2965 else 3353 else
2966 { 3354 {
3355 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2967 part.IgnoreUndoUpdate = true; 3356 part.IgnoreUndoUpdate = true;
2968 part.UpdateRotation(rot); 3357 part.UpdateRotation(rot);
2969 part.OffsetPosition = pos; 3358 part.OffsetPosition = pos;
2970 part.IgnoreUndoUpdate = false; 3359 part.IgnoreUndoUpdate = false;
2971 part.StoreUndoState();
2972 } 3360 }
2973 } 3361 }
2974 } 3362 }
@@ -2982,7 +3370,13 @@ namespace OpenSim.Region.Framework.Scenes
2982 Quaternion axRot = rot; 3370 Quaternion axRot = rot;
2983 Quaternion oldParentRot = m_rootPart.RotationOffset; 3371 Quaternion oldParentRot = m_rootPart.RotationOffset;
2984 3372
2985 m_rootPart.StoreUndoState(); 3373 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3374 bool cancelUndo = false;
3375 if (!m_rootPart.Undoing)
3376 {
3377 m_rootPart.Undoing = true;
3378 cancelUndo = true;
3379 }
2986 m_rootPart.UpdateRotation(rot); 3380 m_rootPart.UpdateRotation(rot);
2987 if (m_rootPart.PhysActor != null) 3381 if (m_rootPart.PhysActor != null)
2988 { 3382 {
@@ -3006,17 +3400,12 @@ namespace OpenSim.Region.Framework.Scenes
3006 newRot *= Quaternion.Inverse(axRot); 3400 newRot *= Quaternion.Inverse(axRot);
3007 prim.RotationOffset = newRot; 3401 prim.RotationOffset = newRot;
3008 prim.ScheduleTerseUpdate(); 3402 prim.ScheduleTerseUpdate();
3403 prim.IgnoreUndoUpdate = false;
3009 } 3404 }
3010 } 3405 }
3011 3406 if (cancelUndo == true)
3012 for (int i = 0; i < parts.Length; i++)
3013 { 3407 {
3014 SceneObjectPart childpart = parts[i]; 3408 m_rootPart.Undoing = false;
3015 if (childpart != m_rootPart)
3016 {
3017 childpart.IgnoreUndoUpdate = false;
3018 childpart.StoreUndoState();
3019 }
3020 } 3409 }
3021 3410
3022 m_rootPart.ScheduleTerseUpdate(); 3411 m_rootPart.ScheduleTerseUpdate();
@@ -3242,7 +3631,6 @@ namespace OpenSim.Region.Framework.Scenes
3242 public float GetMass() 3631 public float GetMass()
3243 { 3632 {
3244 float retmass = 0f; 3633 float retmass = 0f;
3245
3246 SceneObjectPart[] parts = m_parts.GetArray(); 3634 SceneObjectPart[] parts = m_parts.GetArray();
3247 for (int i = 0; i < parts.Length; i++) 3635 for (int i = 0; i < parts.Length; i++)
3248 retmass += parts[i].GetMass(); 3636 retmass += parts[i].GetMass();
@@ -3358,6 +3746,14 @@ namespace OpenSim.Region.Framework.Scenes
3358 SetFromItemID(uuid); 3746 SetFromItemID(uuid);
3359 } 3747 }
3360 3748
3749 public void ResetOwnerChangeFlag()
3750 {
3751 ForEachPart(delegate(SceneObjectPart part)
3752 {
3753 part.ResetOwnerChangeFlag();
3754 });
3755 }
3756
3361 #endregion 3757 #endregion
3362 } 3758 }
3363} 3759}