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.cs661
1 files changed, 530 insertions, 131 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 5513584..a00a7c4 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -105,8 +106,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 106 /// since the group's last persistent backup
106 /// </summary> 107 /// </summary>
107 private bool m_hasGroupChanged = false; 108 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 109 private long timeFirstChanged = 0;
109 private long timeLastChanged; 110 private long timeLastChanged = 0;
111 private long m_maxPersistTime = 0;
112 private long m_minPersistTime = 0;
113 private Random m_rand;
114 private bool m_suspendUpdates;
115 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
116
117 public bool areUpdatesSuspended
118 {
119 get
120 {
121 return m_suspendUpdates;
122 }
123 set
124 {
125 m_suspendUpdates = value;
126 if (!value)
127 {
128 QueueForUpdateCheck();
129 }
130 }
131 }
110 132
111 public bool HasGroupChanged 133 public bool HasGroupChanged
112 { 134 {
@@ -114,9 +136,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 136 {
115 if (value) 137 if (value)
116 { 138 {
139 if (m_isBackedUp)
140 {
141 m_scene.SceneGraph.FireChangeBackup(this);
142 }
117 timeLastChanged = DateTime.Now.Ticks; 143 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 144 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 145 timeFirstChanged = DateTime.Now.Ticks;
146 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
147 {
148 if (m_rand == null)
149 {
150 byte[] val = new byte[16];
151 m_rootPart.UUID.ToBytes(val, 0);
152 m_rand = new Random(BitConverter.ToInt32(val, 0));
153 }
154
155 if (m_scene.GetRootAgentCount() == 0)
156 {
157 //If the region is empty, this change has been made by an automated process
158 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
159
160 float factor = 1.5f + (float)(m_rand.NextDouble());
161 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
162 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
163 }
164 else
165 {
166 //If the region is not empty, we want to obey the minimum and maximum persist times
167 //but add a random factor so we stagger the object persistance a little
168 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
169 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
170 }
171 }
120 } 172 }
121 m_hasGroupChanged = value; 173 m_hasGroupChanged = value;
122 } 174 }
@@ -132,8 +184,19 @@ namespace OpenSim.Region.Framework.Scenes
132 return false; 184 return false;
133 if (m_scene.ShuttingDown) 185 if (m_scene.ShuttingDown)
134 return true; 186 return true;
187
188 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
189 {
190 m_maxPersistTime = m_scene.m_persistAfter;
191 m_minPersistTime = m_scene.m_dontPersistBefore;
192 }
193
135 long currentTime = DateTime.Now.Ticks; 194 long currentTime = DateTime.Now.Ticks;
136 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 195
196 if (timeLastChanged == 0) timeLastChanged = currentTime;
197 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
198
199 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
137 return true; 200 return true;
138 return false; 201 return false;
139 } 202 }
@@ -176,10 +239,10 @@ namespace OpenSim.Region.Framework.Scenes
176 239
177 private bool m_scriptListens_atTarget; 240 private bool m_scriptListens_atTarget;
178 private bool m_scriptListens_notAtTarget; 241 private bool m_scriptListens_notAtTarget;
179
180 private bool m_scriptListens_atRotTarget; 242 private bool m_scriptListens_atRotTarget;
181 private bool m_scriptListens_notAtRotTarget; 243 private bool m_scriptListens_notAtRotTarget;
182 244
245 public bool m_dupeInProgress = false;
183 internal Dictionary<UUID, string> m_savedScriptState; 246 internal Dictionary<UUID, string> m_savedScriptState;
184 247
185 #region Properties 248 #region Properties
@@ -219,7 +282,13 @@ namespace OpenSim.Region.Framework.Scenes
219 public virtual Quaternion Rotation 282 public virtual Quaternion Rotation
220 { 283 {
221 get { return m_rotation; } 284 get { return m_rotation; }
222 set { m_rotation = value; } 285 set {
286 foreach(SceneObjectPart p in m_parts.GetArray())
287 {
288 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
289 }
290 m_rotation = value;
291 }
223 } 292 }
224 293
225 public Quaternion GroupRotation 294 public Quaternion GroupRotation
@@ -293,7 +362,11 @@ namespace OpenSim.Region.Framework.Scenes
293 { 362 {
294 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 363 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
295 } 364 }
296 365
366 foreach (SceneObjectPart part in m_parts.GetArray())
367 {
368 part.IgnoreUndoUpdate = true;
369 }
297 if (RootPart.GetStatusSandbox()) 370 if (RootPart.GetStatusSandbox())
298 { 371 {
299 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 372 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -304,10 +377,31 @@ namespace OpenSim.Region.Framework.Scenes
304 return; 377 return;
305 } 378 }
306 } 379 }
307
308 SceneObjectPart[] parts = m_parts.GetArray(); 380 SceneObjectPart[] parts = m_parts.GetArray();
309 for (int i = 0; i < parts.Length; i++) 381 foreach (SceneObjectPart part in parts)
310 parts[i].GroupPosition = val; 382 {
383 part.IgnoreUndoUpdate = false;
384 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
385 part.GroupPosition = val;
386 if (!m_dupeInProgress)
387 {
388 part.TriggerScriptChangedEvent(Changed.POSITION);
389 }
390 }
391 if (!m_dupeInProgress)
392 {
393 foreach (ScenePresence av in m_linkedAvatars)
394 {
395 SceneObjectPart p;
396 if (m_parts.TryGetValue(av.LinkedPrim, out p))
397 {
398 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
399 av.AbsolutePosition += offset;
400 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
401 av.SendFullUpdateToAllClients();
402 }
403 }
404 }
311 405
312 //if (m_rootPart.PhysActor != null) 406 //if (m_rootPart.PhysActor != null)
313 //{ 407 //{
@@ -458,6 +552,7 @@ namespace OpenSim.Region.Framework.Scenes
458 /// </summary> 552 /// </summary>
459 public SceneObjectGroup() 553 public SceneObjectGroup()
460 { 554 {
555
461 } 556 }
462 557
463 /// <summary> 558 /// <summary>
@@ -474,7 +569,7 @@ namespace OpenSim.Region.Framework.Scenes
474 /// Constructor. This object is added to the scene later via AttachToScene() 569 /// Constructor. This object is added to the scene later via AttachToScene()
475 /// </summary> 570 /// </summary>
476 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 571 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
477 { 572 {
478 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 573 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
479 } 574 }
480 575
@@ -520,6 +615,9 @@ namespace OpenSim.Region.Framework.Scenes
520 /// </summary> 615 /// </summary>
521 public virtual void AttachToBackup() 616 public virtual void AttachToBackup()
522 { 617 {
618 if (IsAttachment) return;
619 m_scene.SceneGraph.FireAttachToBackup(this);
620
523 if (InSceneBackup) 621 if (InSceneBackup)
524 { 622 {
525 //m_log.DebugFormat( 623 //m_log.DebugFormat(
@@ -635,9 +733,9 @@ namespace OpenSim.Region.Framework.Scenes
635 result.normal = inter.normal; 733 result.normal = inter.normal;
636 result.distance = inter.distance; 734 result.distance = inter.distance;
637 } 735 }
736
638 } 737 }
639 } 738 }
640
641 return result; 739 return result;
642 } 740 }
643 741
@@ -657,17 +755,19 @@ namespace OpenSim.Region.Framework.Scenes
657 minZ = 8192f; 755 minZ = 8192f;
658 756
659 SceneObjectPart[] parts = m_parts.GetArray(); 757 SceneObjectPart[] parts = m_parts.GetArray();
660 for (int i = 0; i < parts.Length; i++) 758 foreach (SceneObjectPart part in parts)
661 { 759 {
662 SceneObjectPart part = parts[i];
663
664 Vector3 worldPos = part.GetWorldPosition(); 760 Vector3 worldPos = part.GetWorldPosition();
665 Vector3 offset = worldPos - AbsolutePosition; 761 Vector3 offset = worldPos - AbsolutePosition;
666 Quaternion worldRot; 762 Quaternion worldRot;
667 if (part.ParentID == 0) 763 if (part.ParentID == 0)
764 {
668 worldRot = part.RotationOffset; 765 worldRot = part.RotationOffset;
766 }
669 else 767 else
768 {
670 worldRot = part.GetWorldRotation(); 769 worldRot = part.GetWorldRotation();
770 }
671 771
672 Vector3 frontTopLeft; 772 Vector3 frontTopLeft;
673 Vector3 frontTopRight; 773 Vector3 frontTopRight;
@@ -679,6 +779,8 @@ namespace OpenSim.Region.Framework.Scenes
679 Vector3 backBottomLeft; 779 Vector3 backBottomLeft;
680 Vector3 backBottomRight; 780 Vector3 backBottomRight;
681 781
782 // Vector3[] corners = new Vector3[8];
783
682 Vector3 orig = Vector3.Zero; 784 Vector3 orig = Vector3.Zero;
683 785
684 frontTopLeft.X = orig.X - (part.Scale.X / 2); 786 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -713,6 +815,38 @@ namespace OpenSim.Region.Framework.Scenes
713 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 815 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
714 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 816 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
715 817
818
819
820 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
821 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
822 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
823 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
824 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
825 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
826 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
827 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
828
829 //for (int i = 0; i < 8; i++)
830 //{
831 // corners[i] = corners[i] * worldRot;
832 // corners[i] += offset;
833
834 // if (corners[i].X > maxX)
835 // maxX = corners[i].X;
836 // if (corners[i].X < minX)
837 // minX = corners[i].X;
838
839 // if (corners[i].Y > maxY)
840 // maxY = corners[i].Y;
841 // if (corners[i].Y < minY)
842 // minY = corners[i].Y;
843
844 // if (corners[i].Z > maxZ)
845 // maxZ = corners[i].Y;
846 // if (corners[i].Z < minZ)
847 // minZ = corners[i].Z;
848 //}
849
716 frontTopLeft = frontTopLeft * worldRot; 850 frontTopLeft = frontTopLeft * worldRot;
717 frontTopRight = frontTopRight * worldRot; 851 frontTopRight = frontTopRight * worldRot;
718 frontBottomLeft = frontBottomLeft * worldRot; 852 frontBottomLeft = frontBottomLeft * worldRot;
@@ -734,6 +868,15 @@ namespace OpenSim.Region.Framework.Scenes
734 backTopLeft += offset; 868 backTopLeft += offset;
735 backTopRight += offset; 869 backTopRight += offset;
736 870
871 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
872 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
873 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
874 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
875 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
876 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
877 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
878 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
879
737 if (frontTopRight.X > maxX) 880 if (frontTopRight.X > maxX)
738 maxX = frontTopRight.X; 881 maxX = frontTopRight.X;
739 if (frontTopLeft.X > maxX) 882 if (frontTopLeft.X > maxX)
@@ -879,15 +1022,20 @@ namespace OpenSim.Region.Framework.Scenes
879 1022
880 public void SaveScriptedState(XmlTextWriter writer) 1023 public void SaveScriptedState(XmlTextWriter writer)
881 { 1024 {
1025 SaveScriptedState(writer, false);
1026 }
1027
1028 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1029 {
882 XmlDocument doc = new XmlDocument(); 1030 XmlDocument doc = new XmlDocument();
883 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1031 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
884 1032
885 SceneObjectPart[] parts = m_parts.GetArray(); 1033 SceneObjectPart[] parts = m_parts.GetArray();
886 for (int i = 0; i < parts.Length; i++) 1034 for (int i = 0; i < parts.Length; i++)
887 { 1035 {
888 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1036 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
889 foreach (KeyValuePair<UUID, string> kvp in pstates) 1037 foreach (KeyValuePair<UUID, string> kvp in pstates)
890 states.Add(kvp.Key, kvp.Value); 1038 states[kvp.Key] = kvp.Value;
891 } 1039 }
892 1040
893 if (states.Count > 0) 1041 if (states.Count > 0)
@@ -906,6 +1054,118 @@ namespace OpenSim.Region.Framework.Scenes
906 } 1054 }
907 } 1055 }
908 1056
1057 /// <summary>
1058 /// Add the avatar to this linkset (avatar is sat).
1059 /// </summary>
1060 /// <param name="agentID"></param>
1061 public void AddAvatar(UUID agentID)
1062 {
1063 ScenePresence presence;
1064 if (m_scene.TryGetScenePresence(agentID, out presence))
1065 {
1066 if (!m_linkedAvatars.Contains(presence))
1067 {
1068 m_linkedAvatars.Add(presence);
1069 }
1070 }
1071 }
1072
1073 /// <summary>
1074 /// Delete the avatar from this linkset (avatar is unsat).
1075 /// </summary>
1076 /// <param name="agentID"></param>
1077 public void DeleteAvatar(UUID agentID)
1078 {
1079 ScenePresence presence;
1080 if (m_scene.TryGetScenePresence(agentID, out presence))
1081 {
1082 if (m_linkedAvatars.Contains(presence))
1083 {
1084 m_linkedAvatars.Remove(presence);
1085 }
1086 }
1087 }
1088
1089 /// <summary>
1090 /// Returns the list of linked presences (avatars sat on this group)
1091 /// </summary>
1092 /// <param name="agentID"></param>
1093 public List<ScenePresence> GetLinkedAvatars()
1094 {
1095 return m_linkedAvatars;
1096 }
1097
1098 /// <summary>
1099 /// Attach this scene object to the given avatar.
1100 /// </summary>
1101 /// <param name="agentID"></param>
1102 /// <param name="attachmentpoint"></param>
1103 /// <param name="AttachOffset"></param>
1104 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1105 {
1106 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1107 if (avatar != null)
1108 {
1109 // don't attach attachments to child agents
1110 if (avatar.IsChildAgent) return;
1111
1112// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1113
1114 DetachFromBackup();
1115
1116 // Remove from database and parcel prim count
1117 m_scene.DeleteFromStorage(UUID);
1118 m_scene.EventManager.TriggerParcelPrimCountTainted();
1119
1120 m_rootPart.AttachedAvatar = agentID;
1121
1122 //Anakin Lohner bug #3839
1123 lock (m_parts)
1124 {
1125 foreach (SceneObjectPart p in m_parts.GetArray())
1126 {
1127 p.AttachedAvatar = agentID;
1128 }
1129 }
1130
1131 if (m_rootPart.PhysActor != null)
1132 {
1133 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1134 m_rootPart.PhysActor = null;
1135 }
1136
1137 AbsolutePosition = AttachOffset;
1138 m_rootPart.AttachedPos = AttachOffset;
1139 m_rootPart.IsAttachment = true;
1140
1141 m_rootPart.SetParentLocalId(avatar.LocalId);
1142 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1143
1144 avatar.AddAttachment(this);
1145
1146 if (!silent)
1147 {
1148 // Killing it here will cause the client to deselect it
1149 // It then reappears on the avatar, deselected
1150 // through the full update below
1151 //
1152 if (IsSelected)
1153 {
1154 m_scene.SendKillObject(m_rootPart.LocalId);
1155 }
1156
1157 IsSelected = false; // fudge....
1158 ScheduleGroupForFullUpdate();
1159 }
1160 }
1161 else
1162 {
1163 m_log.WarnFormat(
1164 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1165 UUID, agentID, Scene.RegionInfo.RegionName);
1166 }
1167 }
1168
909 public byte GetAttachmentPoint() 1169 public byte GetAttachmentPoint()
910 { 1170 {
911 return m_rootPart.Shape.State; 1171 return m_rootPart.Shape.State;
@@ -1032,7 +1292,10 @@ namespace OpenSim.Region.Framework.Scenes
1032 public void AddPart(SceneObjectPart part) 1292 public void AddPart(SceneObjectPart part)
1033 { 1293 {
1034 part.SetParent(this); 1294 part.SetParent(this);
1035 part.LinkNum = m_parts.Add(part.UUID, part); 1295 m_parts.Add(part.UUID, part);
1296
1297 part.LinkNum = m_parts.Count;
1298
1036 if (part.LinkNum == 2 && RootPart != null) 1299 if (part.LinkNum == 2 && RootPart != null)
1037 RootPart.LinkNum = 1; 1300 RootPart.LinkNum = 1;
1038 } 1301 }
@@ -1116,7 +1379,7 @@ namespace OpenSim.Region.Framework.Scenes
1116 1379
1117 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1380 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1118 { 1381 {
1119 part.StoreUndoState(); 1382 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1120 part.OnGrab(offsetPos, remoteClient); 1383 part.OnGrab(offsetPos, remoteClient);
1121 } 1384 }
1122 1385
@@ -1136,6 +1399,11 @@ namespace OpenSim.Region.Framework.Scenes
1136 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1399 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1137 public void DeleteGroupFromScene(bool silent) 1400 public void DeleteGroupFromScene(bool silent)
1138 { 1401 {
1402 // We need to keep track of this state in case this group is still queued for backup.
1403 m_isDeleted = true;
1404
1405 DetachFromBackup();
1406
1139 SceneObjectPart[] parts = m_parts.GetArray(); 1407 SceneObjectPart[] parts = m_parts.GetArray();
1140 for (int i = 0; i < parts.Length; i++) 1408 for (int i = 0; i < parts.Length; i++)
1141 { 1409 {
@@ -1154,6 +1422,8 @@ namespace OpenSim.Region.Framework.Scenes
1154 } 1422 }
1155 }); 1423 });
1156 } 1424 }
1425
1426
1157 } 1427 }
1158 1428
1159 public void AddScriptLPS(int count) 1429 public void AddScriptLPS(int count)
@@ -1250,7 +1520,12 @@ namespace OpenSim.Region.Framework.Scenes
1250 1520
1251 public void SetOwnerId(UUID userId) 1521 public void SetOwnerId(UUID userId)
1252 { 1522 {
1253 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1523 ForEachPart(delegate(SceneObjectPart part)
1524 {
1525
1526 part.OwnerID = userId;
1527
1528 });
1254 } 1529 }
1255 1530
1256 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1531 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1286,7 +1561,10 @@ namespace OpenSim.Region.Framework.Scenes
1286 // any exception propogate upwards. 1561 // any exception propogate upwards.
1287 try 1562 try
1288 { 1563 {
1289 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1564 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1565 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1566 m_scene.LoadingPrims) // Land may not be valid yet
1567
1290 { 1568 {
1291 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1569 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1292 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1570 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1318,6 +1596,20 @@ namespace OpenSim.Region.Framework.Scenes
1318 // don't backup while it's selected or you're asking for changes mid stream. 1596 // don't backup while it's selected or you're asking for changes mid stream.
1319 if (isTimeToPersist() || forcedBackup) 1597 if (isTimeToPersist() || forcedBackup)
1320 { 1598 {
1599 if (m_rootPart.PhysActor != null &&
1600 (!m_rootPart.PhysActor.IsPhysical))
1601 {
1602 // Possible ghost prim
1603 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1604 {
1605 foreach (SceneObjectPart part in m_parts.GetArray())
1606 {
1607 // Re-set physics actor positions and
1608 // orientations
1609 part.GroupPosition = m_rootPart.GroupPosition;
1610 }
1611 }
1612 }
1321// m_log.DebugFormat( 1613// m_log.DebugFormat(
1322// "[SCENE]: Storing {0}, {1} in {2}", 1614// "[SCENE]: Storing {0}, {1} in {2}",
1323// Name, UUID, m_scene.RegionInfo.RegionName); 1615// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1380,81 +1672,106 @@ namespace OpenSim.Region.Framework.Scenes
1380 /// <returns></returns> 1672 /// <returns></returns>
1381 public SceneObjectGroup Copy(bool userExposed) 1673 public SceneObjectGroup Copy(bool userExposed)
1382 { 1674 {
1383 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1675 SceneObjectGroup dupe;
1384 dupe.m_isBackedUp = false; 1676 try
1385 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1677 {
1678 m_dupeInProgress = true;
1679 dupe = (SceneObjectGroup)MemberwiseClone();
1680 dupe.m_isBackedUp = false;
1681 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1386 1682
1387 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1683 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1388 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1684 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1389 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1685 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1390 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1686 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1391 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1687 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1392 // then restore it's attachment state 1688 // then restore it's attachment state
1393 1689
1394 // This is only necessary when userExposed is false! 1690 // This is only necessary when userExposed is false!
1395 1691
1396 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1692 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1397
1398 if (!userExposed)
1399 dupe.RootPart.IsAttachment = true;
1400 1693
1401 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1694 if (!userExposed)
1695 dupe.RootPart.IsAttachment = true;
1402 1696
1403 if (!userExposed) 1697 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1404 {
1405 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1406 }
1407 1698
1408 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1699 if (!userExposed)
1409 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1700 {
1701 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1702 }
1410 1703
1411 if (userExposed) 1704 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1412 dupe.m_rootPart.TrimPermissions(); 1705 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1413 1706
1414 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1707 if (userExposed)
1415 1708 dupe.m_rootPart.TrimPermissions();
1416 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1709
1710 /// may need to create a new Physics actor.
1711 if (dupe.RootPart.PhysActor != null && userExposed)
1417 { 1712 {
1418 return p1.LinkNum.CompareTo(p2.LinkNum); 1713 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1714
1715 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1716 dupe.RootPart.Name,
1717 pbs,
1718 dupe.RootPart.AbsolutePosition,
1719 dupe.RootPart.Scale,
1720 dupe.RootPart.RotationOffset,
1721 dupe.RootPart.PhysActor.IsPhysical);
1722
1723 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1724 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1419 } 1725 }
1420 );
1421 1726
1422 foreach (SceneObjectPart part in partList) 1727 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1423 { 1728
1424 if (part.UUID != m_rootPart.UUID) 1729 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1730 {
1731 return p1.LinkNum.CompareTo(p2.LinkNum);
1732 }
1733 );
1734
1735 foreach (SceneObjectPart part in partList)
1425 { 1736 {
1426 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1737 if (part.UUID != m_rootPart.UUID)
1427 newPart.LinkNum = part.LinkNum; 1738 {
1428 } 1739 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1740
1741 newPart.LinkNum = part.LinkNum;
1742 }
1429 1743
1430 // Need to duplicate the physics actor as well 1744 // Need to duplicate the physics actor as well
1431 if (part.PhysActor != null && userExposed) 1745 if (part.PhysActor != null && userExposed)
1746 {
1747 PrimitiveBaseShape pbs = part.Shape;
1748
1749 part.PhysActor
1750 = m_scene.PhysicsScene.AddPrimShape(
1751 string.Format("{0}/{1}", part.Name, part.UUID),
1752 pbs,
1753 part.AbsolutePosition,
1754 part.Scale,
1755 part.RotationOffset,
1756 part.PhysActor.IsPhysical);
1757
1758 part.PhysActor.LocalID = part.LocalId;
1759 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1760 }
1761 }
1762 if (userExposed)
1432 { 1763 {
1433 PrimitiveBaseShape pbs = part.Shape; 1764 dupe.UpdateParentIDs();
1434 1765 dupe.HasGroupChanged = true;
1435 part.PhysActor 1766 dupe.AttachToBackup();
1436 = m_scene.PhysicsScene.AddPrimShape( 1767
1437 string.Format("{0}/{1}", part.Name, part.UUID), 1768 ScheduleGroupForFullUpdate();
1438 pbs,
1439 part.AbsolutePosition,
1440 part.Scale,
1441 part.RotationOffset,
1442 part.PhysActor.IsPhysical);
1443
1444 part.PhysActor.LocalID = part.LocalId;
1445 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1446 } 1769 }
1447 } 1770 }
1448 1771 finally
1449 if (userExposed)
1450 { 1772 {
1451 dupe.UpdateParentIDs(); 1773 m_dupeInProgress = false;
1452 dupe.HasGroupChanged = true;
1453 dupe.AttachToBackup();
1454
1455 ScheduleGroupForFullUpdate();
1456 } 1774 }
1457
1458 return dupe; 1775 return dupe;
1459 } 1776 }
1460 1777
@@ -1645,13 +1962,40 @@ namespace OpenSim.Region.Framework.Scenes
1645 } 1962 }
1646 } 1963 }
1647 1964
1965 public void rotLookAt(Quaternion target, float strength, float damping)
1966 {
1967 SceneObjectPart rootpart = m_rootPart;
1968 if (rootpart != null)
1969 {
1970 if (IsAttachment)
1971 {
1972 /*
1973 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1974 if (avatar != null)
1975 {
1976 Rotate the Av?
1977 } */
1978 }
1979 else
1980 {
1981 if (rootpart.PhysActor != null)
1982 { // APID must be implemented in your physics system for this to function.
1983 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1984 rootpart.PhysActor.APIDStrength = strength;
1985 rootpart.PhysActor.APIDDamping = damping;
1986 rootpart.PhysActor.APIDActive = true;
1987 }
1988 }
1989 }
1990 }
1991
1648 public void stopLookAt() 1992 public void stopLookAt()
1649 { 1993 {
1650 SceneObjectPart rootpart = m_rootPart; 1994 SceneObjectPart rootpart = m_rootPart;
1651 if (rootpart != null) 1995 if (rootpart != null)
1652 { 1996 {
1653 if (rootpart.PhysActor != null) 1997 if (rootpart.PhysActor != null)
1654 { 1998 { // APID must be implemented in your physics system for this to function.
1655 rootpart.PhysActor.APIDActive = false; 1999 rootpart.PhysActor.APIDActive = false;
1656 } 2000 }
1657 } 2001 }
@@ -1717,6 +2061,8 @@ namespace OpenSim.Region.Framework.Scenes
1717 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2061 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1718 { 2062 {
1719 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2063 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2064 newPart.SetParent(this);
2065
1720 AddPart(newPart); 2066 AddPart(newPart);
1721 2067
1722 SetPartAsNonRoot(newPart); 2068 SetPartAsNonRoot(newPart);
@@ -1863,11 +2209,11 @@ namespace OpenSim.Region.Framework.Scenes
1863 /// Immediately send a full update for this scene object. 2209 /// Immediately send a full update for this scene object.
1864 /// </summary> 2210 /// </summary>
1865 public void SendGroupFullUpdate() 2211 public void SendGroupFullUpdate()
1866 { 2212 {
1867 if (IsDeleted) 2213 if (IsDeleted)
1868 return; 2214 return;
1869 2215
1870// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2216// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1871 2217
1872 RootPart.SendFullUpdateToAllClients(); 2218 RootPart.SendFullUpdateToAllClients();
1873 2219
@@ -2056,12 +2402,15 @@ namespace OpenSim.Region.Framework.Scenes
2056 part.LinkNum += objectGroup.PrimCount; 2402 part.LinkNum += objectGroup.PrimCount;
2057 } 2403 }
2058 } 2404 }
2405 }
2059 2406
2060 linkPart.LinkNum = 2; 2407 linkPart.LinkNum = 2;
2061 2408
2062 linkPart.SetParent(this); 2409 linkPart.SetParent(this);
2063 linkPart.CreateSelected = true; 2410 linkPart.CreateSelected = true;
2064 2411
2412 lock (m_parts.SyncRoot)
2413 {
2065 //if (linkPart.PhysActor != null) 2414 //if (linkPart.PhysActor != null)
2066 //{ 2415 //{
2067 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2416 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2218,6 +2567,8 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2567 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2568 public virtual void DetachFromBackup()
2220 { 2569 {
2570 m_scene.SceneGraph.FireDetachFromBackup(this);
2571
2221 if (m_isBackedUp) 2572 if (m_isBackedUp)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2573 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2574
@@ -2522,6 +2873,17 @@ namespace OpenSim.Region.Framework.Scenes
2522 } 2873 }
2523 } 2874 }
2524 2875
2876
2877
2878 /// <summary>
2879 /// Gets the number of parts
2880 /// </summary>
2881 /// <returns></returns>
2882 public int GetPartCount()
2883 {
2884 return Parts.Count();
2885 }
2886
2525 /// <summary> 2887 /// <summary>
2526 /// Update the texture entry for this part 2888 /// Update the texture entry for this part
2527 /// </summary> 2889 /// </summary>
@@ -2583,11 +2945,9 @@ namespace OpenSim.Region.Framework.Scenes
2583 scale.Y = m_scene.m_maxNonphys; 2945 scale.Y = m_scene.m_maxNonphys;
2584 if (scale.Z > m_scene.m_maxNonphys) 2946 if (scale.Z > m_scene.m_maxNonphys)
2585 scale.Z = m_scene.m_maxNonphys; 2947 scale.Z = m_scene.m_maxNonphys;
2586
2587 SceneObjectPart part = GetChildPart(localID); 2948 SceneObjectPart part = GetChildPart(localID);
2588 if (part != null) 2949 if (part != null)
2589 { 2950 {
2590 part.Resize(scale);
2591 if (part.PhysActor != null) 2951 if (part.PhysActor != null)
2592 { 2952 {
2593 if (part.PhysActor.IsPhysical) 2953 if (part.PhysActor.IsPhysical)
@@ -2602,7 +2962,7 @@ namespace OpenSim.Region.Framework.Scenes
2602 part.PhysActor.Size = scale; 2962 part.PhysActor.Size = scale;
2603 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2963 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2604 } 2964 }
2605 //if (part.UUID != m_rootPart.UUID) 2965 part.Resize(scale);
2606 2966
2607 HasGroupChanged = true; 2967 HasGroupChanged = true;
2608 ScheduleGroupForFullUpdate(); 2968 ScheduleGroupForFullUpdate();
@@ -2624,7 +2984,6 @@ namespace OpenSim.Region.Framework.Scenes
2624 SceneObjectPart part = GetChildPart(localID); 2984 SceneObjectPart part = GetChildPart(localID);
2625 if (part != null) 2985 if (part != null)
2626 { 2986 {
2627 part.IgnoreUndoUpdate = true;
2628 if (scale.X > m_scene.m_maxNonphys) 2987 if (scale.X > m_scene.m_maxNonphys)
2629 scale.X = m_scene.m_maxNonphys; 2988 scale.X = m_scene.m_maxNonphys;
2630 if (scale.Y > m_scene.m_maxNonphys) 2989 if (scale.Y > m_scene.m_maxNonphys)
@@ -2661,7 +3020,7 @@ namespace OpenSim.Region.Framework.Scenes
2661 3020
2662 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3021 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2663 { 3022 {
2664 if (oldSize.X * x > m_scene.m_maxPhys) 3023 if (oldSize.X*x > m_scene.m_maxPhys)
2665 { 3024 {
2666 f = m_scene.m_maxPhys / oldSize.X; 3025 f = m_scene.m_maxPhys / oldSize.X;
2667 a = f / x; 3026 a = f / x;
@@ -2669,7 +3028,7 @@ namespace OpenSim.Region.Framework.Scenes
2669 y *= a; 3028 y *= a;
2670 z *= a; 3029 z *= a;
2671 } 3030 }
2672 if (oldSize.Y * y > m_scene.m_maxPhys) 3031 if (oldSize.Y*y > m_scene.m_maxPhys)
2673 { 3032 {
2674 f = m_scene.m_maxPhys / oldSize.Y; 3033 f = m_scene.m_maxPhys / oldSize.Y;
2675 a = f / y; 3034 a = f / y;
@@ -2677,7 +3036,7 @@ namespace OpenSim.Region.Framework.Scenes
2677 y *= a; 3036 y *= a;
2678 z *= a; 3037 z *= a;
2679 } 3038 }
2680 if (oldSize.Z * z > m_scene.m_maxPhys) 3039 if (oldSize.Z*z > m_scene.m_maxPhys)
2681 { 3040 {
2682 f = m_scene.m_maxPhys / oldSize.Z; 3041 f = m_scene.m_maxPhys / oldSize.Z;
2683 a = f / z; 3042 a = f / z;
@@ -2688,7 +3047,7 @@ namespace OpenSim.Region.Framework.Scenes
2688 } 3047 }
2689 else 3048 else
2690 { 3049 {
2691 if (oldSize.X * x > m_scene.m_maxNonphys) 3050 if (oldSize.X*x > m_scene.m_maxNonphys)
2692 { 3051 {
2693 f = m_scene.m_maxNonphys / oldSize.X; 3052 f = m_scene.m_maxNonphys / oldSize.X;
2694 a = f / x; 3053 a = f / x;
@@ -2696,7 +3055,7 @@ namespace OpenSim.Region.Framework.Scenes
2696 y *= a; 3055 y *= a;
2697 z *= a; 3056 z *= a;
2698 } 3057 }
2699 if (oldSize.Y * y > m_scene.m_maxNonphys) 3058 if (oldSize.Y*y > m_scene.m_maxNonphys)
2700 { 3059 {
2701 f = m_scene.m_maxNonphys / oldSize.Y; 3060 f = m_scene.m_maxNonphys / oldSize.Y;
2702 a = f / y; 3061 a = f / y;
@@ -2704,7 +3063,7 @@ namespace OpenSim.Region.Framework.Scenes
2704 y *= a; 3063 y *= a;
2705 z *= a; 3064 z *= a;
2706 } 3065 }
2707 if (oldSize.Z * z > m_scene.m_maxNonphys) 3066 if (oldSize.Z*z > m_scene.m_maxNonphys)
2708 { 3067 {
2709 f = m_scene.m_maxNonphys / oldSize.Z; 3068 f = m_scene.m_maxNonphys / oldSize.Z;
2710 a = f / z; 3069 a = f / z;
@@ -2714,7 +3073,6 @@ namespace OpenSim.Region.Framework.Scenes
2714 } 3073 }
2715 } 3074 }
2716 obPart.IgnoreUndoUpdate = false; 3075 obPart.IgnoreUndoUpdate = false;
2717 obPart.StoreUndoState();
2718 } 3076 }
2719 } 3077 }
2720 } 3078 }
@@ -2722,8 +3080,13 @@ namespace OpenSim.Region.Framework.Scenes
2722 Vector3 prevScale = part.Scale; 3080 Vector3 prevScale = part.Scale;
2723 prevScale.X *= x; 3081 prevScale.X *= x;
2724 prevScale.Y *= y; 3082 prevScale.Y *= y;
2725 prevScale.Z *= z; 3083 prevScale.Z *= z;;
3084
3085 part.IgnoreUndoUpdate = false;
3086 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3087 part.IgnoreUndoUpdate = true;
2726 part.Resize(prevScale); 3088 part.Resize(prevScale);
3089 part.IgnoreUndoUpdate = false;
2727 3090
2728 parts = m_parts.GetArray(); 3091 parts = m_parts.GetArray();
2729 for (int i = 0; i < parts.Length; i++) 3092 for (int i = 0; i < parts.Length; i++)
@@ -2732,19 +3095,26 @@ namespace OpenSim.Region.Framework.Scenes
2732 obPart.IgnoreUndoUpdate = true; 3095 obPart.IgnoreUndoUpdate = true;
2733 if (obPart.UUID != m_rootPart.UUID) 3096 if (obPart.UUID != m_rootPart.UUID)
2734 { 3097 {
2735 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3098 if (obPart.UUID != m_rootPart.UUID)
2736 currentpos.X *= x; 3099 {
2737 currentpos.Y *= y; 3100 obPart.IgnoreUndoUpdate = false;
2738 currentpos.Z *= z; 3101 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2739 Vector3 newSize = new Vector3(obPart.Scale); 3102 obPart.IgnoreUndoUpdate = true;
2740 newSize.X *= x; 3103
2741 newSize.Y *= y; 3104 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2742 newSize.Z *= z; 3105 currentpos.X *= x;
2743 obPart.Resize(newSize); 3106 currentpos.Y *= y;
2744 obPart.UpdateOffSet(currentpos); 3107 currentpos.Z *= z;
3108 Vector3 newSize = new Vector3(obPart.Scale);
3109 newSize.X *= x;
3110 newSize.Y *= y;
3111 newSize.Z *= z;
3112 obPart.Resize(newSize);
3113 obPart.UpdateOffSet(currentpos);
3114 }
3115 obPart.IgnoreUndoUpdate = false;
2745 } 3116 }
2746 obPart.IgnoreUndoUpdate = false; 3117 obPart.IgnoreUndoUpdate = false;
2747 obPart.StoreUndoState();
2748 } 3118 }
2749 3119
2750 if (part.PhysActor != null) 3120 if (part.PhysActor != null)
@@ -2754,7 +3124,6 @@ namespace OpenSim.Region.Framework.Scenes
2754 } 3124 }
2755 3125
2756 part.IgnoreUndoUpdate = false; 3126 part.IgnoreUndoUpdate = false;
2757 part.StoreUndoState();
2758 HasGroupChanged = true; 3127 HasGroupChanged = true;
2759 ScheduleGroupForTerseUpdate(); 3128 ScheduleGroupForTerseUpdate();
2760 } 3129 }
@@ -2770,14 +3139,11 @@ namespace OpenSim.Region.Framework.Scenes
2770 /// <param name="pos"></param> 3139 /// <param name="pos"></param>
2771 public void UpdateGroupPosition(Vector3 pos) 3140 public void UpdateGroupPosition(Vector3 pos)
2772 { 3141 {
2773 SceneObjectPart[] parts = m_parts.GetArray();
2774 for (int i = 0; i < parts.Length; i++)
2775 parts[i].StoreUndoState();
2776
2777 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3142 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2778 { 3143 {
2779 if (IsAttachment) 3144 if (IsAttachment)
2780 { 3145 {
3146 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2781 m_rootPart.AttachedPos = pos; 3147 m_rootPart.AttachedPos = pos;
2782 } 3148 }
2783 if (RootPart.GetStatusSandbox()) 3149 if (RootPart.GetStatusSandbox())
@@ -2811,7 +3177,7 @@ namespace OpenSim.Region.Framework.Scenes
2811 3177
2812 SceneObjectPart[] parts = m_parts.GetArray(); 3178 SceneObjectPart[] parts = m_parts.GetArray();
2813 for (int i = 0; i < parts.Length; i++) 3179 for (int i = 0; i < parts.Length; i++)
2814 parts[i].StoreUndoState(); 3180 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2815 3181
2816 if (part != null) 3182 if (part != null)
2817 { 3183 {
@@ -2836,7 +3202,7 @@ namespace OpenSim.Region.Framework.Scenes
2836 { 3202 {
2837 SceneObjectPart[] parts = m_parts.GetArray(); 3203 SceneObjectPart[] parts = m_parts.GetArray();
2838 for (int i = 0; i < parts.Length; i++) 3204 for (int i = 0; i < parts.Length; i++)
2839 parts[i].StoreUndoState(); 3205 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2840 3206
2841 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3207 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2842 Vector3 oldPos = 3208 Vector3 oldPos =
@@ -2857,10 +3223,27 @@ namespace OpenSim.Region.Framework.Scenes
2857 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3223 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2858 } 3224 }
2859 3225
2860 AbsolutePosition = newPos; 3226 //We have to set undoing here because otherwise an undo state will be saved
3227 if (!m_rootPart.Undoing)
3228 {
3229 m_rootPart.Undoing = true;
3230 AbsolutePosition = newPos;
3231 m_rootPart.Undoing = false;
3232 }
3233 else
3234 {
3235 AbsolutePosition = newPos;
3236 }
2861 3237
2862 HasGroupChanged = true; 3238 HasGroupChanged = true;
2863 ScheduleGroupForTerseUpdate(); 3239 if (m_rootPart.Undoing)
3240 {
3241 ScheduleGroupForFullUpdate();
3242 }
3243 else
3244 {
3245 ScheduleGroupForTerseUpdate();
3246 }
2864 } 3247 }
2865 3248
2866 public void OffsetForNewRegion(Vector3 offset) 3249 public void OffsetForNewRegion(Vector3 offset)
@@ -2880,7 +3263,7 @@ namespace OpenSim.Region.Framework.Scenes
2880 { 3263 {
2881 SceneObjectPart[] parts = m_parts.GetArray(); 3264 SceneObjectPart[] parts = m_parts.GetArray();
2882 for (int i = 0; i < parts.Length; i++) 3265 for (int i = 0; i < parts.Length; i++)
2883 parts[i].StoreUndoState(); 3266 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2884 3267
2885 m_rootPart.UpdateRotation(rot); 3268 m_rootPart.UpdateRotation(rot);
2886 3269
@@ -2904,7 +3287,7 @@ namespace OpenSim.Region.Framework.Scenes
2904 { 3287 {
2905 SceneObjectPart[] parts = m_parts.GetArray(); 3288 SceneObjectPart[] parts = m_parts.GetArray();
2906 for (int i = 0; i < parts.Length; i++) 3289 for (int i = 0; i < parts.Length; i++)
2907 parts[i].StoreUndoState(); 3290 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2908 3291
2909 m_rootPart.UpdateRotation(rot); 3292 m_rootPart.UpdateRotation(rot);
2910 3293
@@ -2929,10 +3312,9 @@ namespace OpenSim.Region.Framework.Scenes
2929 public void UpdateSingleRotation(Quaternion rot, uint localID) 3312 public void UpdateSingleRotation(Quaternion rot, uint localID)
2930 { 3313 {
2931 SceneObjectPart part = GetChildPart(localID); 3314 SceneObjectPart part = GetChildPart(localID);
2932
2933 SceneObjectPart[] parts = m_parts.GetArray(); 3315 SceneObjectPart[] parts = m_parts.GetArray();
2934 for (int i = 0; i < parts.Length; i++) 3316 for (int i = 0; i < parts.Length; i++)
2935 parts[i].StoreUndoState(); 3317 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2936 3318
2937 if (part != null) 3319 if (part != null)
2938 { 3320 {
@@ -2960,15 +3342,24 @@ namespace OpenSim.Region.Framework.Scenes
2960 if (part.UUID == m_rootPart.UUID) 3342 if (part.UUID == m_rootPart.UUID)
2961 { 3343 {
2962 UpdateRootRotation(rot); 3344 UpdateRootRotation(rot);
2963 AbsolutePosition = pos; 3345 if (!m_rootPart.Undoing)
3346 {
3347 m_rootPart.Undoing = true;
3348 AbsolutePosition = pos;
3349 m_rootPart.Undoing = false;
3350 }
3351 else
3352 {
3353 AbsolutePosition = pos;
3354 }
2964 } 3355 }
2965 else 3356 else
2966 { 3357 {
3358 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2967 part.IgnoreUndoUpdate = true; 3359 part.IgnoreUndoUpdate = true;
2968 part.UpdateRotation(rot); 3360 part.UpdateRotation(rot);
2969 part.OffsetPosition = pos; 3361 part.OffsetPosition = pos;
2970 part.IgnoreUndoUpdate = false; 3362 part.IgnoreUndoUpdate = false;
2971 part.StoreUndoState();
2972 } 3363 }
2973 } 3364 }
2974 } 3365 }
@@ -2982,7 +3373,13 @@ namespace OpenSim.Region.Framework.Scenes
2982 Quaternion axRot = rot; 3373 Quaternion axRot = rot;
2983 Quaternion oldParentRot = m_rootPart.RotationOffset; 3374 Quaternion oldParentRot = m_rootPart.RotationOffset;
2984 3375
2985 m_rootPart.StoreUndoState(); 3376 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3377 bool cancelUndo = false;
3378 if (!m_rootPart.Undoing)
3379 {
3380 m_rootPart.Undoing = true;
3381 cancelUndo = true;
3382 }
2986 m_rootPart.UpdateRotation(rot); 3383 m_rootPart.UpdateRotation(rot);
2987 if (m_rootPart.PhysActor != null) 3384 if (m_rootPart.PhysActor != null)
2988 { 3385 {
@@ -3006,17 +3403,12 @@ namespace OpenSim.Region.Framework.Scenes
3006 newRot *= Quaternion.Inverse(axRot); 3403 newRot *= Quaternion.Inverse(axRot);
3007 prim.RotationOffset = newRot; 3404 prim.RotationOffset = newRot;
3008 prim.ScheduleTerseUpdate(); 3405 prim.ScheduleTerseUpdate();
3406 prim.IgnoreUndoUpdate = false;
3009 } 3407 }
3010 } 3408 }
3011 3409 if (cancelUndo == true)
3012 for (int i = 0; i < parts.Length; i++)
3013 { 3410 {
3014 SceneObjectPart childpart = parts[i]; 3411 m_rootPart.Undoing = false;
3015 if (childpart != m_rootPart)
3016 {
3017 childpart.IgnoreUndoUpdate = false;
3018 childpart.StoreUndoState();
3019 }
3020 } 3412 }
3021 3413
3022 m_rootPart.ScheduleTerseUpdate(); 3414 m_rootPart.ScheduleTerseUpdate();
@@ -3242,7 +3634,6 @@ namespace OpenSim.Region.Framework.Scenes
3242 public float GetMass() 3634 public float GetMass()
3243 { 3635 {
3244 float retmass = 0f; 3636 float retmass = 0f;
3245
3246 SceneObjectPart[] parts = m_parts.GetArray(); 3637 SceneObjectPart[] parts = m_parts.GetArray();
3247 for (int i = 0; i < parts.Length; i++) 3638 for (int i = 0; i < parts.Length; i++)
3248 retmass += parts[i].GetMass(); 3639 retmass += parts[i].GetMass();
@@ -3358,6 +3749,14 @@ namespace OpenSim.Region.Framework.Scenes
3358 SetFromItemID(uuid); 3749 SetFromItemID(uuid);
3359 } 3750 }
3360 3751
3752 public void ResetOwnerChangeFlag()
3753 {
3754 ForEachPart(delegate(SceneObjectPart part)
3755 {
3756 part.ResetOwnerChangeFlag();
3757 });
3758 }
3759
3361 #endregion 3760 #endregion
3362 } 3761 }
3363} 3762}