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.cs559
1 files changed, 495 insertions, 64 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 234eb7d..17f02c2 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
@@ -286,7 +349,9 @@ namespace OpenSim.Region.Framework.Scenes
286 public virtual Quaternion Rotation 349 public virtual Quaternion Rotation
287 { 350 {
288 get { return m_rotation; } 351 get { return m_rotation; }
289 set { m_rotation = value; } 352 set {
353 m_rotation = value;
354 }
290 } 355 }
291 356
292 public Quaternion GroupRotation 357 public Quaternion GroupRotation
@@ -397,7 +462,11 @@ namespace OpenSim.Region.Framework.Scenes
397 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 462 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
398 } 463 }
399 } 464 }
400 465
466 foreach (SceneObjectPart part in m_parts.GetArray())
467 {
468 part.IgnoreUndoUpdate = true;
469 }
401 if (RootPart.GetStatusSandbox()) 470 if (RootPart.GetStatusSandbox())
402 { 471 {
403 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 472 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -411,10 +480,29 @@ namespace OpenSim.Region.Framework.Scenes
411 return; 480 return;
412 } 481 }
413 } 482 }
414
415 SceneObjectPart[] parts = m_parts.GetArray(); 483 SceneObjectPart[] parts = m_parts.GetArray();
416 for (int i = 0; i < parts.Length; i++) 484 foreach (SceneObjectPart part in parts)
417 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;
497 if (m_parts.TryGetValue(av.LinkedPrim, 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 }
418 506
419 //if (m_rootPart.PhysActor != null) 507 //if (m_rootPart.PhysActor != null)
420 //{ 508 //{
@@ -573,6 +661,7 @@ namespace OpenSim.Region.Framework.Scenes
573 /// </summary> 661 /// </summary>
574 public SceneObjectGroup() 662 public SceneObjectGroup()
575 { 663 {
664
576 } 665 }
577 666
578 /// <summary> 667 /// <summary>
@@ -589,7 +678,7 @@ namespace OpenSim.Region.Framework.Scenes
589 /// Constructor. This object is added to the scene later via AttachToScene() 678 /// Constructor. This object is added to the scene later via AttachToScene()
590 /// </summary> 679 /// </summary>
591 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 680 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
592 { 681 {
593 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 682 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
594 } 683 }
595 684
@@ -637,6 +726,9 @@ namespace OpenSim.Region.Framework.Scenes
637 /// </summary> 726 /// </summary>
638 public virtual void AttachToBackup() 727 public virtual void AttachToBackup()
639 { 728 {
729 if (IsAttachment) return;
730 m_scene.SceneGraph.FireAttachToBackup(this);
731
640 if (InSceneBackup) 732 if (InSceneBackup)
641 { 733 {
642 //m_log.DebugFormat( 734 //m_log.DebugFormat(
@@ -679,6 +771,9 @@ namespace OpenSim.Region.Framework.Scenes
679 771
680 ApplyPhysics(m_scene.m_physicalPrim); 772 ApplyPhysics(m_scene.m_physicalPrim);
681 773
774 if (RootPart.PhysActor != null)
775 RootPart.Buoyancy = RootPart.Buoyancy;
776
682 // 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
683 // 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.
684 //ScheduleGroupForFullUpdate(); 779 //ScheduleGroupForFullUpdate();
@@ -724,9 +819,9 @@ namespace OpenSim.Region.Framework.Scenes
724 result.normal = inter.normal; 819 result.normal = inter.normal;
725 result.distance = inter.distance; 820 result.distance = inter.distance;
726 } 821 }
822
727 } 823 }
728 } 824 }
729
730 return result; 825 return result;
731 } 826 }
732 827
@@ -746,17 +841,19 @@ namespace OpenSim.Region.Framework.Scenes
746 minZ = 8192f; 841 minZ = 8192f;
747 842
748 SceneObjectPart[] parts = m_parts.GetArray(); 843 SceneObjectPart[] parts = m_parts.GetArray();
749 for (int i = 0; i < parts.Length; i++) 844 foreach (SceneObjectPart part in parts)
750 { 845 {
751 SceneObjectPart part = parts[i];
752
753 Vector3 worldPos = part.GetWorldPosition(); 846 Vector3 worldPos = part.GetWorldPosition();
754 Vector3 offset = worldPos - AbsolutePosition; 847 Vector3 offset = worldPos - AbsolutePosition;
755 Quaternion worldRot; 848 Quaternion worldRot;
756 if (part.ParentID == 0) 849 if (part.ParentID == 0)
850 {
757 worldRot = part.RotationOffset; 851 worldRot = part.RotationOffset;
852 }
758 else 853 else
854 {
759 worldRot = part.GetWorldRotation(); 855 worldRot = part.GetWorldRotation();
856 }
760 857
761 Vector3 frontTopLeft; 858 Vector3 frontTopLeft;
762 Vector3 frontTopRight; 859 Vector3 frontTopRight;
@@ -768,6 +865,8 @@ namespace OpenSim.Region.Framework.Scenes
768 Vector3 backBottomLeft; 865 Vector3 backBottomLeft;
769 Vector3 backBottomRight; 866 Vector3 backBottomRight;
770 867
868 // Vector3[] corners = new Vector3[8];
869
771 Vector3 orig = Vector3.Zero; 870 Vector3 orig = Vector3.Zero;
772 871
773 frontTopLeft.X = orig.X - (part.Scale.X / 2); 872 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -802,6 +901,38 @@ namespace OpenSim.Region.Framework.Scenes
802 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 901 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
803 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 902 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
804 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
805 frontTopLeft = frontTopLeft * worldRot; 936 frontTopLeft = frontTopLeft * worldRot;
806 frontTopRight = frontTopRight * worldRot; 937 frontTopRight = frontTopRight * worldRot;
807 frontBottomLeft = frontBottomLeft * worldRot; 938 frontBottomLeft = frontBottomLeft * worldRot;
@@ -823,6 +954,15 @@ namespace OpenSim.Region.Framework.Scenes
823 backTopLeft += offset; 954 backTopLeft += offset;
824 backTopRight += offset; 955 backTopRight += offset;
825 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
826 if (frontTopRight.X > maxX) 966 if (frontTopRight.X > maxX)
827 maxX = frontTopRight.X; 967 maxX = frontTopRight.X;
828 if (frontTopLeft.X > maxX) 968 if (frontTopLeft.X > maxX)
@@ -968,15 +1108,20 @@ namespace OpenSim.Region.Framework.Scenes
968 1108
969 public void SaveScriptedState(XmlTextWriter writer) 1109 public void SaveScriptedState(XmlTextWriter writer)
970 { 1110 {
1111 SaveScriptedState(writer, false);
1112 }
1113
1114 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1115 {
971 XmlDocument doc = new XmlDocument(); 1116 XmlDocument doc = new XmlDocument();
972 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1117 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
973 1118
974 SceneObjectPart[] parts = m_parts.GetArray(); 1119 SceneObjectPart[] parts = m_parts.GetArray();
975 for (int i = 0; i < parts.Length; i++) 1120 for (int i = 0; i < parts.Length; i++)
976 { 1121 {
977 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1122 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
978 foreach (KeyValuePair<UUID, string> kvp in pstates) 1123 foreach (KeyValuePair<UUID, string> kvp in pstates)
979 states.Add(kvp.Key, kvp.Value); 1124 states[kvp.Key] = kvp.Value;
980 } 1125 }
981 1126
982 if (states.Count > 0) 1127 if (states.Count > 0)
@@ -996,6 +1141,168 @@ namespace OpenSim.Region.Framework.Scenes
996 } 1141 }
997 1142
998 /// <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, m_scene.m_physicalPrim);
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>
999 /// 1306 ///
1000 /// </summary> 1307 /// </summary>
1001 /// <param name="part"></param> 1308 /// <param name="part"></param>
@@ -1052,7 +1359,10 @@ namespace OpenSim.Region.Framework.Scenes
1052 public void AddPart(SceneObjectPart part) 1359 public void AddPart(SceneObjectPart part)
1053 { 1360 {
1054 part.SetParent(this); 1361 part.SetParent(this);
1055 part.LinkNum = m_parts.Add(part.UUID, part); 1362 m_parts.Add(part.UUID, part);
1363
1364 part.LinkNum = m_parts.Count;
1365
1056 if (part.LinkNum == 2) 1366 if (part.LinkNum == 2)
1057 RootPart.LinkNum = 1; 1367 RootPart.LinkNum = 1;
1058 } 1368 }
@@ -1160,6 +1470,11 @@ namespace OpenSim.Region.Framework.Scenes
1160 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1470 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1161 public void DeleteGroupFromScene(bool silent) 1471 public void DeleteGroupFromScene(bool silent)
1162 { 1472 {
1473 // We need to keep track of this state in case this group is still queued for backup.
1474 IsDeleted = true;
1475
1476 DetachFromBackup();
1477
1163 SceneObjectPart[] parts = m_parts.GetArray(); 1478 SceneObjectPart[] parts = m_parts.GetArray();
1164 for (int i = 0; i < parts.Length; i++) 1479 for (int i = 0; i < parts.Length; i++)
1165 { 1480 {
@@ -1171,17 +1486,19 @@ namespace OpenSim.Region.Framework.Scenes
1171 avatar.StandUp(); 1486 avatar.StandUp();
1172 1487
1173 if (!silent) 1488 if (!silent)
1174 { 1489 {
1175 part.UpdateFlag = 0; 1490 part.UpdateFlag = 0;
1176 if (part == m_rootPart) 1491 if (part == m_rootPart)
1177 { 1492 {
1178 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || 1493 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) ||
1179 (AttachmentPoint < 31) || (AttachmentPoint > 38)) 1494 (AttachmentPoint < 31) || (AttachmentPoint > 38))
1180 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); 1495 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint>() {part.LocalId});
1181 } 1496 }
1182 } 1497 }
1183 }); 1498 });
1184 } 1499 }
1500
1501
1185 } 1502 }
1186 1503
1187 public void AddScriptLPS(int count) 1504 public void AddScriptLPS(int count)
@@ -1278,7 +1595,12 @@ namespace OpenSim.Region.Framework.Scenes
1278 1595
1279 public void SetOwnerId(UUID userId) 1596 public void SetOwnerId(UUID userId)
1280 { 1597 {
1281 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1598 ForEachPart(delegate(SceneObjectPart part)
1599 {
1600
1601 part.OwnerID = userId;
1602
1603 });
1282 } 1604 }
1283 1605
1284 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1606 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1310,11 +1632,17 @@ namespace OpenSim.Region.Framework.Scenes
1310 return; 1632 return;
1311 } 1633 }
1312 1634
1635 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1636 return;
1637
1313 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1638 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1314 // any exception propogate upwards. 1639 // any exception propogate upwards.
1315 try 1640 try
1316 { 1641 {
1317 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1642 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1643 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1644 m_scene.LoadingPrims) // Land may not be valid yet
1645
1318 { 1646 {
1319 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1647 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1320 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1648 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1341,6 +1669,7 @@ namespace OpenSim.Region.Framework.Scenes
1341 } 1669 }
1342 } 1670 }
1343 } 1671 }
1672
1344 } 1673 }
1345 1674
1346 if (m_scene.UseBackup && HasGroupChanged) 1675 if (m_scene.UseBackup && HasGroupChanged)
@@ -1348,6 +1677,20 @@ namespace OpenSim.Region.Framework.Scenes
1348 // don't backup while it's selected or you're asking for changes mid stream. 1677 // don't backup while it's selected or you're asking for changes mid stream.
1349 if (isTimeToPersist() || forcedBackup) 1678 if (isTimeToPersist() || forcedBackup)
1350 { 1679 {
1680 if (m_rootPart.PhysActor != null &&
1681 (!m_rootPart.PhysActor.IsPhysical))
1682 {
1683 // Possible ghost prim
1684 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1685 {
1686 foreach (SceneObjectPart part in m_parts.GetArray())
1687 {
1688 // Re-set physics actor positions and
1689 // orientations
1690 part.GroupPosition = m_rootPart.GroupPosition;
1691 }
1692 }
1693 }
1351// m_log.DebugFormat( 1694// m_log.DebugFormat(
1352// "[SCENE]: Storing {0}, {1} in {2}", 1695// "[SCENE]: Storing {0}, {1} in {2}",
1353// Name, UUID, m_scene.RegionInfo.RegionName); 1696// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1425,7 +1768,7 @@ namespace OpenSim.Region.Framework.Scenes
1425 // This is only necessary when userExposed is false! 1768 // This is only necessary when userExposed is false!
1426 1769
1427 bool previousAttachmentStatus = dupe.IsAttachment; 1770 bool previousAttachmentStatus = dupe.IsAttachment;
1428 1771
1429 if (!userExposed) 1772 if (!userExposed)
1430 dupe.IsAttachment = true; 1773 dupe.IsAttachment = true;
1431 1774
@@ -1443,11 +1786,11 @@ namespace OpenSim.Region.Framework.Scenes
1443 dupe.m_rootPart.TrimPermissions(); 1786 dupe.m_rootPart.TrimPermissions();
1444 1787
1445 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1788 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1446 1789
1447 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1790 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1448 { 1791 {
1449 return p1.LinkNum.CompareTo(p2.LinkNum); 1792 return p1.LinkNum.CompareTo(p2.LinkNum);
1450 } 1793 }
1451 ); 1794 );
1452 1795
1453 foreach (SceneObjectPart part in partList) 1796 foreach (SceneObjectPart part in partList)
@@ -1467,7 +1810,7 @@ namespace OpenSim.Region.Framework.Scenes
1467 if (part.PhysActor != null && userExposed) 1810 if (part.PhysActor != null && userExposed)
1468 { 1811 {
1469 PrimitiveBaseShape pbs = newPart.Shape; 1812 PrimitiveBaseShape pbs = newPart.Shape;
1470 1813
1471 newPart.PhysActor 1814 newPart.PhysActor
1472 = m_scene.PhysicsScene.AddPrimShape( 1815 = m_scene.PhysicsScene.AddPrimShape(
1473 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1816 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1477,11 +1820,11 @@ namespace OpenSim.Region.Framework.Scenes
1477 newPart.RotationOffset, 1820 newPart.RotationOffset,
1478 part.PhysActor.IsPhysical, 1821 part.PhysActor.IsPhysical,
1479 newPart.LocalId); 1822 newPart.LocalId);
1480 1823
1481 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1824 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1482 } 1825 }
1483 } 1826 }
1484 1827
1485 if (userExposed) 1828 if (userExposed)
1486 { 1829 {
1487 dupe.UpdateParentIDs(); 1830 dupe.UpdateParentIDs();
@@ -1596,6 +1939,7 @@ namespace OpenSim.Region.Framework.Scenes
1596 return Vector3.Zero; 1939 return Vector3.Zero;
1597 } 1940 }
1598 1941
1942 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1599 public void moveToTarget(Vector3 target, float tau) 1943 public void moveToTarget(Vector3 target, float tau)
1600 { 1944 {
1601 if (IsAttachment) 1945 if (IsAttachment)
@@ -1623,10 +1967,44 @@ namespace OpenSim.Region.Framework.Scenes
1623 RootPart.PhysActor.PIDActive = false; 1967 RootPart.PhysActor.PIDActive = false;
1624 } 1968 }
1625 1969
1970 public void rotLookAt(Quaternion target, float strength, float damping)
1971 {
1972 SceneObjectPart rootpart = m_rootPart;
1973 if (rootpart != null)
1974 {
1975 if (IsAttachment)
1976 {
1977 /*
1978 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1979 if (avatar != null)
1980 {
1981 Rotate the Av?
1982 } */
1983 }
1984 else
1985 {
1986 if (rootpart.PhysActor != null)
1987 { // APID must be implemented in your physics system for this to function.
1988 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1989 rootpart.PhysActor.APIDStrength = strength;
1990 rootpart.PhysActor.APIDDamping = damping;
1991 rootpart.PhysActor.APIDActive = true;
1992 }
1993 }
1994 }
1995 }
1996
1626 public void stopLookAt() 1997 public void stopLookAt()
1627 { 1998 {
1628 if (RootPart.PhysActor != null) 1999 SceneObjectPart rootpart = m_rootPart;
1629 RootPart.PhysActor.APIDActive = false; 2000 if (rootpart != null)
2001 {
2002 if (rootpart.PhysActor != null)
2003 { // APID must be implemented in your physics system for this to function.
2004 rootpart.PhysActor.APIDActive = false;
2005 }
2006 }
2007
1630 } 2008 }
1631 2009
1632 /// <summary> 2010 /// <summary>
@@ -1684,6 +2062,8 @@ namespace OpenSim.Region.Framework.Scenes
1684 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2062 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1685 { 2063 {
1686 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2064 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2065 newPart.SetParent(this);
2066
1687 AddPart(newPart); 2067 AddPart(newPart);
1688 2068
1689 SetPartAsNonRoot(newPart); 2069 SetPartAsNonRoot(newPart);
@@ -1830,11 +2210,11 @@ namespace OpenSim.Region.Framework.Scenes
1830 /// Immediately send a full update for this scene object. 2210 /// Immediately send a full update for this scene object.
1831 /// </summary> 2211 /// </summary>
1832 public void SendGroupFullUpdate() 2212 public void SendGroupFullUpdate()
1833 { 2213 {
1834 if (IsDeleted) 2214 if (IsDeleted)
1835 return; 2215 return;
1836 2216
1837// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2217// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1838 2218
1839 RootPart.SendFullUpdateToAllClients(); 2219 RootPart.SendFullUpdateToAllClients();
1840 2220
@@ -2030,12 +2410,15 @@ namespace OpenSim.Region.Framework.Scenes
2030 part.LinkNum += objectGroup.PrimCount; 2410 part.LinkNum += objectGroup.PrimCount;
2031 } 2411 }
2032 } 2412 }
2413 }
2033 2414
2034 linkPart.LinkNum = 2; 2415 linkPart.LinkNum = 2;
2035 2416
2036 linkPart.SetParent(this); 2417 linkPart.SetParent(this);
2037 linkPart.CreateSelected = true; 2418 linkPart.CreateSelected = true;
2038 2419
2420 lock (m_parts.SyncRoot)
2421 {
2039 //if (linkPart.PhysActor != null) 2422 //if (linkPart.PhysActor != null)
2040 //{ 2423 //{
2041 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2424 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2193,6 +2576,7 @@ namespace OpenSim.Region.Framework.Scenes
2193 /// <param name="objectGroup"></param> 2576 /// <param name="objectGroup"></param>
2194 public virtual void DetachFromBackup() 2577 public virtual void DetachFromBackup()
2195 { 2578 {
2579 m_scene.SceneGraph.FireDetachFromBackup(this);
2196 if (m_isBackedUp && Scene != null) 2580 if (m_isBackedUp && Scene != null)
2197 m_scene.EventManager.OnBackup -= ProcessBackup; 2581 m_scene.EventManager.OnBackup -= ProcessBackup;
2198 2582
@@ -2211,7 +2595,8 @@ namespace OpenSim.Region.Framework.Scenes
2211 2595
2212 axPos *= parentRot; 2596 axPos *= parentRot;
2213 part.OffsetPosition = axPos; 2597 part.OffsetPosition = axPos;
2214 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2598 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2599 part.GroupPosition = newPos;
2215 part.OffsetPosition = Vector3.Zero; 2600 part.OffsetPosition = Vector3.Zero;
2216 part.RotationOffset = worldRot; 2601 part.RotationOffset = worldRot;
2217 2602
@@ -2222,7 +2607,7 @@ namespace OpenSim.Region.Framework.Scenes
2222 2607
2223 part.LinkNum = linkNum; 2608 part.LinkNum = linkNum;
2224 2609
2225 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2610 part.OffsetPosition = newPos - AbsolutePosition;
2226 2611
2227 Quaternion rootRotation = m_rootPart.RotationOffset; 2612 Quaternion rootRotation = m_rootPart.RotationOffset;
2228 2613
@@ -2232,7 +2617,7 @@ namespace OpenSim.Region.Framework.Scenes
2232 2617
2233 parentRot = m_rootPart.RotationOffset; 2618 parentRot = m_rootPart.RotationOffset;
2234 oldRot = part.RotationOffset; 2619 oldRot = part.RotationOffset;
2235 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2620 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2236 part.RotationOffset = newRot; 2621 part.RotationOffset = newRot;
2237 } 2622 }
2238 2623
@@ -2479,8 +2864,12 @@ namespace OpenSim.Region.Framework.Scenes
2479 } 2864 }
2480 } 2865 }
2481 2866
2867 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, SetVolumeDetect);
2482 for (int i = 0; i < parts.Length; i++) 2868 for (int i = 0; i < parts.Length; i++)
2483 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2869 {
2870 if (parts[i] != RootPart)
2871 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, SetVolumeDetect);
2872 }
2484 } 2873 }
2485 } 2874 }
2486 2875
@@ -2493,6 +2882,17 @@ namespace OpenSim.Region.Framework.Scenes
2493 } 2882 }
2494 } 2883 }
2495 2884
2885
2886
2887 /// <summary>
2888 /// Gets the number of parts
2889 /// </summary>
2890 /// <returns></returns>
2891 public int GetPartCount()
2892 {
2893 return Parts.Count();
2894 }
2895
2496 /// <summary> 2896 /// <summary>
2497 /// Update the texture entry for this part 2897 /// Update the texture entry for this part
2498 /// </summary> 2898 /// </summary>
@@ -2549,7 +2949,6 @@ namespace OpenSim.Region.Framework.Scenes
2549 { 2949 {
2550// m_log.DebugFormat( 2950// m_log.DebugFormat(
2551// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2951// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2552
2553 RootPart.StoreUndoState(true); 2952 RootPart.StoreUndoState(true);
2554 2953
2555 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2954 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2650,7 +3049,6 @@ namespace OpenSim.Region.Framework.Scenes
2650 prevScale.X *= x; 3049 prevScale.X *= x;
2651 prevScale.Y *= y; 3050 prevScale.Y *= y;
2652 prevScale.Z *= z; 3051 prevScale.Z *= z;
2653
2654// RootPart.IgnoreUndoUpdate = true; 3052// RootPart.IgnoreUndoUpdate = true;
2655 RootPart.Resize(prevScale); 3053 RootPart.Resize(prevScale);
2656// RootPart.IgnoreUndoUpdate = false; 3054// RootPart.IgnoreUndoUpdate = false;
@@ -2681,7 +3079,9 @@ namespace OpenSim.Region.Framework.Scenes
2681 } 3079 }
2682 3080
2683// obPart.IgnoreUndoUpdate = false; 3081// obPart.IgnoreUndoUpdate = false;
2684// obPart.StoreUndoState(); 3082 HasGroupChanged = true;
3083 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3084 ScheduleGroupForTerseUpdate();
2685 } 3085 }
2686 3086
2687// m_log.DebugFormat( 3087// m_log.DebugFormat(
@@ -2741,9 +3141,9 @@ namespace OpenSim.Region.Framework.Scenes
2741 { 3141 {
2742 SceneObjectPart part = GetChildPart(localID); 3142 SceneObjectPart part = GetChildPart(localID);
2743 3143
2744// SceneObjectPart[] parts = m_parts.GetArray(); 3144 SceneObjectPart[] parts = m_parts.GetArray();
2745// for (int i = 0; i < parts.Length; i++) 3145 for (int i = 0; i < parts.Length; i++)
2746// parts[i].StoreUndoState(); 3146 parts[i].StoreUndoState();
2747 3147
2748 if (part != null) 3148 if (part != null)
2749 { 3149 {
@@ -2799,10 +3199,27 @@ namespace OpenSim.Region.Framework.Scenes
2799 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3199 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2800 } 3200 }
2801 3201
2802 AbsolutePosition = newPos; 3202 //We have to set undoing here because otherwise an undo state will be saved
3203 if (!m_rootPart.Undoing)
3204 {
3205 m_rootPart.Undoing = true;
3206 AbsolutePosition = newPos;
3207 m_rootPart.Undoing = false;
3208 }
3209 else
3210 {
3211 AbsolutePosition = newPos;
3212 }
2803 3213
2804 HasGroupChanged = true; 3214 HasGroupChanged = true;
2805 ScheduleGroupForTerseUpdate(); 3215 if (m_rootPart.Undoing)
3216 {
3217 ScheduleGroupForFullUpdate();
3218 }
3219 else
3220 {
3221 ScheduleGroupForTerseUpdate();
3222 }
2806 } 3223 }
2807 3224
2808 public void OffsetForNewRegion(Vector3 offset) 3225 public void OffsetForNewRegion(Vector3 offset)
@@ -2884,10 +3301,7 @@ namespace OpenSim.Region.Framework.Scenes
2884 public void UpdateSingleRotation(Quaternion rot, uint localID) 3301 public void UpdateSingleRotation(Quaternion rot, uint localID)
2885 { 3302 {
2886 SceneObjectPart part = GetChildPart(localID); 3303 SceneObjectPart part = GetChildPart(localID);
2887
2888 SceneObjectPart[] parts = m_parts.GetArray(); 3304 SceneObjectPart[] parts = m_parts.GetArray();
2889 for (int i = 0; i < parts.Length; i++)
2890 parts[i].StoreUndoState();
2891 3305
2892 if (part != null) 3306 if (part != null)
2893 { 3307 {
@@ -2925,7 +3339,16 @@ namespace OpenSim.Region.Framework.Scenes
2925 if (part.UUID == m_rootPart.UUID) 3339 if (part.UUID == m_rootPart.UUID)
2926 { 3340 {
2927 UpdateRootRotation(rot); 3341 UpdateRootRotation(rot);
2928 AbsolutePosition = pos; 3342 if (!m_rootPart.Undoing)
3343 {
3344 m_rootPart.Undoing = true;
3345 AbsolutePosition = pos;
3346 m_rootPart.Undoing = false;
3347 }
3348 else
3349 {
3350 AbsolutePosition = pos;
3351 }
2929 } 3352 }
2930 else 3353 else
2931 { 3354 {
@@ -2949,9 +3372,10 @@ namespace OpenSim.Region.Framework.Scenes
2949 3372
2950 Quaternion axRot = rot; 3373 Quaternion axRot = rot;
2951 Quaternion oldParentRot = m_rootPart.RotationOffset; 3374 Quaternion oldParentRot = m_rootPart.RotationOffset;
2952
2953 m_rootPart.StoreUndoState(); 3375 m_rootPart.StoreUndoState();
2954 m_rootPart.UpdateRotation(rot); 3376
3377 //Don't use UpdateRotation because it schedules an update prematurely
3378 m_rootPart.RotationOffset = rot;
2955 if (m_rootPart.PhysActor != null) 3379 if (m_rootPart.PhysActor != null)
2956 { 3380 {
2957 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3381 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2966,14 +3390,14 @@ namespace OpenSim.Region.Framework.Scenes
2966 { 3390 {
2967 prim.IgnoreUndoUpdate = true; 3391 prim.IgnoreUndoUpdate = true;
2968 Vector3 axPos = prim.OffsetPosition; 3392 Vector3 axPos = prim.OffsetPosition;
3393
2969 axPos *= oldParentRot; 3394 axPos *= oldParentRot;
2970 axPos *= Quaternion.Inverse(axRot); 3395 axPos *= Quaternion.Inverse(axRot);
2971 prim.OffsetPosition = axPos; 3396 prim.OffsetPosition = axPos;
2972 Quaternion primsRot = prim.RotationOffset; 3397
2973 Quaternion newRot = primsRot * oldParentRot; 3398 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
2974 newRot *= Quaternion.Inverse(axRot); 3399
2975 prim.RotationOffset = newRot; 3400 prim.IgnoreUndoUpdate = false;
2976 prim.ScheduleTerseUpdate();
2977 prim.IgnoreUndoUpdate = false; 3401 prim.IgnoreUndoUpdate = false;
2978 } 3402 }
2979 } 3403 }
@@ -2987,8 +3411,8 @@ namespace OpenSim.Region.Framework.Scenes
2987//// childpart.StoreUndoState(); 3411//// childpart.StoreUndoState();
2988// } 3412// }
2989// } 3413// }
2990 3414 HasGroupChanged = true;
2991 m_rootPart.ScheduleTerseUpdate(); 3415 ScheduleGroupForFullUpdate();
2992 3416
2993// m_log.DebugFormat( 3417// m_log.DebugFormat(
2994// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3418// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3216,7 +3640,6 @@ namespace OpenSim.Region.Framework.Scenes
3216 public float GetMass() 3640 public float GetMass()
3217 { 3641 {
3218 float retmass = 0f; 3642 float retmass = 0f;
3219
3220 SceneObjectPart[] parts = m_parts.GetArray(); 3643 SceneObjectPart[] parts = m_parts.GetArray();
3221 for (int i = 0; i < parts.Length; i++) 3644 for (int i = 0; i < parts.Length; i++)
3222 retmass += parts[i].GetMass(); 3645 retmass += parts[i].GetMass();
@@ -3310,6 +3733,14 @@ namespace OpenSim.Region.Framework.Scenes
3310 SetFromItemID(uuid); 3733 SetFromItemID(uuid);
3311 } 3734 }
3312 3735
3736 public void ResetOwnerChangeFlag()
3737 {
3738 ForEachPart(delegate(SceneObjectPart part)
3739 {
3740 part.ResetOwnerChangeFlag();
3741 });
3742 }
3743
3313 #endregion 3744 #endregion
3314 } 3745 }
3315} 3746}