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.cs1051
1 files changed, 742 insertions, 309 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 117f869..9b66fad 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -29,6 +29,7 @@ using 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.Threading; 33using System.Threading;
33using System.Xml; 34using System.Xml;
34using System.Xml.Serialization; 35using System.Xml.Serialization;
@@ -104,8 +105,113 @@ namespace OpenSim.Region.Framework.Scenes
104 /// since the group's last persistent backup 105 /// since the group's last persistent backup
105 /// </summary> 106 /// </summary>
106 private bool m_hasGroupChanged = false; 107 private bool m_hasGroupChanged = false;
107 private long timeFirstChanged; 108 private long timeFirstChanged = 0;
108 private long timeLastChanged; 109 private long timeLastChanged = 0;
110 private long m_maxPersistTime = 0;
111 private long m_minPersistTime = 0;
112 private Random m_rand;
113 private bool m_suspendUpdates;
114 private System.Threading.ReaderWriterLockSlim m_partsLock = new System.Threading.ReaderWriterLockSlim();
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 }
132
133 public void lockPartsForRead(bool locked)
134 {
135 if (locked)
136 {
137 if (m_partsLock.RecursiveReadCount > 0)
138 {
139 m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
140 try
141 {
142 StackTrace stackTrace = new StackTrace(); // get call stack
143 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
144
145 // write call stack method names
146 foreach (StackFrame stackFrame in stackFrames)
147 {
148 m_log.Error("[SceneObjectGroup.m_parts] "+(stackFrame.GetMethod().Name)); // write method name
149 }
150
151 m_partsLock.ExitReadLock();
152 }
153 catch { } // Ignore errors, to allow resync
154 }
155 if (m_partsLock.RecursiveWriteCount > 0)
156 {
157 m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested (write lock exists on this thread). This should not happen and means something needs to be fixed.");
158 try
159 {
160 m_partsLock.ExitWriteLock();
161 }
162 catch { }
163
164 }
165
166 while (!m_partsLock.TryEnterReadLock(60000))
167 {
168 m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire READ lock of m_parts in SceneObjectGroup. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
169 if (m_partsLock.IsWriteLockHeld)
170 {
171 m_partsLock = new System.Threading.ReaderWriterLockSlim();
172 }
173 }
174 }
175 else
176 {
177 if (m_partsLock.RecursiveReadCount > 0)
178 {
179 m_partsLock.ExitReadLock();
180 }
181 }
182 }
183 public void lockPartsForWrite(bool locked)
184 {
185 if (locked)
186 {
187 if (m_partsLock.RecursiveReadCount > 0)
188 {
189 m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
190 m_partsLock.ExitReadLock();
191 }
192 if (m_partsLock.RecursiveWriteCount > 0)
193 {
194 m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
195 m_partsLock.ExitWriteLock();
196 }
197
198 while (!m_partsLock.TryEnterWriteLock(60000))
199 {
200 m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
201 if (m_partsLock.IsWriteLockHeld)
202 {
203 m_partsLock = new System.Threading.ReaderWriterLockSlim();
204 }
205 }
206 }
207 else
208 {
209 if (m_partsLock.RecursiveWriteCount > 0)
210 {
211 m_partsLock.ExitWriteLock();
212 }
213 }
214 }
109 215
110 public bool HasGroupChanged 216 public bool HasGroupChanged
111 { 217 {
@@ -113,9 +219,39 @@ namespace OpenSim.Region.Framework.Scenes
113 { 219 {
114 if (value) 220 if (value)
115 { 221 {
222 if (m_isBackedUp)
223 {
224 m_scene.SceneGraph.FireChangeBackup(this);
225 }
116 timeLastChanged = DateTime.Now.Ticks; 226 timeLastChanged = DateTime.Now.Ticks;
117 if (!m_hasGroupChanged) 227 if (!m_hasGroupChanged)
118 timeFirstChanged = DateTime.Now.Ticks; 228 timeFirstChanged = DateTime.Now.Ticks;
229 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
230 {
231 if (m_rand == null)
232 {
233 byte[] val = new byte[16];
234 m_rootPart.UUID.ToBytes(val, 0);
235 m_rand = new Random(BitConverter.ToInt32(val, 0));
236 }
237
238 if (m_scene.GetRootAgentCount() == 0)
239 {
240 //If the region is empty, this change has been made by an automated process
241 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
242
243 float factor = 1.5f + (float)(m_rand.NextDouble());
244 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
245 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
246 }
247 else
248 {
249 //If the region is not empty, we want to obey the minimum and maximum persist times
250 //but add a random factor so we stagger the object persistance a little
251 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
252 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
253 }
254 }
119 } 255 }
120 m_hasGroupChanged = value; 256 m_hasGroupChanged = value;
121 } 257 }
@@ -131,8 +267,19 @@ namespace OpenSim.Region.Framework.Scenes
131 return false; 267 return false;
132 if (m_scene.ShuttingDown) 268 if (m_scene.ShuttingDown)
133 return true; 269 return true;
270
271 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
272 {
273 m_maxPersistTime = m_scene.m_persistAfter;
274 m_minPersistTime = m_scene.m_dontPersistBefore;
275 }
276
134 long currentTime = DateTime.Now.Ticks; 277 long currentTime = DateTime.Now.Ticks;
135 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 278
279 if (timeLastChanged == 0) timeLastChanged = currentTime;
280 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
281
282 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
136 return true; 283 return true;
137 return false; 284 return false;
138 } 285 }
@@ -181,7 +328,7 @@ namespace OpenSim.Region.Framework.Scenes
181 328
182 private bool m_scriptListens_atRotTarget = false; 329 private bool m_scriptListens_atRotTarget = false;
183 private bool m_scriptListens_notAtRotTarget = false; 330 private bool m_scriptListens_notAtRotTarget = false;
184 331 public bool m_dupeInProgress = false;
185 internal Dictionary<UUID, string> m_savedScriptState = null; 332 internal Dictionary<UUID, string> m_savedScriptState = null;
186 333
187 #region Properties 334 #region Properties
@@ -221,7 +368,21 @@ namespace OpenSim.Region.Framework.Scenes
221 public virtual Quaternion Rotation 368 public virtual Quaternion Rotation
222 { 369 {
223 get { return m_rotation; } 370 get { return m_rotation; }
224 set { m_rotation = value; } 371 set {
372 lockPartsForRead(true);
373 try
374 {
375 foreach(SceneObjectPart p in m_parts.Values)
376 {
377 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
378 }
379 }
380 finally
381 {
382 lockPartsForRead(false);
383 }
384 m_rotation = value;
385 }
225 } 386 }
226 387
227 public Quaternion GroupRotation 388 public Quaternion GroupRotation
@@ -258,13 +419,16 @@ namespace OpenSim.Region.Framework.Scenes
258 set 419 set
259 { 420 {
260 m_regionHandle = value; 421 m_regionHandle = value;
261 lock (m_parts) 422 lockPartsForRead(true);
262 { 423 {
263 foreach (SceneObjectPart part in m_parts.Values) 424 foreach (SceneObjectPart part in m_parts.Values)
264 { 425 {
426
265 part.RegionHandle = m_regionHandle; 427 part.RegionHandle = m_regionHandle;
428
266 } 429 }
267 } 430 }
431 lockPartsForRead(false);
268 } 432 }
269 } 433 }
270 434
@@ -298,6 +462,12 @@ namespace OpenSim.Region.Framework.Scenes
298 { 462 {
299 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 463 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
300 } 464 }
465
466 lockPartsForRead(true);
467 foreach (SceneObjectPart part in m_parts.Values)
468 {
469 part.IgnoreUndoUpdate = true;
470 }
301 if (RootPart.GetStatusSandbox()) 471 if (RootPart.GetStatusSandbox())
302 { 472 {
303 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 473 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -305,14 +475,30 @@ namespace OpenSim.Region.Framework.Scenes
305 RootPart.ScriptSetPhysicsStatus(false); 475 RootPart.ScriptSetPhysicsStatus(false);
306 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), 476 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
307 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); 477 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
478 lockPartsForRead(false);
308 return; 479 return;
309 } 480 }
310 } 481 }
311 lock (m_parts) 482 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
483 lockPartsForRead(false);
484 foreach (SceneObjectPart part in parts)
312 { 485 {
313 foreach (SceneObjectPart part in m_parts.Values) 486 part.IgnoreUndoUpdate = false;
487 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
488 part.GroupPosition = val;
489 if (!m_dupeInProgress)
490 {
491 part.TriggerScriptChangedEvent(Changed.POSITION);
492 }
493 }
494 if (!m_dupeInProgress)
495 {
496 foreach (ScenePresence av in m_linkedAvatars)
314 { 497 {
315 part.GroupPosition = val; 498 Vector3 offset = m_parts[av.LinkedPrim].GetWorldPosition() - av.ParentPosition;
499 av.AbsolutePosition += offset;
500 av.ParentPosition = m_parts[av.LinkedPrim].GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
501 av.SendFullUpdateToAllClients();
316 } 502 }
317 } 503 }
318 504
@@ -457,6 +643,7 @@ namespace OpenSim.Region.Framework.Scenes
457 /// </summary> 643 /// </summary>
458 public SceneObjectGroup() 644 public SceneObjectGroup()
459 { 645 {
646
460 } 647 }
461 648
462 /// <summary> 649 /// <summary>
@@ -473,7 +660,7 @@ namespace OpenSim.Region.Framework.Scenes
473 /// Constructor. This object is added to the scene later via AttachToScene() 660 /// Constructor. This object is added to the scene later via AttachToScene()
474 /// </summary> 661 /// </summary>
475 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 662 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
476 { 663 {
477 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 664 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
478 } 665 }
479 666
@@ -504,13 +691,16 @@ namespace OpenSim.Region.Framework.Scenes
504 691
505 public void SetFromItemID(UUID AssetId) 692 public void SetFromItemID(UUID AssetId)
506 { 693 {
507 lock (m_parts) 694 lockPartsForRead(true);
508 { 695 {
509 foreach (SceneObjectPart part in m_parts.Values) 696 foreach (SceneObjectPart part in m_parts.Values)
510 { 697 {
698
511 part.FromItemID = AssetId; 699 part.FromItemID = AssetId;
700
512 } 701 }
513 } 702 }
703 lockPartsForRead(false);
514 } 704 }
515 705
516 public UUID GetFromItemID() 706 public UUID GetFromItemID()
@@ -523,6 +713,9 @@ namespace OpenSim.Region.Framework.Scenes
523 /// </summary> 713 /// </summary>
524 public virtual void AttachToBackup() 714 public virtual void AttachToBackup()
525 { 715 {
716 if (IsAttachment) return;
717 m_scene.SceneGraph.FireAttachToBackup(this);
718
526 if (InSceneBackup) 719 if (InSceneBackup)
527 { 720 {
528 //m_log.DebugFormat( 721 //m_log.DebugFormat(
@@ -579,7 +772,7 @@ namespace OpenSim.Region.Framework.Scenes
579 Vector3 maxScale = Vector3.Zero; 772 Vector3 maxScale = Vector3.Zero;
580 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 773 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
581 774
582 lock (m_parts) 775 lockPartsForRead(true);
583 { 776 {
584 foreach (SceneObjectPart part in m_parts.Values) 777 foreach (SceneObjectPart part in m_parts.Values)
585 { 778 {
@@ -593,8 +786,11 @@ namespace OpenSim.Region.Framework.Scenes
593 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; 786 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
594 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; 787 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
595 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; 788 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
789
596 } 790 }
597 } 791 }
792 lockPartsForRead(false);
793
598 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; 794 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
599 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; 795 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
600 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; 796 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
@@ -610,10 +806,11 @@ namespace OpenSim.Region.Framework.Scenes
610 806
611 EntityIntersection result = new EntityIntersection(); 807 EntityIntersection result = new EntityIntersection();
612 808
613 lock (m_parts) 809 lockPartsForRead(true);
614 { 810 {
615 foreach (SceneObjectPart part in m_parts.Values) 811 foreach (SceneObjectPart part in m_parts.Values)
616 { 812 {
813
617 // Temporary commented to stop compiler warning 814 // Temporary commented to stop compiler warning
618 //Vector3 partPosition = 815 //Vector3 partPosition =
619 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); 816 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
@@ -641,8 +838,10 @@ namespace OpenSim.Region.Framework.Scenes
641 result.distance = inter.distance; 838 result.distance = inter.distance;
642 } 839 }
643 } 840 }
841
644 } 842 }
645 } 843 }
844 lockPartsForRead(false);
646 return result; 845 return result;
647 } 846 }
648 847
@@ -661,10 +860,11 @@ namespace OpenSim.Region.Framework.Scenes
661 minY = 256f; 860 minY = 256f;
662 minZ = 8192f; 861 minZ = 8192f;
663 862
664 lock(m_parts); 863 lockPartsForRead(true);
665 { 864 {
666 foreach (SceneObjectPart part in m_parts.Values) 865 foreach (SceneObjectPart part in m_parts.Values)
667 { 866 {
867
668 Vector3 worldPos = part.GetWorldPosition(); 868 Vector3 worldPos = part.GetWorldPosition();
669 Vector3 offset = worldPos - AbsolutePosition; 869 Vector3 offset = worldPos - AbsolutePosition;
670 Quaternion worldRot; 870 Quaternion worldRot;
@@ -723,6 +923,8 @@ namespace OpenSim.Region.Framework.Scenes
723 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 923 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
724 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 924 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
725 925
926
927
726 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); 928 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
727 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); 929 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
728 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); 930 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
@@ -894,6 +1096,7 @@ namespace OpenSim.Region.Framework.Scenes
894 minZ = backBottomLeft.Z; 1096 minZ = backBottomLeft.Z;
895 } 1097 }
896 } 1098 }
1099 lockPartsForRead(false);
897 } 1100 }
898 1101
899 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) 1102 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
@@ -929,21 +1132,29 @@ namespace OpenSim.Region.Framework.Scenes
929 1132
930 public void SaveScriptedState(XmlTextWriter writer) 1133 public void SaveScriptedState(XmlTextWriter writer)
931 { 1134 {
1135 SaveScriptedState(writer, false);
1136 }
1137
1138 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1139 {
932 XmlDocument doc = new XmlDocument(); 1140 XmlDocument doc = new XmlDocument();
933 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1141 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
934 1142
935 // Capture script state while holding the lock 1143 // Capture script state while holding the lock
936 lock (m_parts) 1144 lockPartsForRead(true);
937 { 1145 {
938 foreach (SceneObjectPart part in m_parts.Values) 1146 foreach (SceneObjectPart part in m_parts.Values)
939 { 1147 {
940 Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); 1148
1149 Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(oldIDs);
941 foreach (UUID itemid in pstates.Keys) 1150 foreach (UUID itemid in pstates.Keys)
942 { 1151 {
943 states.Add(itemid, pstates[itemid]); 1152 states.Add(itemid, pstates[itemid]);
944 } 1153 }
1154
945 } 1155 }
946 } 1156 }
1157 lockPartsForRead(false);
947 1158
948 if (states.Count > 0) 1159 if (states.Count > 0)
949 { 1160 {
@@ -962,6 +1173,47 @@ namespace OpenSim.Region.Framework.Scenes
962 } 1173 }
963 1174
964 /// <summary> 1175 /// <summary>
1176 /// Add the avatar to this linkset (avatar is sat).
1177 /// </summary>
1178 /// <param name="agentID"></param>
1179 public void AddAvatar(UUID agentID)
1180 {
1181 ScenePresence presence;
1182 if (m_scene.TryGetScenePresence(agentID, out presence))
1183 {
1184 if (!m_linkedAvatars.Contains(presence))
1185 {
1186 m_linkedAvatars.Add(presence);
1187 }
1188 }
1189 }
1190
1191 /// <summary>
1192 /// Delete the avatar from this linkset (avatar is unsat).
1193 /// </summary>
1194 /// <param name="agentID"></param>
1195 public void DeleteAvatar(UUID agentID)
1196 {
1197 ScenePresence presence;
1198 if (m_scene.TryGetScenePresence(agentID, out presence))
1199 {
1200 if (m_linkedAvatars.Contains(presence))
1201 {
1202 m_linkedAvatars.Remove(presence);
1203 }
1204 }
1205 }
1206
1207 /// <summary>
1208 /// Returns the list of linked presences (avatars sat on this group)
1209 /// </summary>
1210 /// <param name="agentID"></param>
1211 public List<ScenePresence> GetLinkedAvatars()
1212 {
1213 return m_linkedAvatars;
1214 }
1215
1216 /// <summary>
965 /// Attach this scene object to the given avatar. 1217 /// Attach this scene object to the given avatar.
966 /// </summary> 1218 /// </summary>
967 /// <param name="agentID"></param> 1219 /// <param name="agentID"></param>
@@ -1112,13 +1364,16 @@ namespace OpenSim.Region.Framework.Scenes
1112 1364
1113 public override void UpdateMovement() 1365 public override void UpdateMovement()
1114 { 1366 {
1115 lock (m_parts) 1367 lockPartsForRead(true);
1116 { 1368 {
1117 foreach (SceneObjectPart part in m_parts.Values) 1369 foreach (SceneObjectPart part in m_parts.Values)
1118 { 1370 {
1371
1119 part.UpdateMovement(); 1372 part.UpdateMovement();
1373
1120 } 1374 }
1121 } 1375 }
1376 lockPartsForRead(false);
1122 } 1377 }
1123 1378
1124 public ushort GetTimeDilation() 1379 public ushort GetTimeDilation()
@@ -1162,7 +1417,7 @@ namespace OpenSim.Region.Framework.Scenes
1162 /// <param name="part"></param> 1417 /// <param name="part"></param>
1163 public void AddPart(SceneObjectPart part) 1418 public void AddPart(SceneObjectPart part)
1164 { 1419 {
1165 lock (m_parts) 1420 lockPartsForWrite(true);
1166 { 1421 {
1167 part.SetParent(this); 1422 part.SetParent(this);
1168 m_parts.Add(part.UUID, part); 1423 m_parts.Add(part.UUID, part);
@@ -1172,6 +1427,7 @@ namespace OpenSim.Region.Framework.Scenes
1172 if (part.LinkNum == 2 && RootPart != null) 1427 if (part.LinkNum == 2 && RootPart != null)
1173 RootPart.LinkNum = 1; 1428 RootPart.LinkNum = 1;
1174 } 1429 }
1430 lockPartsForWrite(false);
1175 } 1431 }
1176 1432
1177 /// <summary> 1433 /// <summary>
@@ -1179,28 +1435,33 @@ namespace OpenSim.Region.Framework.Scenes
1179 /// </summary> 1435 /// </summary>
1180 private void UpdateParentIDs() 1436 private void UpdateParentIDs()
1181 { 1437 {
1182 lock (m_parts) 1438 lockPartsForRead(true);
1183 { 1439 {
1184 foreach (SceneObjectPart part in m_parts.Values) 1440 foreach (SceneObjectPart part in m_parts.Values)
1185 { 1441 {
1442
1186 if (part.UUID != m_rootPart.UUID) 1443 if (part.UUID != m_rootPart.UUID)
1187 { 1444 {
1188 part.ParentID = m_rootPart.LocalId; 1445 part.ParentID = m_rootPart.LocalId;
1189 } 1446 }
1447
1190 } 1448 }
1191 } 1449 }
1450 lockPartsForRead(false);
1192 } 1451 }
1193 1452
1194 public void RegenerateFullIDs() 1453 public void RegenerateFullIDs()
1195 { 1454 {
1196 lock (m_parts) 1455 lockPartsForRead(true);
1197 { 1456 {
1198 foreach (SceneObjectPart part in m_parts.Values) 1457 foreach (SceneObjectPart part in m_parts.Values)
1199 { 1458 {
1459
1200 part.UUID = UUID.Random(); 1460 part.UUID = UUID.Random();
1201 1461
1202 } 1462 }
1203 } 1463 }
1464 lockPartsForRead(false);
1204 } 1465 }
1205 1466
1206 // helper provided for parts. 1467 // helper provided for parts.
@@ -1261,7 +1522,7 @@ namespace OpenSim.Region.Framework.Scenes
1261 1522
1262 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1523 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1263 { 1524 {
1264 part.StoreUndoState(); 1525 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1265 part.OnGrab(offsetPos, remoteClient); 1526 part.OnGrab(offsetPos, remoteClient);
1266 } 1527 }
1267 1528
@@ -1281,27 +1542,32 @@ namespace OpenSim.Region.Framework.Scenes
1281 1542
1282 DetachFromBackup(); 1543 DetachFromBackup();
1283 1544
1284 lock (m_parts) 1545 lockPartsForRead(true);
1546 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1547 lockPartsForRead(false);
1548
1549 foreach (SceneObjectPart part in values)
1285 { 1550 {
1286 foreach (SceneObjectPart part in m_parts.Values)
1287 {
1288// part.Inventory.RemoveScriptInstances(); 1551// part.Inventory.RemoveScriptInstances();
1289 Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1552
1553 Scene.ForEachScenePresence(delegate (ScenePresence sp)
1554 {
1555 if (sp.ParentID == LocalId)
1290 { 1556 {
1291 if (avatar.ParentID == LocalId) 1557 sp.StandUp();
1292 { 1558 }
1293 avatar.StandUp();
1294 }
1295 1559
1296 if (!silent) 1560 if (!silent)
1297 { 1561 {
1298 part.UpdateFlag = 0; 1562 part.UpdateFlag = 0;
1299 if (part == m_rootPart) 1563 if (part == m_rootPart)
1300 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); 1564 sp.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1301 } 1565 }
1302 }); 1566 });
1303 } 1567
1304 } 1568 }
1569
1570
1305 } 1571 }
1306 1572
1307 public void AddScriptLPS(int count) 1573 public void AddScriptLPS(int count)
@@ -1326,17 +1592,20 @@ namespace OpenSim.Region.Framework.Scenes
1326 1592
1327 scriptEvents aggregateScriptEvents = 0; 1593 scriptEvents aggregateScriptEvents = 0;
1328 1594
1329 lock (m_parts) 1595 lockPartsForRead(true);
1330 { 1596 {
1331 foreach (SceneObjectPart part in m_parts.Values) 1597 foreach (SceneObjectPart part in m_parts.Values)
1332 { 1598 {
1599
1333 if (part == null) 1600 if (part == null)
1334 continue; 1601 continue;
1335 if (part != RootPart) 1602 if (part != RootPart)
1336 part.Flags = objectflagupdate; 1603 part.Flags = objectflagupdate;
1337 aggregateScriptEvents |= part.AggregateScriptEvents; 1604 aggregateScriptEvents |= part.AggregateScriptEvents;
1605
1338 } 1606 }
1339 } 1607 }
1608 lockPartsForRead(false);
1340 1609
1341 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); 1610 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
1342 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); 1611 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
@@ -1378,42 +1647,52 @@ namespace OpenSim.Region.Framework.Scenes
1378 /// <param name="m_physicalPrim"></param> 1647 /// <param name="m_physicalPrim"></param>
1379 public void ApplyPhysics(bool m_physicalPrim) 1648 public void ApplyPhysics(bool m_physicalPrim)
1380 { 1649 {
1381 lock (m_parts) 1650 lockPartsForRead(true);
1651
1652 if (m_parts.Count > 1)
1382 { 1653 {
1383 if (m_parts.Count > 1) 1654 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1655 lockPartsForRead(false);
1656 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1657 foreach (SceneObjectPart part in values)
1384 { 1658 {
1385 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); 1659
1386 foreach (SceneObjectPart part in m_parts.Values) 1660 if (part.LocalId != m_rootPart.LocalId)
1387 { 1661 {
1388 if (part.LocalId != m_rootPart.LocalId) 1662 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1389 {
1390 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1391 }
1392 } 1663 }
1393 1664
1394 // Hack to get the physics scene geometries in the right spot
1395 ResetChildPrimPhysicsPositions();
1396 }
1397 else
1398 {
1399 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1400 } 1665 }
1666 // Hack to get the physics scene geometries in the right spot
1667 ResetChildPrimPhysicsPositions();
1668 }
1669 else
1670 {
1671 lockPartsForRead(false);
1672 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1401 } 1673 }
1402 } 1674 }
1403 1675
1404 public void SetOwnerId(UUID userId) 1676 public void SetOwnerId(UUID userId)
1405 { 1677 {
1406 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1678 ForEachPart(delegate(SceneObjectPart part)
1679 {
1680
1681 part.OwnerID = userId;
1682
1683 });
1407 } 1684 }
1408 1685
1409 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1686 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1410 { 1687 {
1411 lock (m_parts) 1688 lockPartsForRead(true);
1689 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1690 lockPartsForRead(false);
1691 foreach (SceneObjectPart part in values)
1412 { 1692 {
1413 foreach (SceneObjectPart part in m_parts.Values) 1693
1414 { 1694 whatToDo(part);
1415 whatToDo(part); 1695
1416 }
1417 } 1696 }
1418 } 1697 }
1419 1698
@@ -1436,7 +1715,10 @@ namespace OpenSim.Region.Framework.Scenes
1436 1715
1437 try 1716 try
1438 { 1717 {
1439 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1718 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1719 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1720 m_scene.LoadingPrims) // Land may not be valid yet
1721
1440 { 1722 {
1441 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1723 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1442 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1724 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1468,9 +1750,9 @@ namespace OpenSim.Region.Framework.Scenes
1468 // don't backup while it's selected or you're asking for changes mid stream. 1750 // don't backup while it's selected or you're asking for changes mid stream.
1469 if ((isTimeToPersist()) || (forcedBackup)) 1751 if ((isTimeToPersist()) || (forcedBackup))
1470 { 1752 {
1471 m_log.DebugFormat( 1753 // m_log.DebugFormat(
1472 "[SCENE]: Storing {0}, {1} in {2}", 1754 // "[SCENE]: Storing {0}, {1} in {2}",
1473 Name, UUID, m_scene.RegionInfo.RegionName); 1755 // Name, UUID, m_scene.RegionInfo.RegionName);
1474 1756
1475 SceneObjectGroup backup_group = Copy(false); 1757 SceneObjectGroup backup_group = Copy(false);
1476 backup_group.RootPart.Velocity = RootPart.Velocity; 1758 backup_group.RootPart.Velocity = RootPart.Velocity;
@@ -1512,15 +1794,17 @@ namespace OpenSim.Region.Framework.Scenes
1512 RootPart.SendFullUpdate( 1794 RootPart.SendFullUpdate(
1513 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); 1795 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
1514 1796
1515 lock (m_parts) 1797 lockPartsForRead(true);
1516 { 1798 {
1517 foreach (SceneObjectPart part in m_parts.Values) 1799 foreach (SceneObjectPart part in m_parts.Values)
1518 { 1800 {
1801
1519 if (part != RootPart) 1802 if (part != RootPart)
1520 part.SendFullUpdate( 1803 part.SendFullUpdate(
1521 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); 1804 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
1522 } 1805 }
1523 } 1806 }
1807 lockPartsForRead(false);
1524 } 1808 }
1525 1809
1526 #region Copying 1810 #region Copying
@@ -1532,86 +1816,114 @@ namespace OpenSim.Region.Framework.Scenes
1532 /// <returns></returns> 1816 /// <returns></returns>
1533 public SceneObjectGroup Copy(bool userExposed) 1817 public SceneObjectGroup Copy(bool userExposed)
1534 { 1818 {
1535 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1819 SceneObjectGroup dupe;
1536 dupe.m_isBackedUp = false; 1820 try
1537 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>(); 1821 {
1822 m_dupeInProgress = true;
1823 dupe = (SceneObjectGroup)MemberwiseClone();
1824 dupe.m_isBackedUp = false;
1825 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
1538 1826
1539 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1827 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1540 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1828 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1541 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1829 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1542 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1830 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1543 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1831 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1544 // then restore it's attachment state 1832 // then restore it's attachment state
1545 1833
1546 // This is only necessary when userExposed is false! 1834 // This is only necessary when userExposed is false!
1547 1835
1548 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1836 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1549
1550 if (!userExposed)
1551 dupe.RootPart.IsAttachment = true;
1552 1837
1553 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1838 if (!userExposed)
1839 dupe.RootPart.IsAttachment = true;
1554 1840
1555 if (!userExposed) 1841 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1556 {
1557 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1558 }
1559 1842
1560 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1843 if (!userExposed)
1561 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1844 {
1845 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1846 }
1562 1847
1563 if (userExposed) 1848 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1564 dupe.m_rootPart.TrimPermissions(); 1849 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1565 1850
1566 List<SceneObjectPart> partList; 1851 if (userExposed)
1852 dupe.m_rootPart.TrimPermissions();
1567 1853
1568 lock (m_parts) 1854 /// may need to create a new Physics actor.
1569 { 1855 if (dupe.RootPart.PhysActor != null && userExposed)
1570 partList = new List<SceneObjectPart>(m_parts.Values);
1571 }
1572
1573 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1574 { 1856 {
1575 return p1.LinkNum.CompareTo(p2.LinkNum); 1857 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1858
1859 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1860 dupe.RootPart.Name,
1861 pbs,
1862 dupe.RootPart.AbsolutePosition,
1863 dupe.RootPart.Scale,
1864 dupe.RootPart.RotationOffset,
1865 dupe.RootPart.PhysActor.IsPhysical);
1866
1867 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1868 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1576 } 1869 }
1577 );
1578 1870
1579 foreach (SceneObjectPart part in partList) 1871 lockPartsForRead(true);
1580 { 1872
1581 if (part.UUID != m_rootPart.UUID) 1873 List<SceneObjectPart> partList;
1874
1875 partList = new List<SceneObjectPart>(m_parts.Values);
1876
1877 lockPartsForRead(false);
1878
1879 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1880 {
1881 return p1.LinkNum.CompareTo(p2.LinkNum);
1882 }
1883 );
1884
1885 foreach (SceneObjectPart part in partList)
1582 { 1886 {
1583 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1887 if (part.UUID != m_rootPart.UUID)
1584 newPart.LinkNum = part.LinkNum; 1888 {
1585 } 1889 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1890
1891 newPart.LinkNum = part.LinkNum;
1892 }
1893
1894 // Need to duplicate the physics actor as well
1895 if (part.PhysActor != null && userExposed)
1896 {
1897 PrimitiveBaseShape pbs = part.Shape;
1898
1899 part.PhysActor
1900 = m_scene.PhysicsScene.AddPrimShape(
1901 part.Name,
1902 pbs,
1903 part.AbsolutePosition,
1904 part.Scale,
1905 part.RotationOffset,
1906 part.PhysActor.IsPhysical);
1907
1908 part.PhysActor.LocalID = part.LocalId;
1909 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1910 }
1586 1911
1587 // Need to duplicate the physics actor as well 1912 }
1588 if (part.PhysActor != null && userExposed) 1913 if (userExposed)
1589 { 1914 {
1590 PrimitiveBaseShape pbs = part.Shape; 1915 dupe.UpdateParentIDs();
1591 1916 dupe.HasGroupChanged = true;
1592 part.PhysActor 1917 dupe.AttachToBackup();
1593 = m_scene.PhysicsScene.AddPrimShape( 1918
1594 part.Name, 1919 ScheduleGroupForFullUpdate();
1595 pbs, 1920 }
1596 part.AbsolutePosition, 1921
1597 part.Scale,
1598 part.RotationOffset,
1599 part.PhysActor.IsPhysical);
1600
1601 part.PhysActor.LocalID = part.LocalId;
1602 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1603 }
1604 } 1922 }
1605 1923 finally
1606 if (userExposed)
1607 { 1924 {
1608 dupe.UpdateParentIDs(); 1925 m_dupeInProgress = false;
1609 dupe.HasGroupChanged = true;
1610 dupe.AttachToBackup();
1611
1612 ScheduleGroupForFullUpdate();
1613 } 1926 }
1614
1615 return dupe; 1927 return dupe;
1616 } 1928 }
1617 1929
@@ -1802,13 +2114,40 @@ namespace OpenSim.Region.Framework.Scenes
1802 } 2114 }
1803 } 2115 }
1804 2116
2117 public void rotLookAt(Quaternion target, float strength, float damping)
2118 {
2119 SceneObjectPart rootpart = m_rootPart;
2120 if (rootpart != null)
2121 {
2122 if (IsAttachment)
2123 {
2124 /*
2125 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2126 if (avatar != null)
2127 {
2128 Rotate the Av?
2129 } */
2130 }
2131 else
2132 {
2133 if (rootpart.PhysActor != null)
2134 { // APID must be implemented in your physics system for this to function.
2135 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2136 rootpart.PhysActor.APIDStrength = strength;
2137 rootpart.PhysActor.APIDDamping = damping;
2138 rootpart.PhysActor.APIDActive = true;
2139 }
2140 }
2141 }
2142 }
2143
1805 public void stopLookAt() 2144 public void stopLookAt()
1806 { 2145 {
1807 SceneObjectPart rootpart = m_rootPart; 2146 SceneObjectPart rootpart = m_rootPart;
1808 if (rootpart != null) 2147 if (rootpart != null)
1809 { 2148 {
1810 if (rootpart.PhysActor != null) 2149 if (rootpart.PhysActor != null)
1811 { 2150 { // APID must be implemented in your physics system for this to function.
1812 rootpart.PhysActor.APIDActive = false; 2151 rootpart.PhysActor.APIDActive = false;
1813 } 2152 }
1814 } 2153 }
@@ -1876,10 +2215,11 @@ namespace OpenSim.Region.Framework.Scenes
1876 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2215 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1877 newPart.SetParent(this); 2216 newPart.SetParent(this);
1878 2217
1879 lock (m_parts) 2218 lockPartsForWrite(true);
1880 { 2219 {
1881 m_parts.Add(newPart.UUID, newPart); 2220 m_parts.Add(newPart.UUID, newPart);
1882 } 2221 }
2222 lockPartsForWrite(false);
1883 2223
1884 SetPartAsNonRoot(newPart); 2224 SetPartAsNonRoot(newPart);
1885 2225
@@ -1942,7 +2282,7 @@ namespace OpenSim.Region.Framework.Scenes
1942 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) 2282 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1943 // return; 2283 // return;
1944 2284
1945 lock (m_parts) 2285 lockPartsForRead(true);
1946 { 2286 {
1947 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2287 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1948 2288
@@ -1962,9 +2302,12 @@ namespace OpenSim.Region.Framework.Scenes
1962 { 2302 {
1963 if (!IsSelected) 2303 if (!IsSelected)
1964 part.UpdateLookAt(); 2304 part.UpdateLookAt();
2305
1965 part.SendScheduledUpdates(); 2306 part.SendScheduledUpdates();
2307
1966 } 2308 }
1967 } 2309 }
2310 lockPartsForRead(false);
1968 } 2311 }
1969 2312
1970 public void ScheduleFullUpdateToAvatar(ScenePresence presence) 2313 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
@@ -1973,27 +2316,29 @@ namespace OpenSim.Region.Framework.Scenes
1973 2316
1974 RootPart.AddFullUpdateToAvatar(presence); 2317 RootPart.AddFullUpdateToAvatar(presence);
1975 2318
1976 lock (m_parts) 2319 lockPartsForRead(true);
1977 { 2320 {
1978 foreach (SceneObjectPart part in m_parts.Values) 2321 foreach (SceneObjectPart part in m_parts.Values)
1979 { 2322 {
2323
1980 if (part != RootPart) 2324 if (part != RootPart)
1981 part.AddFullUpdateToAvatar(presence); 2325 part.AddFullUpdateToAvatar(presence);
2326
1982 } 2327 }
1983 } 2328 }
2329 lockPartsForRead(false);
1984 } 2330 }
1985 2331
1986 public void ScheduleTerseUpdateToAvatar(ScenePresence presence) 2332 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1987 { 2333 {
1988// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); 2334 lockPartsForRead(true);
1989 2335
1990 lock (m_parts) 2336 foreach (SceneObjectPart part in m_parts.Values)
1991 { 2337 {
1992 foreach (SceneObjectPart part in m_parts.Values) 2338 part.AddTerseUpdateToAvatar(presence);
1993 {
1994 part.AddTerseUpdateToAvatar(presence);
1995 }
1996 } 2339 }
2340
2341 lockPartsForRead(false);
1997 } 2342 }
1998 2343
1999 /// <summary> 2344 /// <summary>
@@ -2007,14 +2352,17 @@ namespace OpenSim.Region.Framework.Scenes
2007 checkAtTargets(); 2352 checkAtTargets();
2008 RootPart.ScheduleFullUpdate(); 2353 RootPart.ScheduleFullUpdate();
2009 2354
2010 lock (m_parts) 2355 lockPartsForRead(true);
2011 { 2356 {
2012 foreach (SceneObjectPart part in m_parts.Values) 2357 foreach (SceneObjectPart part in m_parts.Values)
2013 { 2358 {
2359
2014 if (part != RootPart) 2360 if (part != RootPart)
2015 part.ScheduleFullUpdate(); 2361 part.ScheduleFullUpdate();
2362
2016 } 2363 }
2017 } 2364 }
2365 lockPartsForRead(false);
2018 } 2366 }
2019 2367
2020 /// <summary> 2368 /// <summary>
@@ -2022,37 +2370,38 @@ namespace OpenSim.Region.Framework.Scenes
2022 /// </summary> 2370 /// </summary>
2023 public void ScheduleGroupForTerseUpdate() 2371 public void ScheduleGroupForTerseUpdate()
2024 { 2372 {
2025// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); 2373 lockPartsForRead(true);
2026 2374 foreach (SceneObjectPart part in m_parts.Values)
2027 lock (m_parts)
2028 { 2375 {
2029 foreach (SceneObjectPart part in m_parts.Values) 2376 part.ScheduleTerseUpdate();
2030 {
2031 part.ScheduleTerseUpdate();
2032 }
2033 } 2377 }
2378
2379 lockPartsForRead(false);
2034 } 2380 }
2035 2381
2036 /// <summary> 2382 /// <summary>
2037 /// Immediately send a full update for this scene object. 2383 /// Immediately send a full update for this scene object.
2038 /// </summary> 2384 /// </summary>
2039 public void SendGroupFullUpdate() 2385 public void SendGroupFullUpdate()
2040 { 2386 {
2041 if (IsDeleted) 2387 if (IsDeleted)
2042 return; 2388 return;
2043 2389
2044// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2390// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2045 2391
2046 RootPart.SendFullUpdateToAllClients(); 2392 RootPart.SendFullUpdateToAllClients();
2047 2393
2048 lock (m_parts) 2394 lockPartsForRead(true);
2049 { 2395 {
2050 foreach (SceneObjectPart part in m_parts.Values) 2396 foreach (SceneObjectPart part in m_parts.Values)
2051 { 2397 {
2398
2052 if (part != RootPart) 2399 if (part != RootPart)
2053 part.SendFullUpdateToAllClients(); 2400 part.SendFullUpdateToAllClients();
2401
2054 } 2402 }
2055 } 2403 }
2404 lockPartsForRead(false);
2056 } 2405 }
2057 2406
2058 /// <summary> 2407 /// <summary>
@@ -2084,14 +2433,15 @@ namespace OpenSim.Region.Framework.Scenes
2084 { 2433 {
2085 if (IsDeleted) 2434 if (IsDeleted)
2086 return; 2435 return;
2087 2436
2088 lock (m_parts) 2437 lockPartsForRead(true);
2089 { 2438 {
2090 foreach (SceneObjectPart part in m_parts.Values) 2439 foreach (SceneObjectPart part in m_parts.Values)
2091 { 2440 {
2092 part.SendTerseUpdateToAllClients(); 2441 part.SendTerseUpdateToAllClients();
2093 } 2442 }
2094 } 2443 }
2444 lockPartsForRead(false);
2095 } 2445 }
2096 2446
2097 #endregion 2447 #endregion
@@ -2105,16 +2455,18 @@ namespace OpenSim.Region.Framework.Scenes
2105 /// <returns>null if no child part with that linknum or child part</returns> 2455 /// <returns>null if no child part with that linknum or child part</returns>
2106 public SceneObjectPart GetLinkNumPart(int linknum) 2456 public SceneObjectPart GetLinkNumPart(int linknum)
2107 { 2457 {
2108 lock (m_parts) 2458 lockPartsForRead(true);
2109 { 2459 {
2110 foreach (SceneObjectPart part in m_parts.Values) 2460 foreach (SceneObjectPart part in m_parts.Values)
2111 { 2461 {
2112 if (part.LinkNum == linknum) 2462 if (part.LinkNum == linknum)
2113 { 2463 {
2464 lockPartsForRead(false);
2114 return part; 2465 return part;
2115 } 2466 }
2116 } 2467 }
2117 } 2468 }
2469 lockPartsForRead(false);
2118 2470
2119 return null; 2471 return null;
2120 } 2472 }
@@ -2142,17 +2494,19 @@ namespace OpenSim.Region.Framework.Scenes
2142 public SceneObjectPart GetChildPart(uint localID) 2494 public SceneObjectPart GetChildPart(uint localID)
2143 { 2495 {
2144 //m_log.DebugFormat("Entered looking for {0}", localID); 2496 //m_log.DebugFormat("Entered looking for {0}", localID);
2145 lock (m_parts) 2497 lockPartsForRead(true);
2146 { 2498 {
2147 foreach (SceneObjectPart part in m_parts.Values) 2499 foreach (SceneObjectPart part in m_parts.Values)
2148 { 2500 {
2149 //m_log.DebugFormat("Found {0}", part.LocalId); 2501 //m_log.DebugFormat("Found {0}", part.LocalId);
2150 if (part.LocalId == localID) 2502 if (part.LocalId == localID)
2151 { 2503 {
2504 lockPartsForRead(false);
2152 return part; 2505 return part;
2153 } 2506 }
2154 } 2507 }
2155 } 2508 }
2509 lockPartsForRead(false);
2156 2510
2157 return null; 2511 return null;
2158 } 2512 }
@@ -2182,17 +2536,19 @@ namespace OpenSim.Region.Framework.Scenes
2182 public bool HasChildPrim(uint localID) 2536 public bool HasChildPrim(uint localID)
2183 { 2537 {
2184 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); 2538 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
2185 lock (m_parts) 2539 lockPartsForRead(true);
2186 { 2540 {
2187 foreach (SceneObjectPart part in m_parts.Values) 2541 foreach (SceneObjectPart part in m_parts.Values)
2188 { 2542 {
2189 //m_log.DebugFormat("Found {0}", part.LocalId); 2543 //m_log.DebugFormat("Found {0}", part.LocalId);
2190 if (part.LocalId == localID) 2544 if (part.LocalId == localID)
2191 { 2545 {
2546 lockPartsForRead(false);
2192 return true; 2547 return true;
2193 } 2548 }
2194 } 2549 }
2195 } 2550 }
2551 lockPartsForRead(false);
2196 2552
2197 return false; 2553 return false;
2198 } 2554 }
@@ -2242,53 +2598,57 @@ namespace OpenSim.Region.Framework.Scenes
2242 if (m_rootPart.LinkNum == 0) 2598 if (m_rootPart.LinkNum == 0)
2243 m_rootPart.LinkNum = 1; 2599 m_rootPart.LinkNum = 1;
2244 2600
2245 lock (m_parts) 2601 lockPartsForWrite(true);
2246 { 2602
2247 m_parts.Add(linkPart.UUID, linkPart); 2603 m_parts.Add(linkPart.UUID, linkPart);
2604
2605 lockPartsForWrite(false);
2248 2606
2249 // Insert in terms of link numbers, the new links 2607 // Insert in terms of link numbers, the new links
2250 // before the current ones (with the exception of 2608 // before the current ones (with the exception of
2251 // the root prim. Shuffle the old ones up 2609 // the root prim. Shuffle the old ones up
2252 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) 2610 lockPartsForRead(true);
2611 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
2612 {
2613 if (kvp.Value.LinkNum != 1)
2253 { 2614 {
2254 if (kvp.Value.LinkNum != 1) 2615 // Don't update root prim link number
2255 { 2616 kvp.Value.LinkNum += objectGroup.PrimCount;
2256 // Don't update root prim link number
2257 kvp.Value.LinkNum += objectGroup.PrimCount;
2258 }
2259 } 2617 }
2618 }
2619 lockPartsForRead(false);
2260 2620
2261 linkPart.LinkNum = 2; 2621 linkPart.LinkNum = 2;
2262 2622
2263 linkPart.SetParent(this); 2623 linkPart.SetParent(this);
2264 linkPart.CreateSelected = true; 2624 linkPart.CreateSelected = true;
2265 2625
2266 //if (linkPart.PhysActor != null) 2626 //if (linkPart.PhysActor != null)
2267 //{ 2627 //{
2268 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2628 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2269 2629
2270 //linkPart.PhysActor = null; 2630 //linkPart.PhysActor = null;
2271 //} 2631 //}
2272 2632
2273 //TODO: rest of parts 2633 //TODO: rest of parts
2274 int linkNum = 3; 2634 int linkNum = 3;
2275 foreach (SceneObjectPart part in objectGroup.Children.Values) 2635 foreach (SceneObjectPart part in objectGroup.Children.Values)
2636 {
2637 if (part.UUID != objectGroup.m_rootPart.UUID)
2276 { 2638 {
2277 if (part.UUID != objectGroup.m_rootPart.UUID) 2639 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2278 {
2279 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2280 }
2281 part.ClearUndoState();
2282 } 2640 }
2641 part.ClearUndoState();
2283 } 2642 }
2284 2643
2285 m_scene.UnlinkSceneObject(objectGroup.UUID, true); 2644 m_scene.UnlinkSceneObject(objectGroup.UUID, true);
2286 objectGroup.m_isDeleted = true; 2645 objectGroup.m_isDeleted = true;
2646
2647 objectGroup.lockPartsForWrite(true);
2287 2648
2288 lock (objectGroup.m_parts) 2649 objectGroup.m_parts.Clear();
2289 { 2650
2290 objectGroup.m_parts.Clear(); 2651 objectGroup.lockPartsForWrite(false);
2291 }
2292 2652
2293 // Can't do this yet since backup still makes use of the root part without any synchronization 2653 // Can't do this yet since backup still makes use of the root part without any synchronization
2294// objectGroup.m_rootPart = null; 2654// objectGroup.m_rootPart = null;
@@ -2358,11 +2718,12 @@ namespace OpenSim.Region.Framework.Scenes
2358 Quaternion worldRot = linkPart.GetWorldRotation(); 2718 Quaternion worldRot = linkPart.GetWorldRotation();
2359 2719
2360 // Remove the part from this object 2720 // Remove the part from this object
2361 lock (m_parts) 2721 lockPartsForWrite(true);
2362 { 2722 {
2363 m_parts.Remove(linkPart.UUID); 2723 m_parts.Remove(linkPart.UUID);
2364 } 2724 }
2365 2725 lockPartsForWrite(false);
2726 lockPartsForRead(true);
2366 if (m_parts.Count == 1 && RootPart != null) //Single prim is left 2727 if (m_parts.Count == 1 && RootPart != null) //Single prim is left
2367 RootPart.LinkNum = 0; 2728 RootPart.LinkNum = 0;
2368 else 2729 else
@@ -2373,6 +2734,7 @@ namespace OpenSim.Region.Framework.Scenes
2373 p.LinkNum--; 2734 p.LinkNum--;
2374 } 2735 }
2375 } 2736 }
2737 lockPartsForRead(false);
2376 2738
2377 linkPart.ParentID = 0; 2739 linkPart.ParentID = 0;
2378 linkPart.LinkNum = 0; 2740 linkPart.LinkNum = 0;
@@ -2416,6 +2778,8 @@ namespace OpenSim.Region.Framework.Scenes
2416 /// <param name="objectGroup"></param> 2778 /// <param name="objectGroup"></param>
2417 public virtual void DetachFromBackup() 2779 public virtual void DetachFromBackup()
2418 { 2780 {
2781 m_scene.SceneGraph.FireDetachFromBackup(this);
2782
2419 if (m_isBackedUp) 2783 if (m_isBackedUp)
2420 m_scene.EventManager.OnBackup -= ProcessBackup; 2784 m_scene.EventManager.OnBackup -= ProcessBackup;
2421 2785
@@ -2694,9 +3058,12 @@ namespace OpenSim.Region.Framework.Scenes
2694 3058
2695 if (selectionPart != null) 3059 if (selectionPart != null)
2696 { 3060 {
2697 lock (m_parts) 3061 lockPartsForRead(true);
3062 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
3063 lockPartsForRead(false);
3064 foreach (SceneObjectPart part in parts)
2698 { 3065 {
2699 foreach (SceneObjectPart part in m_parts.Values) 3066 if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
2700 { 3067 {
2701 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || 3068 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax ||
2702 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || 3069 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax ||
@@ -2706,12 +3073,13 @@ namespace OpenSim.Region.Framework.Scenes
2706 break; 3073 break;
2707 } 3074 }
2708 } 3075 }
3076 }
2709 3077
2710 foreach (SceneObjectPart part in m_parts.Values) 3078 foreach (SceneObjectPart part in parts)
2711 { 3079 {
2712 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3080 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2713 }
2714 } 3081 }
3082
2715 } 3083 }
2716 } 3084 }
2717 3085
@@ -2724,6 +3092,17 @@ namespace OpenSim.Region.Framework.Scenes
2724 } 3092 }
2725 } 3093 }
2726 3094
3095
3096
3097 /// <summary>
3098 /// Gets the number of parts
3099 /// </summary>
3100 /// <returns></returns>
3101 public int GetPartCount()
3102 {
3103 return Children.Count;
3104 }
3105
2727 /// <summary> 3106 /// <summary>
2728 /// Get the parts of this scene object 3107 /// Get the parts of this scene object
2729 /// </summary> 3108 /// </summary>
@@ -2797,11 +3176,9 @@ namespace OpenSim.Region.Framework.Scenes
2797 scale.Y = m_scene.m_maxNonphys; 3176 scale.Y = m_scene.m_maxNonphys;
2798 if (scale.Z > m_scene.m_maxNonphys) 3177 if (scale.Z > m_scene.m_maxNonphys)
2799 scale.Z = m_scene.m_maxNonphys; 3178 scale.Z = m_scene.m_maxNonphys;
2800
2801 SceneObjectPart part = GetChildPart(localID); 3179 SceneObjectPart part = GetChildPart(localID);
2802 if (part != null) 3180 if (part != null)
2803 { 3181 {
2804 part.Resize(scale);
2805 if (part.PhysActor != null) 3182 if (part.PhysActor != null)
2806 { 3183 {
2807 if (part.PhysActor.IsPhysical) 3184 if (part.PhysActor.IsPhysical)
@@ -2816,7 +3193,7 @@ namespace OpenSim.Region.Framework.Scenes
2816 part.PhysActor.Size = scale; 3193 part.PhysActor.Size = scale;
2817 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 3194 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2818 } 3195 }
2819 //if (part.UUID != m_rootPart.UUID) 3196 part.Resize(scale);
2820 3197
2821 HasGroupChanged = true; 3198 HasGroupChanged = true;
2822 ScheduleGroupForFullUpdate(); 3199 ScheduleGroupForFullUpdate();
@@ -2838,7 +3215,6 @@ namespace OpenSim.Region.Framework.Scenes
2838 SceneObjectPart part = GetChildPart(localID); 3215 SceneObjectPart part = GetChildPart(localID);
2839 if (part != null) 3216 if (part != null)
2840 { 3217 {
2841 part.IgnoreUndoUpdate = true;
2842 if (scale.X > m_scene.m_maxNonphys) 3218 if (scale.X > m_scene.m_maxNonphys)
2843 scale.X = m_scene.m_maxNonphys; 3219 scale.X = m_scene.m_maxNonphys;
2844 if (scale.Y > m_scene.m_maxNonphys) 3220 if (scale.Y > m_scene.m_maxNonphys)
@@ -2858,94 +3234,100 @@ namespace OpenSim.Region.Framework.Scenes
2858 float y = (scale.Y / part.Scale.Y); 3234 float y = (scale.Y / part.Scale.Y);
2859 float z = (scale.Z / part.Scale.Z); 3235 float z = (scale.Z / part.Scale.Z);
2860 3236
2861 lock (m_parts) 3237 lockPartsForRead(true);
3238 if (x > 1.0f || y > 1.0f || z > 1.0f)
2862 { 3239 {
2863 if (x > 1.0f || y > 1.0f || z > 1.0f) 3240 foreach (SceneObjectPart obPart in m_parts.Values)
2864 { 3241 {
2865 foreach (SceneObjectPart obPart in m_parts.Values) 3242 if (obPart.UUID != m_rootPart.UUID)
2866 { 3243 {
2867 if (obPart.UUID != m_rootPart.UUID) 3244 Vector3 oldSize = new Vector3(obPart.Scale);
2868 { 3245 obPart.IgnoreUndoUpdate = true;
2869 obPart.IgnoreUndoUpdate = true;
2870 Vector3 oldSize = new Vector3(obPart.Scale);
2871 3246
2872 float f = 1.0f; 3247 float f = 1.0f;
2873 float a = 1.0f; 3248 float a = 1.0f;
2874 3249
2875 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3250 if (part.PhysActor != null && part.PhysActor.IsPhysical)
3251 {
3252 if (oldSize.X*x > m_scene.m_maxPhys)
2876 { 3253 {
2877 if (oldSize.X*x > m_scene.m_maxPhys) 3254 f = m_scene.m_maxPhys / oldSize.X;
2878 { 3255 a = f / x;
2879 f = m_scene.m_maxPhys / oldSize.X; 3256 x *= a;
2880 a = f / x; 3257 y *= a;
2881 x *= a; 3258 z *= a;
2882 y *= a;
2883 z *= a;
2884 }
2885 if (oldSize.Y*y > m_scene.m_maxPhys)
2886 {
2887 f = m_scene.m_maxPhys / oldSize.Y;
2888 a = f / y;
2889 x *= a;
2890 y *= a;
2891 z *= a;
2892 }
2893 if (oldSize.Z*z > m_scene.m_maxPhys)
2894 {
2895 f = m_scene.m_maxPhys / oldSize.Z;
2896 a = f / z;
2897 x *= a;
2898 y *= a;
2899 z *= a;
2900 }
2901 } 3259 }
2902 else 3260 if (oldSize.Y*y > m_scene.m_maxPhys)
3261 {
3262 f = m_scene.m_maxPhys / oldSize.Y;
3263 a = f / y;
3264 x *= a;
3265 y *= a;
3266 z *= a;
3267 }
3268 if (oldSize.Z*z > m_scene.m_maxPhys)
3269 {
3270 f = m_scene.m_maxPhys / oldSize.Z;
3271 a = f / z;
3272 x *= a;
3273 y *= a;
3274 z *= a;
3275 }
3276 }
3277 else
3278 {
3279 if (oldSize.X*x > m_scene.m_maxNonphys)
3280 {
3281 f = m_scene.m_maxNonphys / oldSize.X;
3282 a = f / x;
3283 x *= a;
3284 y *= a;
3285 z *= a;
3286 }
3287 if (oldSize.Y*y > m_scene.m_maxNonphys)
2903 { 3288 {
2904 if (oldSize.X*x > m_scene.m_maxNonphys) 3289 f = m_scene.m_maxNonphys / oldSize.Y;
2905 { 3290 a = f / y;
2906 f = m_scene.m_maxNonphys / oldSize.X; 3291 x *= a;
2907 a = f / x; 3292 y *= a;
2908 x *= a; 3293 z *= a;
2909 y *= a;
2910 z *= a;
2911 }
2912 if (oldSize.Y*y > m_scene.m_maxNonphys)
2913 {
2914 f = m_scene.m_maxNonphys / oldSize.Y;
2915 a = f / y;
2916 x *= a;
2917 y *= a;
2918 z *= a;
2919 }
2920 if (oldSize.Z*z > m_scene.m_maxNonphys)
2921 {
2922 f = m_scene.m_maxNonphys / oldSize.Z;
2923 a = f / z;
2924 x *= a;
2925 y *= a;
2926 z *= a;
2927 }
2928 } 3294 }
2929 obPart.IgnoreUndoUpdate = false; 3295 if (oldSize.Z*z > m_scene.m_maxNonphys)
2930 obPart.StoreUndoState(); 3296 {
3297 f = m_scene.m_maxNonphys / oldSize.Z;
3298 a = f / z;
3299 x *= a;
3300 y *= a;
3301 z *= a;
3302 }
3303
2931 } 3304 }
2932 } 3305 }
2933 } 3306 }
2934 } 3307 }
3308 lockPartsForRead(false);
2935 3309
2936 Vector3 prevScale = part.Scale; 3310 Vector3 prevScale = part.Scale;
2937 prevScale.X *= x; 3311 prevScale.X *= x;
2938 prevScale.Y *= y; 3312 prevScale.Y *= y;
2939 prevScale.Z *= z; 3313 prevScale.Z *= z;;
3314
3315 part.IgnoreUndoUpdate = false;
3316 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3317 part.IgnoreUndoUpdate = true;
2940 part.Resize(prevScale); 3318 part.Resize(prevScale);
3319 part.IgnoreUndoUpdate = false;
2941 3320
2942 lock (m_parts) 3321 lockPartsForRead(true);
2943 { 3322 {
2944 foreach (SceneObjectPart obPart in m_parts.Values) 3323 foreach (SceneObjectPart obPart in m_parts.Values)
2945 { 3324 {
2946 obPart.IgnoreUndoUpdate = true;
2947 if (obPart.UUID != m_rootPart.UUID) 3325 if (obPart.UUID != m_rootPart.UUID)
2948 { 3326 {
3327 obPart.IgnoreUndoUpdate = false;
3328 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3329 obPart.IgnoreUndoUpdate = true;
3330
2949 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3331 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2950 currentpos.X *= x; 3332 currentpos.X *= x;
2951 currentpos.Y *= y; 3333 currentpos.Y *= y;
@@ -2958,9 +3340,9 @@ namespace OpenSim.Region.Framework.Scenes
2958 obPart.UpdateOffSet(currentpos); 3340 obPart.UpdateOffSet(currentpos);
2959 } 3341 }
2960 obPart.IgnoreUndoUpdate = false; 3342 obPart.IgnoreUndoUpdate = false;
2961 obPart.StoreUndoState();
2962 } 3343 }
2963 } 3344 }
3345 lockPartsForRead(false);
2964 3346
2965 if (part.PhysActor != null) 3347 if (part.PhysActor != null)
2966 { 3348 {
@@ -2969,7 +3351,6 @@ namespace OpenSim.Region.Framework.Scenes
2969 } 3351 }
2970 3352
2971 part.IgnoreUndoUpdate = false; 3353 part.IgnoreUndoUpdate = false;
2972 part.StoreUndoState();
2973 HasGroupChanged = true; 3354 HasGroupChanged = true;
2974 ScheduleGroupForTerseUpdate(); 3355 ScheduleGroupForTerseUpdate();
2975 } 3356 }
@@ -2985,14 +3366,11 @@ namespace OpenSim.Region.Framework.Scenes
2985 /// <param name="pos"></param> 3366 /// <param name="pos"></param>
2986 public void UpdateGroupPosition(Vector3 pos) 3367 public void UpdateGroupPosition(Vector3 pos)
2987 { 3368 {
2988 foreach (SceneObjectPart part in Children.Values)
2989 {
2990 part.StoreUndoState();
2991 }
2992 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3369 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2993 { 3370 {
2994 if (IsAttachment) 3371 if (IsAttachment)
2995 { 3372 {
3373 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2996 m_rootPart.AttachedPos = pos; 3374 m_rootPart.AttachedPos = pos;
2997 } 3375 }
2998 if (RootPart.GetStatusSandbox()) 3376 if (RootPart.GetStatusSandbox())
@@ -3025,7 +3403,7 @@ namespace OpenSim.Region.Framework.Scenes
3025 SceneObjectPart part = GetChildPart(localID); 3403 SceneObjectPart part = GetChildPart(localID);
3026 foreach (SceneObjectPart parts in Children.Values) 3404 foreach (SceneObjectPart parts in Children.Values)
3027 { 3405 {
3028 parts.StoreUndoState(); 3406 parts.StoreUndoState(UndoType.STATE_PRIM_POSITION);
3029 } 3407 }
3030 if (part != null) 3408 if (part != null)
3031 { 3409 {
@@ -3050,7 +3428,7 @@ namespace OpenSim.Region.Framework.Scenes
3050 { 3428 {
3051 foreach (SceneObjectPart part in Children.Values) 3429 foreach (SceneObjectPart part in Children.Values)
3052 { 3430 {
3053 part.StoreUndoState(); 3431 part.StoreUndoState(UndoType.STATE_PRIM_POSITION);
3054 } 3432 }
3055 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3433 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3056 Vector3 oldPos = 3434 Vector3 oldPos =
@@ -3063,7 +3441,7 @@ namespace OpenSim.Region.Framework.Scenes
3063 axDiff *= Quaternion.Inverse(partRotation); 3441 axDiff *= Quaternion.Inverse(partRotation);
3064 diff = axDiff; 3442 diff = axDiff;
3065 3443
3066 lock (m_parts) 3444 lockPartsForRead(true);
3067 { 3445 {
3068 foreach (SceneObjectPart obPart in m_parts.Values) 3446 foreach (SceneObjectPart obPart in m_parts.Values)
3069 { 3447 {
@@ -3073,11 +3451,29 @@ namespace OpenSim.Region.Framework.Scenes
3073 } 3451 }
3074 } 3452 }
3075 } 3453 }
3454 lockPartsForRead(false);
3076 3455
3077 AbsolutePosition = newPos; 3456 //We have to set undoing here because otherwise an undo state will be saved
3457 if (!m_rootPart.Undoing)
3458 {
3459 m_rootPart.Undoing = true;
3460 AbsolutePosition = newPos;
3461 m_rootPart.Undoing = false;
3462 }
3463 else
3464 {
3465 AbsolutePosition = newPos;
3466 }
3078 3467
3079 HasGroupChanged = true; 3468 HasGroupChanged = true;
3080 ScheduleGroupForTerseUpdate(); 3469 if (m_rootPart.Undoing)
3470 {
3471 ScheduleGroupForFullUpdate();
3472 }
3473 else
3474 {
3475 ScheduleGroupForTerseUpdate();
3476 }
3081 } 3477 }
3082 3478
3083 public void OffsetForNewRegion(Vector3 offset) 3479 public void OffsetForNewRegion(Vector3 offset)
@@ -3097,7 +3493,7 @@ namespace OpenSim.Region.Framework.Scenes
3097 { 3493 {
3098 foreach (SceneObjectPart parts in Children.Values) 3494 foreach (SceneObjectPart parts in Children.Values)
3099 { 3495 {
3100 parts.StoreUndoState(); 3496 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3101 } 3497 }
3102 m_rootPart.UpdateRotation(rot); 3498 m_rootPart.UpdateRotation(rot);
3103 3499
@@ -3121,7 +3517,7 @@ namespace OpenSim.Region.Framework.Scenes
3121 { 3517 {
3122 foreach (SceneObjectPart parts in Children.Values) 3518 foreach (SceneObjectPart parts in Children.Values)
3123 { 3519 {
3124 parts.StoreUndoState(); 3520 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3125 } 3521 }
3126 m_rootPart.UpdateRotation(rot); 3522 m_rootPart.UpdateRotation(rot);
3127 3523
@@ -3148,7 +3544,7 @@ namespace OpenSim.Region.Framework.Scenes
3148 SceneObjectPart part = GetChildPart(localID); 3544 SceneObjectPart part = GetChildPart(localID);
3149 foreach (SceneObjectPart parts in Children.Values) 3545 foreach (SceneObjectPart parts in Children.Values)
3150 { 3546 {
3151 parts.StoreUndoState(); 3547 parts.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3152 } 3548 }
3153 if (part != null) 3549 if (part != null)
3154 { 3550 {
@@ -3176,15 +3572,24 @@ namespace OpenSim.Region.Framework.Scenes
3176 if (part.UUID == m_rootPart.UUID) 3572 if (part.UUID == m_rootPart.UUID)
3177 { 3573 {
3178 UpdateRootRotation(rot); 3574 UpdateRootRotation(rot);
3179 AbsolutePosition = pos; 3575 if (!m_rootPart.Undoing)
3576 {
3577 m_rootPart.Undoing = true;
3578 AbsolutePosition = pos;
3579 m_rootPart.Undoing = false;
3580 }
3581 else
3582 {
3583 AbsolutePosition = pos;
3584 }
3180 } 3585 }
3181 else 3586 else
3182 { 3587 {
3588 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3183 part.IgnoreUndoUpdate = true; 3589 part.IgnoreUndoUpdate = true;
3184 part.UpdateRotation(rot); 3590 part.UpdateRotation(rot);
3185 part.OffsetPosition = pos; 3591 part.OffsetPosition = pos;
3186 part.IgnoreUndoUpdate = false; 3592 part.IgnoreUndoUpdate = false;
3187 part.StoreUndoState();
3188 } 3593 }
3189 } 3594 }
3190 } 3595 }
@@ -3198,7 +3603,13 @@ namespace OpenSim.Region.Framework.Scenes
3198 Quaternion axRot = rot; 3603 Quaternion axRot = rot;
3199 Quaternion oldParentRot = m_rootPart.RotationOffset; 3604 Quaternion oldParentRot = m_rootPart.RotationOffset;
3200 3605
3201 m_rootPart.StoreUndoState(); 3606 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3607 bool cancelUndo = false;
3608 if (!m_rootPart.Undoing)
3609 {
3610 m_rootPart.Undoing = true;
3611 cancelUndo = true;
3612 }
3202 m_rootPart.UpdateRotation(rot); 3613 m_rootPart.UpdateRotation(rot);
3203 if (m_rootPart.PhysActor != null) 3614 if (m_rootPart.PhysActor != null)
3204 { 3615 {
@@ -3206,33 +3617,31 @@ namespace OpenSim.Region.Framework.Scenes
3206 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 3617 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
3207 } 3618 }
3208 3619
3209 lock (m_parts) 3620 lockPartsForRead(true);
3621
3622 foreach (SceneObjectPart prim in m_parts.Values)
3210 { 3623 {
3211 foreach (SceneObjectPart prim in m_parts.Values) 3624 if (prim.UUID != m_rootPart.UUID)
3212 { 3625 {
3213 if (prim.UUID != m_rootPart.UUID) 3626 prim.IgnoreUndoUpdate = true;
3214 { 3627 Vector3 axPos = prim.OffsetPosition;
3215 prim.IgnoreUndoUpdate = true; 3628 axPos *= oldParentRot;
3216 Vector3 axPos = prim.OffsetPosition; 3629 axPos *= Quaternion.Inverse(axRot);
3217 axPos *= oldParentRot; 3630 prim.OffsetPosition = axPos;
3218 axPos *= Quaternion.Inverse(axRot); 3631 Quaternion primsRot = prim.RotationOffset;
3219 prim.OffsetPosition = axPos; 3632 Quaternion newRot = primsRot * oldParentRot;
3220 Quaternion primsRot = prim.RotationOffset; 3633 newRot *= Quaternion.Inverse(axRot);
3221 Quaternion newRot = primsRot * oldParentRot; 3634 prim.RotationOffset = newRot;
3222 newRot *= Quaternion.Inverse(axRot); 3635 prim.ScheduleTerseUpdate();
3223 prim.RotationOffset = newRot; 3636 prim.IgnoreUndoUpdate = false;
3224 prim.ScheduleTerseUpdate();
3225 }
3226 } 3637 }
3227 } 3638 }
3228 foreach (SceneObjectPart childpart in Children.Values) 3639 if (cancelUndo == true)
3229 { 3640 {
3230 if (childpart != m_rootPart) 3641 m_rootPart.Undoing = false;
3231 {
3232 childpart.IgnoreUndoUpdate = false;
3233 childpart.StoreUndoState();
3234 }
3235 } 3642 }
3643 lockPartsForRead(false);
3644
3236 m_rootPart.ScheduleTerseUpdate(); 3645 m_rootPart.ScheduleTerseUpdate();
3237 } 3646 }
3238 3647
@@ -3354,7 +3763,7 @@ namespace OpenSim.Region.Framework.Scenes
3354 if (atTargets.Count > 0) 3763 if (atTargets.Count > 0)
3355 { 3764 {
3356 uint[] localids = new uint[0]; 3765 uint[] localids = new uint[0];
3357 lock (m_parts) 3766 lockPartsForRead(true);
3358 { 3767 {
3359 localids = new uint[m_parts.Count]; 3768 localids = new uint[m_parts.Count];
3360 int cntr = 0; 3769 int cntr = 0;
@@ -3364,6 +3773,7 @@ namespace OpenSim.Region.Framework.Scenes
3364 cntr++; 3773 cntr++;
3365 } 3774 }
3366 } 3775 }
3776 lockPartsForRead(false);
3367 3777
3368 for (int ctr = 0; ctr < localids.Length; ctr++) 3778 for (int ctr = 0; ctr < localids.Length; ctr++)
3369 { 3779 {
@@ -3382,7 +3792,7 @@ namespace OpenSim.Region.Framework.Scenes
3382 { 3792 {
3383 //trigger not_at_target 3793 //trigger not_at_target
3384 uint[] localids = new uint[0]; 3794 uint[] localids = new uint[0];
3385 lock (m_parts) 3795 lockPartsForRead(true);
3386 { 3796 {
3387 localids = new uint[m_parts.Count]; 3797 localids = new uint[m_parts.Count];
3388 int cntr = 0; 3798 int cntr = 0;
@@ -3392,7 +3802,8 @@ namespace OpenSim.Region.Framework.Scenes
3392 cntr++; 3802 cntr++;
3393 } 3803 }
3394 } 3804 }
3395 3805 lockPartsForRead(false);
3806
3396 for (int ctr = 0; ctr < localids.Length; ctr++) 3807 for (int ctr = 0; ctr < localids.Length; ctr++)
3397 { 3808 {
3398 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); 3809 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
@@ -3433,7 +3844,8 @@ namespace OpenSim.Region.Framework.Scenes
3433 if (atRotTargets.Count > 0) 3844 if (atRotTargets.Count > 0)
3434 { 3845 {
3435 uint[] localids = new uint[0]; 3846 uint[] localids = new uint[0];
3436 lock (m_parts) 3847 lockPartsForRead(true);
3848 try
3437 { 3849 {
3438 localids = new uint[m_parts.Count]; 3850 localids = new uint[m_parts.Count];
3439 int cntr = 0; 3851 int cntr = 0;
@@ -3443,6 +3855,10 @@ namespace OpenSim.Region.Framework.Scenes
3443 cntr++; 3855 cntr++;
3444 } 3856 }
3445 } 3857 }
3858 finally
3859 {
3860 lockPartsForRead(false);
3861 }
3446 3862
3447 for (int ctr = 0; ctr < localids.Length; ctr++) 3863 for (int ctr = 0; ctr < localids.Length; ctr++)
3448 { 3864 {
@@ -3461,7 +3877,8 @@ namespace OpenSim.Region.Framework.Scenes
3461 { 3877 {
3462 //trigger not_at_target 3878 //trigger not_at_target
3463 uint[] localids = new uint[0]; 3879 uint[] localids = new uint[0];
3464 lock (m_parts) 3880 lockPartsForRead(true);
3881 try
3465 { 3882 {
3466 localids = new uint[m_parts.Count]; 3883 localids = new uint[m_parts.Count];
3467 int cntr = 0; 3884 int cntr = 0;
@@ -3471,6 +3888,10 @@ namespace OpenSim.Region.Framework.Scenes
3471 cntr++; 3888 cntr++;
3472 } 3889 }
3473 } 3890 }
3891 finally
3892 {
3893 lockPartsForRead(false);
3894 }
3474 3895
3475 for (int ctr = 0; ctr < localids.Length; ctr++) 3896 for (int ctr = 0; ctr < localids.Length; ctr++)
3476 { 3897 {
@@ -3484,19 +3905,20 @@ namespace OpenSim.Region.Framework.Scenes
3484 public float GetMass() 3905 public float GetMass()
3485 { 3906 {
3486 float retmass = 0f; 3907 float retmass = 0f;
3487 lock (m_parts) 3908 lockPartsForRead(true);
3488 { 3909 {
3489 foreach (SceneObjectPart part in m_parts.Values) 3910 foreach (SceneObjectPart part in m_parts.Values)
3490 { 3911 {
3491 retmass += part.GetMass(); 3912 retmass += part.GetMass();
3492 } 3913 }
3493 } 3914 }
3915 lockPartsForRead(false);
3494 return retmass; 3916 return retmass;
3495 } 3917 }
3496 3918
3497 public void CheckSculptAndLoad() 3919 public void CheckSculptAndLoad()
3498 { 3920 {
3499 lock (m_parts) 3921 lockPartsForRead(true);
3500 { 3922 {
3501 if (!IsDeleted) 3923 if (!IsDeleted)
3502 { 3924 {
@@ -3521,6 +3943,7 @@ namespace OpenSim.Region.Framework.Scenes
3521 } 3943 }
3522 } 3944 }
3523 } 3945 }
3946 lockPartsForRead(false);
3524 } 3947 }
3525 3948
3526 protected void AssetReceived(string id, Object sender, AssetBase asset) 3949 protected void AssetReceived(string id, Object sender, AssetBase asset)
@@ -3541,7 +3964,7 @@ namespace OpenSim.Region.Framework.Scenes
3541 /// <param name="client"></param> 3964 /// <param name="client"></param>
3542 public void SetGroup(UUID GroupID, IClientAPI client) 3965 public void SetGroup(UUID GroupID, IClientAPI client)
3543 { 3966 {
3544 lock (m_parts) 3967 lockPartsForRead(true);
3545 { 3968 {
3546 foreach (SceneObjectPart part in m_parts.Values) 3969 foreach (SceneObjectPart part in m_parts.Values)
3547 { 3970 {
@@ -3551,6 +3974,7 @@ namespace OpenSim.Region.Framework.Scenes
3551 3974
3552 HasGroupChanged = true; 3975 HasGroupChanged = true;
3553 } 3976 }
3977 lockPartsForRead(false);
3554 3978
3555 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 3979 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
3556 // for the same object with very different properties. The caller must schedule the update. 3980 // for the same object with very different properties. The caller must schedule the update.
@@ -3572,11 +3996,12 @@ namespace OpenSim.Region.Framework.Scenes
3572 3996
3573 public void SetAttachmentPoint(byte point) 3997 public void SetAttachmentPoint(byte point)
3574 { 3998 {
3575 lock (m_parts) 3999 lockPartsForRead(true);
3576 { 4000 {
3577 foreach (SceneObjectPart part in m_parts.Values) 4001 foreach (SceneObjectPart part in m_parts.Values)
3578 part.SetAttachmentPoint(point); 4002 part.SetAttachmentPoint(point);
3579 } 4003 }
4004 lockPartsForRead(false);
3580 } 4005 }
3581 4006
3582 #region ISceneObject 4007 #region ISceneObject
@@ -3610,6 +4035,14 @@ namespace OpenSim.Region.Framework.Scenes
3610 SetFromItemID(uuid); 4035 SetFromItemID(uuid);
3611 } 4036 }
3612 4037
4038 public void ResetOwnerChangeFlag()
4039 {
4040 ForEachPart(delegate(SceneObjectPart part)
4041 {
4042 part.ResetOwnerChangeFlag();
4043 });
4044 }
4045
3613 #endregion 4046 #endregion
3614 } 4047 }
3615} 4048}