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