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 739c5fa..cf7bf16 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 //{
@@ -571,6 +668,7 @@ namespace OpenSim.Region.Framework.Scenes
571 /// </summary> 668 /// </summary>
572 public SceneObjectGroup() 669 public SceneObjectGroup()
573 { 670 {
671
574 } 672 }
575 673
576 /// <summary> 674 /// <summary>
@@ -587,7 +685,7 @@ namespace OpenSim.Region.Framework.Scenes
587 /// Constructor. This object is added to the scene later via AttachToScene() 685 /// Constructor. This object is added to the scene later via AttachToScene()
588 /// </summary> 686 /// </summary>
589 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 687 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
590 { 688 {
591 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 689 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
592 } 690 }
593 691
@@ -635,6 +733,9 @@ namespace OpenSim.Region.Framework.Scenes
635 /// </summary> 733 /// </summary>
636 public virtual void AttachToBackup() 734 public virtual void AttachToBackup()
637 { 735 {
736 if (IsAttachment) return;
737 m_scene.SceneGraph.FireAttachToBackup(this);
738
638 if (InSceneBackup) 739 if (InSceneBackup)
639 { 740 {
640 //m_log.DebugFormat( 741 //m_log.DebugFormat(
@@ -677,6 +778,9 @@ namespace OpenSim.Region.Framework.Scenes
677 778
678 ApplyPhysics(); 779 ApplyPhysics();
679 780
781 if (RootPart.PhysActor != null)
782 RootPart.Buoyancy = RootPart.Buoyancy;
783
680 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 784 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
681 // for the same object with very different properties. The caller must schedule the update. 785 // for the same object with very different properties. The caller must schedule the update.
682 //ScheduleGroupForFullUpdate(); 786 //ScheduleGroupForFullUpdate();
@@ -692,6 +796,10 @@ namespace OpenSim.Region.Framework.Scenes
692 EntityIntersection result = new EntityIntersection(); 796 EntityIntersection result = new EntityIntersection();
693 797
694 SceneObjectPart[] parts = m_parts.GetArray(); 798 SceneObjectPart[] parts = m_parts.GetArray();
799
800 // Find closest hit here
801 float idist = float.MaxValue;
802
695 for (int i = 0; i < parts.Length; i++) 803 for (int i = 0; i < parts.Length; i++)
696 { 804 {
697 SceneObjectPart part = parts[i]; 805 SceneObjectPart part = parts[i];
@@ -706,11 +814,6 @@ namespace OpenSim.Region.Framework.Scenes
706 814
707 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 815 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
708 816
709 // This may need to be updated to the maximum draw distance possible..
710 // We might (and probably will) be checking for prim creation from other sims
711 // when the camera crosses the border.
712 float idist = Constants.RegionSize;
713
714 if (inter.HitTF) 817 if (inter.HitTF)
715 { 818 {
716 // We need to find the closest prim to return to the testcaller along the ray 819 // We need to find the closest prim to return to the testcaller along the ray
@@ -721,10 +824,11 @@ namespace OpenSim.Region.Framework.Scenes
721 result.obj = part; 824 result.obj = part;
722 result.normal = inter.normal; 825 result.normal = inter.normal;
723 result.distance = inter.distance; 826 result.distance = inter.distance;
827
828 idist = inter.distance;
724 } 829 }
725 } 830 }
726 } 831 }
727
728 return result; 832 return result;
729 } 833 }
730 834
@@ -744,17 +848,19 @@ namespace OpenSim.Region.Framework.Scenes
744 minZ = 8192f; 848 minZ = 8192f;
745 849
746 SceneObjectPart[] parts = m_parts.GetArray(); 850 SceneObjectPart[] parts = m_parts.GetArray();
747 for (int i = 0; i < parts.Length; i++) 851 foreach (SceneObjectPart part in parts)
748 { 852 {
749 SceneObjectPart part = parts[i];
750
751 Vector3 worldPos = part.GetWorldPosition(); 853 Vector3 worldPos = part.GetWorldPosition();
752 Vector3 offset = worldPos - AbsolutePosition; 854 Vector3 offset = worldPos - AbsolutePosition;
753 Quaternion worldRot; 855 Quaternion worldRot;
754 if (part.ParentID == 0) 856 if (part.ParentID == 0)
857 {
755 worldRot = part.RotationOffset; 858 worldRot = part.RotationOffset;
859 }
756 else 860 else
861 {
757 worldRot = part.GetWorldRotation(); 862 worldRot = part.GetWorldRotation();
863 }
758 864
759 Vector3 frontTopLeft; 865 Vector3 frontTopLeft;
760 Vector3 frontTopRight; 866 Vector3 frontTopRight;
@@ -766,6 +872,8 @@ namespace OpenSim.Region.Framework.Scenes
766 Vector3 backBottomLeft; 872 Vector3 backBottomLeft;
767 Vector3 backBottomRight; 873 Vector3 backBottomRight;
768 874
875 // Vector3[] corners = new Vector3[8];
876
769 Vector3 orig = Vector3.Zero; 877 Vector3 orig = Vector3.Zero;
770 878
771 frontTopLeft.X = orig.X - (part.Scale.X / 2); 879 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -800,6 +908,38 @@ namespace OpenSim.Region.Framework.Scenes
800 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 908 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
801 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 909 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
802 910
911
912
913 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
914 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
915 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
916 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
917 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
918 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
919 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
920 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
921
922 //for (int i = 0; i < 8; i++)
923 //{
924 // corners[i] = corners[i] * worldRot;
925 // corners[i] += offset;
926
927 // if (corners[i].X > maxX)
928 // maxX = corners[i].X;
929 // if (corners[i].X < minX)
930 // minX = corners[i].X;
931
932 // if (corners[i].Y > maxY)
933 // maxY = corners[i].Y;
934 // if (corners[i].Y < minY)
935 // minY = corners[i].Y;
936
937 // if (corners[i].Z > maxZ)
938 // maxZ = corners[i].Y;
939 // if (corners[i].Z < minZ)
940 // minZ = corners[i].Z;
941 //}
942
803 frontTopLeft = frontTopLeft * worldRot; 943 frontTopLeft = frontTopLeft * worldRot;
804 frontTopRight = frontTopRight * worldRot; 944 frontTopRight = frontTopRight * worldRot;
805 frontBottomLeft = frontBottomLeft * worldRot; 945 frontBottomLeft = frontBottomLeft * worldRot;
@@ -821,6 +961,15 @@ namespace OpenSim.Region.Framework.Scenes
821 backTopLeft += offset; 961 backTopLeft += offset;
822 backTopRight += offset; 962 backTopRight += offset;
823 963
964 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
965 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
966 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
967 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
968 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
969 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
970 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
971 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
972
824 if (frontTopRight.X > maxX) 973 if (frontTopRight.X > maxX)
825 maxX = frontTopRight.X; 974 maxX = frontTopRight.X;
826 if (frontTopLeft.X > maxX) 975 if (frontTopLeft.X > maxX)
@@ -966,15 +1115,20 @@ namespace OpenSim.Region.Framework.Scenes
966 1115
967 public void SaveScriptedState(XmlTextWriter writer) 1116 public void SaveScriptedState(XmlTextWriter writer)
968 { 1117 {
1118 SaveScriptedState(writer, false);
1119 }
1120
1121 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1122 {
969 XmlDocument doc = new XmlDocument(); 1123 XmlDocument doc = new XmlDocument();
970 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1124 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
971 1125
972 SceneObjectPart[] parts = m_parts.GetArray(); 1126 SceneObjectPart[] parts = m_parts.GetArray();
973 for (int i = 0; i < parts.Length; i++) 1127 for (int i = 0; i < parts.Length; i++)
974 { 1128 {
975 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1129 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
976 foreach (KeyValuePair<UUID, string> kvp in pstates) 1130 foreach (KeyValuePair<UUID, string> kvp in pstates)
977 states.Add(kvp.Key, kvp.Value); 1131 states[kvp.Key] = kvp.Value;
978 } 1132 }
979 1133
980 if (states.Count > 0) 1134 if (states.Count > 0)
@@ -994,6 +1148,168 @@ namespace OpenSim.Region.Framework.Scenes
994 } 1148 }
995 1149
996 /// <summary> 1150 /// <summary>
1151 /// Add the avatar to this linkset (avatar is sat).
1152 /// </summary>
1153 /// <param name="agentID"></param>
1154 public void AddAvatar(UUID agentID)
1155 {
1156 ScenePresence presence;
1157 if (m_scene.TryGetScenePresence(agentID, out presence))
1158 {
1159 if (!m_linkedAvatars.Contains(presence))
1160 {
1161 m_linkedAvatars.Add(presence);
1162 }
1163 }
1164 }
1165
1166 /// <summary>
1167 /// Delete the avatar from this linkset (avatar is unsat).
1168 /// </summary>
1169 /// <param name="agentID"></param>
1170 public void DeleteAvatar(UUID agentID)
1171 {
1172 ScenePresence presence;
1173 if (m_scene.TryGetScenePresence(agentID, out presence))
1174 {
1175 if (m_linkedAvatars.Contains(presence))
1176 {
1177 m_linkedAvatars.Remove(presence);
1178 }
1179 }
1180 }
1181
1182 /// <summary>
1183 /// Returns the list of linked presences (avatars sat on this group)
1184 /// </summary>
1185 /// <param name="agentID"></param>
1186 public List<ScenePresence> GetLinkedAvatars()
1187 {
1188 return m_linkedAvatars;
1189 }
1190
1191 /// <summary>
1192 /// Attach this scene object to the given avatar.
1193 /// </summary>
1194 /// <param name="agentID"></param>
1195 /// <param name="attachmentpoint"></param>
1196 /// <param name="AttachOffset"></param>
1197 private void AttachToAgent(
1198 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1199 {
1200 if (avatar != null)
1201 {
1202 // don't attach attachments to child agents
1203 if (avatar.IsChildAgent) return;
1204
1205 // Remove from database and parcel prim count
1206 m_scene.DeleteFromStorage(so.UUID);
1207 m_scene.EventManager.TriggerParcelPrimCountTainted();
1208
1209 so.AttachedAvatar = avatar.UUID;
1210
1211 if (so.RootPart.PhysActor != null)
1212 {
1213 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1214 so.RootPart.PhysActor = null;
1215 }
1216
1217 so.AbsolutePosition = attachOffset;
1218 so.RootPart.AttachedPos = attachOffset;
1219 so.IsAttachment = true;
1220 so.RootPart.SetParentLocalId(avatar.LocalId);
1221 so.AttachmentPoint = attachmentpoint;
1222
1223 avatar.AddAttachment(this);
1224
1225 if (!silent)
1226 {
1227 // Killing it here will cause the client to deselect it
1228 // It then reappears on the avatar, deselected
1229 // through the full update below
1230 //
1231 if (IsSelected)
1232 {
1233 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1234 }
1235
1236 IsSelected = false; // fudge....
1237 ScheduleGroupForFullUpdate();
1238 }
1239 }
1240 else
1241 {
1242 m_log.WarnFormat(
1243 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1244 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1245 }
1246 }
1247
1248 public byte GetAttachmentPoint()
1249 {
1250 return m_rootPart.Shape.State;
1251 }
1252
1253 public void DetachToGround()
1254 {
1255 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1256 if (avatar == null)
1257 return;
1258
1259 avatar.RemoveAttachment(this);
1260
1261 Vector3 detachedpos = new Vector3(127f,127f,127f);
1262 if (avatar == null)
1263 return;
1264
1265 detachedpos = avatar.AbsolutePosition;
1266 RootPart.FromItemID = UUID.Zero;
1267
1268 AbsolutePosition = detachedpos;
1269 AttachedAvatar = UUID.Zero;
1270
1271 //SceneObjectPart[] parts = m_parts.GetArray();
1272 //for (int i = 0; i < parts.Length; i++)
1273 // parts[i].AttachedAvatar = UUID.Zero;
1274
1275 m_rootPart.SetParentLocalId(0);
1276 AttachmentPoint = (byte)0;
1277 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1278 HasGroupChanged = true;
1279 RootPart.Rezzed = DateTime.Now;
1280 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1281 AttachToBackup();
1282 m_scene.EventManager.TriggerParcelPrimCountTainted();
1283 m_rootPart.ScheduleFullUpdate();
1284 m_rootPart.ClearUndoState();
1285 }
1286
1287 public void DetachToInventoryPrep()
1288 {
1289 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1290 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1291 if (avatar != null)
1292 {
1293 //detachedpos = avatar.AbsolutePosition;
1294 avatar.RemoveAttachment(this);
1295 }
1296
1297 AttachedAvatar = UUID.Zero;
1298
1299 /*SceneObjectPart[] parts = m_parts.GetArray();
1300 for (int i = 0; i < parts.Length; i++)
1301 parts[i].AttachedAvatar = UUID.Zero;*/
1302
1303 m_rootPart.SetParentLocalId(0);
1304 //m_rootPart.SetAttachmentPoint((byte)0);
1305 IsAttachment = false;
1306 AbsolutePosition = m_rootPart.AttachedPos;
1307 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1308 //AttachToBackup();
1309 //m_rootPart.ScheduleFullUpdate();
1310 }
1311
1312 /// <summary>
997 /// 1313 ///
998 /// </summary> 1314 /// </summary>
999 /// <param name="part"></param> 1315 /// <param name="part"></param>
@@ -1043,7 +1359,10 @@ namespace OpenSim.Region.Framework.Scenes
1043 public void AddPart(SceneObjectPart part) 1359 public void AddPart(SceneObjectPart part)
1044 { 1360 {
1045 part.SetParent(this); 1361 part.SetParent(this);
1046 part.LinkNum = m_parts.Add(part.UUID, part); 1362 m_parts.Add(part.UUID, part);
1363
1364 part.LinkNum = m_parts.Count;
1365
1047 if (part.LinkNum == 2) 1366 if (part.LinkNum == 2)
1048 RootPart.LinkNum = 1; 1367 RootPart.LinkNum = 1;
1049 } 1368 }
@@ -1151,6 +1470,11 @@ namespace OpenSim.Region.Framework.Scenes
1151 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1470 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1152 public void DeleteGroupFromScene(bool silent) 1471 public void DeleteGroupFromScene(bool silent)
1153 { 1472 {
1473 // We need to keep track of this state in case this group is still queued for backup.
1474 IsDeleted = true;
1475
1476 DetachFromBackup();
1477
1154 SceneObjectPart[] parts = m_parts.GetArray(); 1478 SceneObjectPart[] parts = m_parts.GetArray();
1155 for (int i = 0; i < parts.Length; i++) 1479 for (int i = 0; i < parts.Length; i++)
1156 { 1480 {
@@ -1173,6 +1497,8 @@ namespace OpenSim.Region.Framework.Scenes
1173 } 1497 }
1174 }); 1498 });
1175 } 1499 }
1500
1501
1176 } 1502 }
1177 1503
1178 public void AddScriptLPS(int count) 1504 public void AddScriptLPS(int count)
@@ -1268,7 +1594,12 @@ namespace OpenSim.Region.Framework.Scenes
1268 1594
1269 public void SetOwnerId(UUID userId) 1595 public void SetOwnerId(UUID userId)
1270 { 1596 {
1271 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1597 ForEachPart(delegate(SceneObjectPart part)
1598 {
1599
1600 part.OwnerID = userId;
1601
1602 });
1272 } 1603 }
1273 1604
1274 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1605 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1300,11 +1631,17 @@ namespace OpenSim.Region.Framework.Scenes
1300 return; 1631 return;
1301 } 1632 }
1302 1633
1634 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1635 return;
1636
1303 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1637 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1304 // any exception propogate upwards. 1638 // any exception propogate upwards.
1305 try 1639 try
1306 { 1640 {
1307 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1641 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1642 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1643 m_scene.LoadingPrims) // Land may not be valid yet
1644
1308 { 1645 {
1309 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1646 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1310 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1647 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1331,6 +1668,7 @@ namespace OpenSim.Region.Framework.Scenes
1331 } 1668 }
1332 } 1669 }
1333 } 1670 }
1671
1334 } 1672 }
1335 1673
1336 if (m_scene.UseBackup && HasGroupChanged) 1674 if (m_scene.UseBackup && HasGroupChanged)
@@ -1338,6 +1676,20 @@ namespace OpenSim.Region.Framework.Scenes
1338 // don't backup while it's selected or you're asking for changes mid stream. 1676 // don't backup while it's selected or you're asking for changes mid stream.
1339 if (isTimeToPersist() || forcedBackup) 1677 if (isTimeToPersist() || forcedBackup)
1340 { 1678 {
1679 if (m_rootPart.PhysActor != null &&
1680 (!m_rootPart.PhysActor.IsPhysical))
1681 {
1682 // Possible ghost prim
1683 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1684 {
1685 foreach (SceneObjectPart part in m_parts.GetArray())
1686 {
1687 // Re-set physics actor positions and
1688 // orientations
1689 part.GroupPosition = m_rootPart.GroupPosition;
1690 }
1691 }
1692 }
1341// m_log.DebugFormat( 1693// m_log.DebugFormat(
1342// "[SCENE]: Storing {0}, {1} in {2}", 1694// "[SCENE]: Storing {0}, {1} in {2}",
1343// Name, UUID, m_scene.RegionInfo.RegionName); 1695// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1421,7 +1773,7 @@ namespace OpenSim.Region.Framework.Scenes
1421 // This is only necessary when userExposed is false! 1773 // This is only necessary when userExposed is false!
1422 1774
1423 bool previousAttachmentStatus = dupe.IsAttachment; 1775 bool previousAttachmentStatus = dupe.IsAttachment;
1424 1776
1425 if (!userExposed) 1777 if (!userExposed)
1426 dupe.IsAttachment = true; 1778 dupe.IsAttachment = true;
1427 1779
@@ -1439,11 +1791,11 @@ namespace OpenSim.Region.Framework.Scenes
1439 dupe.m_rootPart.TrimPermissions(); 1791 dupe.m_rootPart.TrimPermissions();
1440 1792
1441 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1793 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1442 1794
1443 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1795 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1444 { 1796 {
1445 return p1.LinkNum.CompareTo(p2.LinkNum); 1797 return p1.LinkNum.CompareTo(p2.LinkNum);
1446 } 1798 }
1447 ); 1799 );
1448 1800
1449 foreach (SceneObjectPart part in partList) 1801 foreach (SceneObjectPart part in partList)
@@ -1463,7 +1815,7 @@ namespace OpenSim.Region.Framework.Scenes
1463 if (part.PhysActor != null && userExposed) 1815 if (part.PhysActor != null && userExposed)
1464 { 1816 {
1465 PrimitiveBaseShape pbs = newPart.Shape; 1817 PrimitiveBaseShape pbs = newPart.Shape;
1466 1818
1467 newPart.PhysActor 1819 newPart.PhysActor
1468 = m_scene.PhysicsScene.AddPrimShape( 1820 = m_scene.PhysicsScene.AddPrimShape(
1469 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1821 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1473,11 +1825,11 @@ namespace OpenSim.Region.Framework.Scenes
1473 newPart.RotationOffset, 1825 newPart.RotationOffset,
1474 part.PhysActor.IsPhysical, 1826 part.PhysActor.IsPhysical,
1475 newPart.LocalId); 1827 newPart.LocalId);
1476 1828
1477 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1829 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1478 } 1830 }
1479 } 1831 }
1480 1832
1481 if (userExposed) 1833 if (userExposed)
1482 { 1834 {
1483 dupe.UpdateParentIDs(); 1835 dupe.UpdateParentIDs();
@@ -1592,6 +1944,7 @@ namespace OpenSim.Region.Framework.Scenes
1592 return Vector3.Zero; 1944 return Vector3.Zero;
1593 } 1945 }
1594 1946
1947 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1595 public void moveToTarget(Vector3 target, float tau) 1948 public void moveToTarget(Vector3 target, float tau)
1596 { 1949 {
1597 if (IsAttachment) 1950 if (IsAttachment)
@@ -1619,6 +1972,46 @@ namespace OpenSim.Region.Framework.Scenes
1619 RootPart.PhysActor.PIDActive = false; 1972 RootPart.PhysActor.PIDActive = false;
1620 } 1973 }
1621 1974
1975 public void rotLookAt(Quaternion target, float strength, float damping)
1976 {
1977 SceneObjectPart rootpart = m_rootPart;
1978 if (rootpart != null)
1979 {
1980 if (IsAttachment)
1981 {
1982 /*
1983 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1984 if (avatar != null)
1985 {
1986 Rotate the Av?
1987 } */
1988 }
1989 else
1990 {
1991 if (rootpart.PhysActor != null)
1992 { // APID must be implemented in your physics system for this to function.
1993 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1994 rootpart.PhysActor.APIDStrength = strength;
1995 rootpart.PhysActor.APIDDamping = damping;
1996 rootpart.PhysActor.APIDActive = true;
1997 }
1998 }
1999 }
2000 }
2001
2002 public void stopLookAt()
2003 {
2004 SceneObjectPart rootpart = m_rootPart;
2005 if (rootpart != null)
2006 {
2007 if (rootpart.PhysActor != null)
2008 { // APID must be implemented in your physics system for this to function.
2009 rootpart.PhysActor.APIDActive = false;
2010 }
2011 }
2012
2013 }
2014
1622 /// <summary> 2015 /// <summary>
1623 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2016 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1624 /// </summary> 2017 /// </summary>
@@ -1674,6 +2067,8 @@ namespace OpenSim.Region.Framework.Scenes
1674 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2067 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1675 { 2068 {
1676 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2069 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2070 newPart.SetParent(this);
2071
1677 AddPart(newPart); 2072 AddPart(newPart);
1678 2073
1679 SetPartAsNonRoot(newPart); 2074 SetPartAsNonRoot(newPart);
@@ -1802,11 +2197,11 @@ namespace OpenSim.Region.Framework.Scenes
1802 /// Immediately send a full update for this scene object. 2197 /// Immediately send a full update for this scene object.
1803 /// </summary> 2198 /// </summary>
1804 public void SendGroupFullUpdate() 2199 public void SendGroupFullUpdate()
1805 { 2200 {
1806 if (IsDeleted) 2201 if (IsDeleted)
1807 return; 2202 return;
1808 2203
1809// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2204// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1810 2205
1811 RootPart.SendFullUpdateToAllClients(); 2206 RootPart.SendFullUpdateToAllClients();
1812 2207
@@ -2007,7 +2402,7 @@ namespace OpenSim.Region.Framework.Scenes
2007 objectGroup.IsDeleted = true; 2402 objectGroup.IsDeleted = true;
2008 2403
2009 objectGroup.m_parts.Clear(); 2404 objectGroup.m_parts.Clear();
2010 2405
2011 // Can't do this yet since backup still makes use of the root part without any synchronization 2406 // Can't do this yet since backup still makes use of the root part without any synchronization
2012// objectGroup.m_rootPart = null; 2407// objectGroup.m_rootPart = null;
2013 2408
@@ -2141,6 +2536,7 @@ namespace OpenSim.Region.Framework.Scenes
2141 /// <param name="objectGroup"></param> 2536 /// <param name="objectGroup"></param>
2142 public virtual void DetachFromBackup() 2537 public virtual void DetachFromBackup()
2143 { 2538 {
2539 m_scene.SceneGraph.FireDetachFromBackup(this);
2144 if (m_isBackedUp && Scene != null) 2540 if (m_isBackedUp && Scene != null)
2145 m_scene.EventManager.OnBackup -= ProcessBackup; 2541 m_scene.EventManager.OnBackup -= ProcessBackup;
2146 2542
@@ -2159,7 +2555,8 @@ namespace OpenSim.Region.Framework.Scenes
2159 2555
2160 axPos *= parentRot; 2556 axPos *= parentRot;
2161 part.OffsetPosition = axPos; 2557 part.OffsetPosition = axPos;
2162 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2558 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2559 part.GroupPosition = newPos;
2163 part.OffsetPosition = Vector3.Zero; 2560 part.OffsetPosition = Vector3.Zero;
2164 part.RotationOffset = worldRot; 2561 part.RotationOffset = worldRot;
2165 2562
@@ -2170,7 +2567,7 @@ namespace OpenSim.Region.Framework.Scenes
2170 2567
2171 part.LinkNum = linkNum; 2568 part.LinkNum = linkNum;
2172 2569
2173 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2570 part.OffsetPosition = newPos - AbsolutePosition;
2174 2571
2175 Quaternion rootRotation = m_rootPart.RotationOffset; 2572 Quaternion rootRotation = m_rootPart.RotationOffset;
2176 2573
@@ -2180,7 +2577,7 @@ namespace OpenSim.Region.Framework.Scenes
2180 2577
2181 parentRot = m_rootPart.RotationOffset; 2578 parentRot = m_rootPart.RotationOffset;
2182 oldRot = part.RotationOffset; 2579 oldRot = part.RotationOffset;
2183 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2580 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2184 part.RotationOffset = newRot; 2581 part.RotationOffset = newRot;
2185 } 2582 }
2186 2583
@@ -2427,8 +2824,12 @@ namespace OpenSim.Region.Framework.Scenes
2427 } 2824 }
2428 } 2825 }
2429 2826
2827 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2430 for (int i = 0; i < parts.Length; i++) 2828 for (int i = 0; i < parts.Length; i++)
2431 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2829 {
2830 if (parts[i] != RootPart)
2831 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2832 }
2432 } 2833 }
2433 } 2834 }
2434 2835
@@ -2441,6 +2842,17 @@ namespace OpenSim.Region.Framework.Scenes
2441 } 2842 }
2442 } 2843 }
2443 2844
2845
2846
2847 /// <summary>
2848 /// Gets the number of parts
2849 /// </summary>
2850 /// <returns></returns>
2851 public int GetPartCount()
2852 {
2853 return Parts.Count();
2854 }
2855
2444 /// <summary> 2856 /// <summary>
2445 /// Update the texture entry for this part 2857 /// Update the texture entry for this part
2446 /// </summary> 2858 /// </summary>
@@ -2502,7 +2914,6 @@ namespace OpenSim.Region.Framework.Scenes
2502 { 2914 {
2503// m_log.DebugFormat( 2915// m_log.DebugFormat(
2504// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2916// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2505
2506 RootPart.StoreUndoState(true); 2917 RootPart.StoreUndoState(true);
2507 2918
2508 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2919 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2603,7 +3014,6 @@ namespace OpenSim.Region.Framework.Scenes
2603 prevScale.X *= x; 3014 prevScale.X *= x;
2604 prevScale.Y *= y; 3015 prevScale.Y *= y;
2605 prevScale.Z *= z; 3016 prevScale.Z *= z;
2606
2607// RootPart.IgnoreUndoUpdate = true; 3017// RootPart.IgnoreUndoUpdate = true;
2608 RootPart.Resize(prevScale); 3018 RootPart.Resize(prevScale);
2609// RootPart.IgnoreUndoUpdate = false; 3019// RootPart.IgnoreUndoUpdate = false;
@@ -2634,7 +3044,9 @@ namespace OpenSim.Region.Framework.Scenes
2634 } 3044 }
2635 3045
2636// obPart.IgnoreUndoUpdate = false; 3046// obPart.IgnoreUndoUpdate = false;
2637// obPart.StoreUndoState(); 3047 HasGroupChanged = true;
3048 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3049 ScheduleGroupForTerseUpdate();
2638 } 3050 }
2639 3051
2640// m_log.DebugFormat( 3052// m_log.DebugFormat(
@@ -2694,9 +3106,9 @@ namespace OpenSim.Region.Framework.Scenes
2694 { 3106 {
2695 SceneObjectPart part = GetChildPart(localID); 3107 SceneObjectPart part = GetChildPart(localID);
2696 3108
2697// SceneObjectPart[] parts = m_parts.GetArray(); 3109 SceneObjectPart[] parts = m_parts.GetArray();
2698// for (int i = 0; i < parts.Length; i++) 3110 for (int i = 0; i < parts.Length; i++)
2699// parts[i].StoreUndoState(); 3111 parts[i].StoreUndoState();
2700 3112
2701 if (part != null) 3113 if (part != null)
2702 { 3114 {
@@ -2752,10 +3164,27 @@ namespace OpenSim.Region.Framework.Scenes
2752 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3164 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2753 } 3165 }
2754 3166
2755 AbsolutePosition = newPos; 3167 //We have to set undoing here because otherwise an undo state will be saved
3168 if (!m_rootPart.Undoing)
3169 {
3170 m_rootPart.Undoing = true;
3171 AbsolutePosition = newPos;
3172 m_rootPart.Undoing = false;
3173 }
3174 else
3175 {
3176 AbsolutePosition = newPos;
3177 }
2756 3178
2757 HasGroupChanged = true; 3179 HasGroupChanged = true;
2758 ScheduleGroupForTerseUpdate(); 3180 if (m_rootPart.Undoing)
3181 {
3182 ScheduleGroupForFullUpdate();
3183 }
3184 else
3185 {
3186 ScheduleGroupForTerseUpdate();
3187 }
2759 } 3188 }
2760 3189
2761 #endregion 3190 #endregion
@@ -2832,10 +3261,7 @@ namespace OpenSim.Region.Framework.Scenes
2832 public void UpdateSingleRotation(Quaternion rot, uint localID) 3261 public void UpdateSingleRotation(Quaternion rot, uint localID)
2833 { 3262 {
2834 SceneObjectPart part = GetChildPart(localID); 3263 SceneObjectPart part = GetChildPart(localID);
2835
2836 SceneObjectPart[] parts = m_parts.GetArray(); 3264 SceneObjectPart[] parts = m_parts.GetArray();
2837 for (int i = 0; i < parts.Length; i++)
2838 parts[i].StoreUndoState();
2839 3265
2840 if (part != null) 3266 if (part != null)
2841 { 3267 {
@@ -2873,7 +3299,16 @@ namespace OpenSim.Region.Framework.Scenes
2873 if (part.UUID == m_rootPart.UUID) 3299 if (part.UUID == m_rootPart.UUID)
2874 { 3300 {
2875 UpdateRootRotation(rot); 3301 UpdateRootRotation(rot);
2876 AbsolutePosition = pos; 3302 if (!m_rootPart.Undoing)
3303 {
3304 m_rootPart.Undoing = true;
3305 AbsolutePosition = pos;
3306 m_rootPart.Undoing = false;
3307 }
3308 else
3309 {
3310 AbsolutePosition = pos;
3311 }
2877 } 3312 }
2878 else 3313 else
2879 { 3314 {
@@ -2897,9 +3332,10 @@ namespace OpenSim.Region.Framework.Scenes
2897 3332
2898 Quaternion axRot = rot; 3333 Quaternion axRot = rot;
2899 Quaternion oldParentRot = m_rootPart.RotationOffset; 3334 Quaternion oldParentRot = m_rootPart.RotationOffset;
2900
2901 m_rootPart.StoreUndoState(); 3335 m_rootPart.StoreUndoState();
2902 m_rootPart.UpdateRotation(rot); 3336
3337 //Don't use UpdateRotation because it schedules an update prematurely
3338 m_rootPart.RotationOffset = rot;
2903 if (m_rootPart.PhysActor != null) 3339 if (m_rootPart.PhysActor != null)
2904 { 3340 {
2905 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3341 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2913,15 +3349,17 @@ namespace OpenSim.Region.Framework.Scenes
2913 if (prim.UUID != m_rootPart.UUID) 3349 if (prim.UUID != m_rootPart.UUID)
2914 { 3350 {
2915 prim.IgnoreUndoUpdate = true; 3351 prim.IgnoreUndoUpdate = true;
3352
3353 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3354 NewRot = Quaternion.Inverse(axRot) * NewRot;
3355 prim.RotationOffset = NewRot;
3356
2916 Vector3 axPos = prim.OffsetPosition; 3357 Vector3 axPos = prim.OffsetPosition;
3358
2917 axPos *= oldParentRot; 3359 axPos *= oldParentRot;
2918 axPos *= Quaternion.Inverse(axRot); 3360 axPos *= Quaternion.Inverse(axRot);
2919 prim.OffsetPosition = axPos; 3361 prim.OffsetPosition = axPos;
2920 Quaternion primsRot = prim.RotationOffset; 3362
2921 Quaternion newRot = oldParentRot * primsRot;
2922 newRot = Quaternion.Inverse(axRot) * newRot;
2923 prim.RotationOffset = newRot;
2924 prim.ScheduleTerseUpdate();
2925 prim.IgnoreUndoUpdate = false; 3363 prim.IgnoreUndoUpdate = false;
2926 } 3364 }
2927 } 3365 }
@@ -2935,8 +3373,8 @@ namespace OpenSim.Region.Framework.Scenes
2935//// childpart.StoreUndoState(); 3373//// childpart.StoreUndoState();
2936// } 3374// }
2937// } 3375// }
2938 3376 HasGroupChanged = true;
2939 m_rootPart.ScheduleTerseUpdate(); 3377 ScheduleGroupForFullUpdate();
2940 3378
2941// m_log.DebugFormat( 3379// m_log.DebugFormat(
2942// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3380// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3164,7 +3602,6 @@ namespace OpenSim.Region.Framework.Scenes
3164 public float GetMass() 3602 public float GetMass()
3165 { 3603 {
3166 float retmass = 0f; 3604 float retmass = 0f;
3167
3168 SceneObjectPart[] parts = m_parts.GetArray(); 3605 SceneObjectPart[] parts = m_parts.GetArray();
3169 for (int i = 0; i < parts.Length; i++) 3606 for (int i = 0; i < parts.Length; i++)
3170 retmass += parts[i].GetMass(); 3607 retmass += parts[i].GetMass();
@@ -3260,6 +3697,14 @@ namespace OpenSim.Region.Framework.Scenes
3260 SetFromItemID(uuid); 3697 SetFromItemID(uuid);
3261 } 3698 }
3262 3699
3700 public void ResetOwnerChangeFlag()
3701 {
3702 ForEachPart(delegate(SceneObjectPart part)
3703 {
3704 part.ResetOwnerChangeFlag();
3705 });
3706 }
3707
3263 #endregion 3708 #endregion
3264 } 3709 }
3265} 3710}