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.cs700
1 files changed, 549 insertions, 151 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index a7107f0..86f06ca 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);
@@ -1324,6 +1601,7 @@ namespace OpenSim.Region.Framework.Scenes
1324 } 1601 }
1325 } 1602 }
1326 } 1603 }
1604
1327 } 1605 }
1328 1606
1329 if (HasGroupChanged) 1607 if (HasGroupChanged)
@@ -1331,6 +1609,20 @@ namespace OpenSim.Region.Framework.Scenes
1331 // don't backup while it's selected or you're asking for changes mid stream. 1609 // don't backup while it's selected or you're asking for changes mid stream.
1332 if (isTimeToPersist() || forcedBackup) 1610 if (isTimeToPersist() || forcedBackup)
1333 { 1611 {
1612 if (m_rootPart.PhysActor != null &&
1613 (!m_rootPart.PhysActor.IsPhysical))
1614 {
1615 // Possible ghost prim
1616 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1617 {
1618 foreach (SceneObjectPart part in m_parts.GetArray())
1619 {
1620 // Re-set physics actor positions and
1621 // orientations
1622 part.GroupPosition = m_rootPart.GroupPosition;
1623 }
1624 }
1625 }
1334// m_log.DebugFormat( 1626// m_log.DebugFormat(
1335// "[SCENE]: Storing {0}, {1} in {2}", 1627// "[SCENE]: Storing {0}, {1} in {2}",
1336// Name, UUID, m_scene.RegionInfo.RegionName); 1628// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1394,81 +1686,90 @@ namespace OpenSim.Region.Framework.Scenes
1394 /// <returns></returns> 1686 /// <returns></returns>
1395 public SceneObjectGroup Copy(bool userExposed) 1687 public SceneObjectGroup Copy(bool userExposed)
1396 { 1688 {
1397 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1689 SceneObjectGroup dupe;
1398 dupe.m_isBackedUp = false; 1690 try
1399 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1691 {
1400 1692 m_dupeInProgress = true;
1401 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1693 dupe = (SceneObjectGroup)MemberwiseClone();
1402 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1694 dupe.m_isBackedUp = false;
1403 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1695 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1404 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1405 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1406 // then restore it's attachment state
1407
1408 // This is only necessary when userExposed is false!
1409 1696
1410 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1697 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1411 1698 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1412 if (!userExposed) 1699 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1413 dupe.RootPart.IsAttachment = true; 1700 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1701 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1702 // then restore it's attachment state
1414 1703
1415 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1704 // This is only necessary when userExposed is false!
1416 1705
1417 if (!userExposed) 1706 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1418 {
1419 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1420 }
1421 1707
1422 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1708 if (!userExposed)
1423 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1709 dupe.RootPart.IsAttachment = true;
1424 1710
1425 if (userExposed) 1711 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1426 dupe.m_rootPart.TrimPermissions();
1427 1712
1428 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1713 if (!userExposed)
1429
1430 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1431 { 1714 {
1432 return p1.LinkNum.CompareTo(p2.LinkNum); 1715 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1433 } 1716 }
1434 );
1435 1717
1436 foreach (SceneObjectPart part in partList) 1718 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1437 { 1719 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1438 if (part.UUID != m_rootPart.UUID) 1720
1721 if (userExposed)
1722 dupe.m_rootPart.TrimPermissions();
1723
1724 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1725
1726 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1727 {
1728 return p1.LinkNum.CompareTo(p2.LinkNum);
1729 }
1730 );
1731
1732 foreach (SceneObjectPart part in partList)
1439 { 1733 {
1440 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1734 if (part.UUID != m_rootPart.UUID)
1441 newPart.LinkNum = part.LinkNum; 1735 {
1442 } 1736 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1443 1737
1444 // Need to duplicate the physics actor as well 1738 newPart.LinkNum = part.LinkNum;
1445 if (part.PhysActor != null && userExposed) 1739 }
1740
1741 // Need to duplicate the physics actor as well
1742 if (part.PhysActor != null && userExposed)
1743 {
1744 PrimitiveBaseShape pbs = part.Shape;
1745
1746 part.PhysActor
1747 = m_scene.PhysicsScene.AddPrimShape(
1748 string.Format("{0}/{1}", part.Name, part.UUID),
1749 pbs,
1750 part.AbsolutePosition,
1751 part.Scale,
1752 part.RotationOffset,
1753 part.PhysActor.IsPhysical);
1754 part.PhysActor.SetMaterial((int)part.Material);
1755
1756 part.PhysActor.LocalID = part.LocalId;
1757 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1758 }
1759 }
1760 if (userExposed)
1446 { 1761 {
1447 PrimitiveBaseShape pbs = part.Shape; 1762 dupe.UpdateParentIDs();
1448 1763 dupe.HasGroupChanged = true;
1449 part.PhysActor 1764 dupe.AttachToBackup();
1450 = m_scene.PhysicsScene.AddPrimShape( 1765
1451 string.Format("{0}/{1}", part.Name, part.UUID), 1766 ScheduleGroupForFullUpdate();
1452 pbs,
1453 part.AbsolutePosition,
1454 part.Scale,
1455 part.RotationOffset,
1456 part.PhysActor.IsPhysical);
1457
1458 part.PhysActor.LocalID = part.LocalId;
1459 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1460 } 1767 }
1461 } 1768 }
1462 1769 finally
1463 if (userExposed)
1464 { 1770 {
1465 dupe.UpdateParentIDs(); 1771 m_dupeInProgress = false;
1466 dupe.HasGroupChanged = true;
1467 dupe.AttachToBackup();
1468
1469 ScheduleGroupForFullUpdate();
1470 } 1772 }
1471
1472 return dupe; 1773 return dupe;
1473 } 1774 }
1474 1775
@@ -1613,6 +1914,7 @@ namespace OpenSim.Region.Framework.Scenes
1613 return Vector3.Zero; 1914 return Vector3.Zero;
1614 } 1915 }
1615 1916
1917 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1616 public void moveToTarget(Vector3 target, float tau) 1918 public void moveToTarget(Vector3 target, float tau)
1617 { 1919 {
1618 SceneObjectPart rootpart = m_rootPart; 1920 SceneObjectPart rootpart = m_rootPart;
@@ -1652,20 +1954,55 @@ namespace OpenSim.Region.Framework.Scenes
1652 SceneObjectPart rootpart = m_rootPart; 1954 SceneObjectPart rootpart = m_rootPart;
1653 if (rootpart != null) 1955 if (rootpart != null)
1654 { 1956 {
1655 if (rootpart.PhysActor != null) 1957 if (IsAttachment)
1958 {
1959 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1960 if (avatar != null) avatar.StopMoveToPosition();
1961 }
1962 else
1656 { 1963 {
1657 rootpart.PhysActor.PIDActive = false; 1964 if (rootpart.PhysActor != null)
1965 {
1966 rootpart.PhysActor.PIDActive = false;
1967 }
1658 } 1968 }
1659 } 1969 }
1660 } 1970 }
1661 1971
1972 public void rotLookAt(Quaternion target, float strength, float damping)
1973 {
1974 SceneObjectPart rootpart = m_rootPart;
1975 if (rootpart != null)
1976 {
1977 if (IsAttachment)
1978 {
1979 /*
1980 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1981 if (avatar != null)
1982 {
1983 Rotate the Av?
1984 } */
1985 }
1986 else
1987 {
1988 if (rootpart.PhysActor != null)
1989 { // APID must be implemented in your physics system for this to function.
1990 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1991 rootpart.PhysActor.APIDStrength = strength;
1992 rootpart.PhysActor.APIDDamping = damping;
1993 rootpart.PhysActor.APIDActive = true;
1994 }
1995 }
1996 }
1997 }
1998
1662 public void stopLookAt() 1999 public void stopLookAt()
1663 { 2000 {
1664 SceneObjectPart rootpart = m_rootPart; 2001 SceneObjectPart rootpart = m_rootPart;
1665 if (rootpart != null) 2002 if (rootpart != null)
1666 { 2003 {
1667 if (rootpart.PhysActor != null) 2004 if (rootpart.PhysActor != null)
1668 { 2005 { // APID must be implemented in your physics system for this to function.
1669 rootpart.PhysActor.APIDActive = false; 2006 rootpart.PhysActor.APIDActive = false;
1670 } 2007 }
1671 } 2008 }
@@ -1731,6 +2068,8 @@ namespace OpenSim.Region.Framework.Scenes
1731 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2068 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1732 { 2069 {
1733 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2070 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2071 newPart.SetParent(this);
2072
1734 AddPart(newPart); 2073 AddPart(newPart);
1735 2074
1736 SetPartAsNonRoot(newPart); 2075 SetPartAsNonRoot(newPart);
@@ -1877,11 +2216,11 @@ namespace OpenSim.Region.Framework.Scenes
1877 /// Immediately send a full update for this scene object. 2216 /// Immediately send a full update for this scene object.
1878 /// </summary> 2217 /// </summary>
1879 public void SendGroupFullUpdate() 2218 public void SendGroupFullUpdate()
1880 { 2219 {
1881 if (IsDeleted) 2220 if (IsDeleted)
1882 return; 2221 return;
1883 2222
1884// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2223// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1885 2224
1886 RootPart.SendFullUpdateToAllClients(); 2225 RootPart.SendFullUpdateToAllClients();
1887 2226
@@ -2070,12 +2409,15 @@ namespace OpenSim.Region.Framework.Scenes
2070 part.LinkNum += objectGroup.PrimCount; 2409 part.LinkNum += objectGroup.PrimCount;
2071 } 2410 }
2072 } 2411 }
2412 }
2073 2413
2074 linkPart.LinkNum = 2; 2414 linkPart.LinkNum = 2;
2075 2415
2076 linkPart.SetParent(this); 2416 linkPart.SetParent(this);
2077 linkPart.CreateSelected = true; 2417 linkPart.CreateSelected = true;
2078 2418
2419 lock (m_parts.SyncRoot)
2420 {
2079 //if (linkPart.PhysActor != null) 2421 //if (linkPart.PhysActor != null)
2080 //{ 2422 //{
2081 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2423 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2233,6 +2575,8 @@ namespace OpenSim.Region.Framework.Scenes
2233 /// <param name="objectGroup"></param> 2575 /// <param name="objectGroup"></param>
2234 public virtual void DetachFromBackup() 2576 public virtual void DetachFromBackup()
2235 { 2577 {
2578 m_scene.SceneGraph.FireDetachFromBackup(this);
2579
2236 if (m_isBackedUp) 2580 if (m_isBackedUp)
2237 m_scene.EventManager.OnBackup -= ProcessBackup; 2581 m_scene.EventManager.OnBackup -= ProcessBackup;
2238 2582
@@ -2251,7 +2595,8 @@ namespace OpenSim.Region.Framework.Scenes
2251 2595
2252 axPos *= parentRot; 2596 axPos *= parentRot;
2253 part.OffsetPosition = axPos; 2597 part.OffsetPosition = axPos;
2254 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2598 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2599 part.GroupPosition = newPos;
2255 part.OffsetPosition = Vector3.Zero; 2600 part.OffsetPosition = Vector3.Zero;
2256 part.RotationOffset = worldRot; 2601 part.RotationOffset = worldRot;
2257 2602
@@ -2262,7 +2607,7 @@ namespace OpenSim.Region.Framework.Scenes
2262 2607
2263 part.LinkNum = linkNum; 2608 part.LinkNum = linkNum;
2264 2609
2265 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2610 part.OffsetPosition = newPos - AbsolutePosition;
2266 2611
2267 Quaternion rootRotation = m_rootPart.RotationOffset; 2612 Quaternion rootRotation = m_rootPart.RotationOffset;
2268 2613
@@ -2272,7 +2617,7 @@ namespace OpenSim.Region.Framework.Scenes
2272 2617
2273 parentRot = m_rootPart.RotationOffset; 2618 parentRot = m_rootPart.RotationOffset;
2274 oldRot = part.RotationOffset; 2619 oldRot = part.RotationOffset;
2275 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2620 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2276 part.RotationOffset = newRot; 2621 part.RotationOffset = newRot;
2277 } 2622 }
2278 2623
@@ -2523,8 +2868,12 @@ namespace OpenSim.Region.Framework.Scenes
2523 } 2868 }
2524 } 2869 }
2525 2870
2871 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2526 for (int i = 0; i < parts.Length; i++) 2872 for (int i = 0; i < parts.Length; i++)
2527 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2873 {
2874 if (parts[i] != RootPart)
2875 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2876 }
2528 } 2877 }
2529 } 2878 }
2530 2879
@@ -2537,6 +2886,17 @@ namespace OpenSim.Region.Framework.Scenes
2537 } 2886 }
2538 } 2887 }
2539 2888
2889
2890
2891 /// <summary>
2892 /// Gets the number of parts
2893 /// </summary>
2894 /// <returns></returns>
2895 public int GetPartCount()
2896 {
2897 return Parts.Count();
2898 }
2899
2540 /// <summary> 2900 /// <summary>
2541 /// Update the texture entry for this part 2901 /// Update the texture entry for this part
2542 /// </summary> 2902 /// </summary>
@@ -2598,11 +2958,9 @@ namespace OpenSim.Region.Framework.Scenes
2598 scale.Y = m_scene.m_maxNonphys; 2958 scale.Y = m_scene.m_maxNonphys;
2599 if (scale.Z > m_scene.m_maxNonphys) 2959 if (scale.Z > m_scene.m_maxNonphys)
2600 scale.Z = m_scene.m_maxNonphys; 2960 scale.Z = m_scene.m_maxNonphys;
2601
2602 SceneObjectPart part = GetChildPart(localID); 2961 SceneObjectPart part = GetChildPart(localID);
2603 if (part != null) 2962 if (part != null)
2604 { 2963 {
2605 part.Resize(scale);
2606 if (part.PhysActor != null) 2964 if (part.PhysActor != null)
2607 { 2965 {
2608 if (part.PhysActor.IsPhysical) 2966 if (part.PhysActor.IsPhysical)
@@ -2617,7 +2975,7 @@ namespace OpenSim.Region.Framework.Scenes
2617 part.PhysActor.Size = scale; 2975 part.PhysActor.Size = scale;
2618 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2976 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2619 } 2977 }
2620 //if (part.UUID != m_rootPart.UUID) 2978 part.Resize(scale);
2621 2979
2622 HasGroupChanged = true; 2980 HasGroupChanged = true;
2623 part.TriggerScriptChangedEvent(Changed.SCALE); 2981 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2640,7 +2998,6 @@ namespace OpenSim.Region.Framework.Scenes
2640 SceneObjectPart part = GetChildPart(localID); 2998 SceneObjectPart part = GetChildPart(localID);
2641 if (part != null) 2999 if (part != null)
2642 { 3000 {
2643 part.IgnoreUndoUpdate = true;
2644 if (scale.X > m_scene.m_maxNonphys) 3001 if (scale.X > m_scene.m_maxNonphys)
2645 scale.X = m_scene.m_maxNonphys; 3002 scale.X = m_scene.m_maxNonphys;
2646 if (scale.Y > m_scene.m_maxNonphys) 3003 if (scale.Y > m_scene.m_maxNonphys)
@@ -2677,7 +3034,7 @@ namespace OpenSim.Region.Framework.Scenes
2677 3034
2678 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3035 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2679 { 3036 {
2680 if (oldSize.X * x > m_scene.m_maxPhys) 3037 if (oldSize.X*x > m_scene.m_maxPhys)
2681 { 3038 {
2682 f = m_scene.m_maxPhys / oldSize.X; 3039 f = m_scene.m_maxPhys / oldSize.X;
2683 a = f / x; 3040 a = f / x;
@@ -2685,7 +3042,7 @@ namespace OpenSim.Region.Framework.Scenes
2685 y *= a; 3042 y *= a;
2686 z *= a; 3043 z *= a;
2687 } 3044 }
2688 if (oldSize.Y * y > m_scene.m_maxPhys) 3045 if (oldSize.Y*y > m_scene.m_maxPhys)
2689 { 3046 {
2690 f = m_scene.m_maxPhys / oldSize.Y; 3047 f = m_scene.m_maxPhys / oldSize.Y;
2691 a = f / y; 3048 a = f / y;
@@ -2693,7 +3050,7 @@ namespace OpenSim.Region.Framework.Scenes
2693 y *= a; 3050 y *= a;
2694 z *= a; 3051 z *= a;
2695 } 3052 }
2696 if (oldSize.Z * z > m_scene.m_maxPhys) 3053 if (oldSize.Z*z > m_scene.m_maxPhys)
2697 { 3054 {
2698 f = m_scene.m_maxPhys / oldSize.Z; 3055 f = m_scene.m_maxPhys / oldSize.Z;
2699 a = f / z; 3056 a = f / z;
@@ -2704,7 +3061,7 @@ namespace OpenSim.Region.Framework.Scenes
2704 } 3061 }
2705 else 3062 else
2706 { 3063 {
2707 if (oldSize.X * x > m_scene.m_maxNonphys) 3064 if (oldSize.X*x > m_scene.m_maxNonphys)
2708 { 3065 {
2709 f = m_scene.m_maxNonphys / oldSize.X; 3066 f = m_scene.m_maxNonphys / oldSize.X;
2710 a = f / x; 3067 a = f / x;
@@ -2712,7 +3069,7 @@ namespace OpenSim.Region.Framework.Scenes
2712 y *= a; 3069 y *= a;
2713 z *= a; 3070 z *= a;
2714 } 3071 }
2715 if (oldSize.Y * y > m_scene.m_maxNonphys) 3072 if (oldSize.Y*y > m_scene.m_maxNonphys)
2716 { 3073 {
2717 f = m_scene.m_maxNonphys / oldSize.Y; 3074 f = m_scene.m_maxNonphys / oldSize.Y;
2718 a = f / y; 3075 a = f / y;
@@ -2720,7 +3077,7 @@ namespace OpenSim.Region.Framework.Scenes
2720 y *= a; 3077 y *= a;
2721 z *= a; 3078 z *= a;
2722 } 3079 }
2723 if (oldSize.Z * z > m_scene.m_maxNonphys) 3080 if (oldSize.Z*z > m_scene.m_maxNonphys)
2724 { 3081 {
2725 f = m_scene.m_maxNonphys / oldSize.Z; 3082 f = m_scene.m_maxNonphys / oldSize.Z;
2726 a = f / z; 3083 a = f / z;
@@ -2730,7 +3087,6 @@ namespace OpenSim.Region.Framework.Scenes
2730 } 3087 }
2731 } 3088 }
2732 obPart.IgnoreUndoUpdate = false; 3089 obPart.IgnoreUndoUpdate = false;
2733 obPart.StoreUndoState();
2734 } 3090 }
2735 } 3091 }
2736 } 3092 }
@@ -2738,8 +3094,13 @@ namespace OpenSim.Region.Framework.Scenes
2738 Vector3 prevScale = part.Scale; 3094 Vector3 prevScale = part.Scale;
2739 prevScale.X *= x; 3095 prevScale.X *= x;
2740 prevScale.Y *= y; 3096 prevScale.Y *= y;
2741 prevScale.Z *= z; 3097 prevScale.Z *= z;;
3098
3099 part.IgnoreUndoUpdate = false;
3100 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3101 part.IgnoreUndoUpdate = true;
2742 part.Resize(prevScale); 3102 part.Resize(prevScale);
3103 part.IgnoreUndoUpdate = false;
2743 3104
2744 parts = m_parts.GetArray(); 3105 parts = m_parts.GetArray();
2745 for (int i = 0; i < parts.Length; i++) 3106 for (int i = 0; i < parts.Length; i++)
@@ -2748,19 +3109,26 @@ namespace OpenSim.Region.Framework.Scenes
2748 obPart.IgnoreUndoUpdate = true; 3109 obPart.IgnoreUndoUpdate = true;
2749 if (obPart.UUID != m_rootPart.UUID) 3110 if (obPart.UUID != m_rootPart.UUID)
2750 { 3111 {
2751 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3112 if (obPart.UUID != m_rootPart.UUID)
2752 currentpos.X *= x; 3113 {
2753 currentpos.Y *= y; 3114 obPart.IgnoreUndoUpdate = false;
2754 currentpos.Z *= z; 3115 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2755 Vector3 newSize = new Vector3(obPart.Scale); 3116 obPart.IgnoreUndoUpdate = true;
2756 newSize.X *= x; 3117
2757 newSize.Y *= y; 3118 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2758 newSize.Z *= z; 3119 currentpos.X *= x;
2759 obPart.Resize(newSize); 3120 currentpos.Y *= y;
2760 obPart.UpdateOffSet(currentpos); 3121 currentpos.Z *= z;
3122 Vector3 newSize = new Vector3(obPart.Scale);
3123 newSize.X *= x;
3124 newSize.Y *= y;
3125 newSize.Z *= z;
3126 obPart.Resize(newSize);
3127 obPart.UpdateOffSet(currentpos);
3128 }
3129 obPart.IgnoreUndoUpdate = false;
2761 } 3130 }
2762 obPart.IgnoreUndoUpdate = false; 3131 obPart.IgnoreUndoUpdate = false;
2763 obPart.StoreUndoState();
2764 } 3132 }
2765 3133
2766 if (part.PhysActor != null) 3134 if (part.PhysActor != null)
@@ -2770,7 +3138,6 @@ namespace OpenSim.Region.Framework.Scenes
2770 } 3138 }
2771 3139
2772 part.IgnoreUndoUpdate = false; 3140 part.IgnoreUndoUpdate = false;
2773 part.StoreUndoState();
2774 HasGroupChanged = true; 3141 HasGroupChanged = true;
2775 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3142 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2776 ScheduleGroupForTerseUpdate(); 3143 ScheduleGroupForTerseUpdate();
@@ -2787,14 +3154,11 @@ namespace OpenSim.Region.Framework.Scenes
2787 /// <param name="pos"></param> 3154 /// <param name="pos"></param>
2788 public void UpdateGroupPosition(Vector3 pos) 3155 public void UpdateGroupPosition(Vector3 pos)
2789 { 3156 {
2790 SceneObjectPart[] parts = m_parts.GetArray();
2791 for (int i = 0; i < parts.Length; i++)
2792 parts[i].StoreUndoState();
2793
2794 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3157 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2795 { 3158 {
2796 if (IsAttachment) 3159 if (IsAttachment)
2797 { 3160 {
3161 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2798 m_rootPart.AttachedPos = pos; 3162 m_rootPart.AttachedPos = pos;
2799 } 3163 }
2800 if (RootPart.GetStatusSandbox()) 3164 if (RootPart.GetStatusSandbox())
@@ -2828,7 +3192,7 @@ namespace OpenSim.Region.Framework.Scenes
2828 3192
2829 SceneObjectPart[] parts = m_parts.GetArray(); 3193 SceneObjectPart[] parts = m_parts.GetArray();
2830 for (int i = 0; i < parts.Length; i++) 3194 for (int i = 0; i < parts.Length; i++)
2831 parts[i].StoreUndoState(); 3195 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2832 3196
2833 if (part != null) 3197 if (part != null)
2834 { 3198 {
@@ -2853,7 +3217,7 @@ namespace OpenSim.Region.Framework.Scenes
2853 { 3217 {
2854 SceneObjectPart[] parts = m_parts.GetArray(); 3218 SceneObjectPart[] parts = m_parts.GetArray();
2855 for (int i = 0; i < parts.Length; i++) 3219 for (int i = 0; i < parts.Length; i++)
2856 parts[i].StoreUndoState(); 3220 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2857 3221
2858 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3222 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2859 Vector3 oldPos = 3223 Vector3 oldPos =
@@ -2874,10 +3238,27 @@ namespace OpenSim.Region.Framework.Scenes
2874 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3238 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2875 } 3239 }
2876 3240
2877 AbsolutePosition = newPos; 3241 //We have to set undoing here because otherwise an undo state will be saved
3242 if (!m_rootPart.Undoing)
3243 {
3244 m_rootPart.Undoing = true;
3245 AbsolutePosition = newPos;
3246 m_rootPart.Undoing = false;
3247 }
3248 else
3249 {
3250 AbsolutePosition = newPos;
3251 }
2878 3252
2879 HasGroupChanged = true; 3253 HasGroupChanged = true;
2880 ScheduleGroupForTerseUpdate(); 3254 if (m_rootPart.Undoing)
3255 {
3256 ScheduleGroupForFullUpdate();
3257 }
3258 else
3259 {
3260 ScheduleGroupForTerseUpdate();
3261 }
2881 } 3262 }
2882 3263
2883 public void OffsetForNewRegion(Vector3 offset) 3264 public void OffsetForNewRegion(Vector3 offset)
@@ -2897,7 +3278,7 @@ namespace OpenSim.Region.Framework.Scenes
2897 { 3278 {
2898 SceneObjectPart[] parts = m_parts.GetArray(); 3279 SceneObjectPart[] parts = m_parts.GetArray();
2899 for (int i = 0; i < parts.Length; i++) 3280 for (int i = 0; i < parts.Length; i++)
2900 parts[i].StoreUndoState(); 3281 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2901 3282
2902 m_rootPart.UpdateRotation(rot); 3283 m_rootPart.UpdateRotation(rot);
2903 3284
@@ -2921,7 +3302,7 @@ namespace OpenSim.Region.Framework.Scenes
2921 { 3302 {
2922 SceneObjectPart[] parts = m_parts.GetArray(); 3303 SceneObjectPart[] parts = m_parts.GetArray();
2923 for (int i = 0; i < parts.Length; i++) 3304 for (int i = 0; i < parts.Length; i++)
2924 parts[i].StoreUndoState(); 3305 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2925 3306
2926 m_rootPart.UpdateRotation(rot); 3307 m_rootPart.UpdateRotation(rot);
2927 3308
@@ -2946,10 +3327,9 @@ namespace OpenSim.Region.Framework.Scenes
2946 public void UpdateSingleRotation(Quaternion rot, uint localID) 3327 public void UpdateSingleRotation(Quaternion rot, uint localID)
2947 { 3328 {
2948 SceneObjectPart part = GetChildPart(localID); 3329 SceneObjectPart part = GetChildPart(localID);
2949
2950 SceneObjectPart[] parts = m_parts.GetArray(); 3330 SceneObjectPart[] parts = m_parts.GetArray();
2951 for (int i = 0; i < parts.Length; i++) 3331 for (int i = 0; i < parts.Length; i++)
2952 parts[i].StoreUndoState(); 3332 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2953 3333
2954 if (part != null) 3334 if (part != null)
2955 { 3335 {
@@ -2977,15 +3357,24 @@ namespace OpenSim.Region.Framework.Scenes
2977 if (part.UUID == m_rootPart.UUID) 3357 if (part.UUID == m_rootPart.UUID)
2978 { 3358 {
2979 UpdateRootRotation(rot); 3359 UpdateRootRotation(rot);
2980 AbsolutePosition = pos; 3360 if (!m_rootPart.Undoing)
3361 {
3362 m_rootPart.Undoing = true;
3363 AbsolutePosition = pos;
3364 m_rootPart.Undoing = false;
3365 }
3366 else
3367 {
3368 AbsolutePosition = pos;
3369 }
2981 } 3370 }
2982 else 3371 else
2983 { 3372 {
3373 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2984 part.IgnoreUndoUpdate = true; 3374 part.IgnoreUndoUpdate = true;
2985 part.UpdateRotation(rot); 3375 part.UpdateRotation(rot);
2986 part.OffsetPosition = pos; 3376 part.OffsetPosition = pos;
2987 part.IgnoreUndoUpdate = false; 3377 part.IgnoreUndoUpdate = false;
2988 part.StoreUndoState();
2989 } 3378 }
2990 } 3379 }
2991 } 3380 }
@@ -2999,8 +3388,16 @@ namespace OpenSim.Region.Framework.Scenes
2999 Quaternion axRot = rot; 3388 Quaternion axRot = rot;
3000 Quaternion oldParentRot = m_rootPart.RotationOffset; 3389 Quaternion oldParentRot = m_rootPart.RotationOffset;
3001 3390
3002 m_rootPart.StoreUndoState(); 3391 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3003 m_rootPart.UpdateRotation(rot); 3392 bool cancelUndo = false;
3393 if (!m_rootPart.Undoing)
3394 {
3395 m_rootPart.Undoing = true;
3396 cancelUndo = true;
3397 }
3398
3399 //Don't use UpdateRotation because it schedules an update prematurely
3400 m_rootPart.RotationOffset = rot;
3004 if (m_rootPart.PhysActor != null) 3401 if (m_rootPart.PhysActor != null)
3005 { 3402 {
3006 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3403 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -3015,28 +3412,22 @@ namespace OpenSim.Region.Framework.Scenes
3015 { 3412 {
3016 prim.IgnoreUndoUpdate = true; 3413 prim.IgnoreUndoUpdate = true;
3017 Vector3 axPos = prim.OffsetPosition; 3414 Vector3 axPos = prim.OffsetPosition;
3415
3018 axPos *= oldParentRot; 3416 axPos *= oldParentRot;
3019 axPos *= Quaternion.Inverse(axRot); 3417 axPos *= Quaternion.Inverse(axRot);
3020 prim.OffsetPosition = axPos; 3418 prim.OffsetPosition = axPos;
3021 Quaternion primsRot = prim.RotationOffset; 3419
3022 Quaternion newRot = primsRot * oldParentRot; 3420 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
3023 newRot *= Quaternion.Inverse(axRot); 3421
3024 prim.RotationOffset = newRot; 3422 prim.IgnoreUndoUpdate = false;
3025 prim.ScheduleTerseUpdate();
3026 } 3423 }
3027 } 3424 }
3028 3425 if (cancelUndo == true)
3029 for (int i = 0; i < parts.Length; i++)
3030 { 3426 {
3031 SceneObjectPart childpart = parts[i]; 3427 m_rootPart.Undoing = false;
3032 if (childpart != m_rootPart)
3033 {
3034 childpart.IgnoreUndoUpdate = false;
3035 childpart.StoreUndoState();
3036 }
3037 } 3428 }
3038 3429 HasGroupChanged = true;
3039 m_rootPart.ScheduleTerseUpdate(); 3430 ScheduleGroupForFullUpdate();
3040 } 3431 }
3041 3432
3042 #endregion 3433 #endregion
@@ -3259,7 +3650,6 @@ namespace OpenSim.Region.Framework.Scenes
3259 public float GetMass() 3650 public float GetMass()
3260 { 3651 {
3261 float retmass = 0f; 3652 float retmass = 0f;
3262
3263 SceneObjectPart[] parts = m_parts.GetArray(); 3653 SceneObjectPart[] parts = m_parts.GetArray();
3264 for (int i = 0; i < parts.Length; i++) 3654 for (int i = 0; i < parts.Length; i++)
3265 retmass += parts[i].GetMass(); 3655 retmass += parts[i].GetMass();
@@ -3375,6 +3765,14 @@ namespace OpenSim.Region.Framework.Scenes
3375 SetFromItemID(uuid); 3765 SetFromItemID(uuid);
3376 } 3766 }
3377 3767
3768 public void ResetOwnerChangeFlag()
3769 {
3770 ForEachPart(delegate(SceneObjectPart part)
3771 {
3772 part.ResetOwnerChangeFlag();
3773 });
3774 }
3775
3378 #endregion 3776 #endregion
3379 } 3777 }
3380} 3778}