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.cs601
1 files changed, 508 insertions, 93 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index a0a7344..6204b4f 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using 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
@@ -131,7 +183,7 @@ namespace OpenSim.Region.Framework.Scenes
131 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 183 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
132 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 184 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 185 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 186 public bool HasGroupChangedDueToDelink { get; set; }
135 187
136 private bool isTimeToPersist() 188 private bool isTimeToPersist()
137 { 189 {
@@ -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 }
@@ -247,10 +310,10 @@ namespace OpenSim.Region.Framework.Scenes
247 310
248 private bool m_scriptListens_atTarget; 311 private bool m_scriptListens_atTarget;
249 private bool m_scriptListens_notAtTarget; 312 private bool m_scriptListens_notAtTarget;
250
251 private bool m_scriptListens_atRotTarget; 313 private bool m_scriptListens_atRotTarget;
252 private bool m_scriptListens_notAtRotTarget; 314 private bool m_scriptListens_notAtRotTarget;
253 315
316 public bool m_dupeInProgress = false;
254 internal Dictionary<UUID, string> m_savedScriptState; 317 internal Dictionary<UUID, string> m_savedScriptState;
255 318
256 #region Properties 319 #region Properties
@@ -281,6 +344,16 @@ namespace OpenSim.Region.Framework.Scenes
281 get { return m_parts.Count; } 344 get { return m_parts.Count; }
282 } 345 }
283 346
347// protected Quaternion m_rotation = Quaternion.Identity;
348//
349// public virtual Quaternion Rotation
350// {
351// get { return m_rotation; }
352// set {
353// m_rotation = value;
354// }
355// }
356
284 public Quaternion GroupRotation 357 public Quaternion GroupRotation
285 { 358 {
286 get { return m_rootPart.RotationOffset; } 359 get { return m_rootPart.RotationOffset; }
@@ -389,7 +462,11 @@ namespace OpenSim.Region.Framework.Scenes
389 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 462 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
390 } 463 }
391 } 464 }
392 465
466 foreach (SceneObjectPart part in m_parts.GetArray())
467 {
468 part.IgnoreUndoUpdate = true;
469 }
393 if (RootPart.GetStatusSandbox()) 470 if (RootPart.GetStatusSandbox())
394 { 471 {
395 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 472 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -403,10 +480,29 @@ namespace OpenSim.Region.Framework.Scenes
403 return; 480 return;
404 } 481 }
405 } 482 }
406
407 SceneObjectPart[] parts = m_parts.GetArray(); 483 SceneObjectPart[] parts = m_parts.GetArray();
408 for (int i = 0; i < parts.Length; i++) 484 foreach (SceneObjectPart part in parts)
409 parts[i].GroupPosition = val; 485 {
486 part.GroupPosition = val;
487 if (!m_dupeInProgress)
488 {
489 part.TriggerScriptChangedEvent(Changed.POSITION);
490 }
491 }
492 if (!m_dupeInProgress)
493 {
494 foreach (ScenePresence av in m_linkedAvatars)
495 {
496 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
497 if (m_parts.TryGetValue(p.UUID, out p))
498 {
499 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
500 av.AbsolutePosition += offset;
501 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
502 av.SendAvatarDataToAllAgents();
503 }
504 }
505 }
410 506
411 //if (m_rootPart.PhysActor != null) 507 //if (m_rootPart.PhysActor != null)
412 //{ 508 //{
@@ -565,6 +661,7 @@ namespace OpenSim.Region.Framework.Scenes
565 /// </summary> 661 /// </summary>
566 public SceneObjectGroup() 662 public SceneObjectGroup()
567 { 663 {
664
568 } 665 }
569 666
570 /// <summary> 667 /// <summary>
@@ -581,7 +678,7 @@ namespace OpenSim.Region.Framework.Scenes
581 /// Constructor. This object is added to the scene later via AttachToScene() 678 /// Constructor. This object is added to the scene later via AttachToScene()
582 /// </summary> 679 /// </summary>
583 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 680 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
584 { 681 {
585 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 682 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
586 } 683 }
587 684
@@ -629,6 +726,9 @@ namespace OpenSim.Region.Framework.Scenes
629 /// </summary> 726 /// </summary>
630 public virtual void AttachToBackup() 727 public virtual void AttachToBackup()
631 { 728 {
729 if (IsAttachment) return;
730 m_scene.SceneGraph.FireAttachToBackup(this);
731
632 if (InSceneBackup) 732 if (InSceneBackup)
633 { 733 {
634 //m_log.DebugFormat( 734 //m_log.DebugFormat(
@@ -671,6 +771,9 @@ namespace OpenSim.Region.Framework.Scenes
671 771
672 ApplyPhysics(m_scene.m_physicalPrim); 772 ApplyPhysics(m_scene.m_physicalPrim);
673 773
774 if (RootPart.PhysActor != null)
775 RootPart.Buoyancy = RootPart.Buoyancy;
776
674 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 777 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
675 // for the same object with very different properties. The caller must schedule the update. 778 // for the same object with very different properties. The caller must schedule the update.
676 //ScheduleGroupForFullUpdate(); 779 //ScheduleGroupForFullUpdate();
@@ -716,9 +819,9 @@ namespace OpenSim.Region.Framework.Scenes
716 result.normal = inter.normal; 819 result.normal = inter.normal;
717 result.distance = inter.distance; 820 result.distance = inter.distance;
718 } 821 }
822
719 } 823 }
720 } 824 }
721
722 return result; 825 return result;
723 } 826 }
724 827
@@ -738,17 +841,19 @@ namespace OpenSim.Region.Framework.Scenes
738 minZ = 8192f; 841 minZ = 8192f;
739 842
740 SceneObjectPart[] parts = m_parts.GetArray(); 843 SceneObjectPart[] parts = m_parts.GetArray();
741 for (int i = 0; i < parts.Length; i++) 844 foreach (SceneObjectPart part in parts)
742 { 845 {
743 SceneObjectPart part = parts[i];
744
745 Vector3 worldPos = part.GetWorldPosition(); 846 Vector3 worldPos = part.GetWorldPosition();
746 Vector3 offset = worldPos - AbsolutePosition; 847 Vector3 offset = worldPos - AbsolutePosition;
747 Quaternion worldRot; 848 Quaternion worldRot;
748 if (part.ParentID == 0) 849 if (part.ParentID == 0)
850 {
749 worldRot = part.RotationOffset; 851 worldRot = part.RotationOffset;
852 }
750 else 853 else
854 {
751 worldRot = part.GetWorldRotation(); 855 worldRot = part.GetWorldRotation();
856 }
752 857
753 Vector3 frontTopLeft; 858 Vector3 frontTopLeft;
754 Vector3 frontTopRight; 859 Vector3 frontTopRight;
@@ -760,6 +865,8 @@ namespace OpenSim.Region.Framework.Scenes
760 Vector3 backBottomLeft; 865 Vector3 backBottomLeft;
761 Vector3 backBottomRight; 866 Vector3 backBottomRight;
762 867
868 // Vector3[] corners = new Vector3[8];
869
763 Vector3 orig = Vector3.Zero; 870 Vector3 orig = Vector3.Zero;
764 871
765 frontTopLeft.X = orig.X - (part.Scale.X / 2); 872 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -794,6 +901,38 @@ namespace OpenSim.Region.Framework.Scenes
794 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 901 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
795 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 902 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
796 903
904
905
906 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
907 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
908 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
909 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
910 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
911 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
912 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
913 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
914
915 //for (int i = 0; i < 8; i++)
916 //{
917 // corners[i] = corners[i] * worldRot;
918 // corners[i] += offset;
919
920 // if (corners[i].X > maxX)
921 // maxX = corners[i].X;
922 // if (corners[i].X < minX)
923 // minX = corners[i].X;
924
925 // if (corners[i].Y > maxY)
926 // maxY = corners[i].Y;
927 // if (corners[i].Y < minY)
928 // minY = corners[i].Y;
929
930 // if (corners[i].Z > maxZ)
931 // maxZ = corners[i].Y;
932 // if (corners[i].Z < minZ)
933 // minZ = corners[i].Z;
934 //}
935
797 frontTopLeft = frontTopLeft * worldRot; 936 frontTopLeft = frontTopLeft * worldRot;
798 frontTopRight = frontTopRight * worldRot; 937 frontTopRight = frontTopRight * worldRot;
799 frontBottomLeft = frontBottomLeft * worldRot; 938 frontBottomLeft = frontBottomLeft * worldRot;
@@ -815,6 +954,15 @@ namespace OpenSim.Region.Framework.Scenes
815 backTopLeft += offset; 954 backTopLeft += offset;
816 backTopRight += offset; 955 backTopRight += offset;
817 956
957 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
958 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
959 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
960 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
961 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
962 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
963 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
964 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
965
818 if (frontTopRight.X > maxX) 966 if (frontTopRight.X > maxX)
819 maxX = frontTopRight.X; 967 maxX = frontTopRight.X;
820 if (frontTopLeft.X > maxX) 968 if (frontTopLeft.X > maxX)
@@ -960,15 +1108,20 @@ namespace OpenSim.Region.Framework.Scenes
960 1108
961 public void SaveScriptedState(XmlTextWriter writer) 1109 public void SaveScriptedState(XmlTextWriter writer)
962 { 1110 {
1111 SaveScriptedState(writer, false);
1112 }
1113
1114 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1115 {
963 XmlDocument doc = new XmlDocument(); 1116 XmlDocument doc = new XmlDocument();
964 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1117 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
965 1118
966 SceneObjectPart[] parts = m_parts.GetArray(); 1119 SceneObjectPart[] parts = m_parts.GetArray();
967 for (int i = 0; i < parts.Length; i++) 1120 for (int i = 0; i < parts.Length; i++)
968 { 1121 {
969 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1122 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
970 foreach (KeyValuePair<UUID, string> kvp in pstates) 1123 foreach (KeyValuePair<UUID, string> kvp in pstates)
971 states.Add(kvp.Key, kvp.Value); 1124 states[kvp.Key] = kvp.Value;
972 } 1125 }
973 1126
974 if (states.Count > 0) 1127 if (states.Count > 0)
@@ -988,6 +1141,168 @@ namespace OpenSim.Region.Framework.Scenes
988 } 1141 }
989 1142
990 /// <summary> 1143 /// <summary>
1144 /// Add the avatar to this linkset (avatar is sat).
1145 /// </summary>
1146 /// <param name="agentID"></param>
1147 public void AddAvatar(UUID agentID)
1148 {
1149 ScenePresence presence;
1150 if (m_scene.TryGetScenePresence(agentID, out presence))
1151 {
1152 if (!m_linkedAvatars.Contains(presence))
1153 {
1154 m_linkedAvatars.Add(presence);
1155 }
1156 }
1157 }
1158
1159 /// <summary>
1160 /// Delete the avatar from this linkset (avatar is unsat).
1161 /// </summary>
1162 /// <param name="agentID"></param>
1163 public void DeleteAvatar(UUID agentID)
1164 {
1165 ScenePresence presence;
1166 if (m_scene.TryGetScenePresence(agentID, out presence))
1167 {
1168 if (m_linkedAvatars.Contains(presence))
1169 {
1170 m_linkedAvatars.Remove(presence);
1171 }
1172 }
1173 }
1174
1175 /// <summary>
1176 /// Returns the list of linked presences (avatars sat on this group)
1177 /// </summary>
1178 /// <param name="agentID"></param>
1179 public List<ScenePresence> GetLinkedAvatars()
1180 {
1181 return m_linkedAvatars;
1182 }
1183
1184 /// <summary>
1185 /// Attach this scene object to the given avatar.
1186 /// </summary>
1187 /// <param name="agentID"></param>
1188 /// <param name="attachmentpoint"></param>
1189 /// <param name="AttachOffset"></param>
1190 private void AttachToAgent(
1191 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1192 {
1193 if (avatar != null)
1194 {
1195 // don't attach attachments to child agents
1196 if (avatar.IsChildAgent) return;
1197
1198 // Remove from database and parcel prim count
1199 m_scene.DeleteFromStorage(so.UUID);
1200 m_scene.EventManager.TriggerParcelPrimCountTainted();
1201
1202 so.AttachedAvatar = avatar.UUID;
1203
1204 if (so.RootPart.PhysActor != null)
1205 {
1206 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1207 so.RootPart.PhysActor = null;
1208 }
1209
1210 so.AbsolutePosition = attachOffset;
1211 so.RootPart.AttachedPos = attachOffset;
1212 so.IsAttachment = true;
1213 so.RootPart.SetParentLocalId(avatar.LocalId);
1214 so.AttachmentPoint = attachmentpoint;
1215
1216 avatar.AddAttachment(this);
1217
1218 if (!silent)
1219 {
1220 // Killing it here will cause the client to deselect it
1221 // It then reappears on the avatar, deselected
1222 // through the full update below
1223 //
1224 if (IsSelected)
1225 {
1226 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1227 }
1228
1229 IsSelected = false; // fudge....
1230 ScheduleGroupForFullUpdate();
1231 }
1232 }
1233 else
1234 {
1235 m_log.WarnFormat(
1236 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1237 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1238 }
1239 }
1240
1241 public byte GetAttachmentPoint()
1242 {
1243 return m_rootPart.Shape.State;
1244 }
1245
1246 public void DetachToGround()
1247 {
1248 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1249 if (avatar == null)
1250 return;
1251
1252 avatar.RemoveAttachment(this);
1253
1254 Vector3 detachedpos = new Vector3(127f,127f,127f);
1255 if (avatar == null)
1256 return;
1257
1258 detachedpos = avatar.AbsolutePosition;
1259 RootPart.FromItemID = UUID.Zero;
1260
1261 AbsolutePosition = detachedpos;
1262 AttachedAvatar = UUID.Zero;
1263
1264 //SceneObjectPart[] parts = m_parts.GetArray();
1265 //for (int i = 0; i < parts.Length; i++)
1266 // parts[i].AttachedAvatar = UUID.Zero;
1267
1268 m_rootPart.SetParentLocalId(0);
1269 AttachmentPoint = (byte)0;
1270 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1271 HasGroupChanged = true;
1272 RootPart.Rezzed = DateTime.Now;
1273 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1274 AttachToBackup();
1275 m_scene.EventManager.TriggerParcelPrimCountTainted();
1276 m_rootPart.ScheduleFullUpdate();
1277 m_rootPart.ClearUndoState();
1278 }
1279
1280 public void DetachToInventoryPrep()
1281 {
1282 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1283 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1284 if (avatar != null)
1285 {
1286 //detachedpos = avatar.AbsolutePosition;
1287 avatar.RemoveAttachment(this);
1288 }
1289
1290 AttachedAvatar = UUID.Zero;
1291
1292 /*SceneObjectPart[] parts = m_parts.GetArray();
1293 for (int i = 0; i < parts.Length; i++)
1294 parts[i].AttachedAvatar = UUID.Zero;*/
1295
1296 m_rootPart.SetParentLocalId(0);
1297 //m_rootPart.SetAttachmentPoint((byte)0);
1298 IsAttachment = false;
1299 AbsolutePosition = m_rootPart.AttachedPos;
1300 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1301 //AttachToBackup();
1302 //m_rootPart.ScheduleFullUpdate();
1303 }
1304
1305 /// <summary>
991 /// 1306 ///
992 /// </summary> 1307 /// </summary>
993 /// <param name="part"></param> 1308 /// <param name="part"></param>
@@ -1037,7 +1352,10 @@ namespace OpenSim.Region.Framework.Scenes
1037 public void AddPart(SceneObjectPart part) 1352 public void AddPart(SceneObjectPart part)
1038 { 1353 {
1039 part.SetParent(this); 1354 part.SetParent(this);
1040 part.LinkNum = m_parts.Add(part.UUID, part); 1355 m_parts.Add(part.UUID, part);
1356
1357 part.LinkNum = m_parts.Count;
1358
1041 if (part.LinkNum == 2) 1359 if (part.LinkNum == 2)
1042 RootPart.LinkNum = 1; 1360 RootPart.LinkNum = 1;
1043 } 1361 }
@@ -1145,6 +1463,11 @@ namespace OpenSim.Region.Framework.Scenes
1145 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1463 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1146 public void DeleteGroupFromScene(bool silent) 1464 public void DeleteGroupFromScene(bool silent)
1147 { 1465 {
1466 // We need to keep track of this state in case this group is still queued for backup.
1467 IsDeleted = true;
1468
1469 DetachFromBackup();
1470
1148 SceneObjectPart[] parts = m_parts.GetArray(); 1471 SceneObjectPart[] parts = m_parts.GetArray();
1149 for (int i = 0; i < parts.Length; i++) 1472 for (int i = 0; i < parts.Length; i++)
1150 { 1473 {
@@ -1162,11 +1485,13 @@ namespace OpenSim.Region.Framework.Scenes
1162 { 1485 {
1163 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || 1486 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) ||
1164 (AttachmentPoint < 31) || (AttachmentPoint > 38)) 1487 (AttachmentPoint < 31) || (AttachmentPoint > 38))
1165 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); 1488 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint>() {part.LocalId});
1166 } 1489 }
1167 } 1490 }
1168 }); 1491 });
1169 } 1492 }
1493
1494
1170 } 1495 }
1171 1496
1172 public void AddScriptLPS(int count) 1497 public void AddScriptLPS(int count)
@@ -1263,7 +1588,12 @@ namespace OpenSim.Region.Framework.Scenes
1263 1588
1264 public void SetOwnerId(UUID userId) 1589 public void SetOwnerId(UUID userId)
1265 { 1590 {
1266 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1591 ForEachPart(delegate(SceneObjectPart part)
1592 {
1593
1594 part.OwnerID = userId;
1595
1596 });
1267 } 1597 }
1268 1598
1269 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1599 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1295,11 +1625,17 @@ namespace OpenSim.Region.Framework.Scenes
1295 return; 1625 return;
1296 } 1626 }
1297 1627
1628 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1629 return;
1630
1298 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1631 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1299 // any exception propogate upwards. 1632 // any exception propogate upwards.
1300 try 1633 try
1301 { 1634 {
1302 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1635 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1636 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1637 m_scene.LoadingPrims) // Land may not be valid yet
1638
1303 { 1639 {
1304 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1640 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1305 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1641 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1326,6 +1662,7 @@ namespace OpenSim.Region.Framework.Scenes
1326 } 1662 }
1327 } 1663 }
1328 } 1664 }
1665
1329 } 1666 }
1330 1667
1331 if (m_scene.UseBackup && HasGroupChanged) 1668 if (m_scene.UseBackup && HasGroupChanged)
@@ -1333,6 +1670,20 @@ namespace OpenSim.Region.Framework.Scenes
1333 // don't backup while it's selected or you're asking for changes mid stream. 1670 // don't backup while it's selected or you're asking for changes mid stream.
1334 if (isTimeToPersist() || forcedBackup) 1671 if (isTimeToPersist() || forcedBackup)
1335 { 1672 {
1673 if (m_rootPart.PhysActor != null &&
1674 (!m_rootPart.PhysActor.IsPhysical))
1675 {
1676 // Possible ghost prim
1677 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1678 {
1679 foreach (SceneObjectPart part in m_parts.GetArray())
1680 {
1681 // Re-set physics actor positions and
1682 // orientations
1683 part.GroupPosition = m_rootPart.GroupPosition;
1684 }
1685 }
1686 }
1336// m_log.DebugFormat( 1687// m_log.DebugFormat(
1337// "[SCENE]: Storing {0}, {1} in {2}", 1688// "[SCENE]: Storing {0}, {1} in {2}",
1338// Name, UUID, m_scene.RegionInfo.RegionName); 1689// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1410,7 +1761,7 @@ namespace OpenSim.Region.Framework.Scenes
1410 // This is only necessary when userExposed is false! 1761 // This is only necessary when userExposed is false!
1411 1762
1412 bool previousAttachmentStatus = dupe.IsAttachment; 1763 bool previousAttachmentStatus = dupe.IsAttachment;
1413 1764
1414 if (!userExposed) 1765 if (!userExposed)
1415 dupe.IsAttachment = true; 1766 dupe.IsAttachment = true;
1416 1767
@@ -1428,11 +1779,11 @@ namespace OpenSim.Region.Framework.Scenes
1428 dupe.m_rootPart.TrimPermissions(); 1779 dupe.m_rootPart.TrimPermissions();
1429 1780
1430 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1781 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1431 1782
1432 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1783 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1433 { 1784 {
1434 return p1.LinkNum.CompareTo(p2.LinkNum); 1785 return p1.LinkNum.CompareTo(p2.LinkNum);
1435 } 1786 }
1436 ); 1787 );
1437 1788
1438 foreach (SceneObjectPart part in partList) 1789 foreach (SceneObjectPart part in partList)
@@ -1452,7 +1803,7 @@ namespace OpenSim.Region.Framework.Scenes
1452 if (part.PhysActor != null && userExposed) 1803 if (part.PhysActor != null && userExposed)
1453 { 1804 {
1454 PrimitiveBaseShape pbs = newPart.Shape; 1805 PrimitiveBaseShape pbs = newPart.Shape;
1455 1806
1456 newPart.PhysActor 1807 newPart.PhysActor
1457 = m_scene.PhysicsScene.AddPrimShape( 1808 = m_scene.PhysicsScene.AddPrimShape(
1458 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1809 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1462,11 +1813,11 @@ namespace OpenSim.Region.Framework.Scenes
1462 newPart.RotationOffset, 1813 newPart.RotationOffset,
1463 part.PhysActor.IsPhysical, 1814 part.PhysActor.IsPhysical,
1464 newPart.LocalId); 1815 newPart.LocalId);
1465 1816
1466 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1817 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1467 } 1818 }
1468 } 1819 }
1469 1820
1470 if (userExposed) 1821 if (userExposed)
1471 { 1822 {
1472 dupe.UpdateParentIDs(); 1823 dupe.UpdateParentIDs();
@@ -1581,6 +1932,7 @@ namespace OpenSim.Region.Framework.Scenes
1581 return Vector3.Zero; 1932 return Vector3.Zero;
1582 } 1933 }
1583 1934
1935 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1584 public void moveToTarget(Vector3 target, float tau) 1936 public void moveToTarget(Vector3 target, float tau)
1585 { 1937 {
1586 if (IsAttachment) 1938 if (IsAttachment)
@@ -1608,10 +1960,44 @@ namespace OpenSim.Region.Framework.Scenes
1608 RootPart.PhysActor.PIDActive = false; 1960 RootPart.PhysActor.PIDActive = false;
1609 } 1961 }
1610 1962
1963 public void rotLookAt(Quaternion target, float strength, float damping)
1964 {
1965 SceneObjectPart rootpart = m_rootPart;
1966 if (rootpart != null)
1967 {
1968 if (IsAttachment)
1969 {
1970 /*
1971 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1972 if (avatar != null)
1973 {
1974 Rotate the Av?
1975 } */
1976 }
1977 else
1978 {
1979 if (rootpart.PhysActor != null)
1980 { // APID must be implemented in your physics system for this to function.
1981 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1982 rootpart.PhysActor.APIDStrength = strength;
1983 rootpart.PhysActor.APIDDamping = damping;
1984 rootpart.PhysActor.APIDActive = true;
1985 }
1986 }
1987 }
1988 }
1989
1611 public void stopLookAt() 1990 public void stopLookAt()
1612 { 1991 {
1613 if (RootPart.PhysActor != null) 1992 SceneObjectPart rootpart = m_rootPart;
1614 RootPart.PhysActor.APIDActive = false; 1993 if (rootpart != null)
1994 {
1995 if (rootpart.PhysActor != null)
1996 { // APID must be implemented in your physics system for this to function.
1997 rootpart.PhysActor.APIDActive = false;
1998 }
1999 }
2000
1615 } 2001 }
1616 2002
1617 /// <summary> 2003 /// <summary>
@@ -1669,6 +2055,8 @@ namespace OpenSim.Region.Framework.Scenes
1669 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2055 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1670 { 2056 {
1671 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2057 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2058 newPart.SetParent(this);
2059
1672 AddPart(newPart); 2060 AddPart(newPart);
1673 2061
1674 SetPartAsNonRoot(newPart); 2062 SetPartAsNonRoot(newPart);
@@ -1815,11 +2203,11 @@ namespace OpenSim.Region.Framework.Scenes
1815 /// Immediately send a full update for this scene object. 2203 /// Immediately send a full update for this scene object.
1816 /// </summary> 2204 /// </summary>
1817 public void SendGroupFullUpdate() 2205 public void SendGroupFullUpdate()
1818 { 2206 {
1819 if (IsDeleted) 2207 if (IsDeleted)
1820 return; 2208 return;
1821 2209
1822// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2210// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1823 2211
1824 RootPart.SendFullUpdateToAllClients(); 2212 RootPart.SendFullUpdateToAllClients();
1825 2213
@@ -1963,16 +2351,6 @@ namespace OpenSim.Region.Framework.Scenes
1963 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2351 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1964 public void LinkToGroup(SceneObjectGroup objectGroup) 2352 public void LinkToGroup(SceneObjectGroup objectGroup)
1965 { 2353 {
1966 // Make sure we have sent any pending unlinks or stuff.
1967 //if (objectGroup.RootPart.UpdateFlag > 0)
1968 //{
1969 // m_log.WarnFormat(
1970 // "[SCENE OBJECT GROUP]: Forcing send of linkset {0}, {1} to {2}, {3} as its still waiting.",
1971 // objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
1972
1973 // objectGroup.RootPart.SendScheduledUpdates();
1974 //}
1975
1976// m_log.DebugFormat( 2354// m_log.DebugFormat(
1977// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2355// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1978// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); 2356// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1983,6 +2361,7 @@ namespace OpenSim.Region.Framework.Scenes
1983 Quaternion oldRootRotation = linkPart.RotationOffset; 2361 Quaternion oldRootRotation = linkPart.RotationOffset;
1984 2362
1985 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2363 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2364 linkPart.ParentID = m_rootPart.LocalId;
1986 linkPart.GroupPosition = AbsolutePosition; 2365 linkPart.GroupPosition = AbsolutePosition;
1987 Vector3 axPos = linkPart.OffsetPosition; 2366 Vector3 axPos = linkPart.OffsetPosition;
1988 2367
@@ -1995,42 +2374,27 @@ namespace OpenSim.Region.Framework.Scenes
1995 linkPart.RotationOffset = newRot; 2374 linkPart.RotationOffset = newRot;
1996 2375
1997 linkPart.ParentID = m_rootPart.LocalId; 2376 linkPart.ParentID = m_rootPart.LocalId;
2377
1998 if (m_rootPart.LinkNum == 0) 2378 if (m_rootPart.LinkNum == 0)
1999 m_rootPart.LinkNum = 1; 2379 m_rootPart.LinkNum = 1;
2000 2380
2001 lock (m_parts.SyncRoot) 2381 lock (m_parts.SyncRoot)
2002 { 2382 {
2003 m_parts.Add(linkPart.UUID, linkPart); 2383 int linkNum = PrimCount + 1;
2004
2005 // Insert in terms of link numbers, the new links
2006 // before the current ones (with the exception of
2007 // the root prim. Shuffle the old ones up
2008 SceneObjectPart[] parts = m_parts.GetArray();
2009 for (int i = 0; i < parts.Length; i++)
2010 {
2011 SceneObjectPart part = parts[i];
2012 if (part.LinkNum != 1)
2013 {
2014 // Don't update root prim link number
2015 part.LinkNum += objectGroup.PrimCount;
2016 }
2017 }
2018 2384
2019 linkPart.LinkNum = 2; 2385 m_parts.Add(linkPart.UUID, linkPart);
2020 2386
2021 linkPart.SetParent(this); 2387 linkPart.SetParent(this);
2022 linkPart.CreateSelected = true; 2388 linkPart.CreateSelected = true;
2023 2389
2024 //if (linkPart.PhysActor != null) 2390 linkPart.LinkNum = linkNum++;
2025 //{
2026 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2027
2028 //linkPart.PhysActor = null;
2029 //}
2030 2391
2031 //TODO: rest of parts
2032 int linkNum = 3;
2033 SceneObjectPart[] ogParts = objectGroup.Parts; 2392 SceneObjectPart[] ogParts = objectGroup.Parts;
2393 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
2394 {
2395 return a.LinkNum - b.LinkNum;
2396 });
2397
2034 for (int i = 0; i < ogParts.Length; i++) 2398 for (int i = 0; i < ogParts.Length; i++)
2035 { 2399 {
2036 SceneObjectPart part = ogParts[i]; 2400 SceneObjectPart part = ogParts[i];
@@ -2178,6 +2542,7 @@ namespace OpenSim.Region.Framework.Scenes
2178 /// <param name="objectGroup"></param> 2542 /// <param name="objectGroup"></param>
2179 public virtual void DetachFromBackup() 2543 public virtual void DetachFromBackup()
2180 { 2544 {
2545 m_scene.SceneGraph.FireDetachFromBackup(this);
2181 if (m_isBackedUp && Scene != null) 2546 if (m_isBackedUp && Scene != null)
2182 m_scene.EventManager.OnBackup -= ProcessBackup; 2547 m_scene.EventManager.OnBackup -= ProcessBackup;
2183 2548
@@ -2196,7 +2561,8 @@ namespace OpenSim.Region.Framework.Scenes
2196 2561
2197 axPos *= parentRot; 2562 axPos *= parentRot;
2198 part.OffsetPosition = axPos; 2563 part.OffsetPosition = axPos;
2199 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2564 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2565 part.GroupPosition = newPos;
2200 part.OffsetPosition = Vector3.Zero; 2566 part.OffsetPosition = Vector3.Zero;
2201 part.RotationOffset = worldRot; 2567 part.RotationOffset = worldRot;
2202 2568
@@ -2207,7 +2573,7 @@ namespace OpenSim.Region.Framework.Scenes
2207 2573
2208 part.LinkNum = linkNum; 2574 part.LinkNum = linkNum;
2209 2575
2210 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2576 part.OffsetPosition = newPos - AbsolutePosition;
2211 2577
2212 Quaternion rootRotation = m_rootPart.RotationOffset; 2578 Quaternion rootRotation = m_rootPart.RotationOffset;
2213 2579
@@ -2217,7 +2583,7 @@ namespace OpenSim.Region.Framework.Scenes
2217 2583
2218 parentRot = m_rootPart.RotationOffset; 2584 parentRot = m_rootPart.RotationOffset;
2219 oldRot = part.RotationOffset; 2585 oldRot = part.RotationOffset;
2220 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2586 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2221 part.RotationOffset = newRot; 2587 part.RotationOffset = newRot;
2222 } 2588 }
2223 2589
@@ -2464,8 +2830,12 @@ namespace OpenSim.Region.Framework.Scenes
2464 } 2830 }
2465 } 2831 }
2466 2832
2833 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, SetVolumeDetect);
2467 for (int i = 0; i < parts.Length; i++) 2834 for (int i = 0; i < parts.Length; i++)
2468 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2835 {
2836 if (parts[i] != RootPart)
2837 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, SetVolumeDetect);
2838 }
2469 } 2839 }
2470 } 2840 }
2471 2841
@@ -2478,6 +2848,17 @@ namespace OpenSim.Region.Framework.Scenes
2478 } 2848 }
2479 } 2849 }
2480 2850
2851
2852
2853 /// <summary>
2854 /// Gets the number of parts
2855 /// </summary>
2856 /// <returns></returns>
2857 public int GetPartCount()
2858 {
2859 return Parts.Count();
2860 }
2861
2481 /// <summary> 2862 /// <summary>
2482 /// Update the texture entry for this part 2863 /// Update the texture entry for this part
2483 /// </summary> 2864 /// </summary>
@@ -2534,7 +2915,6 @@ namespace OpenSim.Region.Framework.Scenes
2534 { 2915 {
2535// m_log.DebugFormat( 2916// m_log.DebugFormat(
2536// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2917// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2537
2538 RootPart.StoreUndoState(true); 2918 RootPart.StoreUndoState(true);
2539 2919
2540 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2920 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2635,7 +3015,6 @@ namespace OpenSim.Region.Framework.Scenes
2635 prevScale.X *= x; 3015 prevScale.X *= x;
2636 prevScale.Y *= y; 3016 prevScale.Y *= y;
2637 prevScale.Z *= z; 3017 prevScale.Z *= z;
2638
2639// RootPart.IgnoreUndoUpdate = true; 3018// RootPart.IgnoreUndoUpdate = true;
2640 RootPart.Resize(prevScale); 3019 RootPart.Resize(prevScale);
2641// RootPart.IgnoreUndoUpdate = false; 3020// RootPart.IgnoreUndoUpdate = false;
@@ -2666,7 +3045,9 @@ namespace OpenSim.Region.Framework.Scenes
2666 } 3045 }
2667 3046
2668// obPart.IgnoreUndoUpdate = false; 3047// obPart.IgnoreUndoUpdate = false;
2669// obPart.StoreUndoState(); 3048 HasGroupChanged = true;
3049 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3050 ScheduleGroupForTerseUpdate();
2670 } 3051 }
2671 3052
2672// m_log.DebugFormat( 3053// m_log.DebugFormat(
@@ -2726,9 +3107,9 @@ namespace OpenSim.Region.Framework.Scenes
2726 { 3107 {
2727 SceneObjectPart part = GetChildPart(localID); 3108 SceneObjectPart part = GetChildPart(localID);
2728 3109
2729// SceneObjectPart[] parts = m_parts.GetArray(); 3110 SceneObjectPart[] parts = m_parts.GetArray();
2730// for (int i = 0; i < parts.Length; i++) 3111 for (int i = 0; i < parts.Length; i++)
2731// parts[i].StoreUndoState(); 3112 parts[i].StoreUndoState();
2732 3113
2733 if (part != null) 3114 if (part != null)
2734 { 3115 {
@@ -2784,10 +3165,27 @@ namespace OpenSim.Region.Framework.Scenes
2784 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3165 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2785 } 3166 }
2786 3167
2787 AbsolutePosition = newPos; 3168 //We have to set undoing here because otherwise an undo state will be saved
3169 if (!m_rootPart.Undoing)
3170 {
3171 m_rootPart.Undoing = true;
3172 AbsolutePosition = newPos;
3173 m_rootPart.Undoing = false;
3174 }
3175 else
3176 {
3177 AbsolutePosition = newPos;
3178 }
2788 3179
2789 HasGroupChanged = true; 3180 HasGroupChanged = true;
2790 ScheduleGroupForTerseUpdate(); 3181 if (m_rootPart.Undoing)
3182 {
3183 ScheduleGroupForFullUpdate();
3184 }
3185 else
3186 {
3187 ScheduleGroupForTerseUpdate();
3188 }
2791 } 3189 }
2792 3190
2793 #endregion 3191 #endregion
@@ -2864,10 +3262,7 @@ namespace OpenSim.Region.Framework.Scenes
2864 public void UpdateSingleRotation(Quaternion rot, uint localID) 3262 public void UpdateSingleRotation(Quaternion rot, uint localID)
2865 { 3263 {
2866 SceneObjectPart part = GetChildPart(localID); 3264 SceneObjectPart part = GetChildPart(localID);
2867
2868 SceneObjectPart[] parts = m_parts.GetArray(); 3265 SceneObjectPart[] parts = m_parts.GetArray();
2869 for (int i = 0; i < parts.Length; i++)
2870 parts[i].StoreUndoState();
2871 3266
2872 if (part != null) 3267 if (part != null)
2873 { 3268 {
@@ -2905,7 +3300,16 @@ namespace OpenSim.Region.Framework.Scenes
2905 if (part.UUID == m_rootPart.UUID) 3300 if (part.UUID == m_rootPart.UUID)
2906 { 3301 {
2907 UpdateRootRotation(rot); 3302 UpdateRootRotation(rot);
2908 AbsolutePosition = pos; 3303 if (!m_rootPart.Undoing)
3304 {
3305 m_rootPart.Undoing = true;
3306 AbsolutePosition = pos;
3307 m_rootPart.Undoing = false;
3308 }
3309 else
3310 {
3311 AbsolutePosition = pos;
3312 }
2909 } 3313 }
2910 else 3314 else
2911 { 3315 {
@@ -2929,9 +3333,10 @@ namespace OpenSim.Region.Framework.Scenes
2929 3333
2930 Quaternion axRot = rot; 3334 Quaternion axRot = rot;
2931 Quaternion oldParentRot = m_rootPart.RotationOffset; 3335 Quaternion oldParentRot = m_rootPart.RotationOffset;
2932
2933 m_rootPart.StoreUndoState(); 3336 m_rootPart.StoreUndoState();
2934 m_rootPart.UpdateRotation(rot); 3337
3338 //Don't use UpdateRotation because it schedules an update prematurely
3339 m_rootPart.RotationOffset = rot;
2935 if (m_rootPart.PhysActor != null) 3340 if (m_rootPart.PhysActor != null)
2936 { 3341 {
2937 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3342 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2945,15 +3350,18 @@ namespace OpenSim.Region.Framework.Scenes
2945 if (prim.UUID != m_rootPart.UUID) 3350 if (prim.UUID != m_rootPart.UUID)
2946 { 3351 {
2947 prim.IgnoreUndoUpdate = true; 3352 prim.IgnoreUndoUpdate = true;
3353
3354 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3355 NewRot = Quaternion.Inverse(axRot) * NewRot;
3356 prim.RotationOffset = NewRot;
3357
2948 Vector3 axPos = prim.OffsetPosition; 3358 Vector3 axPos = prim.OffsetPosition;
3359
2949 axPos *= oldParentRot; 3360 axPos *= oldParentRot;
2950 axPos *= Quaternion.Inverse(axRot); 3361 axPos *= Quaternion.Inverse(axRot);
2951 prim.OffsetPosition = axPos; 3362 prim.OffsetPosition = axPos;
2952 Quaternion primsRot = prim.RotationOffset; 3363
2953 Quaternion newRot = primsRot * oldParentRot; 3364 prim.IgnoreUndoUpdate = false;
2954 newRot *= Quaternion.Inverse(axRot);
2955 prim.RotationOffset = newRot;
2956 prim.ScheduleTerseUpdate();
2957 prim.IgnoreUndoUpdate = false; 3365 prim.IgnoreUndoUpdate = false;
2958 } 3366 }
2959 } 3367 }
@@ -2967,8 +3375,8 @@ namespace OpenSim.Region.Framework.Scenes
2967//// childpart.StoreUndoState(); 3375//// childpart.StoreUndoState();
2968// } 3376// }
2969// } 3377// }
2970 3378 HasGroupChanged = true;
2971 m_rootPart.ScheduleTerseUpdate(); 3379 ScheduleGroupForFullUpdate();
2972 3380
2973// m_log.DebugFormat( 3381// m_log.DebugFormat(
2974// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3382// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3196,7 +3604,6 @@ namespace OpenSim.Region.Framework.Scenes
3196 public float GetMass() 3604 public float GetMass()
3197 { 3605 {
3198 float retmass = 0f; 3606 float retmass = 0f;
3199
3200 SceneObjectPart[] parts = m_parts.GetArray(); 3607 SceneObjectPart[] parts = m_parts.GetArray();
3201 for (int i = 0; i < parts.Length; i++) 3608 for (int i = 0; i < parts.Length; i++)
3202 retmass += parts[i].GetMass(); 3609 retmass += parts[i].GetMass();
@@ -3290,6 +3697,14 @@ namespace OpenSim.Region.Framework.Scenes
3290 SetFromItemID(uuid); 3697 SetFromItemID(uuid);
3291 } 3698 }
3292 3699
3700 public void ResetOwnerChangeFlag()
3701 {
3702 ForEachPart(delegate(SceneObjectPart part)
3703 {
3704 part.ResetOwnerChangeFlag();
3705 });
3706 }
3707
3293 #endregion 3708 #endregion
3294 } 3709 }
3295} 3710}