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