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.cs569
1 files changed, 507 insertions, 62 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index e7f2fdb..c31cbab 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
@@ -287,6 +350,16 @@ namespace OpenSim.Region.Framework.Scenes
287 get { return m_parts.Count; } 350 get { return m_parts.Count; }
288 } 351 }
289 352
353// protected Quaternion m_rotation = Quaternion.Identity;
354//
355// public virtual Quaternion Rotation
356// {
357// get { return m_rotation; }
358// set {
359// m_rotation = value;
360// }
361// }
362
290 public Quaternion GroupRotation 363 public Quaternion GroupRotation
291 { 364 {
292 get { return m_rootPart.RotationOffset; } 365 get { return m_rootPart.RotationOffset; }
@@ -395,7 +468,11 @@ namespace OpenSim.Region.Framework.Scenes
395 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 468 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
396 } 469 }
397 } 470 }
398 471
472 foreach (SceneObjectPart part in m_parts.GetArray())
473 {
474 part.IgnoreUndoUpdate = true;
475 }
399 if (RootPart.GetStatusSandbox()) 476 if (RootPart.GetStatusSandbox())
400 { 477 {
401 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 478 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -409,10 +486,30 @@ namespace OpenSim.Region.Framework.Scenes
409 return; 486 return;
410 } 487 }
411 } 488 }
412
413 SceneObjectPart[] parts = m_parts.GetArray(); 489 SceneObjectPart[] parts = m_parts.GetArray();
414 for (int i = 0; i < parts.Length; i++) 490 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
415 parts[i].GroupPosition = val; 491 if (m_dupeInProgress)
492 triggerScriptEvent = false;
493 foreach (SceneObjectPart part in parts)
494 {
495 part.GroupPosition = val;
496 if (triggerScriptEvent)
497 part.TriggerScriptChangedEvent(Changed.POSITION);
498 }
499 if (!m_dupeInProgress)
500 {
501 foreach (ScenePresence av in m_linkedAvatars)
502 {
503 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
504 if (m_parts.TryGetValue(p.UUID, out p))
505 {
506 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
507 av.AbsolutePosition += offset;
508 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
509 av.SendAvatarDataToAllAgents();
510 }
511 }
512 }
416 513
417 //if (m_rootPart.PhysActor != null) 514 //if (m_rootPart.PhysActor != null)
418 //{ 515 //{
@@ -577,6 +674,7 @@ namespace OpenSim.Region.Framework.Scenes
577 /// </summary> 674 /// </summary>
578 public SceneObjectGroup() 675 public SceneObjectGroup()
579 { 676 {
677
580 } 678 }
581 679
582 /// <summary> 680 /// <summary>
@@ -593,7 +691,7 @@ namespace OpenSim.Region.Framework.Scenes
593 /// Constructor. This object is added to the scene later via AttachToScene() 691 /// Constructor. This object is added to the scene later via AttachToScene()
594 /// </summary> 692 /// </summary>
595 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 693 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
596 { 694 {
597 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 695 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
598 } 696 }
599 697
@@ -641,6 +739,9 @@ namespace OpenSim.Region.Framework.Scenes
641 /// </summary> 739 /// </summary>
642 public virtual void AttachToBackup() 740 public virtual void AttachToBackup()
643 { 741 {
742 if (IsAttachment) return;
743 m_scene.SceneGraph.FireAttachToBackup(this);
744
644 if (InSceneBackup) 745 if (InSceneBackup)
645 { 746 {
646 //m_log.DebugFormat( 747 //m_log.DebugFormat(
@@ -683,6 +784,9 @@ namespace OpenSim.Region.Framework.Scenes
683 784
684 ApplyPhysics(); 785 ApplyPhysics();
685 786
787 if (RootPart.PhysActor != null)
788 RootPart.Buoyancy = RootPart.Buoyancy;
789
686 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 790 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
687 // for the same object with very different properties. The caller must schedule the update. 791 // for the same object with very different properties. The caller must schedule the update.
688 //ScheduleGroupForFullUpdate(); 792 //ScheduleGroupForFullUpdate();
@@ -698,6 +802,10 @@ namespace OpenSim.Region.Framework.Scenes
698 EntityIntersection result = new EntityIntersection(); 802 EntityIntersection result = new EntityIntersection();
699 803
700 SceneObjectPart[] parts = m_parts.GetArray(); 804 SceneObjectPart[] parts = m_parts.GetArray();
805
806 // Find closest hit here
807 float idist = float.MaxValue;
808
701 for (int i = 0; i < parts.Length; i++) 809 for (int i = 0; i < parts.Length; i++)
702 { 810 {
703 SceneObjectPart part = parts[i]; 811 SceneObjectPart part = parts[i];
@@ -712,11 +820,6 @@ namespace OpenSim.Region.Framework.Scenes
712 820
713 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 821 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
714 822
715 // This may need to be updated to the maximum draw distance possible..
716 // We might (and probably will) be checking for prim creation from other sims
717 // when the camera crosses the border.
718 float idist = Constants.RegionSize;
719
720 if (inter.HitTF) 823 if (inter.HitTF)
721 { 824 {
722 // We need to find the closest prim to return to the testcaller along the ray 825 // We need to find the closest prim to return to the testcaller along the ray
@@ -727,10 +830,11 @@ namespace OpenSim.Region.Framework.Scenes
727 result.obj = part; 830 result.obj = part;
728 result.normal = inter.normal; 831 result.normal = inter.normal;
729 result.distance = inter.distance; 832 result.distance = inter.distance;
833
834 idist = inter.distance;
730 } 835 }
731 } 836 }
732 } 837 }
733
734 return result; 838 return result;
735 } 839 }
736 840
@@ -750,17 +854,19 @@ namespace OpenSim.Region.Framework.Scenes
750 minZ = 8192f; 854 minZ = 8192f;
751 855
752 SceneObjectPart[] parts = m_parts.GetArray(); 856 SceneObjectPart[] parts = m_parts.GetArray();
753 for (int i = 0; i < parts.Length; i++) 857 foreach (SceneObjectPart part in parts)
754 { 858 {
755 SceneObjectPart part = parts[i];
756
757 Vector3 worldPos = part.GetWorldPosition(); 859 Vector3 worldPos = part.GetWorldPosition();
758 Vector3 offset = worldPos - AbsolutePosition; 860 Vector3 offset = worldPos - AbsolutePosition;
759 Quaternion worldRot; 861 Quaternion worldRot;
760 if (part.ParentID == 0) 862 if (part.ParentID == 0)
863 {
761 worldRot = part.RotationOffset; 864 worldRot = part.RotationOffset;
865 }
762 else 866 else
867 {
763 worldRot = part.GetWorldRotation(); 868 worldRot = part.GetWorldRotation();
869 }
764 870
765 Vector3 frontTopLeft; 871 Vector3 frontTopLeft;
766 Vector3 frontTopRight; 872 Vector3 frontTopRight;
@@ -772,6 +878,8 @@ namespace OpenSim.Region.Framework.Scenes
772 Vector3 backBottomLeft; 878 Vector3 backBottomLeft;
773 Vector3 backBottomRight; 879 Vector3 backBottomRight;
774 880
881 // Vector3[] corners = new Vector3[8];
882
775 Vector3 orig = Vector3.Zero; 883 Vector3 orig = Vector3.Zero;
776 884
777 frontTopLeft.X = orig.X - (part.Scale.X / 2); 885 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -806,6 +914,38 @@ namespace OpenSim.Region.Framework.Scenes
806 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 914 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
807 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 915 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
808 916
917
918
919 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
920 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
921 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
922 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
923 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
924 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
925 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
926 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
927
928 //for (int i = 0; i < 8; i++)
929 //{
930 // corners[i] = corners[i] * worldRot;
931 // corners[i] += offset;
932
933 // if (corners[i].X > maxX)
934 // maxX = corners[i].X;
935 // if (corners[i].X < minX)
936 // minX = corners[i].X;
937
938 // if (corners[i].Y > maxY)
939 // maxY = corners[i].Y;
940 // if (corners[i].Y < minY)
941 // minY = corners[i].Y;
942
943 // if (corners[i].Z > maxZ)
944 // maxZ = corners[i].Y;
945 // if (corners[i].Z < minZ)
946 // minZ = corners[i].Z;
947 //}
948
809 frontTopLeft = frontTopLeft * worldRot; 949 frontTopLeft = frontTopLeft * worldRot;
810 frontTopRight = frontTopRight * worldRot; 950 frontTopRight = frontTopRight * worldRot;
811 frontBottomLeft = frontBottomLeft * worldRot; 951 frontBottomLeft = frontBottomLeft * worldRot;
@@ -827,6 +967,15 @@ namespace OpenSim.Region.Framework.Scenes
827 backTopLeft += offset; 967 backTopLeft += offset;
828 backTopRight += offset; 968 backTopRight += offset;
829 969
970 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
971 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
972 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
973 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
974 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
975 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
976 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
977 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
978
830 if (frontTopRight.X > maxX) 979 if (frontTopRight.X > maxX)
831 maxX = frontTopRight.X; 980 maxX = frontTopRight.X;
832 if (frontTopLeft.X > maxX) 981 if (frontTopLeft.X > maxX)
@@ -972,15 +1121,20 @@ namespace OpenSim.Region.Framework.Scenes
972 1121
973 public void SaveScriptedState(XmlTextWriter writer) 1122 public void SaveScriptedState(XmlTextWriter writer)
974 { 1123 {
1124 SaveScriptedState(writer, false);
1125 }
1126
1127 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1128 {
975 XmlDocument doc = new XmlDocument(); 1129 XmlDocument doc = new XmlDocument();
976 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1130 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
977 1131
978 SceneObjectPart[] parts = m_parts.GetArray(); 1132 SceneObjectPart[] parts = m_parts.GetArray();
979 for (int i = 0; i < parts.Length; i++) 1133 for (int i = 0; i < parts.Length; i++)
980 { 1134 {
981 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1135 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
982 foreach (KeyValuePair<UUID, string> kvp in pstates) 1136 foreach (KeyValuePair<UUID, string> kvp in pstates)
983 states.Add(kvp.Key, kvp.Value); 1137 states[kvp.Key] = kvp.Value;
984 } 1138 }
985 1139
986 if (states.Count > 0) 1140 if (states.Count > 0)
@@ -1000,6 +1154,168 @@ namespace OpenSim.Region.Framework.Scenes
1000 } 1154 }
1001 1155
1002 /// <summary> 1156 /// <summary>
1157 /// Add the avatar to this linkset (avatar is sat).
1158 /// </summary>
1159 /// <param name="agentID"></param>
1160 public void AddAvatar(UUID agentID)
1161 {
1162 ScenePresence presence;
1163 if (m_scene.TryGetScenePresence(agentID, out presence))
1164 {
1165 if (!m_linkedAvatars.Contains(presence))
1166 {
1167 m_linkedAvatars.Add(presence);
1168 }
1169 }
1170 }
1171
1172 /// <summary>
1173 /// Delete the avatar from this linkset (avatar is unsat).
1174 /// </summary>
1175 /// <param name="agentID"></param>
1176 public void DeleteAvatar(UUID agentID)
1177 {
1178 ScenePresence presence;
1179 if (m_scene.TryGetScenePresence(agentID, out presence))
1180 {
1181 if (m_linkedAvatars.Contains(presence))
1182 {
1183 m_linkedAvatars.Remove(presence);
1184 }
1185 }
1186 }
1187
1188 /// <summary>
1189 /// Returns the list of linked presences (avatars sat on this group)
1190 /// </summary>
1191 /// <param name="agentID"></param>
1192 public List<ScenePresence> GetLinkedAvatars()
1193 {
1194 return m_linkedAvatars;
1195 }
1196
1197 /// <summary>
1198 /// Attach this scene object to the given avatar.
1199 /// </summary>
1200 /// <param name="agentID"></param>
1201 /// <param name="attachmentpoint"></param>
1202 /// <param name="AttachOffset"></param>
1203 private void AttachToAgent(
1204 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1205 {
1206 if (avatar != null)
1207 {
1208 // don't attach attachments to child agents
1209 if (avatar.IsChildAgent) return;
1210
1211 // Remove from database and parcel prim count
1212 m_scene.DeleteFromStorage(so.UUID);
1213 m_scene.EventManager.TriggerParcelPrimCountTainted();
1214
1215 so.AttachedAvatar = avatar.UUID;
1216
1217 if (so.RootPart.PhysActor != null)
1218 {
1219 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1220 so.RootPart.PhysActor = null;
1221 }
1222
1223 so.AbsolutePosition = attachOffset;
1224 so.RootPart.AttachedPos = attachOffset;
1225 so.IsAttachment = true;
1226 so.RootPart.SetParentLocalId(avatar.LocalId);
1227 so.AttachmentPoint = attachmentpoint;
1228
1229 avatar.AddAttachment(this);
1230
1231 if (!silent)
1232 {
1233 // Killing it here will cause the client to deselect it
1234 // It then reappears on the avatar, deselected
1235 // through the full update below
1236 //
1237 if (IsSelected)
1238 {
1239 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1240 }
1241
1242 IsSelected = false; // fudge....
1243 ScheduleGroupForFullUpdate();
1244 }
1245 }
1246 else
1247 {
1248 m_log.WarnFormat(
1249 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1250 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1251 }
1252 }
1253
1254 public byte GetAttachmentPoint()
1255 {
1256 return m_rootPart.Shape.State;
1257 }
1258
1259 public void DetachToGround()
1260 {
1261 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1262 if (avatar == null)
1263 return;
1264
1265 avatar.RemoveAttachment(this);
1266
1267 Vector3 detachedpos = new Vector3(127f,127f,127f);
1268 if (avatar == null)
1269 return;
1270
1271 detachedpos = avatar.AbsolutePosition;
1272 RootPart.FromItemID = UUID.Zero;
1273
1274 AbsolutePosition = detachedpos;
1275 AttachedAvatar = UUID.Zero;
1276
1277 //SceneObjectPart[] parts = m_parts.GetArray();
1278 //for (int i = 0; i < parts.Length; i++)
1279 // parts[i].AttachedAvatar = UUID.Zero;
1280
1281 m_rootPart.SetParentLocalId(0);
1282 AttachmentPoint = (byte)0;
1283 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1284 HasGroupChanged = true;
1285 RootPart.Rezzed = DateTime.Now;
1286 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1287 AttachToBackup();
1288 m_scene.EventManager.TriggerParcelPrimCountTainted();
1289 m_rootPart.ScheduleFullUpdate();
1290 m_rootPart.ClearUndoState();
1291 }
1292
1293 public void DetachToInventoryPrep()
1294 {
1295 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1296 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1297 if (avatar != null)
1298 {
1299 //detachedpos = avatar.AbsolutePosition;
1300 avatar.RemoveAttachment(this);
1301 }
1302
1303 AttachedAvatar = UUID.Zero;
1304
1305 /*SceneObjectPart[] parts = m_parts.GetArray();
1306 for (int i = 0; i < parts.Length; i++)
1307 parts[i].AttachedAvatar = UUID.Zero;*/
1308
1309 m_rootPart.SetParentLocalId(0);
1310 //m_rootPart.SetAttachmentPoint((byte)0);
1311 IsAttachment = false;
1312 AbsolutePosition = m_rootPart.AttachedPos;
1313 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1314 //AttachToBackup();
1315 //m_rootPart.ScheduleFullUpdate();
1316 }
1317
1318 /// <summary>
1003 /// 1319 ///
1004 /// </summary> 1320 /// </summary>
1005 /// <param name="part"></param> 1321 /// <param name="part"></param>
@@ -1049,7 +1365,10 @@ namespace OpenSim.Region.Framework.Scenes
1049 public void AddPart(SceneObjectPart part) 1365 public void AddPart(SceneObjectPart part)
1050 { 1366 {
1051 part.SetParent(this); 1367 part.SetParent(this);
1052 part.LinkNum = m_parts.Add(part.UUID, part); 1368 m_parts.Add(part.UUID, part);
1369
1370 part.LinkNum = m_parts.Count;
1371
1053 if (part.LinkNum == 2) 1372 if (part.LinkNum == 2)
1054 RootPart.LinkNum = 1; 1373 RootPart.LinkNum = 1;
1055 } 1374 }
@@ -1157,6 +1476,11 @@ namespace OpenSim.Region.Framework.Scenes
1157 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1476 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1158 public void DeleteGroupFromScene(bool silent) 1477 public void DeleteGroupFromScene(bool silent)
1159 { 1478 {
1479 // We need to keep track of this state in case this group is still queued for backup.
1480 IsDeleted = true;
1481
1482 DetachFromBackup();
1483
1160 SceneObjectPart[] parts = m_parts.GetArray(); 1484 SceneObjectPart[] parts = m_parts.GetArray();
1161 for (int i = 0; i < parts.Length; i++) 1485 for (int i = 0; i < parts.Length; i++)
1162 { 1486 {
@@ -1179,6 +1503,8 @@ namespace OpenSim.Region.Framework.Scenes
1179 } 1503 }
1180 }); 1504 });
1181 } 1505 }
1506
1507
1182 } 1508 }
1183 1509
1184 public void AddScriptLPS(int count) 1510 public void AddScriptLPS(int count)
@@ -1274,7 +1600,12 @@ namespace OpenSim.Region.Framework.Scenes
1274 1600
1275 public void SetOwnerId(UUID userId) 1601 public void SetOwnerId(UUID userId)
1276 { 1602 {
1277 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1603 ForEachPart(delegate(SceneObjectPart part)
1604 {
1605
1606 part.OwnerID = userId;
1607
1608 });
1278 } 1609 }
1279 1610
1280 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1611 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1306,11 +1637,17 @@ namespace OpenSim.Region.Framework.Scenes
1306 return; 1637 return;
1307 } 1638 }
1308 1639
1640 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1641 return;
1642
1309 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1643 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1310 // any exception propogate upwards. 1644 // any exception propogate upwards.
1311 try 1645 try
1312 { 1646 {
1313 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1647 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1648 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1649 m_scene.LoadingPrims) // Land may not be valid yet
1650
1314 { 1651 {
1315 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1652 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1316 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1653 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1337,6 +1674,7 @@ namespace OpenSim.Region.Framework.Scenes
1337 } 1674 }
1338 } 1675 }
1339 } 1676 }
1677
1340 } 1678 }
1341 1679
1342 if (m_scene.UseBackup && HasGroupChanged) 1680 if (m_scene.UseBackup && HasGroupChanged)
@@ -1344,6 +1682,20 @@ namespace OpenSim.Region.Framework.Scenes
1344 // don't backup while it's selected or you're asking for changes mid stream. 1682 // don't backup while it's selected or you're asking for changes mid stream.
1345 if (isTimeToPersist() || forcedBackup) 1683 if (isTimeToPersist() || forcedBackup)
1346 { 1684 {
1685 if (m_rootPart.PhysActor != null &&
1686 (!m_rootPart.PhysActor.IsPhysical))
1687 {
1688 // Possible ghost prim
1689 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1690 {
1691 foreach (SceneObjectPart part in m_parts.GetArray())
1692 {
1693 // Re-set physics actor positions and
1694 // orientations
1695 part.GroupPosition = m_rootPart.GroupPosition;
1696 }
1697 }
1698 }
1347// m_log.DebugFormat( 1699// m_log.DebugFormat(
1348// "[SCENE]: Storing {0}, {1} in {2}", 1700// "[SCENE]: Storing {0}, {1} in {2}",
1349// Name, UUID, m_scene.RegionInfo.RegionName); 1701// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1427,7 +1779,7 @@ namespace OpenSim.Region.Framework.Scenes
1427 // This is only necessary when userExposed is false! 1779 // This is only necessary when userExposed is false!
1428 1780
1429 bool previousAttachmentStatus = dupe.IsAttachment; 1781 bool previousAttachmentStatus = dupe.IsAttachment;
1430 1782
1431 if (!userExposed) 1783 if (!userExposed)
1432 dupe.IsAttachment = true; 1784 dupe.IsAttachment = true;
1433 1785
@@ -1445,11 +1797,11 @@ namespace OpenSim.Region.Framework.Scenes
1445 dupe.m_rootPart.TrimPermissions(); 1797 dupe.m_rootPart.TrimPermissions();
1446 1798
1447 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1799 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1448 1800
1449 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1801 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1450 { 1802 {
1451 return p1.LinkNum.CompareTo(p2.LinkNum); 1803 return p1.LinkNum.CompareTo(p2.LinkNum);
1452 } 1804 }
1453 ); 1805 );
1454 1806
1455 foreach (SceneObjectPart part in partList) 1807 foreach (SceneObjectPart part in partList)
@@ -1469,7 +1821,7 @@ namespace OpenSim.Region.Framework.Scenes
1469 if (part.PhysActor != null && userExposed) 1821 if (part.PhysActor != null && userExposed)
1470 { 1822 {
1471 PrimitiveBaseShape pbs = newPart.Shape; 1823 PrimitiveBaseShape pbs = newPart.Shape;
1472 1824
1473 newPart.PhysActor 1825 newPart.PhysActor
1474 = m_scene.PhysicsScene.AddPrimShape( 1826 = m_scene.PhysicsScene.AddPrimShape(
1475 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1827 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1479,11 +1831,11 @@ namespace OpenSim.Region.Framework.Scenes
1479 newPart.RotationOffset, 1831 newPart.RotationOffset,
1480 part.PhysActor.IsPhysical, 1832 part.PhysActor.IsPhysical,
1481 newPart.LocalId); 1833 newPart.LocalId);
1482 1834
1483 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1835 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1484 } 1836 }
1485 } 1837 }
1486 1838
1487 if (userExposed) 1839 if (userExposed)
1488 { 1840 {
1489 dupe.UpdateParentIDs(); 1841 dupe.UpdateParentIDs();
@@ -1598,6 +1950,7 @@ namespace OpenSim.Region.Framework.Scenes
1598 return Vector3.Zero; 1950 return Vector3.Zero;
1599 } 1951 }
1600 1952
1953 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1601 public void moveToTarget(Vector3 target, float tau) 1954 public void moveToTarget(Vector3 target, float tau)
1602 { 1955 {
1603 if (IsAttachment) 1956 if (IsAttachment)
@@ -1625,6 +1978,46 @@ namespace OpenSim.Region.Framework.Scenes
1625 RootPart.PhysActor.PIDActive = false; 1978 RootPart.PhysActor.PIDActive = false;
1626 } 1979 }
1627 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
2008 public void stopLookAt()
2009 {
2010 SceneObjectPart rootpart = m_rootPart;
2011 if (rootpart != null)
2012 {
2013 if (rootpart.PhysActor != null)
2014 { // APID must be implemented in your physics system for this to function.
2015 rootpart.PhysActor.APIDActive = false;
2016 }
2017 }
2018
2019 }
2020
1628 /// <summary> 2021 /// <summary>
1629 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2022 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1630 /// </summary> 2023 /// </summary>
@@ -1680,6 +2073,8 @@ namespace OpenSim.Region.Framework.Scenes
1680 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2073 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1681 { 2074 {
1682 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2075 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2076 newPart.SetParent(this);
2077
1683 AddPart(newPart); 2078 AddPart(newPart);
1684 2079
1685 SetPartAsNonRoot(newPart); 2080 SetPartAsNonRoot(newPart);
@@ -1808,11 +2203,11 @@ namespace OpenSim.Region.Framework.Scenes
1808 /// Immediately send a full update for this scene object. 2203 /// Immediately send a full update for this scene object.
1809 /// </summary> 2204 /// </summary>
1810 public void SendGroupFullUpdate() 2205 public void SendGroupFullUpdate()
1811 { 2206 {
1812 if (IsDeleted) 2207 if (IsDeleted)
1813 return; 2208 return;
1814 2209
1815// 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);
1816 2211
1817 RootPart.SendFullUpdateToAllClients(); 2212 RootPart.SendFullUpdateToAllClients();
1818 2213
@@ -2013,7 +2408,7 @@ namespace OpenSim.Region.Framework.Scenes
2013 objectGroup.IsDeleted = true; 2408 objectGroup.IsDeleted = true;
2014 2409
2015 objectGroup.m_parts.Clear(); 2410 objectGroup.m_parts.Clear();
2016 2411
2017 // Can't do this yet since backup still makes use of the root part without any synchronization 2412 // Can't do this yet since backup still makes use of the root part without any synchronization
2018// objectGroup.m_rootPart = null; 2413// objectGroup.m_rootPart = null;
2019 2414
@@ -2147,6 +2542,7 @@ namespace OpenSim.Region.Framework.Scenes
2147 /// <param name="objectGroup"></param> 2542 /// <param name="objectGroup"></param>
2148 public virtual void DetachFromBackup() 2543 public virtual void DetachFromBackup()
2149 { 2544 {
2545 m_scene.SceneGraph.FireDetachFromBackup(this);
2150 if (m_isBackedUp && Scene != null) 2546 if (m_isBackedUp && Scene != null)
2151 m_scene.EventManager.OnBackup -= ProcessBackup; 2547 m_scene.EventManager.OnBackup -= ProcessBackup;
2152 2548
@@ -2165,7 +2561,8 @@ namespace OpenSim.Region.Framework.Scenes
2165 2561
2166 axPos *= parentRot; 2562 axPos *= parentRot;
2167 part.OffsetPosition = axPos; 2563 part.OffsetPosition = axPos;
2168 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2564 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2565 part.GroupPosition = newPos;
2169 part.OffsetPosition = Vector3.Zero; 2566 part.OffsetPosition = Vector3.Zero;
2170 part.RotationOffset = worldRot; 2567 part.RotationOffset = worldRot;
2171 2568
@@ -2176,7 +2573,7 @@ namespace OpenSim.Region.Framework.Scenes
2176 2573
2177 part.LinkNum = linkNum; 2574 part.LinkNum = linkNum;
2178 2575
2179 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2576 part.OffsetPosition = newPos - AbsolutePosition;
2180 2577
2181 Quaternion rootRotation = m_rootPart.RotationOffset; 2578 Quaternion rootRotation = m_rootPart.RotationOffset;
2182 2579
@@ -2186,7 +2583,7 @@ namespace OpenSim.Region.Framework.Scenes
2186 2583
2187 parentRot = m_rootPart.RotationOffset; 2584 parentRot = m_rootPart.RotationOffset;
2188 oldRot = part.RotationOffset; 2585 oldRot = part.RotationOffset;
2189 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2586 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2190 part.RotationOffset = newRot; 2587 part.RotationOffset = newRot;
2191 } 2588 }
2192 2589
@@ -2433,8 +2830,12 @@ namespace OpenSim.Region.Framework.Scenes
2433 } 2830 }
2434 } 2831 }
2435 2832
2833 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2436 for (int i = 0; i < parts.Length; i++) 2834 for (int i = 0; i < parts.Length; i++)
2437 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2835 {
2836 if (parts[i] != RootPart)
2837 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2838 }
2438 } 2839 }
2439 } 2840 }
2440 2841
@@ -2447,6 +2848,17 @@ namespace OpenSim.Region.Framework.Scenes
2447 } 2848 }
2448 } 2849 }
2449 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
2450 /// <summary> 2862 /// <summary>
2451 /// Update the texture entry for this part 2863 /// Update the texture entry for this part
2452 /// </summary> 2864 /// </summary>
@@ -2508,7 +2920,6 @@ namespace OpenSim.Region.Framework.Scenes
2508 { 2920 {
2509// m_log.DebugFormat( 2921// m_log.DebugFormat(
2510// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2922// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2511
2512 RootPart.StoreUndoState(true); 2923 RootPart.StoreUndoState(true);
2513 2924
2514 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2925 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2609,7 +3020,6 @@ namespace OpenSim.Region.Framework.Scenes
2609 prevScale.X *= x; 3020 prevScale.X *= x;
2610 prevScale.Y *= y; 3021 prevScale.Y *= y;
2611 prevScale.Z *= z; 3022 prevScale.Z *= z;
2612
2613// RootPart.IgnoreUndoUpdate = true; 3023// RootPart.IgnoreUndoUpdate = true;
2614 RootPart.Resize(prevScale); 3024 RootPart.Resize(prevScale);
2615// RootPart.IgnoreUndoUpdate = false; 3025// RootPart.IgnoreUndoUpdate = false;
@@ -2640,7 +3050,9 @@ namespace OpenSim.Region.Framework.Scenes
2640 } 3050 }
2641 3051
2642// obPart.IgnoreUndoUpdate = false; 3052// obPart.IgnoreUndoUpdate = false;
2643// obPart.StoreUndoState(); 3053 HasGroupChanged = true;
3054 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3055 ScheduleGroupForTerseUpdate();
2644 } 3056 }
2645 3057
2646// m_log.DebugFormat( 3058// m_log.DebugFormat(
@@ -2700,9 +3112,9 @@ namespace OpenSim.Region.Framework.Scenes
2700 { 3112 {
2701 SceneObjectPart part = GetChildPart(localID); 3113 SceneObjectPart part = GetChildPart(localID);
2702 3114
2703// SceneObjectPart[] parts = m_parts.GetArray(); 3115 SceneObjectPart[] parts = m_parts.GetArray();
2704// for (int i = 0; i < parts.Length; i++) 3116 for (int i = 0; i < parts.Length; i++)
2705// parts[i].StoreUndoState(); 3117 parts[i].StoreUndoState();
2706 3118
2707 if (part != null) 3119 if (part != null)
2708 { 3120 {
@@ -2758,10 +3170,27 @@ namespace OpenSim.Region.Framework.Scenes
2758 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3170 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2759 } 3171 }
2760 3172
2761 AbsolutePosition = newPos; 3173 //We have to set undoing here because otherwise an undo state will be saved
3174 if (!m_rootPart.Undoing)
3175 {
3176 m_rootPart.Undoing = true;
3177 AbsolutePosition = newPos;
3178 m_rootPart.Undoing = false;
3179 }
3180 else
3181 {
3182 AbsolutePosition = newPos;
3183 }
2762 3184
2763 HasGroupChanged = true; 3185 HasGroupChanged = true;
2764 ScheduleGroupForTerseUpdate(); 3186 if (m_rootPart.Undoing)
3187 {
3188 ScheduleGroupForFullUpdate();
3189 }
3190 else
3191 {
3192 ScheduleGroupForTerseUpdate();
3193 }
2765 } 3194 }
2766 3195
2767 #endregion 3196 #endregion
@@ -2838,10 +3267,7 @@ namespace OpenSim.Region.Framework.Scenes
2838 public void UpdateSingleRotation(Quaternion rot, uint localID) 3267 public void UpdateSingleRotation(Quaternion rot, uint localID)
2839 { 3268 {
2840 SceneObjectPart part = GetChildPart(localID); 3269 SceneObjectPart part = GetChildPart(localID);
2841
2842 SceneObjectPart[] parts = m_parts.GetArray(); 3270 SceneObjectPart[] parts = m_parts.GetArray();
2843 for (int i = 0; i < parts.Length; i++)
2844 parts[i].StoreUndoState();
2845 3271
2846 if (part != null) 3272 if (part != null)
2847 { 3273 {
@@ -2879,7 +3305,16 @@ namespace OpenSim.Region.Framework.Scenes
2879 if (part.UUID == m_rootPart.UUID) 3305 if (part.UUID == m_rootPart.UUID)
2880 { 3306 {
2881 UpdateRootRotation(rot); 3307 UpdateRootRotation(rot);
2882 AbsolutePosition = pos; 3308 if (!m_rootPart.Undoing)
3309 {
3310 m_rootPart.Undoing = true;
3311 AbsolutePosition = pos;
3312 m_rootPart.Undoing = false;
3313 }
3314 else
3315 {
3316 AbsolutePosition = pos;
3317 }
2883 } 3318 }
2884 else 3319 else
2885 { 3320 {
@@ -2903,9 +3338,10 @@ namespace OpenSim.Region.Framework.Scenes
2903 3338
2904 Quaternion axRot = rot; 3339 Quaternion axRot = rot;
2905 Quaternion oldParentRot = m_rootPart.RotationOffset; 3340 Quaternion oldParentRot = m_rootPart.RotationOffset;
2906
2907 m_rootPart.StoreUndoState(); 3341 m_rootPart.StoreUndoState();
2908 m_rootPart.UpdateRotation(rot); 3342
3343 //Don't use UpdateRotation because it schedules an update prematurely
3344 m_rootPart.RotationOffset = rot;
2909 if (m_rootPart.PhysActor != null) 3345 if (m_rootPart.PhysActor != null)
2910 { 3346 {
2911 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3347 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2919,15 +3355,17 @@ namespace OpenSim.Region.Framework.Scenes
2919 if (prim.UUID != m_rootPart.UUID) 3355 if (prim.UUID != m_rootPart.UUID)
2920 { 3356 {
2921 prim.IgnoreUndoUpdate = true; 3357 prim.IgnoreUndoUpdate = true;
3358
3359 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3360 NewRot = Quaternion.Inverse(axRot) * NewRot;
3361 prim.RotationOffset = NewRot;
3362
2922 Vector3 axPos = prim.OffsetPosition; 3363 Vector3 axPos = prim.OffsetPosition;
3364
2923 axPos *= oldParentRot; 3365 axPos *= oldParentRot;
2924 axPos *= Quaternion.Inverse(axRot); 3366 axPos *= Quaternion.Inverse(axRot);
2925 prim.OffsetPosition = axPos; 3367 prim.OffsetPosition = axPos;
2926 Quaternion primsRot = prim.RotationOffset; 3368
2927 Quaternion newRot = oldParentRot * primsRot;
2928 newRot = Quaternion.Inverse(axRot) * newRot;
2929 prim.RotationOffset = newRot;
2930 prim.ScheduleTerseUpdate();
2931 prim.IgnoreUndoUpdate = false; 3369 prim.IgnoreUndoUpdate = false;
2932 } 3370 }
2933 } 3371 }
@@ -2941,8 +3379,8 @@ namespace OpenSim.Region.Framework.Scenes
2941//// childpart.StoreUndoState(); 3379//// childpart.StoreUndoState();
2942// } 3380// }
2943// } 3381// }
2944 3382 HasGroupChanged = true;
2945 m_rootPart.ScheduleTerseUpdate(); 3383 ScheduleGroupForFullUpdate();
2946 3384
2947// m_log.DebugFormat( 3385// m_log.DebugFormat(
2948// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3386// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3170,7 +3608,6 @@ namespace OpenSim.Region.Framework.Scenes
3170 public float GetMass() 3608 public float GetMass()
3171 { 3609 {
3172 float retmass = 0f; 3610 float retmass = 0f;
3173
3174 SceneObjectPart[] parts = m_parts.GetArray(); 3611 SceneObjectPart[] parts = m_parts.GetArray();
3175 for (int i = 0; i < parts.Length; i++) 3612 for (int i = 0; i < parts.Length; i++)
3176 retmass += parts[i].GetMass(); 3613 retmass += parts[i].GetMass();
@@ -3266,6 +3703,14 @@ namespace OpenSim.Region.Framework.Scenes
3266 SetFromItemID(uuid); 3703 SetFromItemID(uuid);
3267 } 3704 }
3268 3705
3706 public void ResetOwnerChangeFlag()
3707 {
3708 ForEachPart(delegate(SceneObjectPart part)
3709 {
3710 part.ResetOwnerChangeFlag();
3711 });
3712 }
3713
3269 #endregion 3714 #endregion
3270 } 3715 }
3271} 3716}