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.cs1152
1 files changed, 825 insertions, 327 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 64a6dd5..5a586d4 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
@@ -261,13 +422,16 @@ namespace OpenSim.Region.Framework.Scenes
261 set 422 set
262 { 423 {
263 m_regionHandle = value; 424 m_regionHandle = value;
264 lock (m_parts) 425 lockPartsForRead(true);
265 { 426 {
266 foreach (SceneObjectPart part in m_parts.Values) 427 foreach (SceneObjectPart part in m_parts.Values)
267 { 428 {
429
268 part.RegionHandle = m_regionHandle; 430 part.RegionHandle = m_regionHandle;
431
269 } 432 }
270 } 433 }
434 lockPartsForRead(false);
271 } 435 }
272 } 436 }
273 437
@@ -301,7 +465,12 @@ namespace OpenSim.Region.Framework.Scenes
301 { 465 {
302 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 466 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
303 } 467 }
304 468
469 lockPartsForRead(true);
470 foreach (SceneObjectPart part in m_parts.Values)
471 {
472 part.IgnoreUndoUpdate = true;
473 }
305 if (RootPart.GetStatusSandbox()) 474 if (RootPart.GetStatusSandbox())
306 { 475 {
307 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 476 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -309,15 +478,30 @@ namespace OpenSim.Region.Framework.Scenes
309 RootPart.ScriptSetPhysicsStatus(false); 478 RootPart.ScriptSetPhysicsStatus(false);
310 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), 479 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
311 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); 480 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
481 lockPartsForRead(false);
312 return; 482 return;
313 } 483 }
314 } 484 }
315 485 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
316 lock (m_parts) 486 lockPartsForRead(false);
487 foreach (SceneObjectPart part in parts)
317 { 488 {
318 foreach (SceneObjectPart part in m_parts.Values) 489 part.IgnoreUndoUpdate = false;
490 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
491 part.GroupPosition = val;
492 if (!m_dupeInProgress)
319 { 493 {
320 part.GroupPosition = val; 494 part.TriggerScriptChangedEvent(Changed.POSITION);
495 }
496 }
497 if (!m_dupeInProgress)
498 {
499 foreach (ScenePresence av in m_linkedAvatars)
500 {
501 Vector3 offset = m_parts[av.LinkedPrim].GetWorldPosition() - av.ParentPosition;
502 av.AbsolutePosition += offset;
503 av.ParentPosition = m_parts[av.LinkedPrim].GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
504 av.SendFullUpdateToAllClients();
321 } 505 }
322 } 506 }
323 507
@@ -471,6 +655,7 @@ namespace OpenSim.Region.Framework.Scenes
471 /// </summary> 655 /// </summary>
472 public SceneObjectGroup() 656 public SceneObjectGroup()
473 { 657 {
658
474 } 659 }
475 660
476 /// <summary> 661 /// <summary>
@@ -487,7 +672,7 @@ namespace OpenSim.Region.Framework.Scenes
487 /// Constructor. This object is added to the scene later via AttachToScene() 672 /// Constructor. This object is added to the scene later via AttachToScene()
488 /// </summary> 673 /// </summary>
489 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 674 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
490 { 675 {
491 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 676 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
492 } 677 }
493 678
@@ -518,13 +703,16 @@ namespace OpenSim.Region.Framework.Scenes
518 703
519 public void SetFromItemID(UUID AssetId) 704 public void SetFromItemID(UUID AssetId)
520 { 705 {
521 lock (m_parts) 706 lockPartsForRead(true);
522 { 707 {
523 foreach (SceneObjectPart part in m_parts.Values) 708 foreach (SceneObjectPart part in m_parts.Values)
524 { 709 {
710
525 part.FromItemID = AssetId; 711 part.FromItemID = AssetId;
712
526 } 713 }
527 } 714 }
715 lockPartsForRead(false);
528 } 716 }
529 717
530 public UUID GetFromItemID() 718 public UUID GetFromItemID()
@@ -537,6 +725,9 @@ namespace OpenSim.Region.Framework.Scenes
537 /// </summary> 725 /// </summary>
538 public virtual void AttachToBackup() 726 public virtual void AttachToBackup()
539 { 727 {
728 if (IsAttachment) return;
729 m_scene.SceneGraph.FireAttachToBackup(this);
730
540 if (InSceneBackup) 731 if (InSceneBackup)
541 { 732 {
542 //m_log.DebugFormat( 733 //m_log.DebugFormat(
@@ -595,7 +786,7 @@ namespace OpenSim.Region.Framework.Scenes
595 Vector3 maxScale = Vector3.Zero; 786 Vector3 maxScale = Vector3.Zero;
596 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 787 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
597 788
598 lock (m_parts) 789 lockPartsForRead(true);
599 { 790 {
600 foreach (SceneObjectPart part in m_parts.Values) 791 foreach (SceneObjectPart part in m_parts.Values)
601 { 792 {
@@ -609,8 +800,11 @@ namespace OpenSim.Region.Framework.Scenes
609 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; 800 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
610 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; 801 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
611 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; 802 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
803
612 } 804 }
613 } 805 }
806 lockPartsForRead(false);
807
614 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; 808 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
615 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; 809 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
616 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; 810 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
@@ -626,10 +820,11 @@ namespace OpenSim.Region.Framework.Scenes
626 820
627 EntityIntersection result = new EntityIntersection(); 821 EntityIntersection result = new EntityIntersection();
628 822
629 lock (m_parts) 823 lockPartsForRead(true);
630 { 824 {
631 foreach (SceneObjectPart part in m_parts.Values) 825 foreach (SceneObjectPart part in m_parts.Values)
632 { 826 {
827
633 // Temporary commented to stop compiler warning 828 // Temporary commented to stop compiler warning
634 //Vector3 partPosition = 829 //Vector3 partPosition =
635 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); 830 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
@@ -657,8 +852,10 @@ namespace OpenSim.Region.Framework.Scenes
657 result.distance = inter.distance; 852 result.distance = inter.distance;
658 } 853 }
659 } 854 }
855
660 } 856 }
661 } 857 }
858 lockPartsForRead(false);
662 return result; 859 return result;
663 } 860 }
664 861
@@ -677,10 +874,11 @@ namespace OpenSim.Region.Framework.Scenes
677 minY = 256f; 874 minY = 256f;
678 minZ = 8192f; 875 minZ = 8192f;
679 876
680 lock(m_parts) 877 lockPartsForRead(true);
681 { 878 {
682 foreach (SceneObjectPart part in m_parts.Values) 879 foreach (SceneObjectPart part in m_parts.Values)
683 { 880 {
881
684 Vector3 worldPos = part.GetWorldPosition(); 882 Vector3 worldPos = part.GetWorldPosition();
685 Vector3 offset = worldPos - AbsolutePosition; 883 Vector3 offset = worldPos - AbsolutePosition;
686 Quaternion worldRot; 884 Quaternion worldRot;
@@ -739,6 +937,8 @@ namespace OpenSim.Region.Framework.Scenes
739 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 937 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
740 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 938 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
741 939
940
941
742 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); 942 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
743 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); 943 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
744 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); 944 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
@@ -910,6 +1110,7 @@ namespace OpenSim.Region.Framework.Scenes
910 minZ = backBottomLeft.Z; 1110 minZ = backBottomLeft.Z;
911 } 1111 }
912 } 1112 }
1113 lockPartsForRead(false);
913 } 1114 }
914 1115
915 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) 1116 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
@@ -945,21 +1146,29 @@ namespace OpenSim.Region.Framework.Scenes
945 1146
946 public void SaveScriptedState(XmlTextWriter writer) 1147 public void SaveScriptedState(XmlTextWriter writer)
947 { 1148 {
1149 SaveScriptedState(writer, false);
1150 }
1151
1152 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1153 {
948 XmlDocument doc = new XmlDocument(); 1154 XmlDocument doc = new XmlDocument();
949 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1155 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
950 1156
951 // Capture script state while holding the lock 1157 // Capture script state while holding the lock
952 lock (m_parts) 1158 lockPartsForRead(true);
953 { 1159 {
954 foreach (SceneObjectPart part in m_parts.Values) 1160 foreach (SceneObjectPart part in m_parts.Values)
955 { 1161 {
956 Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); 1162
1163 Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(oldIDs);
957 foreach (UUID itemid in pstates.Keys) 1164 foreach (UUID itemid in pstates.Keys)
958 { 1165 {
959 states.Add(itemid, pstates[itemid]); 1166 states.Add(itemid, pstates[itemid]);
960 } 1167 }
1168
961 } 1169 }
962 } 1170 }
1171 lockPartsForRead(false);
963 1172
964 if (states.Count > 0) 1173 if (states.Count > 0)
965 { 1174 {
@@ -977,6 +1186,118 @@ namespace OpenSim.Region.Framework.Scenes
977 } 1186 }
978 } 1187 }
979 1188
1189 /// <summary>
1190 /// Add the avatar to this linkset (avatar is sat).
1191 /// </summary>
1192 /// <param name="agentID"></param>
1193 public void AddAvatar(UUID agentID)
1194 {
1195 ScenePresence presence;
1196 if (m_scene.TryGetScenePresence(agentID, out presence))
1197 {
1198 if (!m_linkedAvatars.Contains(presence))
1199 {
1200 m_linkedAvatars.Add(presence);
1201 }
1202 }
1203 }
1204
1205 /// <summary>
1206 /// Delete the avatar from this linkset (avatar is unsat).
1207 /// </summary>
1208 /// <param name="agentID"></param>
1209 public void DeleteAvatar(UUID agentID)
1210 {
1211 ScenePresence presence;
1212 if (m_scene.TryGetScenePresence(agentID, out presence))
1213 {
1214 if (m_linkedAvatars.Contains(presence))
1215 {
1216 m_linkedAvatars.Remove(presence);
1217 }
1218 }
1219 }
1220
1221 /// <summary>
1222 /// Returns the list of linked presences (avatars sat on this group)
1223 /// </summary>
1224 /// <param name="agentID"></param>
1225 public List<ScenePresence> GetLinkedAvatars()
1226 {
1227 return m_linkedAvatars;
1228 }
1229
1230 /// <summary>
1231 /// Attach this scene object to the given avatar.
1232 /// </summary>
1233 /// <param name="agentID"></param>
1234 /// <param name="attachmentpoint"></param>
1235 /// <param name="AttachOffset"></param>
1236 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1237 {
1238 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1239 if (avatar != null)
1240 {
1241 // don't attach attachments to child agents
1242 if (avatar.IsChildAgent) return;
1243
1244// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1245
1246 DetachFromBackup();
1247
1248 // Remove from database and parcel prim count
1249 m_scene.DeleteFromStorage(UUID);
1250 m_scene.EventManager.TriggerParcelPrimCountTainted();
1251
1252 m_rootPart.AttachedAvatar = agentID;
1253
1254 //Anakin Lohner bug #3839
1255 lock (m_parts)
1256 {
1257 foreach (SceneObjectPart p in m_parts.Values)
1258 {
1259 p.AttachedAvatar = agentID;
1260 }
1261 }
1262
1263 if (m_rootPart.PhysActor != null)
1264 {
1265 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1266 m_rootPart.PhysActor = null;
1267 }
1268
1269 AbsolutePosition = AttachOffset;
1270 m_rootPart.AttachedPos = AttachOffset;
1271 m_rootPart.IsAttachment = true;
1272
1273 m_rootPart.SetParentLocalId(avatar.LocalId);
1274 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1275
1276 avatar.AddAttachment(this);
1277
1278 if (!silent)
1279 {
1280 // Killing it here will cause the client to deselect it
1281 // It then reappears on the avatar, deselected
1282 // through the full update below
1283 //
1284 if (IsSelected)
1285 {
1286 m_scene.SendKillObject(m_rootPart.LocalId);
1287 }
1288
1289 IsSelected = false; // fudge....
1290 ScheduleGroupForFullUpdate();
1291 }
1292 }
1293 else
1294 {
1295 m_log.WarnFormat(
1296 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1297 UUID, agentID, Scene.RegionInfo.RegionName);
1298 }
1299 }
1300
980 public byte GetAttachmentPoint() 1301 public byte GetAttachmentPoint()
981 { 1302 {
982 return m_rootPart.Shape.State; 1303 return m_rootPart.Shape.State;
@@ -1068,13 +1389,16 @@ namespace OpenSim.Region.Framework.Scenes
1068 1389
1069 public override void UpdateMovement() 1390 public override void UpdateMovement()
1070 { 1391 {
1071 lock (m_parts) 1392 lockPartsForRead(true);
1072 { 1393 {
1073 foreach (SceneObjectPart part in m_parts.Values) 1394 foreach (SceneObjectPart part in m_parts.Values)
1074 { 1395 {
1396
1075 part.UpdateMovement(); 1397 part.UpdateMovement();
1398
1076 } 1399 }
1077 } 1400 }
1401 lockPartsForRead(false);
1078 } 1402 }
1079 1403
1080 public ushort GetTimeDilation() 1404 public ushort GetTimeDilation()
@@ -1117,7 +1441,7 @@ namespace OpenSim.Region.Framework.Scenes
1117 /// <param name="part"></param> 1441 /// <param name="part"></param>
1118 public void AddPart(SceneObjectPart part) 1442 public void AddPart(SceneObjectPart part)
1119 { 1443 {
1120 lock (m_parts) 1444 lockPartsForWrite(true);
1121 { 1445 {
1122 part.SetParent(this); 1446 part.SetParent(this);
1123 m_parts.Add(part.UUID, part); 1447 m_parts.Add(part.UUID, part);
@@ -1127,6 +1451,7 @@ namespace OpenSim.Region.Framework.Scenes
1127 if (part.LinkNum == 2 && RootPart != null) 1451 if (part.LinkNum == 2 && RootPart != null)
1128 RootPart.LinkNum = 1; 1452 RootPart.LinkNum = 1;
1129 } 1453 }
1454 lockPartsForWrite(false);
1130 } 1455 }
1131 1456
1132 /// <summary> 1457 /// <summary>
@@ -1134,28 +1459,33 @@ namespace OpenSim.Region.Framework.Scenes
1134 /// </summary> 1459 /// </summary>
1135 private void UpdateParentIDs() 1460 private void UpdateParentIDs()
1136 { 1461 {
1137 lock (m_parts) 1462 lockPartsForRead(true);
1138 { 1463 {
1139 foreach (SceneObjectPart part in m_parts.Values) 1464 foreach (SceneObjectPart part in m_parts.Values)
1140 { 1465 {
1466
1141 if (part.UUID != m_rootPart.UUID) 1467 if (part.UUID != m_rootPart.UUID)
1142 { 1468 {
1143 part.ParentID = m_rootPart.LocalId; 1469 part.ParentID = m_rootPart.LocalId;
1144 } 1470 }
1471
1145 } 1472 }
1146 } 1473 }
1474 lockPartsForRead(false);
1147 } 1475 }
1148 1476
1149 public void RegenerateFullIDs() 1477 public void RegenerateFullIDs()
1150 { 1478 {
1151 lock (m_parts) 1479 lockPartsForRead(true);
1152 { 1480 {
1153 foreach (SceneObjectPart part in m_parts.Values) 1481 foreach (SceneObjectPart part in m_parts.Values)
1154 { 1482 {
1483
1155 part.UUID = UUID.Random(); 1484 part.UUID = UUID.Random();
1156 1485
1157 } 1486 }
1158 } 1487 }
1488 lockPartsForRead(false);
1159 } 1489 }
1160 1490
1161 // helper provided for parts. 1491 // helper provided for parts.
@@ -1216,7 +1546,7 @@ namespace OpenSim.Region.Framework.Scenes
1216 1546
1217 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1547 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1218 { 1548 {
1219 part.StoreUndoState(); 1549 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1220 part.OnGrab(offsetPos, remoteClient); 1550 part.OnGrab(offsetPos, remoteClient);
1221 } 1551 }
1222 1552
@@ -1236,27 +1566,32 @@ namespace OpenSim.Region.Framework.Scenes
1236 1566
1237 DetachFromBackup(); 1567 DetachFromBackup();
1238 1568
1239 lock (m_parts) 1569 lockPartsForRead(true);
1570 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1571 lockPartsForRead(false);
1572
1573 foreach (SceneObjectPart part in values)
1240 { 1574 {
1241 foreach (SceneObjectPart part in m_parts.Values)
1242 {
1243// part.Inventory.RemoveScriptInstances(); 1575// part.Inventory.RemoveScriptInstances();
1244 Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1576
1577 Scene.ForEachScenePresence(delegate (ScenePresence sp)
1578 {
1579 if (sp.ParentID == LocalId)
1245 { 1580 {
1246 if (avatar.ParentID == LocalId) 1581 sp.StandUp();
1247 { 1582 }
1248 avatar.StandUp();
1249 }
1250 1583
1251 if (!silent) 1584 if (!silent)
1252 { 1585 {
1253 part.UpdateFlag = 0; 1586 part.UpdateFlag = 0;
1254 if (part == m_rootPart) 1587 if (part == m_rootPart)
1255 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); 1588 sp.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1256 } 1589 }
1257 }); 1590 });
1258 } 1591
1259 } 1592 }
1593
1594
1260 } 1595 }
1261 1596
1262 public void AddScriptLPS(int count) 1597 public void AddScriptLPS(int count)
@@ -1281,17 +1616,20 @@ namespace OpenSim.Region.Framework.Scenes
1281 1616
1282 scriptEvents aggregateScriptEvents = 0; 1617 scriptEvents aggregateScriptEvents = 0;
1283 1618
1284 lock (m_parts) 1619 lockPartsForRead(true);
1285 { 1620 {
1286 foreach (SceneObjectPart part in m_parts.Values) 1621 foreach (SceneObjectPart part in m_parts.Values)
1287 { 1622 {
1623
1288 if (part == null) 1624 if (part == null)
1289 continue; 1625 continue;
1290 if (part != RootPart) 1626 if (part != RootPart)
1291 part.Flags = objectflagupdate; 1627 part.Flags = objectflagupdate;
1292 aggregateScriptEvents |= part.AggregateScriptEvents; 1628 aggregateScriptEvents |= part.AggregateScriptEvents;
1629
1293 } 1630 }
1294 } 1631 }
1632 lockPartsForRead(false);
1295 1633
1296 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); 1634 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
1297 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); 1635 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
@@ -1333,42 +1671,52 @@ namespace OpenSim.Region.Framework.Scenes
1333 /// <param name="m_physicalPrim"></param> 1671 /// <param name="m_physicalPrim"></param>
1334 public void ApplyPhysics(bool m_physicalPrim) 1672 public void ApplyPhysics(bool m_physicalPrim)
1335 { 1673 {
1336 lock (m_parts) 1674 lockPartsForRead(true);
1675
1676 if (m_parts.Count > 1)
1337 { 1677 {
1338 if (m_parts.Count > 1) 1678 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1679 lockPartsForRead(false);
1680 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1681 foreach (SceneObjectPart part in values)
1339 { 1682 {
1340 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); 1683
1341 foreach (SceneObjectPart part in m_parts.Values) 1684 if (part.LocalId != m_rootPart.LocalId)
1342 { 1685 {
1343 if (part.LocalId != m_rootPart.LocalId) 1686 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1344 {
1345 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1346 }
1347 } 1687 }
1348 1688
1349 // Hack to get the physics scene geometries in the right spot
1350 ResetChildPrimPhysicsPositions();
1351 }
1352 else
1353 {
1354 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1355 } 1689 }
1690 // Hack to get the physics scene geometries in the right spot
1691 ResetChildPrimPhysicsPositions();
1692 }
1693 else
1694 {
1695 lockPartsForRead(false);
1696 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1356 } 1697 }
1357 } 1698 }
1358 1699
1359 public void SetOwnerId(UUID userId) 1700 public void SetOwnerId(UUID userId)
1360 { 1701 {
1361 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1702 ForEachPart(delegate(SceneObjectPart part)
1703 {
1704
1705 part.OwnerID = userId;
1706
1707 });
1362 } 1708 }
1363 1709
1364 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1710 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1365 { 1711 {
1366 lock (m_parts) 1712 lockPartsForRead(true);
1713 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1714 lockPartsForRead(false);
1715 foreach (SceneObjectPart part in values)
1367 { 1716 {
1368 foreach (SceneObjectPart part in m_parts.Values) 1717
1369 { 1718 whatToDo(part);
1370 whatToDo(part); 1719
1371 }
1372 } 1720 }
1373 } 1721 }
1374 1722
@@ -1391,7 +1739,10 @@ namespace OpenSim.Region.Framework.Scenes
1391 1739
1392 try 1740 try
1393 { 1741 {
1394 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1742 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1743 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1744 m_scene.LoadingPrims) // Land may not be valid yet
1745
1395 { 1746 {
1396 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1747 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1397 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1748 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1423,9 +1774,9 @@ namespace OpenSim.Region.Framework.Scenes
1423 // don't backup while it's selected or you're asking for changes mid stream. 1774 // don't backup while it's selected or you're asking for changes mid stream.
1424 if ((isTimeToPersist()) || (forcedBackup)) 1775 if ((isTimeToPersist()) || (forcedBackup))
1425 { 1776 {
1426 m_log.DebugFormat( 1777 // m_log.DebugFormat(
1427 "[SCENE]: Storing {0}, {1} in {2}", 1778 // "[SCENE]: Storing {0}, {1} in {2}",
1428 Name, UUID, m_scene.RegionInfo.RegionName); 1779 // Name, UUID, m_scene.RegionInfo.RegionName);
1429 1780
1430 SceneObjectGroup backup_group = Copy(false); 1781 SceneObjectGroup backup_group = Copy(false);
1431 backup_group.RootPart.Velocity = RootPart.Velocity; 1782 backup_group.RootPart.Velocity = RootPart.Velocity;
@@ -1467,15 +1818,17 @@ namespace OpenSim.Region.Framework.Scenes
1467 RootPart.SendFullUpdate( 1818 RootPart.SendFullUpdate(
1468 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); 1819 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
1469 1820
1470 lock (m_parts) 1821 lockPartsForRead(true);
1471 { 1822 {
1472 foreach (SceneObjectPart part in m_parts.Values) 1823 foreach (SceneObjectPart part in m_parts.Values)
1473 { 1824 {
1825
1474 if (part != RootPart) 1826 if (part != RootPart)
1475 part.SendFullUpdate( 1827 part.SendFullUpdate(
1476 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); 1828 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
1477 } 1829 }
1478 } 1830 }
1831 lockPartsForRead(false);
1479 } 1832 }
1480 1833
1481 #region Copying 1834 #region Copying
@@ -1487,86 +1840,114 @@ namespace OpenSim.Region.Framework.Scenes
1487 /// <returns></returns> 1840 /// <returns></returns>
1488 public SceneObjectGroup Copy(bool userExposed) 1841 public SceneObjectGroup Copy(bool userExposed)
1489 { 1842 {
1490 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1843 SceneObjectGroup dupe;
1491 dupe.m_isBackedUp = false; 1844 try
1492 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>(); 1845 {
1846 m_dupeInProgress = true;
1847 dupe = (SceneObjectGroup)MemberwiseClone();
1848 dupe.m_isBackedUp = false;
1849 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
1493 1850
1494 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1851 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1495 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1852 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1496 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1853 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1497 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1854 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1498 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1855 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1499 // then restore it's attachment state 1856 // then restore it's attachment state
1500 1857
1501 // This is only necessary when userExposed is false! 1858 // This is only necessary when userExposed is false!
1502 1859
1503 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1860 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1504
1505 if (!userExposed)
1506 dupe.RootPart.IsAttachment = true;
1507 1861
1508 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1862 if (!userExposed)
1863 dupe.RootPart.IsAttachment = true;
1509 1864
1510 if (!userExposed) 1865 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1511 {
1512 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1513 }
1514 1866
1515 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1867 if (!userExposed)
1516 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1868 {
1869 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1870 }
1517 1871
1518 if (userExposed) 1872 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1519 dupe.m_rootPart.TrimPermissions(); 1873 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1520 1874
1521 List<SceneObjectPart> partList; 1875 if (userExposed)
1876 dupe.m_rootPart.TrimPermissions();
1522 1877
1523 lock (m_parts) 1878 /// may need to create a new Physics actor.
1524 { 1879 if (dupe.RootPart.PhysActor != null && userExposed)
1525 partList = new List<SceneObjectPart>(m_parts.Values);
1526 }
1527
1528 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1529 { 1880 {
1530 return p1.LinkNum.CompareTo(p2.LinkNum); 1881 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1882
1883 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1884 dupe.RootPart.Name,
1885 pbs,
1886 dupe.RootPart.AbsolutePosition,
1887 dupe.RootPart.Scale,
1888 dupe.RootPart.RotationOffset,
1889 dupe.RootPart.PhysActor.IsPhysical);
1890
1891 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1892 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1531 } 1893 }
1532 );
1533 1894
1534 foreach (SceneObjectPart part in partList) 1895 lockPartsForRead(true);
1535 { 1896
1536 if (part.UUID != m_rootPart.UUID) 1897 List<SceneObjectPart> partList;
1898
1899 partList = new List<SceneObjectPart>(m_parts.Values);
1900
1901 lockPartsForRead(false);
1902
1903 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1904 {
1905 return p1.LinkNum.CompareTo(p2.LinkNum);
1906 }
1907 );
1908
1909 foreach (SceneObjectPart part in partList)
1537 { 1910 {
1538 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1911 if (part.UUID != m_rootPart.UUID)
1539 newPart.LinkNum = part.LinkNum; 1912 {
1540 } 1913 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1541 1914
1542 // Need to duplicate the physics actor as well 1915 newPart.LinkNum = part.LinkNum;
1543 if (part.PhysActor != null && userExposed) 1916 }
1917
1918 // Need to duplicate the physics actor as well
1919 if (part.PhysActor != null && userExposed)
1920 {
1921 PrimitiveBaseShape pbs = part.Shape;
1922
1923 part.PhysActor
1924 = m_scene.PhysicsScene.AddPrimShape(
1925 part.Name,
1926 pbs,
1927 part.AbsolutePosition,
1928 part.Scale,
1929 part.RotationOffset,
1930 part.PhysActor.IsPhysical);
1931
1932 part.PhysActor.LocalID = part.LocalId;
1933 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1934 }
1935
1936 }
1937 if (userExposed)
1544 { 1938 {
1545 PrimitiveBaseShape pbs = part.Shape; 1939 dupe.UpdateParentIDs();
1546 1940 dupe.HasGroupChanged = true;
1547 part.PhysActor 1941 dupe.AttachToBackup();
1548 = m_scene.PhysicsScene.AddPrimShape( 1942
1549 part.Name, 1943 ScheduleGroupForFullUpdate();
1550 pbs, 1944 }
1551 part.AbsolutePosition, 1945
1552 part.Scale,
1553 part.RotationOffset,
1554 part.PhysActor.IsPhysical);
1555
1556 part.PhysActor.LocalID = part.LocalId;
1557 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1558 }
1559 } 1946 }
1560 1947 finally
1561 if (userExposed)
1562 { 1948 {
1563 dupe.UpdateParentIDs(); 1949 m_dupeInProgress = false;
1564 dupe.HasGroupChanged = true;
1565 dupe.AttachToBackup();
1566
1567 ScheduleGroupForFullUpdate();
1568 } 1950 }
1569
1570 return dupe; 1951 return dupe;
1571 } 1952 }
1572 1953
@@ -1757,13 +2138,40 @@ namespace OpenSim.Region.Framework.Scenes
1757 } 2138 }
1758 } 2139 }
1759 2140
2141 public void rotLookAt(Quaternion target, float strength, float damping)
2142 {
2143 SceneObjectPart rootpart = m_rootPart;
2144 if (rootpart != null)
2145 {
2146 if (IsAttachment)
2147 {
2148 /*
2149 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2150 if (avatar != null)
2151 {
2152 Rotate the Av?
2153 } */
2154 }
2155 else
2156 {
2157 if (rootpart.PhysActor != null)
2158 { // APID must be implemented in your physics system for this to function.
2159 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2160 rootpart.PhysActor.APIDStrength = strength;
2161 rootpart.PhysActor.APIDDamping = damping;
2162 rootpart.PhysActor.APIDActive = true;
2163 }
2164 }
2165 }
2166 }
2167
1760 public void stopLookAt() 2168 public void stopLookAt()
1761 { 2169 {
1762 SceneObjectPart rootpart = m_rootPart; 2170 SceneObjectPart rootpart = m_rootPart;
1763 if (rootpart != null) 2171 if (rootpart != null)
1764 { 2172 {
1765 if (rootpart.PhysActor != null) 2173 if (rootpart.PhysActor != null)
1766 { 2174 { // APID must be implemented in your physics system for this to function.
1767 rootpart.PhysActor.APIDActive = false; 2175 rootpart.PhysActor.APIDActive = false;
1768 } 2176 }
1769 } 2177 }
@@ -1828,14 +2236,14 @@ namespace OpenSim.Region.Framework.Scenes
1828 /// <param name="cGroupID"></param> 2236 /// <param name="cGroupID"></param>
1829 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2237 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1830 { 2238 {
1831 SceneObjectPart newPart = null; 2239 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1832 2240 newPart.SetParent(this);
1833 lock (m_parts) 2241
1834 { 2242 lockPartsForWrite(true);
1835 newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2243 {
1836 newPart.SetParent(this);
1837 m_parts.Add(newPart.UUID, newPart); 2244 m_parts.Add(newPart.UUID, newPart);
1838 } 2245 }
2246 lockPartsForWrite(false);
1839 2247
1840 SetPartAsNonRoot(newPart); 2248 SetPartAsNonRoot(newPart);
1841 2249
@@ -1899,6 +2307,8 @@ namespace OpenSim.Region.Framework.Scenes
1899 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) 2307 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1900 // return; 2308 // return;
1901 2309
2310 lockPartsForRead(true);
2311
1902 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2312 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1903 2313
1904 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) 2314 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
@@ -1914,8 +2324,7 @@ namespace OpenSim.Region.Framework.Scenes
1914 } 2324 }
1915 2325
1916 List<SceneObjectPart> partList = null; 2326 List<SceneObjectPart> partList = null;
1917 lock (m_parts) 2327 partList = new List<SceneObjectPart>(m_parts.Values);
1918 partList = new List<SceneObjectPart>(m_parts.Values);
1919 2328
1920 foreach (SceneObjectPart part in partList) 2329 foreach (SceneObjectPart part in partList)
1921 { 2330 {
@@ -1923,6 +2332,7 @@ namespace OpenSim.Region.Framework.Scenes
1923 part.UpdateLookAt(); 2332 part.UpdateLookAt();
1924 part.SendScheduledUpdates(); 2333 part.SendScheduledUpdates();
1925 } 2334 }
2335 lockPartsForRead(false);
1926 } 2336 }
1927 2337
1928 public void ScheduleFullUpdateToAvatar(ScenePresence presence) 2338 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
@@ -1931,27 +2341,29 @@ namespace OpenSim.Region.Framework.Scenes
1931 2341
1932 RootPart.AddFullUpdateToAvatar(presence); 2342 RootPart.AddFullUpdateToAvatar(presence);
1933 2343
1934 lock (m_parts) 2344 lockPartsForRead(true);
1935 { 2345 {
1936 foreach (SceneObjectPart part in m_parts.Values) 2346 foreach (SceneObjectPart part in m_parts.Values)
1937 { 2347 {
2348
1938 if (part != RootPart) 2349 if (part != RootPart)
1939 part.AddFullUpdateToAvatar(presence); 2350 part.AddFullUpdateToAvatar(presence);
2351
1940 } 2352 }
1941 } 2353 }
2354 lockPartsForRead(false);
1942 } 2355 }
1943 2356
1944 public void ScheduleTerseUpdateToAvatar(ScenePresence presence) 2357 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1945 { 2358 {
1946// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); 2359 lockPartsForRead(true);
1947 2360
1948 lock (m_parts) 2361 foreach (SceneObjectPart part in m_parts.Values)
1949 { 2362 {
1950 foreach (SceneObjectPart part in m_parts.Values) 2363 part.AddTerseUpdateToAvatar(presence);
1951 {
1952 part.AddTerseUpdateToAvatar(presence);
1953 }
1954 } 2364 }
2365
2366 lockPartsForRead(false);
1955 } 2367 }
1956 2368
1957 /// <summary> 2369 /// <summary>
@@ -1965,14 +2377,17 @@ namespace OpenSim.Region.Framework.Scenes
1965 checkAtTargets(); 2377 checkAtTargets();
1966 RootPart.ScheduleFullUpdate(); 2378 RootPart.ScheduleFullUpdate();
1967 2379
1968 lock (m_parts) 2380 lockPartsForRead(true);
1969 { 2381 {
1970 foreach (SceneObjectPart part in m_parts.Values) 2382 foreach (SceneObjectPart part in m_parts.Values)
1971 { 2383 {
2384
1972 if (part != RootPart) 2385 if (part != RootPart)
1973 part.ScheduleFullUpdate(); 2386 part.ScheduleFullUpdate();
2387
1974 } 2388 }
1975 } 2389 }
2390 lockPartsForRead(false);
1976 } 2391 }
1977 2392
1978 /// <summary> 2393 /// <summary>
@@ -1980,37 +2395,38 @@ namespace OpenSim.Region.Framework.Scenes
1980 /// </summary> 2395 /// </summary>
1981 public void ScheduleGroupForTerseUpdate() 2396 public void ScheduleGroupForTerseUpdate()
1982 { 2397 {
1983// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); 2398 lockPartsForRead(true);
1984 2399 foreach (SceneObjectPart part in m_parts.Values)
1985 lock (m_parts)
1986 { 2400 {
1987 foreach (SceneObjectPart part in m_parts.Values) 2401 part.ScheduleTerseUpdate();
1988 {
1989 part.ScheduleTerseUpdate();
1990 }
1991 } 2402 }
2403
2404 lockPartsForRead(false);
1992 } 2405 }
1993 2406
1994 /// <summary> 2407 /// <summary>
1995 /// Immediately send a full update for this scene object. 2408 /// Immediately send a full update for this scene object.
1996 /// </summary> 2409 /// </summary>
1997 public void SendGroupFullUpdate() 2410 public void SendGroupFullUpdate()
1998 { 2411 {
1999 if (IsDeleted) 2412 if (IsDeleted)
2000 return; 2413 return;
2001 2414
2002// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2415// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2003 2416
2004 RootPart.SendFullUpdateToAllClients(); 2417 RootPart.SendFullUpdateToAllClients();
2005 2418
2006 lock (m_parts) 2419 lockPartsForRead(true);
2007 { 2420 {
2008 foreach (SceneObjectPart part in m_parts.Values) 2421 foreach (SceneObjectPart part in m_parts.Values)
2009 { 2422 {
2423
2010 if (part != RootPart) 2424 if (part != RootPart)
2011 part.SendFullUpdateToAllClients(); 2425 part.SendFullUpdateToAllClients();
2426
2012 } 2427 }
2013 } 2428 }
2429 lockPartsForRead(false);
2014 } 2430 }
2015 2431
2016 /// <summary> 2432 /// <summary>
@@ -2042,14 +2458,15 @@ namespace OpenSim.Region.Framework.Scenes
2042 { 2458 {
2043 if (IsDeleted) 2459 if (IsDeleted)
2044 return; 2460 return;
2045 2461
2046 lock (m_parts) 2462 lockPartsForRead(true);
2047 { 2463 {
2048 foreach (SceneObjectPart part in m_parts.Values) 2464 foreach (SceneObjectPart part in m_parts.Values)
2049 { 2465 {
2050 part.SendTerseUpdateToAllClients(); 2466 part.SendTerseUpdateToAllClients();
2051 } 2467 }
2052 } 2468 }
2469 lockPartsForRead(false);
2053 } 2470 }
2054 2471
2055 #endregion 2472 #endregion
@@ -2063,16 +2480,18 @@ namespace OpenSim.Region.Framework.Scenes
2063 /// <returns>null if no child part with that linknum or child part</returns> 2480 /// <returns>null if no child part with that linknum or child part</returns>
2064 public SceneObjectPart GetLinkNumPart(int linknum) 2481 public SceneObjectPart GetLinkNumPart(int linknum)
2065 { 2482 {
2066 lock (m_parts) 2483 lockPartsForRead(true);
2067 { 2484 {
2068 foreach (SceneObjectPart part in m_parts.Values) 2485 foreach (SceneObjectPart part in m_parts.Values)
2069 { 2486 {
2070 if (part.LinkNum == linknum) 2487 if (part.LinkNum == linknum)
2071 { 2488 {
2489 lockPartsForRead(false);
2072 return part; 2490 return part;
2073 } 2491 }
2074 } 2492 }
2075 } 2493 }
2494 lockPartsForRead(false);
2076 2495
2077 return null; 2496 return null;
2078 } 2497 }
@@ -2105,17 +2524,19 @@ namespace OpenSim.Region.Framework.Scenes
2105 public SceneObjectPart GetChildPart(uint localID) 2524 public SceneObjectPart GetChildPart(uint localID)
2106 { 2525 {
2107 //m_log.DebugFormat("Entered looking for {0}", localID); 2526 //m_log.DebugFormat("Entered looking for {0}", localID);
2108 lock (m_parts) 2527 lockPartsForRead(true);
2109 { 2528 {
2110 foreach (SceneObjectPart part in m_parts.Values) 2529 foreach (SceneObjectPart part in m_parts.Values)
2111 { 2530 {
2112 //m_log.DebugFormat("Found {0}", part.LocalId); 2531 //m_log.DebugFormat("Found {0}", part.LocalId);
2113 if (part.LocalId == localID) 2532 if (part.LocalId == localID)
2114 { 2533 {
2534 lockPartsForRead(false);
2115 return part; 2535 return part;
2116 } 2536 }
2117 } 2537 }
2118 } 2538 }
2539 lockPartsForRead(false);
2119 2540
2120 return null; 2541 return null;
2121 } 2542 }
@@ -2146,17 +2567,19 @@ namespace OpenSim.Region.Framework.Scenes
2146 public bool HasChildPrim(uint localID) 2567 public bool HasChildPrim(uint localID)
2147 { 2568 {
2148 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); 2569 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
2149 lock (m_parts) 2570 lockPartsForRead(true);
2150 { 2571 {
2151 foreach (SceneObjectPart part in m_parts.Values) 2572 foreach (SceneObjectPart part in m_parts.Values)
2152 { 2573 {
2153 //m_log.DebugFormat("Found {0}", part.LocalId); 2574 //m_log.DebugFormat("Found {0}", part.LocalId);
2154 if (part.LocalId == localID) 2575 if (part.LocalId == localID)
2155 { 2576 {
2577 lockPartsForRead(false);
2156 return true; 2578 return true;
2157 } 2579 }
2158 } 2580 }
2159 } 2581 }
2582 lockPartsForRead(false);
2160 2583
2161 return false; 2584 return false;
2162 } 2585 }
@@ -2206,53 +2629,57 @@ namespace OpenSim.Region.Framework.Scenes
2206 if (m_rootPart.LinkNum == 0) 2629 if (m_rootPart.LinkNum == 0)
2207 m_rootPart.LinkNum = 1; 2630 m_rootPart.LinkNum = 1;
2208 2631
2209 lock (m_parts) 2632 lockPartsForWrite(true);
2210 { 2633
2211 m_parts.Add(linkPart.UUID, linkPart); 2634 m_parts.Add(linkPart.UUID, linkPart);
2635
2636 lockPartsForWrite(false);
2212 2637
2213 // Insert in terms of link numbers, the new links 2638 // Insert in terms of link numbers, the new links
2214 // before the current ones (with the exception of 2639 // before the current ones (with the exception of
2215 // the root prim. Shuffle the old ones up 2640 // the root prim. Shuffle the old ones up
2216 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) 2641 lockPartsForRead(true);
2642 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
2643 {
2644 if (kvp.Value.LinkNum != 1)
2217 { 2645 {
2218 if (kvp.Value.LinkNum != 1) 2646 // Don't update root prim link number
2219 { 2647 kvp.Value.LinkNum += objectGroup.PrimCount;
2220 // Don't update root prim link number
2221 kvp.Value.LinkNum += objectGroup.PrimCount;
2222 }
2223 } 2648 }
2649 }
2650 lockPartsForRead(false);
2224 2651
2225 linkPart.LinkNum = 2; 2652 linkPart.LinkNum = 2;
2226 2653
2227 linkPart.SetParent(this); 2654 linkPart.SetParent(this);
2228 linkPart.CreateSelected = true; 2655 linkPart.CreateSelected = true;
2229 2656
2230 //if (linkPart.PhysActor != null) 2657 //if (linkPart.PhysActor != null)
2231 //{ 2658 //{
2232 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2659 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2233 2660
2234 //linkPart.PhysActor = null; 2661 //linkPart.PhysActor = null;
2235 //} 2662 //}
2236 2663
2237 //TODO: rest of parts 2664 //TODO: rest of parts
2238 int linkNum = 3; 2665 int linkNum = 3;
2239 foreach (SceneObjectPart part in objectGroup.Children.Values) 2666 foreach (SceneObjectPart part in objectGroup.Children.Values)
2667 {
2668 if (part.UUID != objectGroup.m_rootPart.UUID)
2240 { 2669 {
2241 if (part.UUID != objectGroup.m_rootPart.UUID) 2670 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2242 {
2243 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2244 }
2245 part.ClearUndoState();
2246 } 2671 }
2672 part.ClearUndoState();
2247 } 2673 }
2248 2674
2249 m_scene.UnlinkSceneObject(objectGroup.UUID, true); 2675 m_scene.UnlinkSceneObject(objectGroup.UUID, true);
2250 objectGroup.m_isDeleted = true; 2676 objectGroup.m_isDeleted = true;
2677
2678 objectGroup.lockPartsForWrite(true);
2251 2679
2252 lock (objectGroup.m_parts) 2680 objectGroup.m_parts.Clear();
2253 { 2681
2254 objectGroup.m_parts.Clear(); 2682 objectGroup.lockPartsForWrite(false);
2255 }
2256 2683
2257 // Can't do this yet since backup still makes use of the root part without any synchronization 2684 // Can't do this yet since backup still makes use of the root part without any synchronization
2258// objectGroup.m_rootPart = null; 2685// objectGroup.m_rootPart = null;
@@ -2322,23 +2749,23 @@ namespace OpenSim.Region.Framework.Scenes
2322 Quaternion worldRot = linkPart.GetWorldRotation(); 2749 Quaternion worldRot = linkPart.GetWorldRotation();
2323 2750
2324 // Remove the part from this object 2751 // Remove the part from this object
2325 lock (m_parts) 2752 lockPartsForWrite(true);
2326 { 2753 {
2327 m_parts.Remove(linkPart.UUID); 2754 m_parts.Remove(linkPart.UUID);
2328 2755 }
2329 if (m_parts.Count == 1 && RootPart != null) //Single prim is left 2756 lockPartsForWrite(false);
2757 lockPartsForRead(true);
2758 if (m_parts.Count == 1 && RootPart != null) //Single prim is left
2759 RootPart.LinkNum = 0;
2760 else
2761 {
2762 foreach (SceneObjectPart p in m_parts.Values)
2330 { 2763 {
2331 RootPart.LinkNum = 0; 2764 if (p.LinkNum > linkPart.LinkNum)
2765 p.LinkNum--;
2332 } 2766 }
2333 else
2334 {
2335 foreach (SceneObjectPart p in m_parts.Values)
2336 {
2337 if (p.LinkNum > linkPart.LinkNum)
2338 p.LinkNum--;
2339 }
2340 }
2341 } 2767 }
2768 lockPartsForRead(false);
2342 2769
2343 linkPart.ParentID = 0; 2770 linkPart.ParentID = 0;
2344 linkPart.LinkNum = 0; 2771 linkPart.LinkNum = 0;
@@ -2382,6 +2809,8 @@ namespace OpenSim.Region.Framework.Scenes
2382 /// <param name="objectGroup"></param> 2809 /// <param name="objectGroup"></param>
2383 public virtual void DetachFromBackup() 2810 public virtual void DetachFromBackup()
2384 { 2811 {
2812 m_scene.SceneGraph.FireDetachFromBackup(this);
2813
2385 if (m_isBackedUp) 2814 if (m_isBackedUp)
2386 m_scene.EventManager.OnBackup -= ProcessBackup; 2815 m_scene.EventManager.OnBackup -= ProcessBackup;
2387 2816
@@ -2660,9 +3089,12 @@ namespace OpenSim.Region.Framework.Scenes
2660 3089
2661 if (selectionPart != null) 3090 if (selectionPart != null)
2662 { 3091 {
2663 lock (m_parts) 3092 lockPartsForRead(true);
3093 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
3094 lockPartsForRead(false);
3095 foreach (SceneObjectPart part in parts)
2664 { 3096 {
2665 foreach (SceneObjectPart part in m_parts.Values) 3097 if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
2666 { 3098 {
2667 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || 3099 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax ||
2668 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || 3100 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax ||
@@ -2672,12 +3104,13 @@ namespace OpenSim.Region.Framework.Scenes
2672 break; 3104 break;
2673 } 3105 }
2674 } 3106 }
3107 }
2675 3108
2676 foreach (SceneObjectPart part in m_parts.Values) 3109 foreach (SceneObjectPart part in parts)
2677 { 3110 {
2678 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3111 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2679 }
2680 } 3112 }
3113
2681 } 3114 }
2682 } 3115 }
2683 3116
@@ -2690,6 +3123,17 @@ namespace OpenSim.Region.Framework.Scenes
2690 } 3123 }
2691 } 3124 }
2692 3125
3126
3127
3128 /// <summary>
3129 /// Gets the number of parts
3130 /// </summary>
3131 /// <returns></returns>
3132 public int GetPartCount()
3133 {
3134 return Children.Count;
3135 }
3136
2693 /// <summary> 3137 /// <summary>
2694 /// Get the parts of this scene object 3138 /// Get the parts of this scene object
2695 /// </summary> 3139 /// </summary>
@@ -2766,11 +3210,9 @@ namespace OpenSim.Region.Framework.Scenes
2766 scale.Y = m_scene.m_maxNonphys; 3210 scale.Y = m_scene.m_maxNonphys;
2767 if (scale.Z > m_scene.m_maxNonphys) 3211 if (scale.Z > m_scene.m_maxNonphys)
2768 scale.Z = m_scene.m_maxNonphys; 3212 scale.Z = m_scene.m_maxNonphys;
2769
2770 SceneObjectPart part = GetChildPart(localID); 3213 SceneObjectPart part = GetChildPart(localID);
2771 if (part != null) 3214 if (part != null)
2772 { 3215 {
2773 part.Resize(scale);
2774 if (part.PhysActor != null) 3216 if (part.PhysActor != null)
2775 { 3217 {
2776 if (part.PhysActor.IsPhysical) 3218 if (part.PhysActor.IsPhysical)
@@ -2785,7 +3227,7 @@ namespace OpenSim.Region.Framework.Scenes
2785 part.PhysActor.Size = scale; 3227 part.PhysActor.Size = scale;
2786 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 3228 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2787 } 3229 }
2788 //if (part.UUID != m_rootPart.UUID) 3230 part.Resize(scale);
2789 3231
2790 HasGroupChanged = true; 3232 HasGroupChanged = true;
2791 ScheduleGroupForFullUpdate(); 3233 ScheduleGroupForFullUpdate();
@@ -2807,7 +3249,6 @@ namespace OpenSim.Region.Framework.Scenes
2807 SceneObjectPart part = GetChildPart(localID); 3249 SceneObjectPart part = GetChildPart(localID);
2808 if (part != null) 3250 if (part != null)
2809 { 3251 {
2810 part.IgnoreUndoUpdate = true;
2811 if (scale.X > m_scene.m_maxNonphys) 3252 if (scale.X > m_scene.m_maxNonphys)
2812 scale.X = m_scene.m_maxNonphys; 3253 scale.X = m_scene.m_maxNonphys;
2813 if (scale.Y > m_scene.m_maxNonphys) 3254 if (scale.Y > m_scene.m_maxNonphys)
@@ -2827,94 +3268,100 @@ namespace OpenSim.Region.Framework.Scenes
2827 float y = (scale.Y / part.Scale.Y); 3268 float y = (scale.Y / part.Scale.Y);
2828 float z = (scale.Z / part.Scale.Z); 3269 float z = (scale.Z / part.Scale.Z);
2829 3270
2830 lock (m_parts) 3271 lockPartsForRead(true);
3272 if (x > 1.0f || y > 1.0f || z > 1.0f)
2831 { 3273 {
2832 if (x > 1.0f || y > 1.0f || z > 1.0f) 3274 foreach (SceneObjectPart obPart in m_parts.Values)
2833 { 3275 {
2834 foreach (SceneObjectPart obPart in m_parts.Values) 3276 if (obPart.UUID != m_rootPart.UUID)
2835 { 3277 {
2836 if (obPart.UUID != m_rootPart.UUID) 3278 Vector3 oldSize = new Vector3(obPart.Scale);
2837 { 3279 obPart.IgnoreUndoUpdate = true;
2838 obPart.IgnoreUndoUpdate = true;
2839 Vector3 oldSize = new Vector3(obPart.Scale);
2840 3280
2841 float f = 1.0f; 3281 float f = 1.0f;
2842 float a = 1.0f; 3282 float a = 1.0f;
2843 3283
2844 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3284 if (part.PhysActor != null && part.PhysActor.IsPhysical)
3285 {
3286 if (oldSize.X*x > m_scene.m_maxPhys)
2845 { 3287 {
2846 if (oldSize.X*x > m_scene.m_maxPhys) 3288 f = m_scene.m_maxPhys / oldSize.X;
2847 { 3289 a = f / x;
2848 f = m_scene.m_maxPhys / oldSize.X; 3290 x *= a;
2849 a = f / x; 3291 y *= a;
2850 x *= a; 3292 z *= a;
2851 y *= a;
2852 z *= a;
2853 }
2854 if (oldSize.Y*y > m_scene.m_maxPhys)
2855 {
2856 f = m_scene.m_maxPhys / oldSize.Y;
2857 a = f / y;
2858 x *= a;
2859 y *= a;
2860 z *= a;
2861 }
2862 if (oldSize.Z*z > m_scene.m_maxPhys)
2863 {
2864 f = m_scene.m_maxPhys / oldSize.Z;
2865 a = f / z;
2866 x *= a;
2867 y *= a;
2868 z *= a;
2869 }
2870 } 3293 }
2871 else 3294 if (oldSize.Y*y > m_scene.m_maxPhys)
3295 {
3296 f = m_scene.m_maxPhys / oldSize.Y;
3297 a = f / y;
3298 x *= a;
3299 y *= a;
3300 z *= a;
3301 }
3302 if (oldSize.Z*z > m_scene.m_maxPhys)
2872 { 3303 {
2873 if (oldSize.X*x > m_scene.m_maxNonphys) 3304 f = m_scene.m_maxPhys / oldSize.Z;
2874 { 3305 a = f / z;
2875 f = m_scene.m_maxNonphys / oldSize.X; 3306 x *= a;
2876 a = f / x; 3307 y *= a;
2877 x *= a; 3308 z *= a;
2878 y *= a;
2879 z *= a;
2880 }
2881 if (oldSize.Y*y > m_scene.m_maxNonphys)
2882 {
2883 f = m_scene.m_maxNonphys / oldSize.Y;
2884 a = f / y;
2885 x *= a;
2886 y *= a;
2887 z *= a;
2888 }
2889 if (oldSize.Z*z > m_scene.m_maxNonphys)
2890 {
2891 f = m_scene.m_maxNonphys / oldSize.Z;
2892 a = f / z;
2893 x *= a;
2894 y *= a;
2895 z *= a;
2896 }
2897 } 3309 }
2898 obPart.IgnoreUndoUpdate = false; 3310 }
2899 obPart.StoreUndoState(); 3311 else
3312 {
3313 if (oldSize.X*x > m_scene.m_maxNonphys)
3314 {
3315 f = m_scene.m_maxNonphys / oldSize.X;
3316 a = f / x;
3317 x *= a;
3318 y *= a;
3319 z *= a;
3320 }
3321 if (oldSize.Y*y > m_scene.m_maxNonphys)
3322 {
3323 f = m_scene.m_maxNonphys / oldSize.Y;
3324 a = f / y;
3325 x *= a;
3326 y *= a;
3327 z *= a;
3328 }
3329 if (oldSize.Z*z > m_scene.m_maxNonphys)
3330 {
3331 f = m_scene.m_maxNonphys / oldSize.Z;
3332 a = f / z;
3333 x *= a;
3334 y *= a;
3335 z *= a;
3336 }
3337
2900 } 3338 }
2901 } 3339 }
2902 } 3340 }
2903 } 3341 }
3342 lockPartsForRead(false);
2904 3343
2905 Vector3 prevScale = part.Scale; 3344 Vector3 prevScale = part.Scale;
2906 prevScale.X *= x; 3345 prevScale.X *= x;
2907 prevScale.Y *= y; 3346 prevScale.Y *= y;
2908 prevScale.Z *= z; 3347 prevScale.Z *= z;;
3348
3349 part.IgnoreUndoUpdate = false;
3350 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3351 part.IgnoreUndoUpdate = true;
2909 part.Resize(prevScale); 3352 part.Resize(prevScale);
3353 part.IgnoreUndoUpdate = false;
2910 3354
2911 lock (m_parts) 3355 lockPartsForRead(true);
2912 { 3356 {
2913 foreach (SceneObjectPart obPart in m_parts.Values) 3357 foreach (SceneObjectPart obPart in m_parts.Values)
2914 { 3358 {
2915 obPart.IgnoreUndoUpdate = true;
2916 if (obPart.UUID != m_rootPart.UUID) 3359 if (obPart.UUID != m_rootPart.UUID)
2917 { 3360 {
3361 obPart.IgnoreUndoUpdate = false;
3362 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3363 obPart.IgnoreUndoUpdate = true;
3364
2918 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3365 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2919 currentpos.X *= x; 3366 currentpos.X *= x;
2920 currentpos.Y *= y; 3367 currentpos.Y *= y;
@@ -2927,9 +3374,9 @@ namespace OpenSim.Region.Framework.Scenes
2927 obPart.UpdateOffSet(currentpos); 3374 obPart.UpdateOffSet(currentpos);
2928 } 3375 }
2929 obPart.IgnoreUndoUpdate = false; 3376 obPart.IgnoreUndoUpdate = false;
2930 obPart.StoreUndoState();
2931 } 3377 }
2932 } 3378 }
3379 lockPartsForRead(false);
2933 3380
2934 if (part.PhysActor != null) 3381 if (part.PhysActor != null)
2935 { 3382 {
@@ -2938,7 +3385,6 @@ namespace OpenSim.Region.Framework.Scenes
2938 } 3385 }
2939 3386
2940 part.IgnoreUndoUpdate = false; 3387 part.IgnoreUndoUpdate = false;
2941 part.StoreUndoState();
2942 HasGroupChanged = true; 3388 HasGroupChanged = true;
2943 ScheduleGroupForTerseUpdate(); 3389 ScheduleGroupForTerseUpdate();
2944 } 3390 }
@@ -2954,14 +3400,11 @@ namespace OpenSim.Region.Framework.Scenes
2954 /// <param name="pos"></param> 3400 /// <param name="pos"></param>
2955 public void UpdateGroupPosition(Vector3 pos) 3401 public void UpdateGroupPosition(Vector3 pos)
2956 { 3402 {
2957 foreach (SceneObjectPart part in Children.Values)
2958 {
2959 part.StoreUndoState();
2960 }
2961 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3403 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2962 { 3404 {
2963 if (IsAttachment) 3405 if (IsAttachment)
2964 { 3406 {
3407 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2965 m_rootPart.AttachedPos = pos; 3408 m_rootPart.AttachedPos = pos;
2966 } 3409 }
2967 if (RootPart.GetStatusSandbox()) 3410 if (RootPart.GetStatusSandbox())
@@ -2994,7 +3437,7 @@ namespace OpenSim.Region.Framework.Scenes
2994 SceneObjectPart part = GetChildPart(localID); 3437 SceneObjectPart part = GetChildPart(localID);
2995 foreach (SceneObjectPart parts in Children.Values) 3438 foreach (SceneObjectPart parts in Children.Values)
2996 { 3439 {
2997 parts.StoreUndoState(); 3440 parts.StoreUndoState(UndoType.STATE_PRIM_POSITION);
2998 } 3441 }
2999 if (part != null) 3442 if (part != null)
3000 { 3443 {
@@ -3019,7 +3462,7 @@ namespace OpenSim.Region.Framework.Scenes
3019 { 3462 {
3020 foreach (SceneObjectPart part in Children.Values) 3463 foreach (SceneObjectPart part in Children.Values)
3021 { 3464 {
3022 part.StoreUndoState(); 3465 part.StoreUndoState(UndoType.STATE_PRIM_POSITION);
3023 } 3466 }
3024 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3467 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3025 Vector3 oldPos = 3468 Vector3 oldPos =
@@ -3032,7 +3475,7 @@ namespace OpenSim.Region.Framework.Scenes
3032 axDiff *= Quaternion.Inverse(partRotation); 3475 axDiff *= Quaternion.Inverse(partRotation);
3033 diff = axDiff; 3476 diff = axDiff;
3034 3477
3035 lock (m_parts) 3478 lockPartsForRead(true);
3036 { 3479 {
3037 foreach (SceneObjectPart obPart in m_parts.Values) 3480 foreach (SceneObjectPart obPart in m_parts.Values)
3038 { 3481 {
@@ -3042,11 +3485,29 @@ namespace OpenSim.Region.Framework.Scenes
3042 } 3485 }
3043 } 3486 }
3044 } 3487 }
3488 lockPartsForRead(false);
3045 3489
3046 AbsolutePosition = newPos; 3490 //We have to set undoing here because otherwise an undo state will be saved
3491 if (!m_rootPart.Undoing)
3492 {
3493 m_rootPart.Undoing = true;
3494 AbsolutePosition = newPos;
3495 m_rootPart.Undoing = false;
3496 }
3497 else
3498 {
3499 AbsolutePosition = newPos;
3500 }
3047 3501
3048 HasGroupChanged = true; 3502 HasGroupChanged = true;
3049 ScheduleGroupForTerseUpdate(); 3503 if (m_rootPart.Undoing)
3504 {
3505 ScheduleGroupForFullUpdate();
3506 }
3507 else
3508 {
3509 ScheduleGroupForTerseUpdate();
3510 }
3050 } 3511 }
3051 3512
3052 public void OffsetForNewRegion(Vector3 offset) 3513 public void OffsetForNewRegion(Vector3 offset)
@@ -3066,7 +3527,7 @@ namespace OpenSim.Region.Framework.Scenes
3066 { 3527 {
3067 foreach (SceneObjectPart parts in Children.Values) 3528 foreach (SceneObjectPart parts in Children.Values)
3068 { 3529 {
3069 parts.StoreUndoState(); 3530 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3070 } 3531 }
3071 m_rootPart.UpdateRotation(rot); 3532 m_rootPart.UpdateRotation(rot);
3072 3533
@@ -3090,7 +3551,7 @@ namespace OpenSim.Region.Framework.Scenes
3090 { 3551 {
3091 foreach (SceneObjectPart parts in Children.Values) 3552 foreach (SceneObjectPart parts in Children.Values)
3092 { 3553 {
3093 parts.StoreUndoState(); 3554 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3094 } 3555 }
3095 m_rootPart.UpdateRotation(rot); 3556 m_rootPart.UpdateRotation(rot);
3096 3557
@@ -3117,7 +3578,7 @@ namespace OpenSim.Region.Framework.Scenes
3117 SceneObjectPart part = GetChildPart(localID); 3578 SceneObjectPart part = GetChildPart(localID);
3118 foreach (SceneObjectPart parts in Children.Values) 3579 foreach (SceneObjectPart parts in Children.Values)
3119 { 3580 {
3120 parts.StoreUndoState(); 3581 parts.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3121 } 3582 }
3122 if (part != null) 3583 if (part != null)
3123 { 3584 {
@@ -3145,15 +3606,24 @@ namespace OpenSim.Region.Framework.Scenes
3145 if (part.UUID == m_rootPart.UUID) 3606 if (part.UUID == m_rootPart.UUID)
3146 { 3607 {
3147 UpdateRootRotation(rot); 3608 UpdateRootRotation(rot);
3148 AbsolutePosition = pos; 3609 if (!m_rootPart.Undoing)
3610 {
3611 m_rootPart.Undoing = true;
3612 AbsolutePosition = pos;
3613 m_rootPart.Undoing = false;
3614 }
3615 else
3616 {
3617 AbsolutePosition = pos;
3618 }
3149 } 3619 }
3150 else 3620 else
3151 { 3621 {
3622 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3152 part.IgnoreUndoUpdate = true; 3623 part.IgnoreUndoUpdate = true;
3153 part.UpdateRotation(rot); 3624 part.UpdateRotation(rot);
3154 part.OffsetPosition = pos; 3625 part.OffsetPosition = pos;
3155 part.IgnoreUndoUpdate = false; 3626 part.IgnoreUndoUpdate = false;
3156 part.StoreUndoState();
3157 } 3627 }
3158 } 3628 }
3159 } 3629 }
@@ -3167,7 +3637,13 @@ namespace OpenSim.Region.Framework.Scenes
3167 Quaternion axRot = rot; 3637 Quaternion axRot = rot;
3168 Quaternion oldParentRot = m_rootPart.RotationOffset; 3638 Quaternion oldParentRot = m_rootPart.RotationOffset;
3169 3639
3170 m_rootPart.StoreUndoState(); 3640 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3641 bool cancelUndo = false;
3642 if (!m_rootPart.Undoing)
3643 {
3644 m_rootPart.Undoing = true;
3645 cancelUndo = true;
3646 }
3171 m_rootPart.UpdateRotation(rot); 3647 m_rootPart.UpdateRotation(rot);
3172 if (m_rootPart.PhysActor != null) 3648 if (m_rootPart.PhysActor != null)
3173 { 3649 {
@@ -3175,33 +3651,31 @@ namespace OpenSim.Region.Framework.Scenes
3175 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 3651 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
3176 } 3652 }
3177 3653
3178 lock (m_parts) 3654 lockPartsForRead(true);
3655
3656 foreach (SceneObjectPart prim in m_parts.Values)
3179 { 3657 {
3180 foreach (SceneObjectPart prim in m_parts.Values) 3658 if (prim.UUID != m_rootPart.UUID)
3181 { 3659 {
3182 if (prim.UUID != m_rootPart.UUID) 3660 prim.IgnoreUndoUpdate = true;
3183 { 3661 Vector3 axPos = prim.OffsetPosition;
3184 prim.IgnoreUndoUpdate = true; 3662 axPos *= oldParentRot;
3185 Vector3 axPos = prim.OffsetPosition; 3663 axPos *= Quaternion.Inverse(axRot);
3186 axPos *= oldParentRot; 3664 prim.OffsetPosition = axPos;
3187 axPos *= Quaternion.Inverse(axRot); 3665 Quaternion primsRot = prim.RotationOffset;
3188 prim.OffsetPosition = axPos; 3666 Quaternion newRot = primsRot * oldParentRot;
3189 Quaternion primsRot = prim.RotationOffset; 3667 newRot *= Quaternion.Inverse(axRot);
3190 Quaternion newRot = primsRot * oldParentRot; 3668 prim.RotationOffset = newRot;
3191 newRot *= Quaternion.Inverse(axRot); 3669 prim.ScheduleTerseUpdate();
3192 prim.RotationOffset = newRot; 3670 prim.IgnoreUndoUpdate = false;
3193 prim.ScheduleTerseUpdate();
3194 }
3195 } 3671 }
3196 } 3672 }
3197 foreach (SceneObjectPart childpart in Children.Values) 3673 if (cancelUndo == true)
3198 { 3674 {
3199 if (childpart != m_rootPart) 3675 m_rootPart.Undoing = false;
3200 {
3201 childpart.IgnoreUndoUpdate = false;
3202 childpart.StoreUndoState();
3203 }
3204 } 3676 }
3677 lockPartsForRead(false);
3678
3205 m_rootPart.ScheduleTerseUpdate(); 3679 m_rootPart.ScheduleTerseUpdate();
3206 } 3680 }
3207 3681
@@ -3323,7 +3797,7 @@ namespace OpenSim.Region.Framework.Scenes
3323 if (atTargets.Count > 0) 3797 if (atTargets.Count > 0)
3324 { 3798 {
3325 uint[] localids = new uint[0]; 3799 uint[] localids = new uint[0];
3326 lock (m_parts) 3800 lockPartsForRead(true);
3327 { 3801 {
3328 localids = new uint[m_parts.Count]; 3802 localids = new uint[m_parts.Count];
3329 int cntr = 0; 3803 int cntr = 0;
@@ -3333,6 +3807,7 @@ namespace OpenSim.Region.Framework.Scenes
3333 cntr++; 3807 cntr++;
3334 } 3808 }
3335 } 3809 }
3810 lockPartsForRead(false);
3336 3811
3337 for (int ctr = 0; ctr < localids.Length; ctr++) 3812 for (int ctr = 0; ctr < localids.Length; ctr++)
3338 { 3813 {
@@ -3351,7 +3826,7 @@ namespace OpenSim.Region.Framework.Scenes
3351 { 3826 {
3352 //trigger not_at_target 3827 //trigger not_at_target
3353 uint[] localids = new uint[0]; 3828 uint[] localids = new uint[0];
3354 lock (m_parts) 3829 lockPartsForRead(true);
3355 { 3830 {
3356 localids = new uint[m_parts.Count]; 3831 localids = new uint[m_parts.Count];
3357 int cntr = 0; 3832 int cntr = 0;
@@ -3361,7 +3836,8 @@ namespace OpenSim.Region.Framework.Scenes
3361 cntr++; 3836 cntr++;
3362 } 3837 }
3363 } 3838 }
3364 3839 lockPartsForRead(false);
3840
3365 for (int ctr = 0; ctr < localids.Length; ctr++) 3841 for (int ctr = 0; ctr < localids.Length; ctr++)
3366 { 3842 {
3367 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); 3843 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
@@ -3402,7 +3878,8 @@ namespace OpenSim.Region.Framework.Scenes
3402 if (atRotTargets.Count > 0) 3878 if (atRotTargets.Count > 0)
3403 { 3879 {
3404 uint[] localids = new uint[0]; 3880 uint[] localids = new uint[0];
3405 lock (m_parts) 3881 lockPartsForRead(true);
3882 try
3406 { 3883 {
3407 localids = new uint[m_parts.Count]; 3884 localids = new uint[m_parts.Count];
3408 int cntr = 0; 3885 int cntr = 0;
@@ -3412,6 +3889,10 @@ namespace OpenSim.Region.Framework.Scenes
3412 cntr++; 3889 cntr++;
3413 } 3890 }
3414 } 3891 }
3892 finally
3893 {
3894 lockPartsForRead(false);
3895 }
3415 3896
3416 for (int ctr = 0; ctr < localids.Length; ctr++) 3897 for (int ctr = 0; ctr < localids.Length; ctr++)
3417 { 3898 {
@@ -3430,7 +3911,8 @@ namespace OpenSim.Region.Framework.Scenes
3430 { 3911 {
3431 //trigger not_at_target 3912 //trigger not_at_target
3432 uint[] localids = new uint[0]; 3913 uint[] localids = new uint[0];
3433 lock (m_parts) 3914 lockPartsForRead(true);
3915 try
3434 { 3916 {
3435 localids = new uint[m_parts.Count]; 3917 localids = new uint[m_parts.Count];
3436 int cntr = 0; 3918 int cntr = 0;
@@ -3440,6 +3922,10 @@ namespace OpenSim.Region.Framework.Scenes
3440 cntr++; 3922 cntr++;
3441 } 3923 }
3442 } 3924 }
3925 finally
3926 {
3927 lockPartsForRead(false);
3928 }
3443 3929
3444 for (int ctr = 0; ctr < localids.Length; ctr++) 3930 for (int ctr = 0; ctr < localids.Length; ctr++)
3445 { 3931 {
@@ -3453,19 +3939,20 @@ namespace OpenSim.Region.Framework.Scenes
3453 public float GetMass() 3939 public float GetMass()
3454 { 3940 {
3455 float retmass = 0f; 3941 float retmass = 0f;
3456 lock (m_parts) 3942 lockPartsForRead(true);
3457 { 3943 {
3458 foreach (SceneObjectPart part in m_parts.Values) 3944 foreach (SceneObjectPart part in m_parts.Values)
3459 { 3945 {
3460 retmass += part.GetMass(); 3946 retmass += part.GetMass();
3461 } 3947 }
3462 } 3948 }
3949 lockPartsForRead(false);
3463 return retmass; 3950 return retmass;
3464 } 3951 }
3465 3952
3466 public void CheckSculptAndLoad() 3953 public void CheckSculptAndLoad()
3467 { 3954 {
3468 lock (m_parts) 3955 lockPartsForRead(true);
3469 { 3956 {
3470 if (!IsDeleted) 3957 if (!IsDeleted)
3471 { 3958 {
@@ -3490,6 +3977,7 @@ namespace OpenSim.Region.Framework.Scenes
3490 } 3977 }
3491 } 3978 }
3492 } 3979 }
3980 lockPartsForRead(false);
3493 } 3981 }
3494 3982
3495 protected void AssetReceived(string id, Object sender, AssetBase asset) 3983 protected void AssetReceived(string id, Object sender, AssetBase asset)
@@ -3510,7 +3998,7 @@ namespace OpenSim.Region.Framework.Scenes
3510 /// <param name="client"></param> 3998 /// <param name="client"></param>
3511 public void SetGroup(UUID GroupID, IClientAPI client) 3999 public void SetGroup(UUID GroupID, IClientAPI client)
3512 { 4000 {
3513 lock (m_parts) 4001 lockPartsForRead(true);
3514 { 4002 {
3515 foreach (SceneObjectPart part in m_parts.Values) 4003 foreach (SceneObjectPart part in m_parts.Values)
3516 { 4004 {
@@ -3520,6 +4008,7 @@ namespace OpenSim.Region.Framework.Scenes
3520 4008
3521 HasGroupChanged = true; 4009 HasGroupChanged = true;
3522 } 4010 }
4011 lockPartsForRead(false);
3523 4012
3524 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 4013 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
3525 // for the same object with very different properties. The caller must schedule the update. 4014 // for the same object with very different properties. The caller must schedule the update.
@@ -3541,11 +4030,12 @@ namespace OpenSim.Region.Framework.Scenes
3541 4030
3542 public void SetAttachmentPoint(byte point) 4031 public void SetAttachmentPoint(byte point)
3543 { 4032 {
3544 lock (m_parts) 4033 lockPartsForRead(true);
3545 { 4034 {
3546 foreach (SceneObjectPart part in m_parts.Values) 4035 foreach (SceneObjectPart part in m_parts.Values)
3547 part.SetAttachmentPoint(point); 4036 part.SetAttachmentPoint(point);
3548 } 4037 }
4038 lockPartsForRead(false);
3549 } 4039 }
3550 4040
3551 #region ISceneObject 4041 #region ISceneObject
@@ -3579,6 +4069,14 @@ namespace OpenSim.Region.Framework.Scenes
3579 SetFromItemID(uuid); 4069 SetFromItemID(uuid);
3580 } 4070 }
3581 4071
4072 public void ResetOwnerChangeFlag()
4073 {
4074 ForEachPart(delegate(SceneObjectPart part)
4075 {
4076 part.ResetOwnerChangeFlag();
4077 });
4078 }
4079
3582 #endregion 4080 #endregion
3583 } 4081 }
3584} 4082}