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 4ec530e..f3964c2 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
@@ -522,6 +617,9 @@ namespace OpenSim.Region.Framework.Scenes
522 /// </summary> 617 /// </summary>
523 public virtual void AttachToBackup() 618 public virtual void AttachToBackup()
524 { 619 {
620 if (IsAttachment) return;
621 m_scene.SceneGraph.FireAttachToBackup(this);
622
525 if (InSceneBackup) 623 if (InSceneBackup)
526 { 624 {
527 //m_log.DebugFormat( 625 //m_log.DebugFormat(
@@ -637,9 +735,9 @@ namespace OpenSim.Region.Framework.Scenes
637 result.normal = inter.normal; 735 result.normal = inter.normal;
638 result.distance = inter.distance; 736 result.distance = inter.distance;
639 } 737 }
738
640 } 739 }
641 } 740 }
642
643 return result; 741 return result;
644 } 742 }
645 743
@@ -659,17 +757,19 @@ namespace OpenSim.Region.Framework.Scenes
659 minZ = 8192f; 757 minZ = 8192f;
660 758
661 SceneObjectPart[] parts = m_parts.GetArray(); 759 SceneObjectPart[] parts = m_parts.GetArray();
662 for (int i = 0; i < parts.Length; i++) 760 foreach (SceneObjectPart part in parts)
663 { 761 {
664 SceneObjectPart part = parts[i];
665
666 Vector3 worldPos = part.GetWorldPosition(); 762 Vector3 worldPos = part.GetWorldPosition();
667 Vector3 offset = worldPos - AbsolutePosition; 763 Vector3 offset = worldPos - AbsolutePosition;
668 Quaternion worldRot; 764 Quaternion worldRot;
669 if (part.ParentID == 0) 765 if (part.ParentID == 0)
766 {
670 worldRot = part.RotationOffset; 767 worldRot = part.RotationOffset;
768 }
671 else 769 else
770 {
672 worldRot = part.GetWorldRotation(); 771 worldRot = part.GetWorldRotation();
772 }
673 773
674 Vector3 frontTopLeft; 774 Vector3 frontTopLeft;
675 Vector3 frontTopRight; 775 Vector3 frontTopRight;
@@ -681,6 +781,8 @@ namespace OpenSim.Region.Framework.Scenes
681 Vector3 backBottomLeft; 781 Vector3 backBottomLeft;
682 Vector3 backBottomRight; 782 Vector3 backBottomRight;
683 783
784 // Vector3[] corners = new Vector3[8];
785
684 Vector3 orig = Vector3.Zero; 786 Vector3 orig = Vector3.Zero;
685 787
686 frontTopLeft.X = orig.X - (part.Scale.X / 2); 788 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -715,6 +817,38 @@ namespace OpenSim.Region.Framework.Scenes
715 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 817 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
716 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 818 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
717 819
820
821
822 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
823 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
824 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
825 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
826 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
827 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
828 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
829 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
830
831 //for (int i = 0; i < 8; i++)
832 //{
833 // corners[i] = corners[i] * worldRot;
834 // corners[i] += offset;
835
836 // if (corners[i].X > maxX)
837 // maxX = corners[i].X;
838 // if (corners[i].X < minX)
839 // minX = corners[i].X;
840
841 // if (corners[i].Y > maxY)
842 // maxY = corners[i].Y;
843 // if (corners[i].Y < minY)
844 // minY = corners[i].Y;
845
846 // if (corners[i].Z > maxZ)
847 // maxZ = corners[i].Y;
848 // if (corners[i].Z < minZ)
849 // minZ = corners[i].Z;
850 //}
851
718 frontTopLeft = frontTopLeft * worldRot; 852 frontTopLeft = frontTopLeft * worldRot;
719 frontTopRight = frontTopRight * worldRot; 853 frontTopRight = frontTopRight * worldRot;
720 frontBottomLeft = frontBottomLeft * worldRot; 854 frontBottomLeft = frontBottomLeft * worldRot;
@@ -736,6 +870,15 @@ namespace OpenSim.Region.Framework.Scenes
736 backTopLeft += offset; 870 backTopLeft += offset;
737 backTopRight += offset; 871 backTopRight += offset;
738 872
873 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
874 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
875 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
876 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
877 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
878 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
879 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
880 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
881
739 if (frontTopRight.X > maxX) 882 if (frontTopRight.X > maxX)
740 maxX = frontTopRight.X; 883 maxX = frontTopRight.X;
741 if (frontTopLeft.X > maxX) 884 if (frontTopLeft.X > maxX)
@@ -881,15 +1024,20 @@ namespace OpenSim.Region.Framework.Scenes
881 1024
882 public void SaveScriptedState(XmlTextWriter writer) 1025 public void SaveScriptedState(XmlTextWriter writer)
883 { 1026 {
1027 SaveScriptedState(writer, false);
1028 }
1029
1030 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1031 {
884 XmlDocument doc = new XmlDocument(); 1032 XmlDocument doc = new XmlDocument();
885 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1033 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
886 1034
887 SceneObjectPart[] parts = m_parts.GetArray(); 1035 SceneObjectPart[] parts = m_parts.GetArray();
888 for (int i = 0; i < parts.Length; i++) 1036 for (int i = 0; i < parts.Length; i++)
889 { 1037 {
890 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1038 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
891 foreach (KeyValuePair<UUID, string> kvp in pstates) 1039 foreach (KeyValuePair<UUID, string> kvp in pstates)
892 states.Add(kvp.Key, kvp.Value); 1040 states[kvp.Key] = kvp.Value;
893 } 1041 }
894 1042
895 if (states.Count > 0) 1043 if (states.Count > 0)
@@ -908,6 +1056,118 @@ namespace OpenSim.Region.Framework.Scenes
908 } 1056 }
909 } 1057 }
910 1058
1059 /// <summary>
1060 /// Add the avatar to this linkset (avatar is sat).
1061 /// </summary>
1062 /// <param name="agentID"></param>
1063 public void AddAvatar(UUID agentID)
1064 {
1065 ScenePresence presence;
1066 if (m_scene.TryGetScenePresence(agentID, out presence))
1067 {
1068 if (!m_linkedAvatars.Contains(presence))
1069 {
1070 m_linkedAvatars.Add(presence);
1071 }
1072 }
1073 }
1074
1075 /// <summary>
1076 /// Delete the avatar from this linkset (avatar is unsat).
1077 /// </summary>
1078 /// <param name="agentID"></param>
1079 public void DeleteAvatar(UUID agentID)
1080 {
1081 ScenePresence presence;
1082 if (m_scene.TryGetScenePresence(agentID, out presence))
1083 {
1084 if (m_linkedAvatars.Contains(presence))
1085 {
1086 m_linkedAvatars.Remove(presence);
1087 }
1088 }
1089 }
1090
1091 /// <summary>
1092 /// Returns the list of linked presences (avatars sat on this group)
1093 /// </summary>
1094 /// <param name="agentID"></param>
1095 public List<ScenePresence> GetLinkedAvatars()
1096 {
1097 return m_linkedAvatars;
1098 }
1099
1100 /// <summary>
1101 /// Attach this scene object to the given avatar.
1102 /// </summary>
1103 /// <param name="agentID"></param>
1104 /// <param name="attachmentpoint"></param>
1105 /// <param name="AttachOffset"></param>
1106 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1107 {
1108 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1109 if (avatar != null)
1110 {
1111 // don't attach attachments to child agents
1112 if (avatar.IsChildAgent) return;
1113
1114// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1115
1116 DetachFromBackup();
1117
1118 // Remove from database and parcel prim count
1119 m_scene.DeleteFromStorage(UUID);
1120 m_scene.EventManager.TriggerParcelPrimCountTainted();
1121
1122 m_rootPart.AttachedAvatar = agentID;
1123
1124 //Anakin Lohner bug #3839
1125 lock (m_parts)
1126 {
1127 foreach (SceneObjectPart p in m_parts.GetArray())
1128 {
1129 p.AttachedAvatar = agentID;
1130 }
1131 }
1132
1133 if (m_rootPart.PhysActor != null)
1134 {
1135 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1136 m_rootPart.PhysActor = null;
1137 }
1138
1139 AbsolutePosition = AttachOffset;
1140 m_rootPart.AttachedPos = AttachOffset;
1141 m_rootPart.IsAttachment = true;
1142
1143 m_rootPart.SetParentLocalId(avatar.LocalId);
1144 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1145
1146 avatar.AddAttachment(this);
1147
1148 if (!silent)
1149 {
1150 // Killing it here will cause the client to deselect it
1151 // It then reappears on the avatar, deselected
1152 // through the full update below
1153 //
1154 if (IsSelected)
1155 {
1156 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1157 }
1158
1159 IsSelected = false; // fudge....
1160 ScheduleGroupForFullUpdate();
1161 }
1162 }
1163 else
1164 {
1165 m_log.WarnFormat(
1166 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1167 UUID, agentID, Scene.RegionInfo.RegionName);
1168 }
1169 }
1170
911 public byte GetAttachmentPoint() 1171 public byte GetAttachmentPoint()
912 { 1172 {
913 return m_rootPart.Shape.State; 1173 return m_rootPart.Shape.State;
@@ -1034,7 +1294,10 @@ namespace OpenSim.Region.Framework.Scenes
1034 public void AddPart(SceneObjectPart part) 1294 public void AddPart(SceneObjectPart part)
1035 { 1295 {
1036 part.SetParent(this); 1296 part.SetParent(this);
1037 part.LinkNum = m_parts.Add(part.UUID, part); 1297 m_parts.Add(part.UUID, part);
1298
1299 part.LinkNum = m_parts.Count;
1300
1038 if (part.LinkNum == 2 && RootPart != null) 1301 if (part.LinkNum == 2 && RootPart != null)
1039 RootPart.LinkNum = 1; 1302 RootPart.LinkNum = 1;
1040 } 1303 }
@@ -1118,7 +1381,7 @@ namespace OpenSim.Region.Framework.Scenes
1118 1381
1119 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1382 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1120 { 1383 {
1121 part.StoreUndoState(); 1384 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1122 part.OnGrab(offsetPos, remoteClient); 1385 part.OnGrab(offsetPos, remoteClient);
1123 } 1386 }
1124 1387
@@ -1138,6 +1401,11 @@ namespace OpenSim.Region.Framework.Scenes
1138 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1401 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1139 public void DeleteGroupFromScene(bool silent) 1402 public void DeleteGroupFromScene(bool silent)
1140 { 1403 {
1404 // We need to keep track of this state in case this group is still queued for backup.
1405 m_isDeleted = true;
1406
1407 DetachFromBackup();
1408
1141 SceneObjectPart[] parts = m_parts.GetArray(); 1409 SceneObjectPart[] parts = m_parts.GetArray();
1142 for (int i = 0; i < parts.Length; i++) 1410 for (int i = 0; i < parts.Length; i++)
1143 { 1411 {
@@ -1149,13 +1417,11 @@ namespace OpenSim.Region.Framework.Scenes
1149 avatar.StandUp(); 1417 avatar.StandUp();
1150 1418
1151 if (!silent) 1419 if (!silent)
1152 {
1153 part.UpdateFlag = 0; 1420 part.UpdateFlag = 0;
1154 if (part == m_rootPart)
1155 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1156 }
1157 }); 1421 });
1158 } 1422 }
1423
1424
1159 } 1425 }
1160 1426
1161 public void AddScriptLPS(int count) 1427 public void AddScriptLPS(int count)
@@ -1252,7 +1518,12 @@ namespace OpenSim.Region.Framework.Scenes
1252 1518
1253 public void SetOwnerId(UUID userId) 1519 public void SetOwnerId(UUID userId)
1254 { 1520 {
1255 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1521 ForEachPart(delegate(SceneObjectPart part)
1522 {
1523
1524 part.OwnerID = userId;
1525
1526 });
1256 } 1527 }
1257 1528
1258 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1529 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1284,11 +1555,17 @@ namespace OpenSim.Region.Framework.Scenes
1284 return; 1555 return;
1285 } 1556 }
1286 1557
1558 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1559 return;
1560
1287 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1561 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1288 // any exception propogate upwards. 1562 // any exception propogate upwards.
1289 try 1563 try
1290 { 1564 {
1291 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1565 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1566 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1567 m_scene.LoadingPrims) // Land may not be valid yet
1568
1292 { 1569 {
1293 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1570 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1294 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1571 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1313,6 +1590,7 @@ namespace OpenSim.Region.Framework.Scenes
1313 } 1590 }
1314 } 1591 }
1315 } 1592 }
1593
1316 } 1594 }
1317 1595
1318 if (HasGroupChanged) 1596 if (HasGroupChanged)
@@ -1320,6 +1598,20 @@ namespace OpenSim.Region.Framework.Scenes
1320 // don't backup while it's selected or you're asking for changes mid stream. 1598 // don't backup while it's selected or you're asking for changes mid stream.
1321 if (isTimeToPersist() || forcedBackup) 1599 if (isTimeToPersist() || forcedBackup)
1322 { 1600 {
1601 if (m_rootPart.PhysActor != null &&
1602 (!m_rootPart.PhysActor.IsPhysical))
1603 {
1604 // Possible ghost prim
1605 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1606 {
1607 foreach (SceneObjectPart part in m_parts.GetArray())
1608 {
1609 // Re-set physics actor positions and
1610 // orientations
1611 part.GroupPosition = m_rootPart.GroupPosition;
1612 }
1613 }
1614 }
1323// m_log.DebugFormat( 1615// m_log.DebugFormat(
1324// "[SCENE]: Storing {0}, {1} in {2}", 1616// "[SCENE]: Storing {0}, {1} in {2}",
1325// Name, UUID, m_scene.RegionInfo.RegionName); 1617// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1382,81 +1674,89 @@ namespace OpenSim.Region.Framework.Scenes
1382 /// <returns></returns> 1674 /// <returns></returns>
1383 public SceneObjectGroup Copy(bool userExposed) 1675 public SceneObjectGroup Copy(bool userExposed)
1384 { 1676 {
1385 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1677 SceneObjectGroup dupe;
1386 dupe.m_isBackedUp = false; 1678 try
1387 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1679 {
1388 1680 m_dupeInProgress = true;
1389 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1681 dupe = (SceneObjectGroup)MemberwiseClone();
1390 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1682 dupe.m_isBackedUp = false;
1391 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1683 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1392 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1393 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1394 // then restore it's attachment state
1395
1396 // This is only necessary when userExposed is false!
1397 1684
1398 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1685 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1399 1686 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1400 if (!userExposed) 1687 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1401 dupe.RootPart.IsAttachment = true; 1688 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1689 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1690 // then restore it's attachment state
1402 1691
1403 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1692 // This is only necessary when userExposed is false!
1404 1693
1405 if (!userExposed) 1694 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1406 {
1407 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1408 }
1409 1695
1410 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1696 if (!userExposed)
1411 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1697 dupe.RootPart.IsAttachment = true;
1412 1698
1413 if (userExposed) 1699 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1414 dupe.m_rootPart.TrimPermissions();
1415 1700
1416 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1701 if (!userExposed)
1417
1418 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1419 { 1702 {
1420 return p1.LinkNum.CompareTo(p2.LinkNum); 1703 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1421 } 1704 }
1422 );
1423 1705
1424 foreach (SceneObjectPart part in partList) 1706 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1425 { 1707 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1426 if (part.UUID != m_rootPart.UUID) 1708
1709 if (userExposed)
1710 dupe.m_rootPart.TrimPermissions();
1711
1712 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1713
1714 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1715 {
1716 return p1.LinkNum.CompareTo(p2.LinkNum);
1717 }
1718 );
1719
1720 foreach (SceneObjectPart part in partList)
1427 { 1721 {
1428 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1722 if (part.UUID != m_rootPart.UUID)
1429 newPart.LinkNum = part.LinkNum; 1723 {
1430 } 1724 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1431 1725
1432 // Need to duplicate the physics actor as well 1726 newPart.LinkNum = part.LinkNum;
1433 if (part.PhysActor != null && userExposed) 1727 }
1728
1729 // Need to duplicate the physics actor as well
1730 if (part.PhysActor != null && userExposed)
1731 {
1732 PrimitiveBaseShape pbs = part.Shape;
1733
1734 part.PhysActor
1735 = m_scene.PhysicsScene.AddPrimShape(
1736 string.Format("{0}/{1}", part.Name, part.UUID),
1737 pbs,
1738 part.AbsolutePosition,
1739 part.Scale,
1740 part.RotationOffset,
1741 part.PhysActor.IsPhysical);
1742
1743 part.PhysActor.LocalID = part.LocalId;
1744 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1745 }
1746 }
1747 if (userExposed)
1434 { 1748 {
1435 PrimitiveBaseShape pbs = part.Shape; 1749 dupe.UpdateParentIDs();
1436 1750 dupe.HasGroupChanged = true;
1437 part.PhysActor 1751 dupe.AttachToBackup();
1438 = m_scene.PhysicsScene.AddPrimShape( 1752
1439 string.Format("{0}/{1}", part.Name, part.UUID), 1753 ScheduleGroupForFullUpdate();
1440 pbs,
1441 part.AbsolutePosition,
1442 part.Scale,
1443 part.RotationOffset,
1444 part.PhysActor.IsPhysical);
1445
1446 part.PhysActor.LocalID = part.LocalId;
1447 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1448 } 1754 }
1449 } 1755 }
1450 1756 finally
1451 if (userExposed)
1452 { 1757 {
1453 dupe.UpdateParentIDs(); 1758 m_dupeInProgress = false;
1454 dupe.HasGroupChanged = true;
1455 dupe.AttachToBackup();
1456
1457 ScheduleGroupForFullUpdate();
1458 } 1759 }
1459
1460 return dupe; 1760 return dupe;
1461 } 1761 }
1462 1762
@@ -1647,13 +1947,40 @@ namespace OpenSim.Region.Framework.Scenes
1647 } 1947 }
1648 } 1948 }
1649 1949
1950 public void rotLookAt(Quaternion target, float strength, float damping)
1951 {
1952 SceneObjectPart rootpart = m_rootPart;
1953 if (rootpart != null)
1954 {
1955 if (IsAttachment)
1956 {
1957 /*
1958 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1959 if (avatar != null)
1960 {
1961 Rotate the Av?
1962 } */
1963 }
1964 else
1965 {
1966 if (rootpart.PhysActor != null)
1967 { // APID must be implemented in your physics system for this to function.
1968 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1969 rootpart.PhysActor.APIDStrength = strength;
1970 rootpart.PhysActor.APIDDamping = damping;
1971 rootpart.PhysActor.APIDActive = true;
1972 }
1973 }
1974 }
1975 }
1976
1650 public void stopLookAt() 1977 public void stopLookAt()
1651 { 1978 {
1652 SceneObjectPart rootpart = m_rootPart; 1979 SceneObjectPart rootpart = m_rootPart;
1653 if (rootpart != null) 1980 if (rootpart != null)
1654 { 1981 {
1655 if (rootpart.PhysActor != null) 1982 if (rootpart.PhysActor != null)
1656 { 1983 { // APID must be implemented in your physics system for this to function.
1657 rootpart.PhysActor.APIDActive = false; 1984 rootpart.PhysActor.APIDActive = false;
1658 } 1985 }
1659 } 1986 }
@@ -1719,6 +2046,8 @@ namespace OpenSim.Region.Framework.Scenes
1719 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2046 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1720 { 2047 {
1721 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2048 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2049 newPart.SetParent(this);
2050
1722 AddPart(newPart); 2051 AddPart(newPart);
1723 2052
1724 SetPartAsNonRoot(newPart); 2053 SetPartAsNonRoot(newPart);
@@ -1865,11 +2194,11 @@ namespace OpenSim.Region.Framework.Scenes
1865 /// Immediately send a full update for this scene object. 2194 /// Immediately send a full update for this scene object.
1866 /// </summary> 2195 /// </summary>
1867 public void SendGroupFullUpdate() 2196 public void SendGroupFullUpdate()
1868 { 2197 {
1869 if (IsDeleted) 2198 if (IsDeleted)
1870 return; 2199 return;
1871 2200
1872// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2201// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1873 2202
1874 RootPart.SendFullUpdateToAllClients(); 2203 RootPart.SendFullUpdateToAllClients();
1875 2204
@@ -2058,12 +2387,15 @@ namespace OpenSim.Region.Framework.Scenes
2058 part.LinkNum += objectGroup.PrimCount; 2387 part.LinkNum += objectGroup.PrimCount;
2059 } 2388 }
2060 } 2389 }
2390 }
2061 2391
2062 linkPart.LinkNum = 2; 2392 linkPart.LinkNum = 2;
2063 2393
2064 linkPart.SetParent(this); 2394 linkPart.SetParent(this);
2065 linkPart.CreateSelected = true; 2395 linkPart.CreateSelected = true;
2066 2396
2397 lock (m_parts.SyncRoot)
2398 {
2067 //if (linkPart.PhysActor != null) 2399 //if (linkPart.PhysActor != null)
2068 //{ 2400 //{
2069 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2401 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2220,6 +2552,8 @@ namespace OpenSim.Region.Framework.Scenes
2220 /// <param name="objectGroup"></param> 2552 /// <param name="objectGroup"></param>
2221 public virtual void DetachFromBackup() 2553 public virtual void DetachFromBackup()
2222 { 2554 {
2555 m_scene.SceneGraph.FireDetachFromBackup(this);
2556
2223 if (m_isBackedUp) 2557 if (m_isBackedUp)
2224 m_scene.EventManager.OnBackup -= ProcessBackup; 2558 m_scene.EventManager.OnBackup -= ProcessBackup;
2225 2559
@@ -2524,6 +2858,17 @@ namespace OpenSim.Region.Framework.Scenes
2524 } 2858 }
2525 } 2859 }
2526 2860
2861
2862
2863 /// <summary>
2864 /// Gets the number of parts
2865 /// </summary>
2866 /// <returns></returns>
2867 public int GetPartCount()
2868 {
2869 return Parts.Count();
2870 }
2871
2527 /// <summary> 2872 /// <summary>
2528 /// Update the texture entry for this part 2873 /// Update the texture entry for this part
2529 /// </summary> 2874 /// </summary>
@@ -2585,11 +2930,9 @@ namespace OpenSim.Region.Framework.Scenes
2585 scale.Y = m_scene.m_maxNonphys; 2930 scale.Y = m_scene.m_maxNonphys;
2586 if (scale.Z > m_scene.m_maxNonphys) 2931 if (scale.Z > m_scene.m_maxNonphys)
2587 scale.Z = m_scene.m_maxNonphys; 2932 scale.Z = m_scene.m_maxNonphys;
2588
2589 SceneObjectPart part = GetChildPart(localID); 2933 SceneObjectPart part = GetChildPart(localID);
2590 if (part != null) 2934 if (part != null)
2591 { 2935 {
2592 part.Resize(scale);
2593 if (part.PhysActor != null) 2936 if (part.PhysActor != null)
2594 { 2937 {
2595 if (part.PhysActor.IsPhysical) 2938 if (part.PhysActor.IsPhysical)
@@ -2604,7 +2947,7 @@ namespace OpenSim.Region.Framework.Scenes
2604 part.PhysActor.Size = scale; 2947 part.PhysActor.Size = scale;
2605 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2948 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2606 } 2949 }
2607 //if (part.UUID != m_rootPart.UUID) 2950 part.Resize(scale);
2608 2951
2609 HasGroupChanged = true; 2952 HasGroupChanged = true;
2610 part.TriggerScriptChangedEvent(Changed.SCALE); 2953 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2627,7 +2970,6 @@ namespace OpenSim.Region.Framework.Scenes
2627 SceneObjectPart part = GetChildPart(localID); 2970 SceneObjectPart part = GetChildPart(localID);
2628 if (part != null) 2971 if (part != null)
2629 { 2972 {
2630 part.IgnoreUndoUpdate = true;
2631 if (scale.X > m_scene.m_maxNonphys) 2973 if (scale.X > m_scene.m_maxNonphys)
2632 scale.X = m_scene.m_maxNonphys; 2974 scale.X = m_scene.m_maxNonphys;
2633 if (scale.Y > m_scene.m_maxNonphys) 2975 if (scale.Y > m_scene.m_maxNonphys)
@@ -2664,7 +3006,7 @@ namespace OpenSim.Region.Framework.Scenes
2664 3006
2665 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3007 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2666 { 3008 {
2667 if (oldSize.X * x > m_scene.m_maxPhys) 3009 if (oldSize.X*x > m_scene.m_maxPhys)
2668 { 3010 {
2669 f = m_scene.m_maxPhys / oldSize.X; 3011 f = m_scene.m_maxPhys / oldSize.X;
2670 a = f / x; 3012 a = f / x;
@@ -2672,7 +3014,7 @@ namespace OpenSim.Region.Framework.Scenes
2672 y *= a; 3014 y *= a;
2673 z *= a; 3015 z *= a;
2674 } 3016 }
2675 if (oldSize.Y * y > m_scene.m_maxPhys) 3017 if (oldSize.Y*y > m_scene.m_maxPhys)
2676 { 3018 {
2677 f = m_scene.m_maxPhys / oldSize.Y; 3019 f = m_scene.m_maxPhys / oldSize.Y;
2678 a = f / y; 3020 a = f / y;
@@ -2680,7 +3022,7 @@ namespace OpenSim.Region.Framework.Scenes
2680 y *= a; 3022 y *= a;
2681 z *= a; 3023 z *= a;
2682 } 3024 }
2683 if (oldSize.Z * z > m_scene.m_maxPhys) 3025 if (oldSize.Z*z > m_scene.m_maxPhys)
2684 { 3026 {
2685 f = m_scene.m_maxPhys / oldSize.Z; 3027 f = m_scene.m_maxPhys / oldSize.Z;
2686 a = f / z; 3028 a = f / z;
@@ -2691,7 +3033,7 @@ namespace OpenSim.Region.Framework.Scenes
2691 } 3033 }
2692 else 3034 else
2693 { 3035 {
2694 if (oldSize.X * x > m_scene.m_maxNonphys) 3036 if (oldSize.X*x > m_scene.m_maxNonphys)
2695 { 3037 {
2696 f = m_scene.m_maxNonphys / oldSize.X; 3038 f = m_scene.m_maxNonphys / oldSize.X;
2697 a = f / x; 3039 a = f / x;
@@ -2699,7 +3041,7 @@ namespace OpenSim.Region.Framework.Scenes
2699 y *= a; 3041 y *= a;
2700 z *= a; 3042 z *= a;
2701 } 3043 }
2702 if (oldSize.Y * y > m_scene.m_maxNonphys) 3044 if (oldSize.Y*y > m_scene.m_maxNonphys)
2703 { 3045 {
2704 f = m_scene.m_maxNonphys / oldSize.Y; 3046 f = m_scene.m_maxNonphys / oldSize.Y;
2705 a = f / y; 3047 a = f / y;
@@ -2707,7 +3049,7 @@ namespace OpenSim.Region.Framework.Scenes
2707 y *= a; 3049 y *= a;
2708 z *= a; 3050 z *= a;
2709 } 3051 }
2710 if (oldSize.Z * z > m_scene.m_maxNonphys) 3052 if (oldSize.Z*z > m_scene.m_maxNonphys)
2711 { 3053 {
2712 f = m_scene.m_maxNonphys / oldSize.Z; 3054 f = m_scene.m_maxNonphys / oldSize.Z;
2713 a = f / z; 3055 a = f / z;
@@ -2717,7 +3059,6 @@ namespace OpenSim.Region.Framework.Scenes
2717 } 3059 }
2718 } 3060 }
2719 obPart.IgnoreUndoUpdate = false; 3061 obPart.IgnoreUndoUpdate = false;
2720 obPart.StoreUndoState();
2721 } 3062 }
2722 } 3063 }
2723 } 3064 }
@@ -2725,8 +3066,13 @@ namespace OpenSim.Region.Framework.Scenes
2725 Vector3 prevScale = part.Scale; 3066 Vector3 prevScale = part.Scale;
2726 prevScale.X *= x; 3067 prevScale.X *= x;
2727 prevScale.Y *= y; 3068 prevScale.Y *= y;
2728 prevScale.Z *= z; 3069 prevScale.Z *= z;;
3070
3071 part.IgnoreUndoUpdate = false;
3072 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3073 part.IgnoreUndoUpdate = true;
2729 part.Resize(prevScale); 3074 part.Resize(prevScale);
3075 part.IgnoreUndoUpdate = false;
2730 3076
2731 parts = m_parts.GetArray(); 3077 parts = m_parts.GetArray();
2732 for (int i = 0; i < parts.Length; i++) 3078 for (int i = 0; i < parts.Length; i++)
@@ -2735,19 +3081,26 @@ namespace OpenSim.Region.Framework.Scenes
2735 obPart.IgnoreUndoUpdate = true; 3081 obPart.IgnoreUndoUpdate = true;
2736 if (obPart.UUID != m_rootPart.UUID) 3082 if (obPart.UUID != m_rootPart.UUID)
2737 { 3083 {
2738 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3084 if (obPart.UUID != m_rootPart.UUID)
2739 currentpos.X *= x; 3085 {
2740 currentpos.Y *= y; 3086 obPart.IgnoreUndoUpdate = false;
2741 currentpos.Z *= z; 3087 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2742 Vector3 newSize = new Vector3(obPart.Scale); 3088 obPart.IgnoreUndoUpdate = true;
2743 newSize.X *= x; 3089
2744 newSize.Y *= y; 3090 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2745 newSize.Z *= z; 3091 currentpos.X *= x;
2746 obPart.Resize(newSize); 3092 currentpos.Y *= y;
2747 obPart.UpdateOffSet(currentpos); 3093 currentpos.Z *= z;
3094 Vector3 newSize = new Vector3(obPart.Scale);
3095 newSize.X *= x;
3096 newSize.Y *= y;
3097 newSize.Z *= z;
3098 obPart.Resize(newSize);
3099 obPart.UpdateOffSet(currentpos);
3100 }
3101 obPart.IgnoreUndoUpdate = false;
2748 } 3102 }
2749 obPart.IgnoreUndoUpdate = false; 3103 obPart.IgnoreUndoUpdate = false;
2750 obPart.StoreUndoState();
2751 } 3104 }
2752 3105
2753 if (part.PhysActor != null) 3106 if (part.PhysActor != null)
@@ -2757,7 +3110,6 @@ namespace OpenSim.Region.Framework.Scenes
2757 } 3110 }
2758 3111
2759 part.IgnoreUndoUpdate = false; 3112 part.IgnoreUndoUpdate = false;
2760 part.StoreUndoState();
2761 HasGroupChanged = true; 3113 HasGroupChanged = true;
2762 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3114 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2763 ScheduleGroupForTerseUpdate(); 3115 ScheduleGroupForTerseUpdate();
@@ -2774,14 +3126,11 @@ namespace OpenSim.Region.Framework.Scenes
2774 /// <param name="pos"></param> 3126 /// <param name="pos"></param>
2775 public void UpdateGroupPosition(Vector3 pos) 3127 public void UpdateGroupPosition(Vector3 pos)
2776 { 3128 {
2777 SceneObjectPart[] parts = m_parts.GetArray();
2778 for (int i = 0; i < parts.Length; i++)
2779 parts[i].StoreUndoState();
2780
2781 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3129 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2782 { 3130 {
2783 if (IsAttachment) 3131 if (IsAttachment)
2784 { 3132 {
3133 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2785 m_rootPart.AttachedPos = pos; 3134 m_rootPart.AttachedPos = pos;
2786 } 3135 }
2787 if (RootPart.GetStatusSandbox()) 3136 if (RootPart.GetStatusSandbox())
@@ -2815,7 +3164,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 3164
2816 SceneObjectPart[] parts = m_parts.GetArray(); 3165 SceneObjectPart[] parts = m_parts.GetArray();
2817 for (int i = 0; i < parts.Length; i++) 3166 for (int i = 0; i < parts.Length; i++)
2818 parts[i].StoreUndoState(); 3167 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2819 3168
2820 if (part != null) 3169 if (part != null)
2821 { 3170 {
@@ -2840,7 +3189,7 @@ namespace OpenSim.Region.Framework.Scenes
2840 { 3189 {
2841 SceneObjectPart[] parts = m_parts.GetArray(); 3190 SceneObjectPart[] parts = m_parts.GetArray();
2842 for (int i = 0; i < parts.Length; i++) 3191 for (int i = 0; i < parts.Length; i++)
2843 parts[i].StoreUndoState(); 3192 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2844 3193
2845 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3194 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2846 Vector3 oldPos = 3195 Vector3 oldPos =
@@ -2861,10 +3210,27 @@ namespace OpenSim.Region.Framework.Scenes
2861 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3210 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2862 } 3211 }
2863 3212
2864 AbsolutePosition = newPos; 3213 //We have to set undoing here because otherwise an undo state will be saved
3214 if (!m_rootPart.Undoing)
3215 {
3216 m_rootPart.Undoing = true;
3217 AbsolutePosition = newPos;
3218 m_rootPart.Undoing = false;
3219 }
3220 else
3221 {
3222 AbsolutePosition = newPos;
3223 }
2865 3224
2866 HasGroupChanged = true; 3225 HasGroupChanged = true;
2867 ScheduleGroupForTerseUpdate(); 3226 if (m_rootPart.Undoing)
3227 {
3228 ScheduleGroupForFullUpdate();
3229 }
3230 else
3231 {
3232 ScheduleGroupForTerseUpdate();
3233 }
2868 } 3234 }
2869 3235
2870 public void OffsetForNewRegion(Vector3 offset) 3236 public void OffsetForNewRegion(Vector3 offset)
@@ -2884,7 +3250,7 @@ namespace OpenSim.Region.Framework.Scenes
2884 { 3250 {
2885 SceneObjectPart[] parts = m_parts.GetArray(); 3251 SceneObjectPart[] parts = m_parts.GetArray();
2886 for (int i = 0; i < parts.Length; i++) 3252 for (int i = 0; i < parts.Length; i++)
2887 parts[i].StoreUndoState(); 3253 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2888 3254
2889 m_rootPart.UpdateRotation(rot); 3255 m_rootPart.UpdateRotation(rot);
2890 3256
@@ -2908,7 +3274,7 @@ namespace OpenSim.Region.Framework.Scenes
2908 { 3274 {
2909 SceneObjectPart[] parts = m_parts.GetArray(); 3275 SceneObjectPart[] parts = m_parts.GetArray();
2910 for (int i = 0; i < parts.Length; i++) 3276 for (int i = 0; i < parts.Length; i++)
2911 parts[i].StoreUndoState(); 3277 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2912 3278
2913 m_rootPart.UpdateRotation(rot); 3279 m_rootPart.UpdateRotation(rot);
2914 3280
@@ -2933,10 +3299,9 @@ namespace OpenSim.Region.Framework.Scenes
2933 public void UpdateSingleRotation(Quaternion rot, uint localID) 3299 public void UpdateSingleRotation(Quaternion rot, uint localID)
2934 { 3300 {
2935 SceneObjectPart part = GetChildPart(localID); 3301 SceneObjectPart part = GetChildPart(localID);
2936
2937 SceneObjectPart[] parts = m_parts.GetArray(); 3302 SceneObjectPart[] parts = m_parts.GetArray();
2938 for (int i = 0; i < parts.Length; i++) 3303 for (int i = 0; i < parts.Length; i++)
2939 parts[i].StoreUndoState(); 3304 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2940 3305
2941 if (part != null) 3306 if (part != null)
2942 { 3307 {
@@ -2964,15 +3329,24 @@ namespace OpenSim.Region.Framework.Scenes
2964 if (part.UUID == m_rootPart.UUID) 3329 if (part.UUID == m_rootPart.UUID)
2965 { 3330 {
2966 UpdateRootRotation(rot); 3331 UpdateRootRotation(rot);
2967 AbsolutePosition = pos; 3332 if (!m_rootPart.Undoing)
3333 {
3334 m_rootPart.Undoing = true;
3335 AbsolutePosition = pos;
3336 m_rootPart.Undoing = false;
3337 }
3338 else
3339 {
3340 AbsolutePosition = pos;
3341 }
2968 } 3342 }
2969 else 3343 else
2970 { 3344 {
3345 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2971 part.IgnoreUndoUpdate = true; 3346 part.IgnoreUndoUpdate = true;
2972 part.UpdateRotation(rot); 3347 part.UpdateRotation(rot);
2973 part.OffsetPosition = pos; 3348 part.OffsetPosition = pos;
2974 part.IgnoreUndoUpdate = false; 3349 part.IgnoreUndoUpdate = false;
2975 part.StoreUndoState();
2976 } 3350 }
2977 } 3351 }
2978 } 3352 }
@@ -2986,7 +3360,13 @@ namespace OpenSim.Region.Framework.Scenes
2986 Quaternion axRot = rot; 3360 Quaternion axRot = rot;
2987 Quaternion oldParentRot = m_rootPart.RotationOffset; 3361 Quaternion oldParentRot = m_rootPart.RotationOffset;
2988 3362
2989 m_rootPart.StoreUndoState(); 3363 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3364 bool cancelUndo = false;
3365 if (!m_rootPart.Undoing)
3366 {
3367 m_rootPart.Undoing = true;
3368 cancelUndo = true;
3369 }
2990 m_rootPart.UpdateRotation(rot); 3370 m_rootPart.UpdateRotation(rot);
2991 if (m_rootPart.PhysActor != null) 3371 if (m_rootPart.PhysActor != null)
2992 { 3372 {
@@ -3010,17 +3390,12 @@ namespace OpenSim.Region.Framework.Scenes
3010 newRot *= Quaternion.Inverse(axRot); 3390 newRot *= Quaternion.Inverse(axRot);
3011 prim.RotationOffset = newRot; 3391 prim.RotationOffset = newRot;
3012 prim.ScheduleTerseUpdate(); 3392 prim.ScheduleTerseUpdate();
3393 prim.IgnoreUndoUpdate = false;
3013 } 3394 }
3014 } 3395 }
3015 3396 if (cancelUndo == true)
3016 for (int i = 0; i < parts.Length; i++)
3017 { 3397 {
3018 SceneObjectPart childpart = parts[i]; 3398 m_rootPart.Undoing = false;
3019 if (childpart != m_rootPart)
3020 {
3021 childpart.IgnoreUndoUpdate = false;
3022 childpart.StoreUndoState();
3023 }
3024 } 3399 }
3025 3400
3026 m_rootPart.ScheduleTerseUpdate(); 3401 m_rootPart.ScheduleTerseUpdate();
@@ -3246,7 +3621,6 @@ namespace OpenSim.Region.Framework.Scenes
3246 public float GetMass() 3621 public float GetMass()
3247 { 3622 {
3248 float retmass = 0f; 3623 float retmass = 0f;
3249
3250 SceneObjectPart[] parts = m_parts.GetArray(); 3624 SceneObjectPart[] parts = m_parts.GetArray();
3251 for (int i = 0; i < parts.Length; i++) 3625 for (int i = 0; i < parts.Length; i++)
3252 retmass += parts[i].GetMass(); 3626 retmass += parts[i].GetMass();
@@ -3362,6 +3736,14 @@ namespace OpenSim.Region.Framework.Scenes
3362 SetFromItemID(uuid); 3736 SetFromItemID(uuid);
3363 } 3737 }
3364 3738
3739 public void ResetOwnerChangeFlag()
3740 {
3741 ForEachPart(delegate(SceneObjectPart part)
3742 {
3743 part.ResetOwnerChangeFlag();
3744 });
3745 }
3746
3365 #endregion 3747 #endregion
3366 } 3748 }
3367} 3749}