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 9bb50db..69bfb9a 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
@@ -305,7 +374,11 @@ namespace OpenSim.Region.Framework.Scenes
305 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 374 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
306 } 375 }
307 } 376 }
308 377
378 foreach (SceneObjectPart part in m_parts.GetArray())
379 {
380 part.IgnoreUndoUpdate = true;
381 }
309 if (RootPart.GetStatusSandbox()) 382 if (RootPart.GetStatusSandbox())
310 { 383 {
311 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 384 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -319,10 +392,31 @@ namespace OpenSim.Region.Framework.Scenes
319 return; 392 return;
320 } 393 }
321 } 394 }
322
323 SceneObjectPart[] parts = m_parts.GetArray(); 395 SceneObjectPart[] parts = m_parts.GetArray();
324 for (int i = 0; i < parts.Length; i++) 396 foreach (SceneObjectPart part in parts)
325 parts[i].GroupPosition = val; 397 {
398 part.IgnoreUndoUpdate = false;
399 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
400 part.GroupPosition = val;
401 if (!m_dupeInProgress)
402 {
403 part.TriggerScriptChangedEvent(Changed.POSITION);
404 }
405 }
406 if (!m_dupeInProgress)
407 {
408 foreach (ScenePresence av in m_linkedAvatars)
409 {
410 SceneObjectPart p;
411 if (m_parts.TryGetValue(av.LinkedPrim, out p))
412 {
413 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
414 av.AbsolutePosition += offset;
415 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
416 av.SendAvatarDataToAllAgents();
417 }
418 }
419 }
326 420
327 //if (m_rootPart.PhysActor != null) 421 //if (m_rootPart.PhysActor != null)
328 //{ 422 //{
@@ -476,6 +570,7 @@ namespace OpenSim.Region.Framework.Scenes
476 /// </summary> 570 /// </summary>
477 public SceneObjectGroup() 571 public SceneObjectGroup()
478 { 572 {
573
479 } 574 }
480 575
481 /// <summary> 576 /// <summary>
@@ -492,7 +587,7 @@ namespace OpenSim.Region.Framework.Scenes
492 /// Constructor. This object is added to the scene later via AttachToScene() 587 /// Constructor. This object is added to the scene later via AttachToScene()
493 /// </summary> 588 /// </summary>
494 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 589 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
495 { 590 {
496 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 591 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
497 } 592 }
498 593
@@ -540,6 +635,9 @@ namespace OpenSim.Region.Framework.Scenes
540 /// </summary> 635 /// </summary>
541 public virtual void AttachToBackup() 636 public virtual void AttachToBackup()
542 { 637 {
638 if (IsAttachment) return;
639 m_scene.SceneGraph.FireAttachToBackup(this);
640
543 if (InSceneBackup) 641 if (InSceneBackup)
544 { 642 {
545 //m_log.DebugFormat( 643 //m_log.DebugFormat(
@@ -655,9 +753,9 @@ namespace OpenSim.Region.Framework.Scenes
655 result.normal = inter.normal; 753 result.normal = inter.normal;
656 result.distance = inter.distance; 754 result.distance = inter.distance;
657 } 755 }
756
658 } 757 }
659 } 758 }
660
661 return result; 759 return result;
662 } 760 }
663 761
@@ -677,17 +775,19 @@ namespace OpenSim.Region.Framework.Scenes
677 minZ = 8192f; 775 minZ = 8192f;
678 776
679 SceneObjectPart[] parts = m_parts.GetArray(); 777 SceneObjectPart[] parts = m_parts.GetArray();
680 for (int i = 0; i < parts.Length; i++) 778 foreach (SceneObjectPart part in parts)
681 { 779 {
682 SceneObjectPart part = parts[i];
683
684 Vector3 worldPos = part.GetWorldPosition(); 780 Vector3 worldPos = part.GetWorldPosition();
685 Vector3 offset = worldPos - AbsolutePosition; 781 Vector3 offset = worldPos - AbsolutePosition;
686 Quaternion worldRot; 782 Quaternion worldRot;
687 if (part.ParentID == 0) 783 if (part.ParentID == 0)
784 {
688 worldRot = part.RotationOffset; 785 worldRot = part.RotationOffset;
786 }
689 else 787 else
788 {
690 worldRot = part.GetWorldRotation(); 789 worldRot = part.GetWorldRotation();
790 }
691 791
692 Vector3 frontTopLeft; 792 Vector3 frontTopLeft;
693 Vector3 frontTopRight; 793 Vector3 frontTopRight;
@@ -699,6 +799,8 @@ namespace OpenSim.Region.Framework.Scenes
699 Vector3 backBottomLeft; 799 Vector3 backBottomLeft;
700 Vector3 backBottomRight; 800 Vector3 backBottomRight;
701 801
802 // Vector3[] corners = new Vector3[8];
803
702 Vector3 orig = Vector3.Zero; 804 Vector3 orig = Vector3.Zero;
703 805
704 frontTopLeft.X = orig.X - (part.Scale.X / 2); 806 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -733,6 +835,38 @@ namespace OpenSim.Region.Framework.Scenes
733 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 835 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
734 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 836 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
735 837
838
839
840 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
841 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
842 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
843 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
844 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
845 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
846 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
847 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
848
849 //for (int i = 0; i < 8; i++)
850 //{
851 // corners[i] = corners[i] * worldRot;
852 // corners[i] += offset;
853
854 // if (corners[i].X > maxX)
855 // maxX = corners[i].X;
856 // if (corners[i].X < minX)
857 // minX = corners[i].X;
858
859 // if (corners[i].Y > maxY)
860 // maxY = corners[i].Y;
861 // if (corners[i].Y < minY)
862 // minY = corners[i].Y;
863
864 // if (corners[i].Z > maxZ)
865 // maxZ = corners[i].Y;
866 // if (corners[i].Z < minZ)
867 // minZ = corners[i].Z;
868 //}
869
736 frontTopLeft = frontTopLeft * worldRot; 870 frontTopLeft = frontTopLeft * worldRot;
737 frontTopRight = frontTopRight * worldRot; 871 frontTopRight = frontTopRight * worldRot;
738 frontBottomLeft = frontBottomLeft * worldRot; 872 frontBottomLeft = frontBottomLeft * worldRot;
@@ -754,6 +888,15 @@ namespace OpenSim.Region.Framework.Scenes
754 backTopLeft += offset; 888 backTopLeft += offset;
755 backTopRight += offset; 889 backTopRight += offset;
756 890
891 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
892 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
893 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
894 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
895 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
896 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
897 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
898 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
899
757 if (frontTopRight.X > maxX) 900 if (frontTopRight.X > maxX)
758 maxX = frontTopRight.X; 901 maxX = frontTopRight.X;
759 if (frontTopLeft.X > maxX) 902 if (frontTopLeft.X > maxX)
@@ -899,15 +1042,20 @@ namespace OpenSim.Region.Framework.Scenes
899 1042
900 public void SaveScriptedState(XmlTextWriter writer) 1043 public void SaveScriptedState(XmlTextWriter writer)
901 { 1044 {
1045 SaveScriptedState(writer, false);
1046 }
1047
1048 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1049 {
902 XmlDocument doc = new XmlDocument(); 1050 XmlDocument doc = new XmlDocument();
903 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1051 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
904 1052
905 SceneObjectPart[] parts = m_parts.GetArray(); 1053 SceneObjectPart[] parts = m_parts.GetArray();
906 for (int i = 0; i < parts.Length; i++) 1054 for (int i = 0; i < parts.Length; i++)
907 { 1055 {
908 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1056 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
909 foreach (KeyValuePair<UUID, string> kvp in pstates) 1057 foreach (KeyValuePair<UUID, string> kvp in pstates)
910 states.Add(kvp.Key, kvp.Value); 1058 states[kvp.Key] = kvp.Value;
911 } 1059 }
912 1060
913 if (states.Count > 0) 1061 if (states.Count > 0)
@@ -926,6 +1074,118 @@ namespace OpenSim.Region.Framework.Scenes
926 } 1074 }
927 } 1075 }
928 1076
1077 /// <summary>
1078 /// Add the avatar to this linkset (avatar is sat).
1079 /// </summary>
1080 /// <param name="agentID"></param>
1081 public void AddAvatar(UUID agentID)
1082 {
1083 ScenePresence presence;
1084 if (m_scene.TryGetScenePresence(agentID, out presence))
1085 {
1086 if (!m_linkedAvatars.Contains(presence))
1087 {
1088 m_linkedAvatars.Add(presence);
1089 }
1090 }
1091 }
1092
1093 /// <summary>
1094 /// Delete the avatar from this linkset (avatar is unsat).
1095 /// </summary>
1096 /// <param name="agentID"></param>
1097 public void DeleteAvatar(UUID agentID)
1098 {
1099 ScenePresence presence;
1100 if (m_scene.TryGetScenePresence(agentID, out presence))
1101 {
1102 if (m_linkedAvatars.Contains(presence))
1103 {
1104 m_linkedAvatars.Remove(presence);
1105 }
1106 }
1107 }
1108
1109 /// <summary>
1110 /// Returns the list of linked presences (avatars sat on this group)
1111 /// </summary>
1112 /// <param name="agentID"></param>
1113 public List<ScenePresence> GetLinkedAvatars()
1114 {
1115 return m_linkedAvatars;
1116 }
1117
1118 /// <summary>
1119 /// Attach this scene object to the given avatar.
1120 /// </summary>
1121 /// <param name="agentID"></param>
1122 /// <param name="attachmentpoint"></param>
1123 /// <param name="AttachOffset"></param>
1124 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1125 {
1126 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1127 if (avatar != null)
1128 {
1129 // don't attach attachments to child agents
1130 if (avatar.IsChildAgent) return;
1131
1132// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1133
1134 DetachFromBackup();
1135
1136 // Remove from database and parcel prim count
1137 m_scene.DeleteFromStorage(UUID);
1138 m_scene.EventManager.TriggerParcelPrimCountTainted();
1139
1140 m_rootPart.AttachedAvatar = agentID;
1141
1142 //Anakin Lohner bug #3839
1143 lock (m_parts)
1144 {
1145 foreach (SceneObjectPart p in m_parts.GetArray())
1146 {
1147 p.AttachedAvatar = agentID;
1148 }
1149 }
1150
1151 if (m_rootPart.PhysActor != null)
1152 {
1153 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1154 m_rootPart.PhysActor = null;
1155 }
1156
1157 AbsolutePosition = AttachOffset;
1158 m_rootPart.AttachedPos = AttachOffset;
1159 m_rootPart.IsAttachment = true;
1160
1161 m_rootPart.SetParentLocalId(avatar.LocalId);
1162 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1163
1164 avatar.AddAttachment(this);
1165
1166 if (!silent)
1167 {
1168 // Killing it here will cause the client to deselect it
1169 // It then reappears on the avatar, deselected
1170 // through the full update below
1171 //
1172 if (IsSelected)
1173 {
1174 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1175 }
1176
1177 IsSelected = false; // fudge....
1178 ScheduleGroupForFullUpdate();
1179 }
1180 }
1181 else
1182 {
1183 m_log.WarnFormat(
1184 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1185 UUID, agentID, Scene.RegionInfo.RegionName);
1186 }
1187 }
1188
929 public byte GetAttachmentPoint() 1189 public byte GetAttachmentPoint()
930 { 1190 {
931 return m_rootPart.Shape.State; 1191 return m_rootPart.Shape.State;
@@ -1052,7 +1312,10 @@ namespace OpenSim.Region.Framework.Scenes
1052 public void AddPart(SceneObjectPart part) 1312 public void AddPart(SceneObjectPart part)
1053 { 1313 {
1054 part.SetParent(this); 1314 part.SetParent(this);
1055 part.LinkNum = m_parts.Add(part.UUID, part); 1315 m_parts.Add(part.UUID, part);
1316
1317 part.LinkNum = m_parts.Count;
1318
1056 if (part.LinkNum == 2 && RootPart != null) 1319 if (part.LinkNum == 2 && RootPart != null)
1057 RootPart.LinkNum = 1; 1320 RootPart.LinkNum = 1;
1058 } 1321 }
@@ -1136,7 +1399,7 @@ namespace OpenSim.Region.Framework.Scenes
1136 1399
1137 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1400 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1138 { 1401 {
1139 part.StoreUndoState(); 1402 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1140 part.OnGrab(offsetPos, remoteClient); 1403 part.OnGrab(offsetPos, remoteClient);
1141 } 1404 }
1142 1405
@@ -1156,6 +1419,11 @@ namespace OpenSim.Region.Framework.Scenes
1156 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1419 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1157 public void DeleteGroupFromScene(bool silent) 1420 public void DeleteGroupFromScene(bool silent)
1158 { 1421 {
1422 // We need to keep track of this state in case this group is still queued for backup.
1423 m_isDeleted = true;
1424
1425 DetachFromBackup();
1426
1159 SceneObjectPart[] parts = m_parts.GetArray(); 1427 SceneObjectPart[] parts = m_parts.GetArray();
1160 for (int i = 0; i < parts.Length; i++) 1428 for (int i = 0; i < parts.Length; i++)
1161 { 1429 {
@@ -1167,13 +1435,11 @@ namespace OpenSim.Region.Framework.Scenes
1167 avatar.StandUp(); 1435 avatar.StandUp();
1168 1436
1169 if (!silent) 1437 if (!silent)
1170 {
1171 part.UpdateFlag = 0; 1438 part.UpdateFlag = 0;
1172 if (part == m_rootPart)
1173 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1174 }
1175 }); 1439 });
1176 } 1440 }
1441
1442
1177 } 1443 }
1178 1444
1179 public void AddScriptLPS(int count) 1445 public void AddScriptLPS(int count)
@@ -1270,7 +1536,12 @@ namespace OpenSim.Region.Framework.Scenes
1270 1536
1271 public void SetOwnerId(UUID userId) 1537 public void SetOwnerId(UUID userId)
1272 { 1538 {
1273 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1539 ForEachPart(delegate(SceneObjectPart part)
1540 {
1541
1542 part.OwnerID = userId;
1543
1544 });
1274 } 1545 }
1275 1546
1276 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1547 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1302,11 +1573,17 @@ namespace OpenSim.Region.Framework.Scenes
1302 return; 1573 return;
1303 } 1574 }
1304 1575
1576 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1577 return;
1578
1305 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1579 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1306 // any exception propogate upwards. 1580 // any exception propogate upwards.
1307 try 1581 try
1308 { 1582 {
1309 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1583 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1584 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1585 m_scene.LoadingPrims) // Land may not be valid yet
1586
1310 { 1587 {
1311 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1588 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1312 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1589 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1333,6 +1610,7 @@ namespace OpenSim.Region.Framework.Scenes
1333 } 1610 }
1334 } 1611 }
1335 } 1612 }
1613
1336 } 1614 }
1337 1615
1338 if (HasGroupChanged) 1616 if (HasGroupChanged)
@@ -1340,6 +1618,20 @@ namespace OpenSim.Region.Framework.Scenes
1340 // don't backup while it's selected or you're asking for changes mid stream. 1618 // don't backup while it's selected or you're asking for changes mid stream.
1341 if (isTimeToPersist() || forcedBackup) 1619 if (isTimeToPersist() || forcedBackup)
1342 { 1620 {
1621 if (m_rootPart.PhysActor != null &&
1622 (!m_rootPart.PhysActor.IsPhysical))
1623 {
1624 // Possible ghost prim
1625 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1626 {
1627 foreach (SceneObjectPart part in m_parts.GetArray())
1628 {
1629 // Re-set physics actor positions and
1630 // orientations
1631 part.GroupPosition = m_rootPart.GroupPosition;
1632 }
1633 }
1634 }
1343// m_log.DebugFormat( 1635// m_log.DebugFormat(
1344// "[SCENE]: Storing {0}, {1} in {2}", 1636// "[SCENE]: Storing {0}, {1} in {2}",
1345// Name, UUID, m_scene.RegionInfo.RegionName); 1637// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1403,81 +1695,90 @@ namespace OpenSim.Region.Framework.Scenes
1403 /// <returns></returns> 1695 /// <returns></returns>
1404 public SceneObjectGroup Copy(bool userExposed) 1696 public SceneObjectGroup Copy(bool userExposed)
1405 { 1697 {
1406 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1698 SceneObjectGroup dupe;
1407 dupe.m_isBackedUp = false; 1699 try
1408 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1700 {
1409 1701 m_dupeInProgress = true;
1410 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1702 dupe = (SceneObjectGroup)MemberwiseClone();
1411 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1703 dupe.m_isBackedUp = false;
1412 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1704 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1413 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1414 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1415 // then restore it's attachment state
1416
1417 // This is only necessary when userExposed is false!
1418 1705
1419 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1706 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1420 1707 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1421 if (!userExposed) 1708 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1422 dupe.RootPart.IsAttachment = true; 1709 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1710 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1711 // then restore it's attachment state
1423 1712
1424 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1713 // This is only necessary when userExposed is false!
1425 1714
1426 if (!userExposed) 1715 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1427 {
1428 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1429 }
1430 1716
1431 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1717 if (!userExposed)
1432 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1718 dupe.RootPart.IsAttachment = true;
1433 1719
1434 if (userExposed) 1720 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1435 dupe.m_rootPart.TrimPermissions();
1436 1721
1437 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1722 if (!userExposed)
1438
1439 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1440 { 1723 {
1441 return p1.LinkNum.CompareTo(p2.LinkNum); 1724 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1442 } 1725 }
1443 );
1444 1726
1445 foreach (SceneObjectPart part in partList) 1727 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1446 { 1728 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1447 if (part.UUID != m_rootPart.UUID) 1729
1730 if (userExposed)
1731 dupe.m_rootPart.TrimPermissions();
1732
1733 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1734
1735 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1736 {
1737 return p1.LinkNum.CompareTo(p2.LinkNum);
1738 }
1739 );
1740
1741 foreach (SceneObjectPart part in partList)
1448 { 1742 {
1449 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1743 if (part.UUID != m_rootPart.UUID)
1450 newPart.LinkNum = part.LinkNum; 1744 {
1451 } 1745 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1452 1746
1453 // Need to duplicate the physics actor as well 1747 newPart.LinkNum = part.LinkNum;
1454 if (part.PhysActor != null && userExposed) 1748 }
1749
1750 // Need to duplicate the physics actor as well
1751 if (part.PhysActor != null && userExposed)
1752 {
1753 PrimitiveBaseShape pbs = part.Shape;
1754
1755 part.PhysActor
1756 = m_scene.PhysicsScene.AddPrimShape(
1757 string.Format("{0}/{1}", part.Name, part.UUID),
1758 pbs,
1759 part.AbsolutePosition,
1760 part.Scale,
1761 part.RotationOffset,
1762 part.PhysActor.IsPhysical);
1763 part.PhysActor.SetMaterial((int)part.Material);
1764
1765 part.PhysActor.LocalID = part.LocalId;
1766 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1767 }
1768 }
1769 if (userExposed)
1455 { 1770 {
1456 PrimitiveBaseShape pbs = part.Shape; 1771 dupe.UpdateParentIDs();
1457 1772 dupe.HasGroupChanged = true;
1458 part.PhysActor 1773 dupe.AttachToBackup();
1459 = m_scene.PhysicsScene.AddPrimShape( 1774
1460 string.Format("{0}/{1}", part.Name, part.UUID), 1775 ScheduleGroupForFullUpdate();
1461 pbs,
1462 part.AbsolutePosition,
1463 part.Scale,
1464 part.RotationOffset,
1465 part.PhysActor.IsPhysical);
1466
1467 part.PhysActor.LocalID = part.LocalId;
1468 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1469 } 1776 }
1470 } 1777 }
1471 1778 finally
1472 if (userExposed)
1473 { 1779 {
1474 dupe.UpdateParentIDs(); 1780 m_dupeInProgress = false;
1475 dupe.HasGroupChanged = true;
1476 dupe.AttachToBackup();
1477
1478 ScheduleGroupForFullUpdate();
1479 } 1781 }
1480
1481 return dupe; 1782 return dupe;
1482 } 1783 }
1483 1784
@@ -1622,6 +1923,7 @@ namespace OpenSim.Region.Framework.Scenes
1622 return Vector3.Zero; 1923 return Vector3.Zero;
1623 } 1924 }
1624 1925
1926 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1625 public void moveToTarget(Vector3 target, float tau) 1927 public void moveToTarget(Vector3 target, float tau)
1626 { 1928 {
1627 SceneObjectPart rootpart = m_rootPart; 1929 SceneObjectPart rootpart = m_rootPart;
@@ -1661,20 +1963,55 @@ namespace OpenSim.Region.Framework.Scenes
1661 SceneObjectPart rootpart = m_rootPart; 1963 SceneObjectPart rootpart = m_rootPart;
1662 if (rootpart != null) 1964 if (rootpart != null)
1663 { 1965 {
1664 if (rootpart.PhysActor != null) 1966 if (IsAttachment)
1967 {
1968 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1969 if (avatar != null) avatar.StopMoveToPosition();
1970 }
1971 else
1665 { 1972 {
1666 rootpart.PhysActor.PIDActive = false; 1973 if (rootpart.PhysActor != null)
1974 {
1975 rootpart.PhysActor.PIDActive = false;
1976 }
1667 } 1977 }
1668 } 1978 }
1669 } 1979 }
1670 1980
1981 public void rotLookAt(Quaternion target, float strength, float damping)
1982 {
1983 SceneObjectPart rootpart = m_rootPart;
1984 if (rootpart != null)
1985 {
1986 if (IsAttachment)
1987 {
1988 /*
1989 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1990 if (avatar != null)
1991 {
1992 Rotate the Av?
1993 } */
1994 }
1995 else
1996 {
1997 if (rootpart.PhysActor != null)
1998 { // APID must be implemented in your physics system for this to function.
1999 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2000 rootpart.PhysActor.APIDStrength = strength;
2001 rootpart.PhysActor.APIDDamping = damping;
2002 rootpart.PhysActor.APIDActive = true;
2003 }
2004 }
2005 }
2006 }
2007
1671 public void stopLookAt() 2008 public void stopLookAt()
1672 { 2009 {
1673 SceneObjectPart rootpart = m_rootPart; 2010 SceneObjectPart rootpart = m_rootPart;
1674 if (rootpart != null) 2011 if (rootpart != null)
1675 { 2012 {
1676 if (rootpart.PhysActor != null) 2013 if (rootpart.PhysActor != null)
1677 { 2014 { // APID must be implemented in your physics system for this to function.
1678 rootpart.PhysActor.APIDActive = false; 2015 rootpart.PhysActor.APIDActive = false;
1679 } 2016 }
1680 } 2017 }
@@ -1740,6 +2077,8 @@ namespace OpenSim.Region.Framework.Scenes
1740 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2077 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1741 { 2078 {
1742 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2079 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2080 newPart.SetParent(this);
2081
1743 AddPart(newPart); 2082 AddPart(newPart);
1744 2083
1745 SetPartAsNonRoot(newPart); 2084 SetPartAsNonRoot(newPart);
@@ -1886,11 +2225,11 @@ namespace OpenSim.Region.Framework.Scenes
1886 /// Immediately send a full update for this scene object. 2225 /// Immediately send a full update for this scene object.
1887 /// </summary> 2226 /// </summary>
1888 public void SendGroupFullUpdate() 2227 public void SendGroupFullUpdate()
1889 { 2228 {
1890 if (IsDeleted) 2229 if (IsDeleted)
1891 return; 2230 return;
1892 2231
1893// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2232// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1894 2233
1895 RootPart.SendFullUpdateToAllClients(); 2234 RootPart.SendFullUpdateToAllClients();
1896 2235
@@ -2079,12 +2418,15 @@ namespace OpenSim.Region.Framework.Scenes
2079 part.LinkNum += objectGroup.PrimCount; 2418 part.LinkNum += objectGroup.PrimCount;
2080 } 2419 }
2081 } 2420 }
2421 }
2082 2422
2083 linkPart.LinkNum = 2; 2423 linkPart.LinkNum = 2;
2084 2424
2085 linkPart.SetParent(this); 2425 linkPart.SetParent(this);
2086 linkPart.CreateSelected = true; 2426 linkPart.CreateSelected = true;
2087 2427
2428 lock (m_parts.SyncRoot)
2429 {
2088 //if (linkPart.PhysActor != null) 2430 //if (linkPart.PhysActor != null)
2089 //{ 2431 //{
2090 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2432 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2242,6 +2584,8 @@ namespace OpenSim.Region.Framework.Scenes
2242 /// <param name="objectGroup"></param> 2584 /// <param name="objectGroup"></param>
2243 public virtual void DetachFromBackup() 2585 public virtual void DetachFromBackup()
2244 { 2586 {
2587 m_scene.SceneGraph.FireDetachFromBackup(this);
2588
2245 if (m_isBackedUp) 2589 if (m_isBackedUp)
2246 m_scene.EventManager.OnBackup -= ProcessBackup; 2590 m_scene.EventManager.OnBackup -= ProcessBackup;
2247 2591
@@ -2260,7 +2604,8 @@ namespace OpenSim.Region.Framework.Scenes
2260 2604
2261 axPos *= parentRot; 2605 axPos *= parentRot;
2262 part.OffsetPosition = axPos; 2606 part.OffsetPosition = axPos;
2263 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2607 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2608 part.GroupPosition = newPos;
2264 part.OffsetPosition = Vector3.Zero; 2609 part.OffsetPosition = Vector3.Zero;
2265 part.RotationOffset = worldRot; 2610 part.RotationOffset = worldRot;
2266 2611
@@ -2271,7 +2616,7 @@ namespace OpenSim.Region.Framework.Scenes
2271 2616
2272 part.LinkNum = linkNum; 2617 part.LinkNum = linkNum;
2273 2618
2274 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2619 part.OffsetPosition = newPos - AbsolutePosition;
2275 2620
2276 Quaternion rootRotation = m_rootPart.RotationOffset; 2621 Quaternion rootRotation = m_rootPart.RotationOffset;
2277 2622
@@ -2281,7 +2626,7 @@ namespace OpenSim.Region.Framework.Scenes
2281 2626
2282 parentRot = m_rootPart.RotationOffset; 2627 parentRot = m_rootPart.RotationOffset;
2283 oldRot = part.RotationOffset; 2628 oldRot = part.RotationOffset;
2284 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2629 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2285 part.RotationOffset = newRot; 2630 part.RotationOffset = newRot;
2286 } 2631 }
2287 2632
@@ -2532,8 +2877,12 @@ namespace OpenSim.Region.Framework.Scenes
2532 } 2877 }
2533 } 2878 }
2534 2879
2880 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2535 for (int i = 0; i < parts.Length; i++) 2881 for (int i = 0; i < parts.Length; i++)
2536 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2882 {
2883 if (parts[i] != RootPart)
2884 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2885 }
2537 } 2886 }
2538 } 2887 }
2539 2888
@@ -2546,6 +2895,17 @@ namespace OpenSim.Region.Framework.Scenes
2546 } 2895 }
2547 } 2896 }
2548 2897
2898
2899
2900 /// <summary>
2901 /// Gets the number of parts
2902 /// </summary>
2903 /// <returns></returns>
2904 public int GetPartCount()
2905 {
2906 return Parts.Count();
2907 }
2908
2549 /// <summary> 2909 /// <summary>
2550 /// Update the texture entry for this part 2910 /// Update the texture entry for this part
2551 /// </summary> 2911 /// </summary>
@@ -2607,11 +2967,9 @@ namespace OpenSim.Region.Framework.Scenes
2607 scale.Y = m_scene.m_maxNonphys; 2967 scale.Y = m_scene.m_maxNonphys;
2608 if (scale.Z > m_scene.m_maxNonphys) 2968 if (scale.Z > m_scene.m_maxNonphys)
2609 scale.Z = m_scene.m_maxNonphys; 2969 scale.Z = m_scene.m_maxNonphys;
2610
2611 SceneObjectPart part = GetChildPart(localID); 2970 SceneObjectPart part = GetChildPart(localID);
2612 if (part != null) 2971 if (part != null)
2613 { 2972 {
2614 part.Resize(scale);
2615 if (part.PhysActor != null) 2973 if (part.PhysActor != null)
2616 { 2974 {
2617 if (part.PhysActor.IsPhysical) 2975 if (part.PhysActor.IsPhysical)
@@ -2626,7 +2984,7 @@ namespace OpenSim.Region.Framework.Scenes
2626 part.PhysActor.Size = scale; 2984 part.PhysActor.Size = scale;
2627 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2985 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2628 } 2986 }
2629 //if (part.UUID != m_rootPart.UUID) 2987 part.Resize(scale);
2630 2988
2631 HasGroupChanged = true; 2989 HasGroupChanged = true;
2632 part.TriggerScriptChangedEvent(Changed.SCALE); 2990 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2649,7 +3007,6 @@ namespace OpenSim.Region.Framework.Scenes
2649 SceneObjectPart part = GetChildPart(localID); 3007 SceneObjectPart part = GetChildPart(localID);
2650 if (part != null) 3008 if (part != null)
2651 { 3009 {
2652 part.IgnoreUndoUpdate = true;
2653 if (scale.X > m_scene.m_maxNonphys) 3010 if (scale.X > m_scene.m_maxNonphys)
2654 scale.X = m_scene.m_maxNonphys; 3011 scale.X = m_scene.m_maxNonphys;
2655 if (scale.Y > m_scene.m_maxNonphys) 3012 if (scale.Y > m_scene.m_maxNonphys)
@@ -2686,7 +3043,7 @@ namespace OpenSim.Region.Framework.Scenes
2686 3043
2687 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3044 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2688 { 3045 {
2689 if (oldSize.X * x > m_scene.m_maxPhys) 3046 if (oldSize.X*x > m_scene.m_maxPhys)
2690 { 3047 {
2691 f = m_scene.m_maxPhys / oldSize.X; 3048 f = m_scene.m_maxPhys / oldSize.X;
2692 a = f / x; 3049 a = f / x;
@@ -2694,7 +3051,7 @@ namespace OpenSim.Region.Framework.Scenes
2694 y *= a; 3051 y *= a;
2695 z *= a; 3052 z *= a;
2696 } 3053 }
2697 if (oldSize.Y * y > m_scene.m_maxPhys) 3054 if (oldSize.Y*y > m_scene.m_maxPhys)
2698 { 3055 {
2699 f = m_scene.m_maxPhys / oldSize.Y; 3056 f = m_scene.m_maxPhys / oldSize.Y;
2700 a = f / y; 3057 a = f / y;
@@ -2702,7 +3059,7 @@ namespace OpenSim.Region.Framework.Scenes
2702 y *= a; 3059 y *= a;
2703 z *= a; 3060 z *= a;
2704 } 3061 }
2705 if (oldSize.Z * z > m_scene.m_maxPhys) 3062 if (oldSize.Z*z > m_scene.m_maxPhys)
2706 { 3063 {
2707 f = m_scene.m_maxPhys / oldSize.Z; 3064 f = m_scene.m_maxPhys / oldSize.Z;
2708 a = f / z; 3065 a = f / z;
@@ -2713,7 +3070,7 @@ namespace OpenSim.Region.Framework.Scenes
2713 } 3070 }
2714 else 3071 else
2715 { 3072 {
2716 if (oldSize.X * x > m_scene.m_maxNonphys) 3073 if (oldSize.X*x > m_scene.m_maxNonphys)
2717 { 3074 {
2718 f = m_scene.m_maxNonphys / oldSize.X; 3075 f = m_scene.m_maxNonphys / oldSize.X;
2719 a = f / x; 3076 a = f / x;
@@ -2721,7 +3078,7 @@ namespace OpenSim.Region.Framework.Scenes
2721 y *= a; 3078 y *= a;
2722 z *= a; 3079 z *= a;
2723 } 3080 }
2724 if (oldSize.Y * y > m_scene.m_maxNonphys) 3081 if (oldSize.Y*y > m_scene.m_maxNonphys)
2725 { 3082 {
2726 f = m_scene.m_maxNonphys / oldSize.Y; 3083 f = m_scene.m_maxNonphys / oldSize.Y;
2727 a = f / y; 3084 a = f / y;
@@ -2729,7 +3086,7 @@ namespace OpenSim.Region.Framework.Scenes
2729 y *= a; 3086 y *= a;
2730 z *= a; 3087 z *= a;
2731 } 3088 }
2732 if (oldSize.Z * z > m_scene.m_maxNonphys) 3089 if (oldSize.Z*z > m_scene.m_maxNonphys)
2733 { 3090 {
2734 f = m_scene.m_maxNonphys / oldSize.Z; 3091 f = m_scene.m_maxNonphys / oldSize.Z;
2735 a = f / z; 3092 a = f / z;
@@ -2739,7 +3096,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 } 3096 }
2740 } 3097 }
2741 obPart.IgnoreUndoUpdate = false; 3098 obPart.IgnoreUndoUpdate = false;
2742 obPart.StoreUndoState();
2743 } 3099 }
2744 } 3100 }
2745 } 3101 }
@@ -2747,8 +3103,13 @@ namespace OpenSim.Region.Framework.Scenes
2747 Vector3 prevScale = part.Scale; 3103 Vector3 prevScale = part.Scale;
2748 prevScale.X *= x; 3104 prevScale.X *= x;
2749 prevScale.Y *= y; 3105 prevScale.Y *= y;
2750 prevScale.Z *= z; 3106 prevScale.Z *= z;;
3107
3108 part.IgnoreUndoUpdate = false;
3109 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3110 part.IgnoreUndoUpdate = true;
2751 part.Resize(prevScale); 3111 part.Resize(prevScale);
3112 part.IgnoreUndoUpdate = false;
2752 3113
2753 parts = m_parts.GetArray(); 3114 parts = m_parts.GetArray();
2754 for (int i = 0; i < parts.Length; i++) 3115 for (int i = 0; i < parts.Length; i++)
@@ -2757,19 +3118,26 @@ namespace OpenSim.Region.Framework.Scenes
2757 obPart.IgnoreUndoUpdate = true; 3118 obPart.IgnoreUndoUpdate = true;
2758 if (obPart.UUID != m_rootPart.UUID) 3119 if (obPart.UUID != m_rootPart.UUID)
2759 { 3120 {
2760 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3121 if (obPart.UUID != m_rootPart.UUID)
2761 currentpos.X *= x; 3122 {
2762 currentpos.Y *= y; 3123 obPart.IgnoreUndoUpdate = false;
2763 currentpos.Z *= z; 3124 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2764 Vector3 newSize = new Vector3(obPart.Scale); 3125 obPart.IgnoreUndoUpdate = true;
2765 newSize.X *= x; 3126
2766 newSize.Y *= y; 3127 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2767 newSize.Z *= z; 3128 currentpos.X *= x;
2768 obPart.Resize(newSize); 3129 currentpos.Y *= y;
2769 obPart.UpdateOffSet(currentpos); 3130 currentpos.Z *= z;
3131 Vector3 newSize = new Vector3(obPart.Scale);
3132 newSize.X *= x;
3133 newSize.Y *= y;
3134 newSize.Z *= z;
3135 obPart.Resize(newSize);
3136 obPart.UpdateOffSet(currentpos);
3137 }
3138 obPart.IgnoreUndoUpdate = false;
2770 } 3139 }
2771 obPart.IgnoreUndoUpdate = false; 3140 obPart.IgnoreUndoUpdate = false;
2772 obPart.StoreUndoState();
2773 } 3141 }
2774 3142
2775 if (part.PhysActor != null) 3143 if (part.PhysActor != null)
@@ -2779,7 +3147,6 @@ namespace OpenSim.Region.Framework.Scenes
2779 } 3147 }
2780 3148
2781 part.IgnoreUndoUpdate = false; 3149 part.IgnoreUndoUpdate = false;
2782 part.StoreUndoState();
2783 HasGroupChanged = true; 3150 HasGroupChanged = true;
2784 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3151 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2785 ScheduleGroupForTerseUpdate(); 3152 ScheduleGroupForTerseUpdate();
@@ -2796,14 +3163,11 @@ namespace OpenSim.Region.Framework.Scenes
2796 /// <param name="pos"></param> 3163 /// <param name="pos"></param>
2797 public void UpdateGroupPosition(Vector3 pos) 3164 public void UpdateGroupPosition(Vector3 pos)
2798 { 3165 {
2799 SceneObjectPart[] parts = m_parts.GetArray();
2800 for (int i = 0; i < parts.Length; i++)
2801 parts[i].StoreUndoState();
2802
2803 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3166 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2804 { 3167 {
2805 if (IsAttachment) 3168 if (IsAttachment)
2806 { 3169 {
3170 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2807 m_rootPart.AttachedPos = pos; 3171 m_rootPart.AttachedPos = pos;
2808 } 3172 }
2809 if (RootPart.GetStatusSandbox()) 3173 if (RootPart.GetStatusSandbox())
@@ -2837,7 +3201,7 @@ namespace OpenSim.Region.Framework.Scenes
2837 3201
2838 SceneObjectPart[] parts = m_parts.GetArray(); 3202 SceneObjectPart[] parts = m_parts.GetArray();
2839 for (int i = 0; i < parts.Length; i++) 3203 for (int i = 0; i < parts.Length; i++)
2840 parts[i].StoreUndoState(); 3204 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2841 3205
2842 if (part != null) 3206 if (part != null)
2843 { 3207 {
@@ -2862,7 +3226,7 @@ namespace OpenSim.Region.Framework.Scenes
2862 { 3226 {
2863 SceneObjectPart[] parts = m_parts.GetArray(); 3227 SceneObjectPart[] parts = m_parts.GetArray();
2864 for (int i = 0; i < parts.Length; i++) 3228 for (int i = 0; i < parts.Length; i++)
2865 parts[i].StoreUndoState(); 3229 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2866 3230
2867 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3231 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2868 Vector3 oldPos = 3232 Vector3 oldPos =
@@ -2883,10 +3247,27 @@ namespace OpenSim.Region.Framework.Scenes
2883 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3247 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2884 } 3248 }
2885 3249
2886 AbsolutePosition = newPos; 3250 //We have to set undoing here because otherwise an undo state will be saved
3251 if (!m_rootPart.Undoing)
3252 {
3253 m_rootPart.Undoing = true;
3254 AbsolutePosition = newPos;
3255 m_rootPart.Undoing = false;
3256 }
3257 else
3258 {
3259 AbsolutePosition = newPos;
3260 }
2887 3261
2888 HasGroupChanged = true; 3262 HasGroupChanged = true;
2889 ScheduleGroupForTerseUpdate(); 3263 if (m_rootPart.Undoing)
3264 {
3265 ScheduleGroupForFullUpdate();
3266 }
3267 else
3268 {
3269 ScheduleGroupForTerseUpdate();
3270 }
2890 } 3271 }
2891 3272
2892 public void OffsetForNewRegion(Vector3 offset) 3273 public void OffsetForNewRegion(Vector3 offset)
@@ -2906,7 +3287,7 @@ namespace OpenSim.Region.Framework.Scenes
2906 { 3287 {
2907 SceneObjectPart[] parts = m_parts.GetArray(); 3288 SceneObjectPart[] parts = m_parts.GetArray();
2908 for (int i = 0; i < parts.Length; i++) 3289 for (int i = 0; i < parts.Length; i++)
2909 parts[i].StoreUndoState(); 3290 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2910 3291
2911 m_rootPart.UpdateRotation(rot); 3292 m_rootPart.UpdateRotation(rot);
2912 3293
@@ -2930,7 +3311,7 @@ namespace OpenSim.Region.Framework.Scenes
2930 { 3311 {
2931 SceneObjectPart[] parts = m_parts.GetArray(); 3312 SceneObjectPart[] parts = m_parts.GetArray();
2932 for (int i = 0; i < parts.Length; i++) 3313 for (int i = 0; i < parts.Length; i++)
2933 parts[i].StoreUndoState(); 3314 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2934 3315
2935 m_rootPart.UpdateRotation(rot); 3316 m_rootPart.UpdateRotation(rot);
2936 3317
@@ -2955,10 +3336,9 @@ namespace OpenSim.Region.Framework.Scenes
2955 public void UpdateSingleRotation(Quaternion rot, uint localID) 3336 public void UpdateSingleRotation(Quaternion rot, uint localID)
2956 { 3337 {
2957 SceneObjectPart part = GetChildPart(localID); 3338 SceneObjectPart part = GetChildPart(localID);
2958
2959 SceneObjectPart[] parts = m_parts.GetArray(); 3339 SceneObjectPart[] parts = m_parts.GetArray();
2960 for (int i = 0; i < parts.Length; i++) 3340 for (int i = 0; i < parts.Length; i++)
2961 parts[i].StoreUndoState(); 3341 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2962 3342
2963 if (part != null) 3343 if (part != null)
2964 { 3344 {
@@ -2986,15 +3366,24 @@ namespace OpenSim.Region.Framework.Scenes
2986 if (part.UUID == m_rootPart.UUID) 3366 if (part.UUID == m_rootPart.UUID)
2987 { 3367 {
2988 UpdateRootRotation(rot); 3368 UpdateRootRotation(rot);
2989 AbsolutePosition = pos; 3369 if (!m_rootPart.Undoing)
3370 {
3371 m_rootPart.Undoing = true;
3372 AbsolutePosition = pos;
3373 m_rootPart.Undoing = false;
3374 }
3375 else
3376 {
3377 AbsolutePosition = pos;
3378 }
2990 } 3379 }
2991 else 3380 else
2992 { 3381 {
3382 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2993 part.IgnoreUndoUpdate = true; 3383 part.IgnoreUndoUpdate = true;
2994 part.UpdateRotation(rot); 3384 part.UpdateRotation(rot);
2995 part.OffsetPosition = pos; 3385 part.OffsetPosition = pos;
2996 part.IgnoreUndoUpdate = false; 3386 part.IgnoreUndoUpdate = false;
2997 part.StoreUndoState();
2998 } 3387 }
2999 } 3388 }
3000 } 3389 }
@@ -3008,8 +3397,16 @@ namespace OpenSim.Region.Framework.Scenes
3008 Quaternion axRot = rot; 3397 Quaternion axRot = rot;
3009 Quaternion oldParentRot = m_rootPart.RotationOffset; 3398 Quaternion oldParentRot = m_rootPart.RotationOffset;
3010 3399
3011 m_rootPart.StoreUndoState(); 3400 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3012 m_rootPart.UpdateRotation(rot); 3401 bool cancelUndo = false;
3402 if (!m_rootPart.Undoing)
3403 {
3404 m_rootPart.Undoing = true;
3405 cancelUndo = true;
3406 }
3407
3408 //Don't use UpdateRotation because it schedules an update prematurely
3409 m_rootPart.RotationOffset = rot;
3013 if (m_rootPart.PhysActor != null) 3410 if (m_rootPart.PhysActor != null)
3014 { 3411 {
3015 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3412 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -3024,28 +3421,22 @@ namespace OpenSim.Region.Framework.Scenes
3024 { 3421 {
3025 prim.IgnoreUndoUpdate = true; 3422 prim.IgnoreUndoUpdate = true;
3026 Vector3 axPos = prim.OffsetPosition; 3423 Vector3 axPos = prim.OffsetPosition;
3424
3027 axPos *= oldParentRot; 3425 axPos *= oldParentRot;
3028 axPos *= Quaternion.Inverse(axRot); 3426 axPos *= Quaternion.Inverse(axRot);
3029 prim.OffsetPosition = axPos; 3427 prim.OffsetPosition = axPos;
3030 Quaternion primsRot = prim.RotationOffset; 3428
3031 Quaternion newRot = primsRot * oldParentRot; 3429 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
3032 newRot *= Quaternion.Inverse(axRot); 3430
3033 prim.RotationOffset = newRot; 3431 prim.IgnoreUndoUpdate = false;
3034 prim.ScheduleTerseUpdate();
3035 } 3432 }
3036 } 3433 }
3037 3434 if (cancelUndo == true)
3038 for (int i = 0; i < parts.Length; i++)
3039 { 3435 {
3040 SceneObjectPart childpart = parts[i]; 3436 m_rootPart.Undoing = false;
3041 if (childpart != m_rootPart)
3042 {
3043 childpart.IgnoreUndoUpdate = false;
3044 childpart.StoreUndoState();
3045 }
3046 } 3437 }
3047 3438 HasGroupChanged = true;
3048 m_rootPart.ScheduleTerseUpdate(); 3439 ScheduleGroupForFullUpdate();
3049 } 3440 }
3050 3441
3051 #endregion 3442 #endregion
@@ -3268,7 +3659,6 @@ namespace OpenSim.Region.Framework.Scenes
3268 public float GetMass() 3659 public float GetMass()
3269 { 3660 {
3270 float retmass = 0f; 3661 float retmass = 0f;
3271
3272 SceneObjectPart[] parts = m_parts.GetArray(); 3662 SceneObjectPart[] parts = m_parts.GetArray();
3273 for (int i = 0; i < parts.Length; i++) 3663 for (int i = 0; i < parts.Length; i++)
3274 retmass += parts[i].GetMass(); 3664 retmass += parts[i].GetMass();
@@ -3384,6 +3774,14 @@ namespace OpenSim.Region.Framework.Scenes
3384 SetFromItemID(uuid); 3774 SetFromItemID(uuid);
3385 } 3775 }
3386 3776
3777 public void ResetOwnerChangeFlag()
3778 {
3779 ForEachPart(delegate(SceneObjectPart part)
3780 {
3781 part.ResetOwnerChangeFlag();
3782 });
3783 }
3784
3387 #endregion 3785 #endregion
3388 } 3786 }
3389} 3787}