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