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.cs567
1 files changed, 503 insertions, 64 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 8860764..3b0d1cd 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,30 @@ 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 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
409 parts[i].GroupPosition = val; 485 if (m_dupeInProgress)
486 triggerScriptEvent = false;
487 foreach (SceneObjectPart part in parts)
488 {
489 part.GroupPosition = val;
490 if (triggerScriptEvent)
491 part.TriggerScriptChangedEvent(Changed.POSITION);
492 }
493 if (!m_dupeInProgress)
494 {
495 foreach (ScenePresence av in m_linkedAvatars)
496 {
497 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
498 if (m_parts.TryGetValue(p.UUID, out p))
499 {
500 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
501 av.AbsolutePosition += offset;
502 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
503 av.SendAvatarDataToAllAgents();
504 }
505 }
506 }
410 507
411 //if (m_rootPart.PhysActor != null) 508 //if (m_rootPart.PhysActor != null)
412 //{ 509 //{
@@ -565,6 +662,7 @@ namespace OpenSim.Region.Framework.Scenes
565 /// </summary> 662 /// </summary>
566 public SceneObjectGroup() 663 public SceneObjectGroup()
567 { 664 {
665
568 } 666 }
569 667
570 /// <summary> 668 /// <summary>
@@ -581,7 +679,7 @@ namespace OpenSim.Region.Framework.Scenes
581 /// Constructor. This object is added to the scene later via AttachToScene() 679 /// Constructor. This object is added to the scene later via AttachToScene()
582 /// </summary> 680 /// </summary>
583 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 681 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
584 { 682 {
585 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 683 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
586 } 684 }
587 685
@@ -629,6 +727,9 @@ namespace OpenSim.Region.Framework.Scenes
629 /// </summary> 727 /// </summary>
630 public virtual void AttachToBackup() 728 public virtual void AttachToBackup()
631 { 729 {
730 if (IsAttachment) return;
731 m_scene.SceneGraph.FireAttachToBackup(this);
732
632 if (InSceneBackup) 733 if (InSceneBackup)
633 { 734 {
634 //m_log.DebugFormat( 735 //m_log.DebugFormat(
@@ -671,6 +772,9 @@ namespace OpenSim.Region.Framework.Scenes
671 772
672 ApplyPhysics(); 773 ApplyPhysics();
673 774
775 if (RootPart.PhysActor != null)
776 RootPart.Buoyancy = RootPart.Buoyancy;
777
674 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 778 // 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. 779 // for the same object with very different properties. The caller must schedule the update.
676 //ScheduleGroupForFullUpdate(); 780 //ScheduleGroupForFullUpdate();
@@ -686,6 +790,10 @@ namespace OpenSim.Region.Framework.Scenes
686 EntityIntersection result = new EntityIntersection(); 790 EntityIntersection result = new EntityIntersection();
687 791
688 SceneObjectPart[] parts = m_parts.GetArray(); 792 SceneObjectPart[] parts = m_parts.GetArray();
793
794 // Find closest hit here
795 float idist = float.MaxValue;
796
689 for (int i = 0; i < parts.Length; i++) 797 for (int i = 0; i < parts.Length; i++)
690 { 798 {
691 SceneObjectPart part = parts[i]; 799 SceneObjectPart part = parts[i];
@@ -700,11 +808,6 @@ namespace OpenSim.Region.Framework.Scenes
700 808
701 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 809 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
702 810
703 // This may need to be updated to the maximum draw distance possible..
704 // We might (and probably will) be checking for prim creation from other sims
705 // when the camera crosses the border.
706 float idist = Constants.RegionSize;
707
708 if (inter.HitTF) 811 if (inter.HitTF)
709 { 812 {
710 // We need to find the closest prim to return to the testcaller along the ray 813 // We need to find the closest prim to return to the testcaller along the ray
@@ -715,10 +818,11 @@ namespace OpenSim.Region.Framework.Scenes
715 result.obj = part; 818 result.obj = part;
716 result.normal = inter.normal; 819 result.normal = inter.normal;
717 result.distance = inter.distance; 820 result.distance = inter.distance;
821
822 idist = inter.distance;
718 } 823 }
719 } 824 }
720 } 825 }
721
722 return result; 826 return result;
723 } 827 }
724 828
@@ -738,17 +842,19 @@ namespace OpenSim.Region.Framework.Scenes
738 minZ = 8192f; 842 minZ = 8192f;
739 843
740 SceneObjectPart[] parts = m_parts.GetArray(); 844 SceneObjectPart[] parts = m_parts.GetArray();
741 for (int i = 0; i < parts.Length; i++) 845 foreach (SceneObjectPart part in parts)
742 { 846 {
743 SceneObjectPart part = parts[i];
744
745 Vector3 worldPos = part.GetWorldPosition(); 847 Vector3 worldPos = part.GetWorldPosition();
746 Vector3 offset = worldPos - AbsolutePosition; 848 Vector3 offset = worldPos - AbsolutePosition;
747 Quaternion worldRot; 849 Quaternion worldRot;
748 if (part.ParentID == 0) 850 if (part.ParentID == 0)
851 {
749 worldRot = part.RotationOffset; 852 worldRot = part.RotationOffset;
853 }
750 else 854 else
855 {
751 worldRot = part.GetWorldRotation(); 856 worldRot = part.GetWorldRotation();
857 }
752 858
753 Vector3 frontTopLeft; 859 Vector3 frontTopLeft;
754 Vector3 frontTopRight; 860 Vector3 frontTopRight;
@@ -760,6 +866,8 @@ namespace OpenSim.Region.Framework.Scenes
760 Vector3 backBottomLeft; 866 Vector3 backBottomLeft;
761 Vector3 backBottomRight; 867 Vector3 backBottomRight;
762 868
869 // Vector3[] corners = new Vector3[8];
870
763 Vector3 orig = Vector3.Zero; 871 Vector3 orig = Vector3.Zero;
764 872
765 frontTopLeft.X = orig.X - (part.Scale.X / 2); 873 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -794,6 +902,38 @@ namespace OpenSim.Region.Framework.Scenes
794 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 902 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
795 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 903 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
796 904
905
906
907 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
908 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
909 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
910 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
911 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
912 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
913 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
914 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
915
916 //for (int i = 0; i < 8; i++)
917 //{
918 // corners[i] = corners[i] * worldRot;
919 // corners[i] += offset;
920
921 // if (corners[i].X > maxX)
922 // maxX = corners[i].X;
923 // if (corners[i].X < minX)
924 // minX = corners[i].X;
925
926 // if (corners[i].Y > maxY)
927 // maxY = corners[i].Y;
928 // if (corners[i].Y < minY)
929 // minY = corners[i].Y;
930
931 // if (corners[i].Z > maxZ)
932 // maxZ = corners[i].Y;
933 // if (corners[i].Z < minZ)
934 // minZ = corners[i].Z;
935 //}
936
797 frontTopLeft = frontTopLeft * worldRot; 937 frontTopLeft = frontTopLeft * worldRot;
798 frontTopRight = frontTopRight * worldRot; 938 frontTopRight = frontTopRight * worldRot;
799 frontBottomLeft = frontBottomLeft * worldRot; 939 frontBottomLeft = frontBottomLeft * worldRot;
@@ -815,6 +955,15 @@ namespace OpenSim.Region.Framework.Scenes
815 backTopLeft += offset; 955 backTopLeft += offset;
816 backTopRight += offset; 956 backTopRight += offset;
817 957
958 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
959 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
960 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
961 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
962 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
963 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
964 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
965 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
966
818 if (frontTopRight.X > maxX) 967 if (frontTopRight.X > maxX)
819 maxX = frontTopRight.X; 968 maxX = frontTopRight.X;
820 if (frontTopLeft.X > maxX) 969 if (frontTopLeft.X > maxX)
@@ -960,15 +1109,20 @@ namespace OpenSim.Region.Framework.Scenes
960 1109
961 public void SaveScriptedState(XmlTextWriter writer) 1110 public void SaveScriptedState(XmlTextWriter writer)
962 { 1111 {
1112 SaveScriptedState(writer, false);
1113 }
1114
1115 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1116 {
963 XmlDocument doc = new XmlDocument(); 1117 XmlDocument doc = new XmlDocument();
964 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1118 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
965 1119
966 SceneObjectPart[] parts = m_parts.GetArray(); 1120 SceneObjectPart[] parts = m_parts.GetArray();
967 for (int i = 0; i < parts.Length; i++) 1121 for (int i = 0; i < parts.Length; i++)
968 { 1122 {
969 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1123 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
970 foreach (KeyValuePair<UUID, string> kvp in pstates) 1124 foreach (KeyValuePair<UUID, string> kvp in pstates)
971 states.Add(kvp.Key, kvp.Value); 1125 states[kvp.Key] = kvp.Value;
972 } 1126 }
973 1127
974 if (states.Count > 0) 1128 if (states.Count > 0)
@@ -988,6 +1142,168 @@ namespace OpenSim.Region.Framework.Scenes
988 } 1142 }
989 1143
990 /// <summary> 1144 /// <summary>
1145 /// Add the avatar to this linkset (avatar is sat).
1146 /// </summary>
1147 /// <param name="agentID"></param>
1148 public void AddAvatar(UUID agentID)
1149 {
1150 ScenePresence presence;
1151 if (m_scene.TryGetScenePresence(agentID, out presence))
1152 {
1153 if (!m_linkedAvatars.Contains(presence))
1154 {
1155 m_linkedAvatars.Add(presence);
1156 }
1157 }
1158 }
1159
1160 /// <summary>
1161 /// Delete the avatar from this linkset (avatar is unsat).
1162 /// </summary>
1163 /// <param name="agentID"></param>
1164 public void DeleteAvatar(UUID agentID)
1165 {
1166 ScenePresence presence;
1167 if (m_scene.TryGetScenePresence(agentID, out presence))
1168 {
1169 if (m_linkedAvatars.Contains(presence))
1170 {
1171 m_linkedAvatars.Remove(presence);
1172 }
1173 }
1174 }
1175
1176 /// <summary>
1177 /// Returns the list of linked presences (avatars sat on this group)
1178 /// </summary>
1179 /// <param name="agentID"></param>
1180 public List<ScenePresence> GetLinkedAvatars()
1181 {
1182 return m_linkedAvatars;
1183 }
1184
1185 /// <summary>
1186 /// Attach this scene object to the given avatar.
1187 /// </summary>
1188 /// <param name="agentID"></param>
1189 /// <param name="attachmentpoint"></param>
1190 /// <param name="AttachOffset"></param>
1191 private void AttachToAgent(
1192 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1193 {
1194 if (avatar != null)
1195 {
1196 // don't attach attachments to child agents
1197 if (avatar.IsChildAgent) return;
1198
1199 // Remove from database and parcel prim count
1200 m_scene.DeleteFromStorage(so.UUID);
1201 m_scene.EventManager.TriggerParcelPrimCountTainted();
1202
1203 so.AttachedAvatar = avatar.UUID;
1204
1205 if (so.RootPart.PhysActor != null)
1206 {
1207 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1208 so.RootPart.PhysActor = null;
1209 }
1210
1211 so.AbsolutePosition = attachOffset;
1212 so.RootPart.AttachedPos = attachOffset;
1213 so.IsAttachment = true;
1214 so.RootPart.SetParentLocalId(avatar.LocalId);
1215 so.AttachmentPoint = attachmentpoint;
1216
1217 avatar.AddAttachment(this);
1218
1219 if (!silent)
1220 {
1221 // Killing it here will cause the client to deselect it
1222 // It then reappears on the avatar, deselected
1223 // through the full update below
1224 //
1225 if (IsSelected)
1226 {
1227 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1228 }
1229
1230 IsSelected = false; // fudge....
1231 ScheduleGroupForFullUpdate();
1232 }
1233 }
1234 else
1235 {
1236 m_log.WarnFormat(
1237 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1238 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1239 }
1240 }
1241
1242 public byte GetAttachmentPoint()
1243 {
1244 return m_rootPart.Shape.State;
1245 }
1246
1247 public void DetachToGround()
1248 {
1249 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1250 if (avatar == null)
1251 return;
1252
1253 avatar.RemoveAttachment(this);
1254
1255 Vector3 detachedpos = new Vector3(127f,127f,127f);
1256 if (avatar == null)
1257 return;
1258
1259 detachedpos = avatar.AbsolutePosition;
1260 RootPart.FromItemID = UUID.Zero;
1261
1262 AbsolutePosition = detachedpos;
1263 AttachedAvatar = UUID.Zero;
1264
1265 //SceneObjectPart[] parts = m_parts.GetArray();
1266 //for (int i = 0; i < parts.Length; i++)
1267 // parts[i].AttachedAvatar = UUID.Zero;
1268
1269 m_rootPart.SetParentLocalId(0);
1270 AttachmentPoint = (byte)0;
1271 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1272 HasGroupChanged = true;
1273 RootPart.Rezzed = DateTime.Now;
1274 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1275 AttachToBackup();
1276 m_scene.EventManager.TriggerParcelPrimCountTainted();
1277 m_rootPart.ScheduleFullUpdate();
1278 m_rootPart.ClearUndoState();
1279 }
1280
1281 public void DetachToInventoryPrep()
1282 {
1283 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1284 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1285 if (avatar != null)
1286 {
1287 //detachedpos = avatar.AbsolutePosition;
1288 avatar.RemoveAttachment(this);
1289 }
1290
1291 AttachedAvatar = UUID.Zero;
1292
1293 /*SceneObjectPart[] parts = m_parts.GetArray();
1294 for (int i = 0; i < parts.Length; i++)
1295 parts[i].AttachedAvatar = UUID.Zero;*/
1296
1297 m_rootPart.SetParentLocalId(0);
1298 //m_rootPart.SetAttachmentPoint((byte)0);
1299 IsAttachment = false;
1300 AbsolutePosition = m_rootPart.AttachedPos;
1301 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1302 //AttachToBackup();
1303 //m_rootPart.ScheduleFullUpdate();
1304 }
1305
1306 /// <summary>
991 /// 1307 ///
992 /// </summary> 1308 /// </summary>
993 /// <param name="part"></param> 1309 /// <param name="part"></param>
@@ -1037,7 +1353,10 @@ namespace OpenSim.Region.Framework.Scenes
1037 public void AddPart(SceneObjectPart part) 1353 public void AddPart(SceneObjectPart part)
1038 { 1354 {
1039 part.SetParent(this); 1355 part.SetParent(this);
1040 part.LinkNum = m_parts.Add(part.UUID, part); 1356 m_parts.Add(part.UUID, part);
1357
1358 part.LinkNum = m_parts.Count;
1359
1041 if (part.LinkNum == 2) 1360 if (part.LinkNum == 2)
1042 RootPart.LinkNum = 1; 1361 RootPart.LinkNum = 1;
1043 } 1362 }
@@ -1145,6 +1464,11 @@ namespace OpenSim.Region.Framework.Scenes
1145 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1464 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1146 public void DeleteGroupFromScene(bool silent) 1465 public void DeleteGroupFromScene(bool silent)
1147 { 1466 {
1467 // We need to keep track of this state in case this group is still queued for backup.
1468 IsDeleted = true;
1469
1470 DetachFromBackup();
1471
1148 SceneObjectPart[] parts = m_parts.GetArray(); 1472 SceneObjectPart[] parts = m_parts.GetArray();
1149 for (int i = 0; i < parts.Length; i++) 1473 for (int i = 0; i < parts.Length; i++)
1150 { 1474 {
@@ -1167,6 +1491,8 @@ namespace OpenSim.Region.Framework.Scenes
1167 } 1491 }
1168 }); 1492 });
1169 } 1493 }
1494
1495
1170 } 1496 }
1171 1497
1172 public void AddScriptLPS(int count) 1498 public void AddScriptLPS(int count)
@@ -1262,7 +1588,12 @@ namespace OpenSim.Region.Framework.Scenes
1262 1588
1263 public void SetOwnerId(UUID userId) 1589 public void SetOwnerId(UUID userId)
1264 { 1590 {
1265 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1591 ForEachPart(delegate(SceneObjectPart part)
1592 {
1593
1594 part.OwnerID = userId;
1595
1596 });
1266 } 1597 }
1267 1598
1268 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1599 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1294,11 +1625,17 @@ namespace OpenSim.Region.Framework.Scenes
1294 return; 1625 return;
1295 } 1626 }
1296 1627
1628 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1629 return;
1630
1297 // 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
1298 // any exception propogate upwards. 1632 // any exception propogate upwards.
1299 try 1633 try
1300 { 1634 {
1301 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
1302 { 1639 {
1303 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1640 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1304 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1641 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1325,6 +1662,7 @@ namespace OpenSim.Region.Framework.Scenes
1325 } 1662 }
1326 } 1663 }
1327 } 1664 }
1665
1328 } 1666 }
1329 1667
1330 if (m_scene.UseBackup && HasGroupChanged) 1668 if (m_scene.UseBackup && HasGroupChanged)
@@ -1332,6 +1670,20 @@ namespace OpenSim.Region.Framework.Scenes
1332 // 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.
1333 if (isTimeToPersist() || forcedBackup) 1671 if (isTimeToPersist() || forcedBackup)
1334 { 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 }
1335// m_log.DebugFormat( 1687// m_log.DebugFormat(
1336// "[SCENE]: Storing {0}, {1} in {2}", 1688// "[SCENE]: Storing {0}, {1} in {2}",
1337// Name, UUID, m_scene.RegionInfo.RegionName); 1689// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1415,7 +1767,7 @@ namespace OpenSim.Region.Framework.Scenes
1415 // This is only necessary when userExposed is false! 1767 // This is only necessary when userExposed is false!
1416 1768
1417 bool previousAttachmentStatus = dupe.IsAttachment; 1769 bool previousAttachmentStatus = dupe.IsAttachment;
1418 1770
1419 if (!userExposed) 1771 if (!userExposed)
1420 dupe.IsAttachment = true; 1772 dupe.IsAttachment = true;
1421 1773
@@ -1433,11 +1785,11 @@ namespace OpenSim.Region.Framework.Scenes
1433 dupe.m_rootPart.TrimPermissions(); 1785 dupe.m_rootPart.TrimPermissions();
1434 1786
1435 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1787 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1436 1788
1437 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1789 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1438 { 1790 {
1439 return p1.LinkNum.CompareTo(p2.LinkNum); 1791 return p1.LinkNum.CompareTo(p2.LinkNum);
1440 } 1792 }
1441 ); 1793 );
1442 1794
1443 foreach (SceneObjectPart part in partList) 1795 foreach (SceneObjectPart part in partList)
@@ -1457,7 +1809,7 @@ namespace OpenSim.Region.Framework.Scenes
1457 if (part.PhysActor != null && userExposed) 1809 if (part.PhysActor != null && userExposed)
1458 { 1810 {
1459 PrimitiveBaseShape pbs = newPart.Shape; 1811 PrimitiveBaseShape pbs = newPart.Shape;
1460 1812
1461 newPart.PhysActor 1813 newPart.PhysActor
1462 = m_scene.PhysicsScene.AddPrimShape( 1814 = m_scene.PhysicsScene.AddPrimShape(
1463 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1815 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1467,11 +1819,11 @@ namespace OpenSim.Region.Framework.Scenes
1467 newPart.RotationOffset, 1819 newPart.RotationOffset,
1468 part.PhysActor.IsPhysical, 1820 part.PhysActor.IsPhysical,
1469 newPart.LocalId); 1821 newPart.LocalId);
1470 1822
1471 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1823 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1472 } 1824 }
1473 } 1825 }
1474 1826
1475 if (userExposed) 1827 if (userExposed)
1476 { 1828 {
1477 dupe.UpdateParentIDs(); 1829 dupe.UpdateParentIDs();
@@ -1586,6 +1938,7 @@ namespace OpenSim.Region.Framework.Scenes
1586 return Vector3.Zero; 1938 return Vector3.Zero;
1587 } 1939 }
1588 1940
1941 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1589 public void moveToTarget(Vector3 target, float tau) 1942 public void moveToTarget(Vector3 target, float tau)
1590 { 1943 {
1591 if (IsAttachment) 1944 if (IsAttachment)
@@ -1613,10 +1966,44 @@ namespace OpenSim.Region.Framework.Scenes
1613 RootPart.PhysActor.PIDActive = false; 1966 RootPart.PhysActor.PIDActive = false;
1614 } 1967 }
1615 1968
1969 public void rotLookAt(Quaternion target, float strength, float damping)
1970 {
1971 SceneObjectPart rootpart = m_rootPart;
1972 if (rootpart != null)
1973 {
1974 if (IsAttachment)
1975 {
1976 /*
1977 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1978 if (avatar != null)
1979 {
1980 Rotate the Av?
1981 } */
1982 }
1983 else
1984 {
1985 if (rootpart.PhysActor != null)
1986 { // APID must be implemented in your physics system for this to function.
1987 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1988 rootpart.PhysActor.APIDStrength = strength;
1989 rootpart.PhysActor.APIDDamping = damping;
1990 rootpart.PhysActor.APIDActive = true;
1991 }
1992 }
1993 }
1994 }
1995
1616 public void stopLookAt() 1996 public void stopLookAt()
1617 { 1997 {
1618 if (RootPart.PhysActor != null) 1998 SceneObjectPart rootpart = m_rootPart;
1619 RootPart.PhysActor.APIDActive = false; 1999 if (rootpart != null)
2000 {
2001 if (rootpart.PhysActor != null)
2002 { // APID must be implemented in your physics system for this to function.
2003 rootpart.PhysActor.APIDActive = false;
2004 }
2005 }
2006
1620 } 2007 }
1621 2008
1622 /// <summary> 2009 /// <summary>
@@ -1674,6 +2061,8 @@ namespace OpenSim.Region.Framework.Scenes
1674 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2061 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1675 { 2062 {
1676 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2063 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2064 newPart.SetParent(this);
2065
1677 AddPart(newPart); 2066 AddPart(newPart);
1678 2067
1679 SetPartAsNonRoot(newPart); 2068 SetPartAsNonRoot(newPart);
@@ -1802,11 +2191,11 @@ namespace OpenSim.Region.Framework.Scenes
1802 /// Immediately send a full update for this scene object. 2191 /// Immediately send a full update for this scene object.
1803 /// </summary> 2192 /// </summary>
1804 public void SendGroupFullUpdate() 2193 public void SendGroupFullUpdate()
1805 { 2194 {
1806 if (IsDeleted) 2195 if (IsDeleted)
1807 return; 2196 return;
1808 2197
1809// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2198// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1810 2199
1811 RootPart.SendFullUpdateToAllClients(); 2200 RootPart.SendFullUpdateToAllClients();
1812 2201
@@ -2007,7 +2396,7 @@ namespace OpenSim.Region.Framework.Scenes
2007 objectGroup.IsDeleted = true; 2396 objectGroup.IsDeleted = true;
2008 2397
2009 objectGroup.m_parts.Clear(); 2398 objectGroup.m_parts.Clear();
2010 2399
2011 // Can't do this yet since backup still makes use of the root part without any synchronization 2400 // Can't do this yet since backup still makes use of the root part without any synchronization
2012// objectGroup.m_rootPart = null; 2401// objectGroup.m_rootPart = null;
2013 2402
@@ -2141,6 +2530,7 @@ namespace OpenSim.Region.Framework.Scenes
2141 /// <param name="objectGroup"></param> 2530 /// <param name="objectGroup"></param>
2142 public virtual void DetachFromBackup() 2531 public virtual void DetachFromBackup()
2143 { 2532 {
2533 m_scene.SceneGraph.FireDetachFromBackup(this);
2144 if (m_isBackedUp && Scene != null) 2534 if (m_isBackedUp && Scene != null)
2145 m_scene.EventManager.OnBackup -= ProcessBackup; 2535 m_scene.EventManager.OnBackup -= ProcessBackup;
2146 2536
@@ -2159,7 +2549,8 @@ namespace OpenSim.Region.Framework.Scenes
2159 2549
2160 axPos *= parentRot; 2550 axPos *= parentRot;
2161 part.OffsetPosition = axPos; 2551 part.OffsetPosition = axPos;
2162 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2552 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2553 part.GroupPosition = newPos;
2163 part.OffsetPosition = Vector3.Zero; 2554 part.OffsetPosition = Vector3.Zero;
2164 part.RotationOffset = worldRot; 2555 part.RotationOffset = worldRot;
2165 2556
@@ -2170,7 +2561,7 @@ namespace OpenSim.Region.Framework.Scenes
2170 2561
2171 part.LinkNum = linkNum; 2562 part.LinkNum = linkNum;
2172 2563
2173 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2564 part.OffsetPosition = newPos - AbsolutePosition;
2174 2565
2175 Quaternion rootRotation = m_rootPart.RotationOffset; 2566 Quaternion rootRotation = m_rootPart.RotationOffset;
2176 2567
@@ -2180,7 +2571,7 @@ namespace OpenSim.Region.Framework.Scenes
2180 2571
2181 parentRot = m_rootPart.RotationOffset; 2572 parentRot = m_rootPart.RotationOffset;
2182 oldRot = part.RotationOffset; 2573 oldRot = part.RotationOffset;
2183 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2574 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2184 part.RotationOffset = newRot; 2575 part.RotationOffset = newRot;
2185 } 2576 }
2186 2577
@@ -2427,8 +2818,12 @@ namespace OpenSim.Region.Framework.Scenes
2427 } 2818 }
2428 } 2819 }
2429 2820
2821 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2430 for (int i = 0; i < parts.Length; i++) 2822 for (int i = 0; i < parts.Length; i++)
2431 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2823 {
2824 if (parts[i] != RootPart)
2825 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2826 }
2432 } 2827 }
2433 } 2828 }
2434 2829
@@ -2441,6 +2836,17 @@ namespace OpenSim.Region.Framework.Scenes
2441 } 2836 }
2442 } 2837 }
2443 2838
2839
2840
2841 /// <summary>
2842 /// Gets the number of parts
2843 /// </summary>
2844 /// <returns></returns>
2845 public int GetPartCount()
2846 {
2847 return Parts.Count();
2848 }
2849
2444 /// <summary> 2850 /// <summary>
2445 /// Update the texture entry for this part 2851 /// Update the texture entry for this part
2446 /// </summary> 2852 /// </summary>
@@ -2502,7 +2908,6 @@ namespace OpenSim.Region.Framework.Scenes
2502 { 2908 {
2503// m_log.DebugFormat( 2909// m_log.DebugFormat(
2504// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2910// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2505
2506 RootPart.StoreUndoState(true); 2911 RootPart.StoreUndoState(true);
2507 2912
2508 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2913 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2603,7 +3008,6 @@ namespace OpenSim.Region.Framework.Scenes
2603 prevScale.X *= x; 3008 prevScale.X *= x;
2604 prevScale.Y *= y; 3009 prevScale.Y *= y;
2605 prevScale.Z *= z; 3010 prevScale.Z *= z;
2606
2607// RootPart.IgnoreUndoUpdate = true; 3011// RootPart.IgnoreUndoUpdate = true;
2608 RootPart.Resize(prevScale); 3012 RootPart.Resize(prevScale);
2609// RootPart.IgnoreUndoUpdate = false; 3013// RootPart.IgnoreUndoUpdate = false;
@@ -2634,7 +3038,9 @@ namespace OpenSim.Region.Framework.Scenes
2634 } 3038 }
2635 3039
2636// obPart.IgnoreUndoUpdate = false; 3040// obPart.IgnoreUndoUpdate = false;
2637// obPart.StoreUndoState(); 3041 HasGroupChanged = true;
3042 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3043 ScheduleGroupForTerseUpdate();
2638 } 3044 }
2639 3045
2640// m_log.DebugFormat( 3046// m_log.DebugFormat(
@@ -2694,9 +3100,9 @@ namespace OpenSim.Region.Framework.Scenes
2694 { 3100 {
2695 SceneObjectPart part = GetChildPart(localID); 3101 SceneObjectPart part = GetChildPart(localID);
2696 3102
2697// SceneObjectPart[] parts = m_parts.GetArray(); 3103 SceneObjectPart[] parts = m_parts.GetArray();
2698// for (int i = 0; i < parts.Length; i++) 3104 for (int i = 0; i < parts.Length; i++)
2699// parts[i].StoreUndoState(); 3105 parts[i].StoreUndoState();
2700 3106
2701 if (part != null) 3107 if (part != null)
2702 { 3108 {
@@ -2752,10 +3158,27 @@ namespace OpenSim.Region.Framework.Scenes
2752 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3158 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2753 } 3159 }
2754 3160
2755 AbsolutePosition = newPos; 3161 //We have to set undoing here because otherwise an undo state will be saved
3162 if (!m_rootPart.Undoing)
3163 {
3164 m_rootPart.Undoing = true;
3165 AbsolutePosition = newPos;
3166 m_rootPart.Undoing = false;
3167 }
3168 else
3169 {
3170 AbsolutePosition = newPos;
3171 }
2756 3172
2757 HasGroupChanged = true; 3173 HasGroupChanged = true;
2758 ScheduleGroupForTerseUpdate(); 3174 if (m_rootPart.Undoing)
3175 {
3176 ScheduleGroupForFullUpdate();
3177 }
3178 else
3179 {
3180 ScheduleGroupForTerseUpdate();
3181 }
2759 } 3182 }
2760 3183
2761 #endregion 3184 #endregion
@@ -2832,10 +3255,7 @@ namespace OpenSim.Region.Framework.Scenes
2832 public void UpdateSingleRotation(Quaternion rot, uint localID) 3255 public void UpdateSingleRotation(Quaternion rot, uint localID)
2833 { 3256 {
2834 SceneObjectPart part = GetChildPart(localID); 3257 SceneObjectPart part = GetChildPart(localID);
2835
2836 SceneObjectPart[] parts = m_parts.GetArray(); 3258 SceneObjectPart[] parts = m_parts.GetArray();
2837 for (int i = 0; i < parts.Length; i++)
2838 parts[i].StoreUndoState();
2839 3259
2840 if (part != null) 3260 if (part != null)
2841 { 3261 {
@@ -2873,7 +3293,16 @@ namespace OpenSim.Region.Framework.Scenes
2873 if (part.UUID == m_rootPart.UUID) 3293 if (part.UUID == m_rootPart.UUID)
2874 { 3294 {
2875 UpdateRootRotation(rot); 3295 UpdateRootRotation(rot);
2876 AbsolutePosition = pos; 3296 if (!m_rootPart.Undoing)
3297 {
3298 m_rootPart.Undoing = true;
3299 AbsolutePosition = pos;
3300 m_rootPart.Undoing = false;
3301 }
3302 else
3303 {
3304 AbsolutePosition = pos;
3305 }
2877 } 3306 }
2878 else 3307 else
2879 { 3308 {
@@ -2897,9 +3326,10 @@ namespace OpenSim.Region.Framework.Scenes
2897 3326
2898 Quaternion axRot = rot; 3327 Quaternion axRot = rot;
2899 Quaternion oldParentRot = m_rootPart.RotationOffset; 3328 Quaternion oldParentRot = m_rootPart.RotationOffset;
2900
2901 m_rootPart.StoreUndoState(); 3329 m_rootPart.StoreUndoState();
2902 m_rootPart.UpdateRotation(rot); 3330
3331 //Don't use UpdateRotation because it schedules an update prematurely
3332 m_rootPart.RotationOffset = rot;
2903 if (m_rootPart.PhysActor != null) 3333 if (m_rootPart.PhysActor != null)
2904 { 3334 {
2905 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3335 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2913,15 +3343,17 @@ namespace OpenSim.Region.Framework.Scenes
2913 if (prim.UUID != m_rootPart.UUID) 3343 if (prim.UUID != m_rootPart.UUID)
2914 { 3344 {
2915 prim.IgnoreUndoUpdate = true; 3345 prim.IgnoreUndoUpdate = true;
3346
3347 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3348 NewRot = Quaternion.Inverse(axRot) * NewRot;
3349 prim.RotationOffset = NewRot;
3350
2916 Vector3 axPos = prim.OffsetPosition; 3351 Vector3 axPos = prim.OffsetPosition;
3352
2917 axPos *= oldParentRot; 3353 axPos *= oldParentRot;
2918 axPos *= Quaternion.Inverse(axRot); 3354 axPos *= Quaternion.Inverse(axRot);
2919 prim.OffsetPosition = axPos; 3355 prim.OffsetPosition = axPos;
2920 Quaternion primsRot = prim.RotationOffset; 3356
2921 Quaternion newRot = oldParentRot * primsRot;
2922 newRot = Quaternion.Inverse(axRot) * newRot;
2923 prim.RotationOffset = newRot;
2924 prim.ScheduleTerseUpdate();
2925 prim.IgnoreUndoUpdate = false; 3357 prim.IgnoreUndoUpdate = false;
2926 } 3358 }
2927 } 3359 }
@@ -2935,8 +3367,8 @@ namespace OpenSim.Region.Framework.Scenes
2935//// childpart.StoreUndoState(); 3367//// childpart.StoreUndoState();
2936// } 3368// }
2937// } 3369// }
2938 3370 HasGroupChanged = true;
2939 m_rootPart.ScheduleTerseUpdate(); 3371 ScheduleGroupForFullUpdate();
2940 3372
2941// m_log.DebugFormat( 3373// m_log.DebugFormat(
2942// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3374// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3164,7 +3596,6 @@ namespace OpenSim.Region.Framework.Scenes
3164 public float GetMass() 3596 public float GetMass()
3165 { 3597 {
3166 float retmass = 0f; 3598 float retmass = 0f;
3167
3168 SceneObjectPart[] parts = m_parts.GetArray(); 3599 SceneObjectPart[] parts = m_parts.GetArray();
3169 for (int i = 0; i < parts.Length; i++) 3600 for (int i = 0; i < parts.Length; i++)
3170 retmass += parts[i].GetMass(); 3601 retmass += parts[i].GetMass();
@@ -3260,6 +3691,14 @@ namespace OpenSim.Region.Framework.Scenes
3260 SetFromItemID(uuid); 3691 SetFromItemID(uuid);
3261 } 3692 }
3262 3693
3694 public void ResetOwnerChangeFlag()
3695 {
3696 ForEachPart(delegate(SceneObjectPart part)
3697 {
3698 part.ResetOwnerChangeFlag();
3699 });
3700 }
3701
3263 #endregion 3702 #endregion
3264 } 3703 }
3265} 3704}