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.cs589
1 files changed, 526 insertions, 63 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 5b838f8..683aafc 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 //{
@@ -578,6 +675,7 @@ namespace OpenSim.Region.Framework.Scenes
578 /// </summary> 675 /// </summary>
579 public SceneObjectGroup() 676 public SceneObjectGroup()
580 { 677 {
678
581 } 679 }
582 680
583 /// <summary> 681 /// <summary>
@@ -594,7 +692,7 @@ namespace OpenSim.Region.Framework.Scenes
594 /// Constructor. This object is added to the scene later via AttachToScene() 692 /// Constructor. This object is added to the scene later via AttachToScene()
595 /// </summary> 693 /// </summary>
596 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 694 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
597 { 695 {
598 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 696 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
599 } 697 }
600 698
@@ -642,6 +740,9 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 740 /// </summary>
643 public virtual void AttachToBackup() 741 public virtual void AttachToBackup()
644 { 742 {
743 if (IsAttachment) return;
744 m_scene.SceneGraph.FireAttachToBackup(this);
745
645 if (InSceneBackup) 746 if (InSceneBackup)
646 { 747 {
647 //m_log.DebugFormat( 748 //m_log.DebugFormat(
@@ -684,6 +785,9 @@ namespace OpenSim.Region.Framework.Scenes
684 785
685 ApplyPhysics(); 786 ApplyPhysics();
686 787
788 if (RootPart.PhysActor != null)
789 RootPart.Buoyancy = RootPart.Buoyancy;
790
687 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 791 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
688 // for the same object with very different properties. The caller must schedule the update. 792 // for the same object with very different properties. The caller must schedule the update.
689 //ScheduleGroupForFullUpdate(); 793 //ScheduleGroupForFullUpdate();
@@ -699,6 +803,10 @@ namespace OpenSim.Region.Framework.Scenes
699 EntityIntersection result = new EntityIntersection(); 803 EntityIntersection result = new EntityIntersection();
700 804
701 SceneObjectPart[] parts = m_parts.GetArray(); 805 SceneObjectPart[] parts = m_parts.GetArray();
806
807 // Find closest hit here
808 float idist = float.MaxValue;
809
702 for (int i = 0; i < parts.Length; i++) 810 for (int i = 0; i < parts.Length; i++)
703 { 811 {
704 SceneObjectPart part = parts[i]; 812 SceneObjectPart part = parts[i];
@@ -713,11 +821,6 @@ namespace OpenSim.Region.Framework.Scenes
713 821
714 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 822 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
715 823
716 // This may need to be updated to the maximum draw distance possible..
717 // We might (and probably will) be checking for prim creation from other sims
718 // when the camera crosses the border.
719 float idist = Constants.RegionSize;
720
721 if (inter.HitTF) 824 if (inter.HitTF)
722 { 825 {
723 // We need to find the closest prim to return to the testcaller along the ray 826 // We need to find the closest prim to return to the testcaller along the ray
@@ -728,10 +831,11 @@ namespace OpenSim.Region.Framework.Scenes
728 result.obj = part; 831 result.obj = part;
729 result.normal = inter.normal; 832 result.normal = inter.normal;
730 result.distance = inter.distance; 833 result.distance = inter.distance;
834
835 idist = inter.distance;
731 } 836 }
732 } 837 }
733 } 838 }
734
735 return result; 839 return result;
736 } 840 }
737 841
@@ -751,17 +855,19 @@ namespace OpenSim.Region.Framework.Scenes
751 minZ = 8192f; 855 minZ = 8192f;
752 856
753 SceneObjectPart[] parts = m_parts.GetArray(); 857 SceneObjectPart[] parts = m_parts.GetArray();
754 for (int i = 0; i < parts.Length; i++) 858 foreach (SceneObjectPart part in parts)
755 { 859 {
756 SceneObjectPart part = parts[i];
757
758 Vector3 worldPos = part.GetWorldPosition(); 860 Vector3 worldPos = part.GetWorldPosition();
759 Vector3 offset = worldPos - AbsolutePosition; 861 Vector3 offset = worldPos - AbsolutePosition;
760 Quaternion worldRot; 862 Quaternion worldRot;
761 if (part.ParentID == 0) 863 if (part.ParentID == 0)
864 {
762 worldRot = part.RotationOffset; 865 worldRot = part.RotationOffset;
866 }
763 else 867 else
868 {
764 worldRot = part.GetWorldRotation(); 869 worldRot = part.GetWorldRotation();
870 }
765 871
766 Vector3 frontTopLeft; 872 Vector3 frontTopLeft;
767 Vector3 frontTopRight; 873 Vector3 frontTopRight;
@@ -773,6 +879,8 @@ namespace OpenSim.Region.Framework.Scenes
773 Vector3 backBottomLeft; 879 Vector3 backBottomLeft;
774 Vector3 backBottomRight; 880 Vector3 backBottomRight;
775 881
882 // Vector3[] corners = new Vector3[8];
883
776 Vector3 orig = Vector3.Zero; 884 Vector3 orig = Vector3.Zero;
777 885
778 frontTopLeft.X = orig.X - (part.Scale.X / 2); 886 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -807,6 +915,38 @@ namespace OpenSim.Region.Framework.Scenes
807 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 915 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
808 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 916 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
809 917
918
919
920 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
921 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
922 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
923 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
924 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
925 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
926 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
927 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
928
929 //for (int i = 0; i < 8; i++)
930 //{
931 // corners[i] = corners[i] * worldRot;
932 // corners[i] += offset;
933
934 // if (corners[i].X > maxX)
935 // maxX = corners[i].X;
936 // if (corners[i].X < minX)
937 // minX = corners[i].X;
938
939 // if (corners[i].Y > maxY)
940 // maxY = corners[i].Y;
941 // if (corners[i].Y < minY)
942 // minY = corners[i].Y;
943
944 // if (corners[i].Z > maxZ)
945 // maxZ = corners[i].Y;
946 // if (corners[i].Z < minZ)
947 // minZ = corners[i].Z;
948 //}
949
810 frontTopLeft = frontTopLeft * worldRot; 950 frontTopLeft = frontTopLeft * worldRot;
811 frontTopRight = frontTopRight * worldRot; 951 frontTopRight = frontTopRight * worldRot;
812 frontBottomLeft = frontBottomLeft * worldRot; 952 frontBottomLeft = frontBottomLeft * worldRot;
@@ -828,6 +968,15 @@ namespace OpenSim.Region.Framework.Scenes
828 backTopLeft += offset; 968 backTopLeft += offset;
829 backTopRight += offset; 969 backTopRight += offset;
830 970
971 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
972 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
973 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
974 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
975 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
976 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
977 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
978 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
979
831 if (frontTopRight.X > maxX) 980 if (frontTopRight.X > maxX)
832 maxX = frontTopRight.X; 981 maxX = frontTopRight.X;
833 if (frontTopLeft.X > maxX) 982 if (frontTopLeft.X > maxX)
@@ -973,15 +1122,20 @@ namespace OpenSim.Region.Framework.Scenes
973 1122
974 public void SaveScriptedState(XmlTextWriter writer) 1123 public void SaveScriptedState(XmlTextWriter writer)
975 { 1124 {
1125 SaveScriptedState(writer, false);
1126 }
1127
1128 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1129 {
976 XmlDocument doc = new XmlDocument(); 1130 XmlDocument doc = new XmlDocument();
977 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1131 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
978 1132
979 SceneObjectPart[] parts = m_parts.GetArray(); 1133 SceneObjectPart[] parts = m_parts.GetArray();
980 for (int i = 0; i < parts.Length; i++) 1134 for (int i = 0; i < parts.Length; i++)
981 { 1135 {
982 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1136 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
983 foreach (KeyValuePair<UUID, string> kvp in pstates) 1137 foreach (KeyValuePair<UUID, string> kvp in pstates)
984 states.Add(kvp.Key, kvp.Value); 1138 states[kvp.Key] = kvp.Value;
985 } 1139 }
986 1140
987 if (states.Count > 0) 1141 if (states.Count > 0)
@@ -1001,6 +1155,168 @@ namespace OpenSim.Region.Framework.Scenes
1001 } 1155 }
1002 1156
1003 /// <summary> 1157 /// <summary>
1158 /// Add the avatar to this linkset (avatar is sat).
1159 /// </summary>
1160 /// <param name="agentID"></param>
1161 public void AddAvatar(UUID agentID)
1162 {
1163 ScenePresence presence;
1164 if (m_scene.TryGetScenePresence(agentID, out presence))
1165 {
1166 if (!m_linkedAvatars.Contains(presence))
1167 {
1168 m_linkedAvatars.Add(presence);
1169 }
1170 }
1171 }
1172
1173 /// <summary>
1174 /// Delete the avatar from this linkset (avatar is unsat).
1175 /// </summary>
1176 /// <param name="agentID"></param>
1177 public void DeleteAvatar(UUID agentID)
1178 {
1179 ScenePresence presence;
1180 if (m_scene.TryGetScenePresence(agentID, out presence))
1181 {
1182 if (m_linkedAvatars.Contains(presence))
1183 {
1184 m_linkedAvatars.Remove(presence);
1185 }
1186 }
1187 }
1188
1189 /// <summary>
1190 /// Returns the list of linked presences (avatars sat on this group)
1191 /// </summary>
1192 /// <param name="agentID"></param>
1193 public List<ScenePresence> GetLinkedAvatars()
1194 {
1195 return m_linkedAvatars;
1196 }
1197
1198 /// <summary>
1199 /// Attach this scene object to the given avatar.
1200 /// </summary>
1201 /// <param name="agentID"></param>
1202 /// <param name="attachmentpoint"></param>
1203 /// <param name="AttachOffset"></param>
1204 private void AttachToAgent(
1205 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1206 {
1207 if (avatar != null)
1208 {
1209 // don't attach attachments to child agents
1210 if (avatar.IsChildAgent) return;
1211
1212 // Remove from database and parcel prim count
1213 m_scene.DeleteFromStorage(so.UUID);
1214 m_scene.EventManager.TriggerParcelPrimCountTainted();
1215
1216 so.AttachedAvatar = avatar.UUID;
1217
1218 if (so.RootPart.PhysActor != null)
1219 {
1220 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1221 so.RootPart.PhysActor = null;
1222 }
1223
1224 so.AbsolutePosition = attachOffset;
1225 so.RootPart.AttachedPos = attachOffset;
1226 so.IsAttachment = true;
1227 so.RootPart.SetParentLocalId(avatar.LocalId);
1228 so.AttachmentPoint = attachmentpoint;
1229
1230 avatar.AddAttachment(this);
1231
1232 if (!silent)
1233 {
1234 // Killing it here will cause the client to deselect it
1235 // It then reappears on the avatar, deselected
1236 // through the full update below
1237 //
1238 if (IsSelected)
1239 {
1240 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1241 }
1242
1243 IsSelected = false; // fudge....
1244 ScheduleGroupForFullUpdate();
1245 }
1246 }
1247 else
1248 {
1249 m_log.WarnFormat(
1250 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1251 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1252 }
1253 }
1254
1255 public byte GetAttachmentPoint()
1256 {
1257 return m_rootPart.Shape.State;
1258 }
1259
1260 public void DetachToGround()
1261 {
1262 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1263 if (avatar == null)
1264 return;
1265
1266 avatar.RemoveAttachment(this);
1267
1268 Vector3 detachedpos = new Vector3(127f,127f,127f);
1269 if (avatar == null)
1270 return;
1271
1272 detachedpos = avatar.AbsolutePosition;
1273 RootPart.FromItemID = UUID.Zero;
1274
1275 AbsolutePosition = detachedpos;
1276 AttachedAvatar = UUID.Zero;
1277
1278 //SceneObjectPart[] parts = m_parts.GetArray();
1279 //for (int i = 0; i < parts.Length; i++)
1280 // parts[i].AttachedAvatar = UUID.Zero;
1281
1282 m_rootPart.SetParentLocalId(0);
1283 AttachmentPoint = (byte)0;
1284 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1285 HasGroupChanged = true;
1286 RootPart.Rezzed = DateTime.Now;
1287 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1288 AttachToBackup();
1289 m_scene.EventManager.TriggerParcelPrimCountTainted();
1290 m_rootPart.ScheduleFullUpdate();
1291 m_rootPart.ClearUndoState();
1292 }
1293
1294 public void DetachToInventoryPrep()
1295 {
1296 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1297 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1298 if (avatar != null)
1299 {
1300 //detachedpos = avatar.AbsolutePosition;
1301 avatar.RemoveAttachment(this);
1302 }
1303
1304 AttachedAvatar = UUID.Zero;
1305
1306 /*SceneObjectPart[] parts = m_parts.GetArray();
1307 for (int i = 0; i < parts.Length; i++)
1308 parts[i].AttachedAvatar = UUID.Zero;*/
1309
1310 m_rootPart.SetParentLocalId(0);
1311 //m_rootPart.SetAttachmentPoint((byte)0);
1312 IsAttachment = false;
1313 AbsolutePosition = m_rootPart.AttachedPos;
1314 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1315 //AttachToBackup();
1316 //m_rootPart.ScheduleFullUpdate();
1317 }
1318
1319 /// <summary>
1004 /// 1320 ///
1005 /// </summary> 1321 /// </summary>
1006 /// <param name="part"></param> 1322 /// <param name="part"></param>
@@ -1050,7 +1366,10 @@ namespace OpenSim.Region.Framework.Scenes
1050 public void AddPart(SceneObjectPart part) 1366 public void AddPart(SceneObjectPart part)
1051 { 1367 {
1052 part.SetParent(this); 1368 part.SetParent(this);
1053 part.LinkNum = m_parts.Add(part.UUID, part); 1369 m_parts.Add(part.UUID, part);
1370
1371 part.LinkNum = m_parts.Count;
1372
1054 if (part.LinkNum == 2) 1373 if (part.LinkNum == 2)
1055 RootPart.LinkNum = 1; 1374 RootPart.LinkNum = 1;
1056 } 1375 }
@@ -1158,6 +1477,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1477 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1159 public void DeleteGroupFromScene(bool silent) 1478 public void DeleteGroupFromScene(bool silent)
1160 { 1479 {
1480 // We need to keep track of this state in case this group is still queued for backup.
1481 IsDeleted = true;
1482
1483 DetachFromBackup();
1484
1161 SceneObjectPart[] parts = m_parts.GetArray(); 1485 SceneObjectPart[] parts = m_parts.GetArray();
1162 for (int i = 0; i < parts.Length; i++) 1486 for (int i = 0; i < parts.Length; i++)
1163 { 1487 {
@@ -1180,6 +1504,8 @@ namespace OpenSim.Region.Framework.Scenes
1180 } 1504 }
1181 }); 1505 });
1182 } 1506 }
1507
1508
1183 } 1509 }
1184 1510
1185 public void AddScriptLPS(int count) 1511 public void AddScriptLPS(int count)
@@ -1275,7 +1601,12 @@ namespace OpenSim.Region.Framework.Scenes
1275 1601
1276 public void SetOwnerId(UUID userId) 1602 public void SetOwnerId(UUID userId)
1277 { 1603 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1604 ForEachPart(delegate(SceneObjectPart part)
1605 {
1606
1607 part.OwnerID = userId;
1608
1609 });
1279 } 1610 }
1280 1611
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1612 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1307,11 +1638,17 @@ namespace OpenSim.Region.Framework.Scenes
1307 return; 1638 return;
1308 } 1639 }
1309 1640
1641 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1642 return;
1643
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1644 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1311 // any exception propogate upwards. 1645 // any exception propogate upwards.
1312 try 1646 try
1313 { 1647 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1648 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1649 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1650 m_scene.LoadingPrims) // Land may not be valid yet
1651
1315 { 1652 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1653 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1654 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1338,6 +1675,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1675 }
1339 } 1676 }
1340 } 1677 }
1678
1341 } 1679 }
1342 1680
1343 if (m_scene.UseBackup && HasGroupChanged) 1681 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,6 +1683,20 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1683 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1684 if (isTimeToPersist() || forcedBackup)
1347 { 1685 {
1686 if (m_rootPart.PhysActor != null &&
1687 (!m_rootPart.PhysActor.IsPhysical))
1688 {
1689 // Possible ghost prim
1690 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1691 {
1692 foreach (SceneObjectPart part in m_parts.GetArray())
1693 {
1694 // Re-set physics actor positions and
1695 // orientations
1696 part.GroupPosition = m_rootPart.GroupPosition;
1697 }
1698 }
1699 }
1348// m_log.DebugFormat( 1700// m_log.DebugFormat(
1349// "[SCENE]: Storing {0}, {1} in {2}", 1701// "[SCENE]: Storing {0}, {1} in {2}",
1350// Name, UUID, m_scene.RegionInfo.RegionName); 1702// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1428,7 +1780,7 @@ namespace OpenSim.Region.Framework.Scenes
1428 // This is only necessary when userExposed is false! 1780 // This is only necessary when userExposed is false!
1429 1781
1430 bool previousAttachmentStatus = dupe.IsAttachment; 1782 bool previousAttachmentStatus = dupe.IsAttachment;
1431 1783
1432 if (!userExposed) 1784 if (!userExposed)
1433 dupe.IsAttachment = true; 1785 dupe.IsAttachment = true;
1434 1786
@@ -1446,11 +1798,11 @@ namespace OpenSim.Region.Framework.Scenes
1446 dupe.m_rootPart.TrimPermissions(); 1798 dupe.m_rootPart.TrimPermissions();
1447 1799
1448 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1800 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1449 1801
1450 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1802 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1451 { 1803 {
1452 return p1.LinkNum.CompareTo(p2.LinkNum); 1804 return p1.LinkNum.CompareTo(p2.LinkNum);
1453 } 1805 }
1454 ); 1806 );
1455 1807
1456 foreach (SceneObjectPart part in partList) 1808 foreach (SceneObjectPart part in partList)
@@ -1470,7 +1822,7 @@ namespace OpenSim.Region.Framework.Scenes
1470 if (part.PhysActor != null && userExposed) 1822 if (part.PhysActor != null && userExposed)
1471 { 1823 {
1472 PrimitiveBaseShape pbs = newPart.Shape; 1824 PrimitiveBaseShape pbs = newPart.Shape;
1473 1825
1474 newPart.PhysActor 1826 newPart.PhysActor
1475 = m_scene.PhysicsScene.AddPrimShape( 1827 = m_scene.PhysicsScene.AddPrimShape(
1476 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1828 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1480,11 +1832,11 @@ namespace OpenSim.Region.Framework.Scenes
1480 newPart.RotationOffset, 1832 newPart.RotationOffset,
1481 part.PhysActor.IsPhysical, 1833 part.PhysActor.IsPhysical,
1482 newPart.LocalId); 1834 newPart.LocalId);
1483 1835
1484 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1836 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1485 } 1837 }
1486 } 1838 }
1487 1839
1488 if (userExposed) 1840 if (userExposed)
1489 { 1841 {
1490 dupe.UpdateParentIDs(); 1842 dupe.UpdateParentIDs();
@@ -1599,6 +1951,7 @@ namespace OpenSim.Region.Framework.Scenes
1599 return Vector3.Zero; 1951 return Vector3.Zero;
1600 } 1952 }
1601 1953
1954 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1602 public void moveToTarget(Vector3 target, float tau) 1955 public void moveToTarget(Vector3 target, float tau)
1603 { 1956 {
1604 if (IsAttachment) 1957 if (IsAttachment)
@@ -1626,6 +1979,46 @@ namespace OpenSim.Region.Framework.Scenes
1626 RootPart.PhysActor.PIDActive = false; 1979 RootPart.PhysActor.PIDActive = false;
1627 } 1980 }
1628 1981
1982 public void rotLookAt(Quaternion target, float strength, float damping)
1983 {
1984 SceneObjectPart rootpart = m_rootPart;
1985 if (rootpart != null)
1986 {
1987 if (IsAttachment)
1988 {
1989 /*
1990 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1991 if (avatar != null)
1992 {
1993 Rotate the Av?
1994 } */
1995 }
1996 else
1997 {
1998 if (rootpart.PhysActor != null)
1999 { // APID must be implemented in your physics system for this to function.
2000 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2001 rootpart.PhysActor.APIDStrength = strength;
2002 rootpart.PhysActor.APIDDamping = damping;
2003 rootpart.PhysActor.APIDActive = true;
2004 }
2005 }
2006 }
2007 }
2008
2009 public void stopLookAt()
2010 {
2011 SceneObjectPart rootpart = m_rootPart;
2012 if (rootpart != null)
2013 {
2014 if (rootpart.PhysActor != null)
2015 { // APID must be implemented in your physics system for this to function.
2016 rootpart.PhysActor.APIDActive = false;
2017 }
2018 }
2019
2020 }
2021
1629 /// <summary> 2022 /// <summary>
1630 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2023 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1631 /// </summary> 2024 /// </summary>
@@ -1681,6 +2074,8 @@ namespace OpenSim.Region.Framework.Scenes
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2074 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2075 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2076 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2077 newPart.SetParent(this);
2078
1684 AddPart(newPart); 2079 AddPart(newPart);
1685 2080
1686 SetPartAsNonRoot(newPart); 2081 SetPartAsNonRoot(newPart);
@@ -1809,11 +2204,11 @@ namespace OpenSim.Region.Framework.Scenes
1809 /// Immediately send a full update for this scene object. 2204 /// Immediately send a full update for this scene object.
1810 /// </summary> 2205 /// </summary>
1811 public void SendGroupFullUpdate() 2206 public void SendGroupFullUpdate()
1812 { 2207 {
1813 if (IsDeleted) 2208 if (IsDeleted)
1814 return; 2209 return;
1815 2210
1816// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2211// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1817 2212
1818 RootPart.SendFullUpdateToAllClients(); 2213 RootPart.SendFullUpdateToAllClients();
1819 2214
@@ -1957,6 +2352,11 @@ namespace OpenSim.Region.Framework.Scenes
1957 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2352 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1958 public void LinkToGroup(SceneObjectGroup objectGroup) 2353 public void LinkToGroup(SceneObjectGroup objectGroup)
1959 { 2354 {
2355 LinkToGroup(objectGroup, false);
2356 }
2357
2358 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2359 {
1960// m_log.DebugFormat( 2360// m_log.DebugFormat(
1961// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2361// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1962// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); 2362// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1990,7 +2390,20 @@ namespace OpenSim.Region.Framework.Scenes
1990 2390
1991 lock (m_parts.SyncRoot) 2391 lock (m_parts.SyncRoot)
1992 { 2392 {
1993 int linkNum = PrimCount + 1; 2393 int linkNum;
2394 if (insert)
2395 {
2396 linkNum = 2;
2397 foreach (SceneObjectPart part in Parts)
2398 {
2399 if (part.LinkNum > 1)
2400 part.LinkNum++;
2401 }
2402 }
2403 else
2404 {
2405 linkNum = PrimCount + 1;
2406 }
1994 2407
1995 m_parts.Add(linkPart.UUID, linkPart); 2408 m_parts.Add(linkPart.UUID, linkPart);
1996 2409
@@ -2018,7 +2431,7 @@ namespace OpenSim.Region.Framework.Scenes
2018 objectGroup.IsDeleted = true; 2431 objectGroup.IsDeleted = true;
2019 2432
2020 objectGroup.m_parts.Clear(); 2433 objectGroup.m_parts.Clear();
2021 2434
2022 // Can't do this yet since backup still makes use of the root part without any synchronization 2435 // Can't do this yet since backup still makes use of the root part without any synchronization
2023// objectGroup.m_rootPart = null; 2436// objectGroup.m_rootPart = null;
2024 2437
@@ -2152,6 +2565,7 @@ namespace OpenSim.Region.Framework.Scenes
2152 /// <param name="objectGroup"></param> 2565 /// <param name="objectGroup"></param>
2153 public virtual void DetachFromBackup() 2566 public virtual void DetachFromBackup()
2154 { 2567 {
2568 m_scene.SceneGraph.FireDetachFromBackup(this);
2155 if (m_isBackedUp && Scene != null) 2569 if (m_isBackedUp && Scene != null)
2156 m_scene.EventManager.OnBackup -= ProcessBackup; 2570 m_scene.EventManager.OnBackup -= ProcessBackup;
2157 2571
@@ -2170,7 +2584,8 @@ namespace OpenSim.Region.Framework.Scenes
2170 2584
2171 axPos *= parentRot; 2585 axPos *= parentRot;
2172 part.OffsetPosition = axPos; 2586 part.OffsetPosition = axPos;
2173 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2587 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2588 part.GroupPosition = newPos;
2174 part.OffsetPosition = Vector3.Zero; 2589 part.OffsetPosition = Vector3.Zero;
2175 part.RotationOffset = worldRot; 2590 part.RotationOffset = worldRot;
2176 2591
@@ -2181,7 +2596,7 @@ namespace OpenSim.Region.Framework.Scenes
2181 2596
2182 part.LinkNum = linkNum; 2597 part.LinkNum = linkNum;
2183 2598
2184 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2599 part.OffsetPosition = newPos - AbsolutePosition;
2185 2600
2186 Quaternion rootRotation = m_rootPart.RotationOffset; 2601 Quaternion rootRotation = m_rootPart.RotationOffset;
2187 2602
@@ -2191,7 +2606,7 @@ namespace OpenSim.Region.Framework.Scenes
2191 2606
2192 parentRot = m_rootPart.RotationOffset; 2607 parentRot = m_rootPart.RotationOffset;
2193 oldRot = part.RotationOffset; 2608 oldRot = part.RotationOffset;
2194 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2609 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2195 part.RotationOffset = newRot; 2610 part.RotationOffset = newRot;
2196 } 2611 }
2197 2612
@@ -2438,8 +2853,12 @@ namespace OpenSim.Region.Framework.Scenes
2438 } 2853 }
2439 } 2854 }
2440 2855
2856 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2441 for (int i = 0; i < parts.Length; i++) 2857 for (int i = 0; i < parts.Length; i++)
2442 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2858 {
2859 if (parts[i] != RootPart)
2860 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2861 }
2443 } 2862 }
2444 } 2863 }
2445 2864
@@ -2452,6 +2871,17 @@ namespace OpenSim.Region.Framework.Scenes
2452 } 2871 }
2453 } 2872 }
2454 2873
2874
2875
2876 /// <summary>
2877 /// Gets the number of parts
2878 /// </summary>
2879 /// <returns></returns>
2880 public int GetPartCount()
2881 {
2882 return Parts.Count();
2883 }
2884
2455 /// <summary> 2885 /// <summary>
2456 /// Update the texture entry for this part 2886 /// Update the texture entry for this part
2457 /// </summary> 2887 /// </summary>
@@ -2513,7 +2943,6 @@ namespace OpenSim.Region.Framework.Scenes
2513 { 2943 {
2514// m_log.DebugFormat( 2944// m_log.DebugFormat(
2515// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2945// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2516
2517 RootPart.StoreUndoState(true); 2946 RootPart.StoreUndoState(true);
2518 2947
2519 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2948 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2614,7 +3043,6 @@ namespace OpenSim.Region.Framework.Scenes
2614 prevScale.X *= x; 3043 prevScale.X *= x;
2615 prevScale.Y *= y; 3044 prevScale.Y *= y;
2616 prevScale.Z *= z; 3045 prevScale.Z *= z;
2617
2618// RootPart.IgnoreUndoUpdate = true; 3046// RootPart.IgnoreUndoUpdate = true;
2619 RootPart.Resize(prevScale); 3047 RootPart.Resize(prevScale);
2620// RootPart.IgnoreUndoUpdate = false; 3048// RootPart.IgnoreUndoUpdate = false;
@@ -2645,7 +3073,9 @@ namespace OpenSim.Region.Framework.Scenes
2645 } 3073 }
2646 3074
2647// obPart.IgnoreUndoUpdate = false; 3075// obPart.IgnoreUndoUpdate = false;
2648// obPart.StoreUndoState(); 3076 HasGroupChanged = true;
3077 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3078 ScheduleGroupForTerseUpdate();
2649 } 3079 }
2650 3080
2651// m_log.DebugFormat( 3081// m_log.DebugFormat(
@@ -2705,9 +3135,9 @@ namespace OpenSim.Region.Framework.Scenes
2705 { 3135 {
2706 SceneObjectPart part = GetChildPart(localID); 3136 SceneObjectPart part = GetChildPart(localID);
2707 3137
2708// SceneObjectPart[] parts = m_parts.GetArray(); 3138 SceneObjectPart[] parts = m_parts.GetArray();
2709// for (int i = 0; i < parts.Length; i++) 3139 for (int i = 0; i < parts.Length; i++)
2710// parts[i].StoreUndoState(); 3140 parts[i].StoreUndoState();
2711 3141
2712 if (part != null) 3142 if (part != null)
2713 { 3143 {
@@ -2763,10 +3193,27 @@ namespace OpenSim.Region.Framework.Scenes
2763 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3193 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2764 } 3194 }
2765 3195
2766 AbsolutePosition = newPos; 3196 //We have to set undoing here because otherwise an undo state will be saved
3197 if (!m_rootPart.Undoing)
3198 {
3199 m_rootPart.Undoing = true;
3200 AbsolutePosition = newPos;
3201 m_rootPart.Undoing = false;
3202 }
3203 else
3204 {
3205 AbsolutePosition = newPos;
3206 }
2767 3207
2768 HasGroupChanged = true; 3208 HasGroupChanged = true;
2769 ScheduleGroupForTerseUpdate(); 3209 if (m_rootPart.Undoing)
3210 {
3211 ScheduleGroupForFullUpdate();
3212 }
3213 else
3214 {
3215 ScheduleGroupForTerseUpdate();
3216 }
2770 } 3217 }
2771 3218
2772 #endregion 3219 #endregion
@@ -2843,10 +3290,7 @@ namespace OpenSim.Region.Framework.Scenes
2843 public void UpdateSingleRotation(Quaternion rot, uint localID) 3290 public void UpdateSingleRotation(Quaternion rot, uint localID)
2844 { 3291 {
2845 SceneObjectPart part = GetChildPart(localID); 3292 SceneObjectPart part = GetChildPart(localID);
2846
2847 SceneObjectPart[] parts = m_parts.GetArray(); 3293 SceneObjectPart[] parts = m_parts.GetArray();
2848 for (int i = 0; i < parts.Length; i++)
2849 parts[i].StoreUndoState();
2850 3294
2851 if (part != null) 3295 if (part != null)
2852 { 3296 {
@@ -2884,7 +3328,16 @@ namespace OpenSim.Region.Framework.Scenes
2884 if (part.UUID == m_rootPart.UUID) 3328 if (part.UUID == m_rootPart.UUID)
2885 { 3329 {
2886 UpdateRootRotation(rot); 3330 UpdateRootRotation(rot);
2887 AbsolutePosition = pos; 3331 if (!m_rootPart.Undoing)
3332 {
3333 m_rootPart.Undoing = true;
3334 AbsolutePosition = pos;
3335 m_rootPart.Undoing = false;
3336 }
3337 else
3338 {
3339 AbsolutePosition = pos;
3340 }
2888 } 3341 }
2889 else 3342 else
2890 { 3343 {
@@ -2908,9 +3361,10 @@ namespace OpenSim.Region.Framework.Scenes
2908 3361
2909 Quaternion axRot = rot; 3362 Quaternion axRot = rot;
2910 Quaternion oldParentRot = m_rootPart.RotationOffset; 3363 Quaternion oldParentRot = m_rootPart.RotationOffset;
2911
2912 m_rootPart.StoreUndoState(); 3364 m_rootPart.StoreUndoState();
2913 m_rootPart.UpdateRotation(rot); 3365
3366 //Don't use UpdateRotation because it schedules an update prematurely
3367 m_rootPart.RotationOffset = rot;
2914 if (m_rootPart.PhysActor != null) 3368 if (m_rootPart.PhysActor != null)
2915 { 3369 {
2916 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3370 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2924,15 +3378,17 @@ namespace OpenSim.Region.Framework.Scenes
2924 if (prim.UUID != m_rootPart.UUID) 3378 if (prim.UUID != m_rootPart.UUID)
2925 { 3379 {
2926 prim.IgnoreUndoUpdate = true; 3380 prim.IgnoreUndoUpdate = true;
3381
3382 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3383 NewRot = Quaternion.Inverse(axRot) * NewRot;
3384 prim.RotationOffset = NewRot;
3385
2927 Vector3 axPos = prim.OffsetPosition; 3386 Vector3 axPos = prim.OffsetPosition;
3387
2928 axPos *= oldParentRot; 3388 axPos *= oldParentRot;
2929 axPos *= Quaternion.Inverse(axRot); 3389 axPos *= Quaternion.Inverse(axRot);
2930 prim.OffsetPosition = axPos; 3390 prim.OffsetPosition = axPos;
2931 Quaternion primsRot = prim.RotationOffset; 3391
2932 Quaternion newRot = oldParentRot * primsRot;
2933 newRot = Quaternion.Inverse(axRot) * newRot;
2934 prim.RotationOffset = newRot;
2935 prim.ScheduleTerseUpdate();
2936 prim.IgnoreUndoUpdate = false; 3392 prim.IgnoreUndoUpdate = false;
2937 } 3393 }
2938 } 3394 }
@@ -2946,8 +3402,8 @@ namespace OpenSim.Region.Framework.Scenes
2946//// childpart.StoreUndoState(); 3402//// childpart.StoreUndoState();
2947// } 3403// }
2948// } 3404// }
2949 3405 HasGroupChanged = true;
2950 m_rootPart.ScheduleTerseUpdate(); 3406 ScheduleGroupForFullUpdate();
2951 3407
2952// m_log.DebugFormat( 3408// m_log.DebugFormat(
2953// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3409// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3175,7 +3631,6 @@ namespace OpenSim.Region.Framework.Scenes
3175 public float GetMass() 3631 public float GetMass()
3176 { 3632 {
3177 float retmass = 0f; 3633 float retmass = 0f;
3178
3179 SceneObjectPart[] parts = m_parts.GetArray(); 3634 SceneObjectPart[] parts = m_parts.GetArray();
3180 for (int i = 0; i < parts.Length; i++) 3635 for (int i = 0; i < parts.Length; i++)
3181 retmass += parts[i].GetMass(); 3636 retmass += parts[i].GetMass();
@@ -3271,6 +3726,14 @@ namespace OpenSim.Region.Framework.Scenes
3271 SetFromItemID(uuid); 3726 SetFromItemID(uuid);
3272 } 3727 }
3273 3728
3729 public void ResetOwnerChangeFlag()
3730 {
3731 ForEachPart(delegate(SceneObjectPart part)
3732 {
3733 part.ResetOwnerChangeFlag();
3734 });
3735 }
3736
3274 #endregion 3737 #endregion
3275 } 3738 }
3276} 3739}