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.cs1155
1 files changed, 833 insertions, 322 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index dc6509d..5b610d3 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,37 @@ namespace OpenSim.Region.Framework.Scenes
1236 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1566 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1237 public void DeleteGroup(bool silent) 1567 public void DeleteGroup(bool silent)
1238 { 1568 {
1239 lock (m_parts) 1569 // We need to keep track of this state in case this group is still queued for backup.
1570 m_isDeleted = true;
1571
1572 DetachFromBackup();
1573
1574 lockPartsForRead(true);
1575 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1576 lockPartsForRead(false);
1577
1578 foreach (SceneObjectPart part in values)
1240 { 1579 {
1241 foreach (SceneObjectPart part in m_parts.Values)
1242 {
1243// part.Inventory.RemoveScriptInstances(); 1580// part.Inventory.RemoveScriptInstances();
1244 Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1581
1582 Scene.ForEachScenePresence(delegate (ScenePresence sp)
1583 {
1584 if (sp.ParentID == LocalId)
1245 { 1585 {
1246 if (avatar.ParentID == LocalId) 1586 sp.StandUp();
1247 { 1587 }
1248 avatar.StandUp();
1249 }
1250 1588
1251 if (!silent) 1589 if (!silent)
1252 { 1590 {
1253 part.UpdateFlag = 0; 1591 part.UpdateFlag = 0;
1254 if (part == m_rootPart) 1592 if (part == m_rootPart)
1255 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); 1593 sp.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1256 } 1594 }
1257 }); 1595 });
1258 } 1596
1259 } 1597 }
1598
1599
1260 } 1600 }
1261 1601
1262 public void AddScriptLPS(int count) 1602 public void AddScriptLPS(int count)
@@ -1281,17 +1621,20 @@ namespace OpenSim.Region.Framework.Scenes
1281 1621
1282 scriptEvents aggregateScriptEvents = 0; 1622 scriptEvents aggregateScriptEvents = 0;
1283 1623
1284 lock (m_parts) 1624 lockPartsForRead(true);
1285 { 1625 {
1286 foreach (SceneObjectPart part in m_parts.Values) 1626 foreach (SceneObjectPart part in m_parts.Values)
1287 { 1627 {
1628
1288 if (part == null) 1629 if (part == null)
1289 continue; 1630 continue;
1290 if (part != RootPart) 1631 if (part != RootPart)
1291 part.Flags = objectflagupdate; 1632 part.Flags = objectflagupdate;
1292 aggregateScriptEvents |= part.AggregateScriptEvents; 1633 aggregateScriptEvents |= part.AggregateScriptEvents;
1634
1293 } 1635 }
1294 } 1636 }
1637 lockPartsForRead(false);
1295 1638
1296 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); 1639 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
1297 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); 1640 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
@@ -1333,42 +1676,52 @@ namespace OpenSim.Region.Framework.Scenes
1333 /// <param name="m_physicalPrim"></param> 1676 /// <param name="m_physicalPrim"></param>
1334 public void ApplyPhysics(bool m_physicalPrim) 1677 public void ApplyPhysics(bool m_physicalPrim)
1335 { 1678 {
1336 lock (m_parts) 1679 lockPartsForRead(true);
1680
1681 if (m_parts.Count > 1)
1337 { 1682 {
1338 if (m_parts.Count > 1) 1683 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1684 lockPartsForRead(false);
1685 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1686 foreach (SceneObjectPart part in values)
1339 { 1687 {
1340 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); 1688
1341 foreach (SceneObjectPart part in m_parts.Values) 1689 if (part.LocalId != m_rootPart.LocalId)
1342 { 1690 {
1343 if (part.LocalId != m_rootPart.LocalId) 1691 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1344 {
1345 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1346 }
1347 } 1692 }
1348 1693
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 } 1694 }
1695 // Hack to get the physics scene geometries in the right spot
1696 ResetChildPrimPhysicsPositions();
1697 }
1698 else
1699 {
1700 lockPartsForRead(false);
1701 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1356 } 1702 }
1357 } 1703 }
1358 1704
1359 public void SetOwnerId(UUID userId) 1705 public void SetOwnerId(UUID userId)
1360 { 1706 {
1361 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1707 ForEachPart(delegate(SceneObjectPart part)
1708 {
1709
1710 part.OwnerID = userId;
1711
1712 });
1362 } 1713 }
1363 1714
1364 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1715 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1365 { 1716 {
1366 lock (m_parts) 1717 lockPartsForRead(true);
1718 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1719 lockPartsForRead(false);
1720 foreach (SceneObjectPart part in values)
1367 { 1721 {
1368 foreach (SceneObjectPart part in m_parts.Values) 1722
1369 { 1723 whatToDo(part);
1370 whatToDo(part); 1724
1371 }
1372 } 1725 }
1373 } 1726 }
1374 1727
@@ -1398,7 +1751,10 @@ namespace OpenSim.Region.Framework.Scenes
1398 // any exception propogate upwards. 1751 // any exception propogate upwards.
1399 try 1752 try
1400 { 1753 {
1401 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1754 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1755 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1756 m_scene.LoadingPrims) // Land may not be valid yet
1757
1402 { 1758 {
1403 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1759 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1404 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1760 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1430,6 +1786,16 @@ namespace OpenSim.Region.Framework.Scenes
1430 // don't backup while it's selected or you're asking for changes mid stream. 1786 // don't backup while it's selected or you're asking for changes mid stream.
1431 if (isTimeToPersist() || forcedBackup) 1787 if (isTimeToPersist() || forcedBackup)
1432 { 1788 {
1789 if (m_rootPart.PhysActor != null &&
1790 (!m_rootPart.PhysActor.IsPhysical))
1791 {
1792 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1793 {
1794 m_rootPart.PhysActor.Position = m_rootPart.GroupPosition;
1795 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
1796 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
1797 }
1798 }
1433// m_log.DebugFormat( 1799// m_log.DebugFormat(
1434// "[SCENE]: Storing {0}, {1} in {2}", 1800// "[SCENE]: Storing {0}, {1} in {2}",
1435// Name, UUID, m_scene.RegionInfo.RegionName); 1801// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1474,15 +1840,17 @@ namespace OpenSim.Region.Framework.Scenes
1474 RootPart.SendFullUpdate( 1840 RootPart.SendFullUpdate(
1475 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); 1841 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
1476 1842
1477 lock (m_parts) 1843 lockPartsForRead(true);
1478 { 1844 {
1479 foreach (SceneObjectPart part in m_parts.Values) 1845 foreach (SceneObjectPart part in m_parts.Values)
1480 { 1846 {
1847
1481 if (part != RootPart) 1848 if (part != RootPart)
1482 part.SendFullUpdate( 1849 part.SendFullUpdate(
1483 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); 1850 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
1484 } 1851 }
1485 } 1852 }
1853 lockPartsForRead(false);
1486 } 1854 }
1487 1855
1488 #region Copying 1856 #region Copying
@@ -1494,86 +1862,112 @@ namespace OpenSim.Region.Framework.Scenes
1494 /// <returns></returns> 1862 /// <returns></returns>
1495 public SceneObjectGroup Copy(bool userExposed) 1863 public SceneObjectGroup Copy(bool userExposed)
1496 { 1864 {
1497 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1865 SceneObjectGroup dupe;
1498 dupe.m_isBackedUp = false; 1866 try
1499 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>(); 1867 {
1868 m_dupeInProgress = true;
1869 dupe = (SceneObjectGroup)MemberwiseClone();
1870 dupe.m_isBackedUp = false;
1871 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
1500 1872
1501 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1873 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1502 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1874 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1503 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1875 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1504 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1876 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1505 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1877 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1506 // then restore it's attachment state 1878 // then restore it's attachment state
1507 1879
1508 // This is only necessary when userExposed is false! 1880 // This is only necessary when userExposed is false!
1509 1881
1510 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1882 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1511
1512 if (!userExposed)
1513 dupe.RootPart.IsAttachment = true;
1514 1883
1515 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1884 if (!userExposed)
1885 dupe.RootPart.IsAttachment = true;
1516 1886
1517 if (!userExposed) 1887 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1518 {
1519 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1520 }
1521 1888
1522 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1889 if (!userExposed)
1523 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1890 {
1891 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1892 }
1524 1893
1525 if (userExposed) 1894 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1526 dupe.m_rootPart.TrimPermissions(); 1895 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1527 1896
1528 List<SceneObjectPart> partList; 1897 if (userExposed)
1898 dupe.m_rootPart.TrimPermissions();
1529 1899
1530 lock (m_parts) 1900 /// may need to create a new Physics actor.
1531 { 1901 if (dupe.RootPart.PhysActor != null && userExposed)
1532 partList = new List<SceneObjectPart>(m_parts.Values);
1533 }
1534
1535 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1536 { 1902 {
1537 return p1.LinkNum.CompareTo(p2.LinkNum); 1903 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1904
1905 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1906 dupe.RootPart.Name,
1907 pbs,
1908 dupe.RootPart.AbsolutePosition,
1909 dupe.RootPart.Scale,
1910 dupe.RootPart.RotationOffset,
1911 dupe.RootPart.PhysActor.IsPhysical);
1912
1913 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1914 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1538 } 1915 }
1539 );
1540 1916
1541 foreach (SceneObjectPart part in partList) 1917 lockPartsForRead(true);
1542 { 1918
1543 if (part.UUID != m_rootPart.UUID) 1919 List<SceneObjectPart> partList;
1920
1921 partList = new List<SceneObjectPart>(m_parts.Values);
1922
1923 lockPartsForRead(false);
1924
1925 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1926 {
1927 return p1.LinkNum.CompareTo(p2.LinkNum);
1928 }
1929 );
1930
1931 foreach (SceneObjectPart part in partList)
1544 { 1932 {
1545 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1933 if (part.UUID != m_rootPart.UUID)
1546 newPart.LinkNum = part.LinkNum; 1934 {
1547 } 1935 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1548 1936
1549 // Need to duplicate the physics actor as well 1937 newPart.LinkNum = part.LinkNum;
1550 if (part.PhysActor != null && userExposed) 1938 }
1939
1940 // Need to duplicate the physics actor as well
1941 if (part.PhysActor != null && userExposed)
1942 {
1943 PrimitiveBaseShape pbs = part.Shape;
1944
1945 part.PhysActor
1946 = m_scene.PhysicsScene.AddPrimShape(
1947 part.Name,
1948 pbs,
1949 part.AbsolutePosition,
1950 part.Scale,
1951 part.RotationOffset,
1952 part.PhysActor.IsPhysical);
1953
1954 part.PhysActor.LocalID = part.LocalId;
1955 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1956 }
1957 }
1958 if (userExposed)
1551 { 1959 {
1552 PrimitiveBaseShape pbs = part.Shape; 1960 dupe.UpdateParentIDs();
1553 1961 dupe.HasGroupChanged = true;
1554 part.PhysActor 1962 dupe.AttachToBackup();
1555 = m_scene.PhysicsScene.AddPrimShape( 1963
1556 part.Name, 1964 ScheduleGroupForFullUpdate();
1557 pbs,
1558 part.AbsolutePosition,
1559 part.Scale,
1560 part.RotationOffset,
1561 part.PhysActor.IsPhysical);
1562
1563 part.PhysActor.LocalID = part.LocalId;
1564 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1565 } 1965 }
1566 } 1966 }
1567 1967 finally
1568 if (userExposed)
1569 { 1968 {
1570 dupe.UpdateParentIDs(); 1969 m_dupeInProgress = false;
1571 dupe.HasGroupChanged = true;
1572 dupe.AttachToBackup();
1573
1574 ScheduleGroupForFullUpdate();
1575 } 1970 }
1576
1577 return dupe; 1971 return dupe;
1578 } 1972 }
1579 1973
@@ -1764,13 +2158,40 @@ namespace OpenSim.Region.Framework.Scenes
1764 } 2158 }
1765 } 2159 }
1766 2160
2161 public void rotLookAt(Quaternion target, float strength, float damping)
2162 {
2163 SceneObjectPart rootpart = m_rootPart;
2164 if (rootpart != null)
2165 {
2166 if (IsAttachment)
2167 {
2168 /*
2169 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2170 if (avatar != null)
2171 {
2172 Rotate the Av?
2173 } */
2174 }
2175 else
2176 {
2177 if (rootpart.PhysActor != null)
2178 { // APID must be implemented in your physics system for this to function.
2179 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2180 rootpart.PhysActor.APIDStrength = strength;
2181 rootpart.PhysActor.APIDDamping = damping;
2182 rootpart.PhysActor.APIDActive = true;
2183 }
2184 }
2185 }
2186 }
2187
1767 public void stopLookAt() 2188 public void stopLookAt()
1768 { 2189 {
1769 SceneObjectPart rootpart = m_rootPart; 2190 SceneObjectPart rootpart = m_rootPart;
1770 if (rootpart != null) 2191 if (rootpart != null)
1771 { 2192 {
1772 if (rootpart.PhysActor != null) 2193 if (rootpart.PhysActor != null)
1773 { 2194 { // APID must be implemented in your physics system for this to function.
1774 rootpart.PhysActor.APIDActive = false; 2195 rootpart.PhysActor.APIDActive = false;
1775 } 2196 }
1776 } 2197 }
@@ -1835,14 +2256,14 @@ namespace OpenSim.Region.Framework.Scenes
1835 /// <param name="cGroupID"></param> 2256 /// <param name="cGroupID"></param>
1836 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2257 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1837 { 2258 {
1838 SceneObjectPart newPart = null; 2259 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1839 2260 newPart.SetParent(this);
1840 lock (m_parts) 2261
2262 lockPartsForWrite(true);
1841 { 2263 {
1842 newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1843 newPart.SetParent(this);
1844 m_parts.Add(newPart.UUID, newPart); 2264 m_parts.Add(newPart.UUID, newPart);
1845 } 2265 }
2266 lockPartsForWrite(false);
1846 2267
1847 SetPartAsNonRoot(newPart); 2268 SetPartAsNonRoot(newPart);
1848 2269
@@ -1906,6 +2327,8 @@ namespace OpenSim.Region.Framework.Scenes
1906 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) 2327 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1907 // return; 2328 // return;
1908 2329
2330 lockPartsForRead(true);
2331
1909 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2332 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1910 2333
1911 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) 2334 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
@@ -1921,8 +2344,7 @@ namespace OpenSim.Region.Framework.Scenes
1921 } 2344 }
1922 2345
1923 List<SceneObjectPart> partList = null; 2346 List<SceneObjectPart> partList = null;
1924 lock (m_parts) 2347 partList = new List<SceneObjectPart>(m_parts.Values);
1925 partList = new List<SceneObjectPart>(m_parts.Values);
1926 2348
1927 foreach (SceneObjectPart part in partList) 2349 foreach (SceneObjectPart part in partList)
1928 { 2350 {
@@ -1930,6 +2352,7 @@ namespace OpenSim.Region.Framework.Scenes
1930 part.UpdateLookAt(); 2352 part.UpdateLookAt();
1931 part.SendScheduledUpdates(); 2353 part.SendScheduledUpdates();
1932 } 2354 }
2355 lockPartsForRead(false);
1933 } 2356 }
1934 2357
1935 public void ScheduleFullUpdateToAvatar(ScenePresence presence) 2358 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
@@ -1938,27 +2361,29 @@ namespace OpenSim.Region.Framework.Scenes
1938 2361
1939 RootPart.AddFullUpdateToAvatar(presence); 2362 RootPart.AddFullUpdateToAvatar(presence);
1940 2363
1941 lock (m_parts) 2364 lockPartsForRead(true);
1942 { 2365 {
1943 foreach (SceneObjectPart part in m_parts.Values) 2366 foreach (SceneObjectPart part in m_parts.Values)
1944 { 2367 {
2368
1945 if (part != RootPart) 2369 if (part != RootPart)
1946 part.AddFullUpdateToAvatar(presence); 2370 part.AddFullUpdateToAvatar(presence);
2371
1947 } 2372 }
1948 } 2373 }
2374 lockPartsForRead(false);
1949 } 2375 }
1950 2376
1951 public void ScheduleTerseUpdateToAvatar(ScenePresence presence) 2377 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1952 { 2378 {
1953// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); 2379 lockPartsForRead(true);
1954 2380
1955 lock (m_parts) 2381 foreach (SceneObjectPart part in m_parts.Values)
1956 { 2382 {
1957 foreach (SceneObjectPart part in m_parts.Values) 2383 part.AddTerseUpdateToAvatar(presence);
1958 {
1959 part.AddTerseUpdateToAvatar(presence);
1960 }
1961 } 2384 }
2385
2386 lockPartsForRead(false);
1962 } 2387 }
1963 2388
1964 /// <summary> 2389 /// <summary>
@@ -1972,14 +2397,17 @@ namespace OpenSim.Region.Framework.Scenes
1972 checkAtTargets(); 2397 checkAtTargets();
1973 RootPart.ScheduleFullUpdate(); 2398 RootPart.ScheduleFullUpdate();
1974 2399
1975 lock (m_parts) 2400 lockPartsForRead(true);
1976 { 2401 {
1977 foreach (SceneObjectPart part in m_parts.Values) 2402 foreach (SceneObjectPart part in m_parts.Values)
1978 { 2403 {
2404
1979 if (part != RootPart) 2405 if (part != RootPart)
1980 part.ScheduleFullUpdate(); 2406 part.ScheduleFullUpdate();
2407
1981 } 2408 }
1982 } 2409 }
2410 lockPartsForRead(false);
1983 } 2411 }
1984 2412
1985 /// <summary> 2413 /// <summary>
@@ -1987,37 +2415,38 @@ namespace OpenSim.Region.Framework.Scenes
1987 /// </summary> 2415 /// </summary>
1988 public void ScheduleGroupForTerseUpdate() 2416 public void ScheduleGroupForTerseUpdate()
1989 { 2417 {
1990// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); 2418 lockPartsForRead(true);
1991 2419 foreach (SceneObjectPart part in m_parts.Values)
1992 lock (m_parts)
1993 { 2420 {
1994 foreach (SceneObjectPart part in m_parts.Values) 2421 part.ScheduleTerseUpdate();
1995 {
1996 part.ScheduleTerseUpdate();
1997 }
1998 } 2422 }
2423
2424 lockPartsForRead(false);
1999 } 2425 }
2000 2426
2001 /// <summary> 2427 /// <summary>
2002 /// Immediately send a full update for this scene object. 2428 /// Immediately send a full update for this scene object.
2003 /// </summary> 2429 /// </summary>
2004 public void SendGroupFullUpdate() 2430 public void SendGroupFullUpdate()
2005 { 2431 {
2006 if (IsDeleted) 2432 if (IsDeleted)
2007 return; 2433 return;
2008 2434
2009// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2435// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2010 2436
2011 RootPart.SendFullUpdateToAllClients(); 2437 RootPart.SendFullUpdateToAllClients();
2012 2438
2013 lock (m_parts) 2439 lockPartsForRead(true);
2014 { 2440 {
2015 foreach (SceneObjectPart part in m_parts.Values) 2441 foreach (SceneObjectPart part in m_parts.Values)
2016 { 2442 {
2443
2017 if (part != RootPart) 2444 if (part != RootPart)
2018 part.SendFullUpdateToAllClients(); 2445 part.SendFullUpdateToAllClients();
2446
2019 } 2447 }
2020 } 2448 }
2449 lockPartsForRead(false);
2021 } 2450 }
2022 2451
2023 /// <summary> 2452 /// <summary>
@@ -2049,14 +2478,15 @@ namespace OpenSim.Region.Framework.Scenes
2049 { 2478 {
2050 if (IsDeleted) 2479 if (IsDeleted)
2051 return; 2480 return;
2052 2481
2053 lock (m_parts) 2482 lockPartsForRead(true);
2054 { 2483 {
2055 foreach (SceneObjectPart part in m_parts.Values) 2484 foreach (SceneObjectPart part in m_parts.Values)
2056 { 2485 {
2057 part.SendTerseUpdateToAllClients(); 2486 part.SendTerseUpdateToAllClients();
2058 } 2487 }
2059 } 2488 }
2489 lockPartsForRead(false);
2060 } 2490 }
2061 2491
2062 #endregion 2492 #endregion
@@ -2070,16 +2500,18 @@ namespace OpenSim.Region.Framework.Scenes
2070 /// <returns>null if no child part with that linknum or child part</returns> 2500 /// <returns>null if no child part with that linknum or child part</returns>
2071 public SceneObjectPart GetLinkNumPart(int linknum) 2501 public SceneObjectPart GetLinkNumPart(int linknum)
2072 { 2502 {
2073 lock (m_parts) 2503 lockPartsForRead(true);
2074 { 2504 {
2075 foreach (SceneObjectPart part in m_parts.Values) 2505 foreach (SceneObjectPart part in m_parts.Values)
2076 { 2506 {
2077 if (part.LinkNum == linknum) 2507 if (part.LinkNum == linknum)
2078 { 2508 {
2509 lockPartsForRead(false);
2079 return part; 2510 return part;
2080 } 2511 }
2081 } 2512 }
2082 } 2513 }
2514 lockPartsForRead(false);
2083 2515
2084 return null; 2516 return null;
2085 } 2517 }
@@ -2105,17 +2537,19 @@ namespace OpenSim.Region.Framework.Scenes
2105 public SceneObjectPart GetChildPart(uint localID) 2537 public SceneObjectPart GetChildPart(uint localID)
2106 { 2538 {
2107 //m_log.DebugFormat("Entered looking for {0}", localID); 2539 //m_log.DebugFormat("Entered looking for {0}", localID);
2108 lock (m_parts) 2540 lockPartsForRead(true);
2109 { 2541 {
2110 foreach (SceneObjectPart part in m_parts.Values) 2542 foreach (SceneObjectPart part in m_parts.Values)
2111 { 2543 {
2112 //m_log.DebugFormat("Found {0}", part.LocalId); 2544 //m_log.DebugFormat("Found {0}", part.LocalId);
2113 if (part.LocalId == localID) 2545 if (part.LocalId == localID)
2114 { 2546 {
2547 lockPartsForRead(false);
2115 return part; 2548 return part;
2116 } 2549 }
2117 } 2550 }
2118 } 2551 }
2552 lockPartsForRead(false);
2119 2553
2120 return null; 2554 return null;
2121 } 2555 }
@@ -2146,17 +2580,19 @@ namespace OpenSim.Region.Framework.Scenes
2146 public bool HasChildPrim(uint localID) 2580 public bool HasChildPrim(uint localID)
2147 { 2581 {
2148 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); 2582 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
2149 lock (m_parts) 2583 lockPartsForRead(true);
2150 { 2584 {
2151 foreach (SceneObjectPart part in m_parts.Values) 2585 foreach (SceneObjectPart part in m_parts.Values)
2152 { 2586 {
2153 //m_log.DebugFormat("Found {0}", part.LocalId); 2587 //m_log.DebugFormat("Found {0}", part.LocalId);
2154 if (part.LocalId == localID) 2588 if (part.LocalId == localID)
2155 { 2589 {
2590 lockPartsForRead(false);
2156 return true; 2591 return true;
2157 } 2592 }
2158 } 2593 }
2159 } 2594 }
2595 lockPartsForRead(false);
2160 2596
2161 return false; 2597 return false;
2162 } 2598 }
@@ -2206,53 +2642,57 @@ namespace OpenSim.Region.Framework.Scenes
2206 if (m_rootPart.LinkNum == 0) 2642 if (m_rootPart.LinkNum == 0)
2207 m_rootPart.LinkNum = 1; 2643 m_rootPart.LinkNum = 1;
2208 2644
2209 lock (m_parts) 2645 lockPartsForWrite(true);
2210 { 2646
2211 m_parts.Add(linkPart.UUID, linkPart); 2647 m_parts.Add(linkPart.UUID, linkPart);
2648
2649 lockPartsForWrite(false);
2212 2650
2213 // Insert in terms of link numbers, the new links 2651 // Insert in terms of link numbers, the new links
2214 // before the current ones (with the exception of 2652 // before the current ones (with the exception of
2215 // the root prim. Shuffle the old ones up 2653 // the root prim. Shuffle the old ones up
2216 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) 2654 lockPartsForRead(true);
2655 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
2656 {
2657 if (kvp.Value.LinkNum != 1)
2217 { 2658 {
2218 if (kvp.Value.LinkNum != 1) 2659 // Don't update root prim link number
2219 { 2660 kvp.Value.LinkNum += objectGroup.PrimCount;
2220 // Don't update root prim link number
2221 kvp.Value.LinkNum += objectGroup.PrimCount;
2222 }
2223 } 2661 }
2662 }
2663 lockPartsForRead(false);
2224 2664
2225 linkPart.LinkNum = 2; 2665 linkPart.LinkNum = 2;
2226 2666
2227 linkPart.SetParent(this); 2667 linkPart.SetParent(this);
2228 linkPart.CreateSelected = true; 2668 linkPart.CreateSelected = true;
2229 2669
2230 //if (linkPart.PhysActor != null) 2670 //if (linkPart.PhysActor != null)
2231 //{ 2671 //{
2232 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2672 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2233 2673
2234 //linkPart.PhysActor = null; 2674 //linkPart.PhysActor = null;
2235 //} 2675 //}
2236 2676
2237 //TODO: rest of parts 2677 //TODO: rest of parts
2238 int linkNum = 3; 2678 int linkNum = 3;
2239 foreach (SceneObjectPart part in objectGroup.Children.Values) 2679 foreach (SceneObjectPart part in objectGroup.Children.Values)
2680 {
2681 if (part.UUID != objectGroup.m_rootPart.UUID)
2240 { 2682 {
2241 if (part.UUID != objectGroup.m_rootPart.UUID) 2683 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2242 {
2243 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2244 }
2245 part.ClearUndoState();
2246 } 2684 }
2685 part.ClearUndoState();
2247 } 2686 }
2248 2687
2249 m_scene.UnlinkSceneObject(objectGroup, true); 2688 m_scene.UnlinkSceneObject(objectGroup, true);
2250 objectGroup.m_isDeleted = true; 2689 objectGroup.m_isDeleted = true;
2690
2691 objectGroup.lockPartsForWrite(true);
2251 2692
2252 lock (objectGroup.m_parts) 2693 objectGroup.m_parts.Clear();
2253 { 2694
2254 objectGroup.m_parts.Clear(); 2695 objectGroup.lockPartsForWrite(false);
2255 }
2256 2696
2257 // Can't do this yet since backup still makes use of the root part without any synchronization 2697 // Can't do this yet since backup still makes use of the root part without any synchronization
2258// objectGroup.m_rootPart = null; 2698// objectGroup.m_rootPart = null;
@@ -2322,23 +2762,23 @@ namespace OpenSim.Region.Framework.Scenes
2322 Quaternion worldRot = linkPart.GetWorldRotation(); 2762 Quaternion worldRot = linkPart.GetWorldRotation();
2323 2763
2324 // Remove the part from this object 2764 // Remove the part from this object
2325 lock (m_parts) 2765 lockPartsForWrite(true);
2326 { 2766 {
2327 m_parts.Remove(linkPart.UUID); 2767 m_parts.Remove(linkPart.UUID);
2328 2768 }
2329 if (m_parts.Count == 1 && RootPart != null) //Single prim is left 2769 lockPartsForWrite(false);
2330 { 2770 lockPartsForRead(true);
2331 RootPart.LinkNum = 0; 2771 if (m_parts.Count == 1 && RootPart != null) //Single prim is left
2332 } 2772 RootPart.LinkNum = 0;
2333 else 2773 else
2774 {
2775 foreach (SceneObjectPart p in m_parts.Values)
2334 { 2776 {
2335 foreach (SceneObjectPart p in m_parts.Values) 2777 if (p.LinkNum > linkPart.LinkNum)
2336 { 2778 p.LinkNum--;
2337 if (p.LinkNum > linkPart.LinkNum)
2338 p.LinkNum--;
2339 }
2340 } 2779 }
2341 } 2780 }
2781 lockPartsForRead(false);
2342 2782
2343 linkPart.ParentID = 0; 2783 linkPart.ParentID = 0;
2344 linkPart.LinkNum = 0; 2784 linkPart.LinkNum = 0;
@@ -2382,6 +2822,8 @@ namespace OpenSim.Region.Framework.Scenes
2382 /// <param name="objectGroup"></param> 2822 /// <param name="objectGroup"></param>
2383 public virtual void DetachFromBackup() 2823 public virtual void DetachFromBackup()
2384 { 2824 {
2825 m_scene.SceneGraph.FireDetachFromBackup(this);
2826
2385 if (m_isBackedUp) 2827 if (m_isBackedUp)
2386 m_scene.EventManager.OnBackup -= ProcessBackup; 2828 m_scene.EventManager.OnBackup -= ProcessBackup;
2387 2829
@@ -2660,9 +3102,12 @@ namespace OpenSim.Region.Framework.Scenes
2660 3102
2661 if (selectionPart != null) 3103 if (selectionPart != null)
2662 { 3104 {
2663 lock (m_parts) 3105 lockPartsForRead(true);
3106 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
3107 lockPartsForRead(false);
3108 foreach (SceneObjectPart part in parts)
2664 { 3109 {
2665 foreach (SceneObjectPart part in m_parts.Values) 3110 if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
2666 { 3111 {
2667 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || 3112 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax ||
2668 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || 3113 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax ||
@@ -2672,12 +3117,13 @@ namespace OpenSim.Region.Framework.Scenes
2672 break; 3117 break;
2673 } 3118 }
2674 } 3119 }
3120 }
2675 3121
2676 foreach (SceneObjectPart part in m_parts.Values) 3122 foreach (SceneObjectPart part in parts)
2677 { 3123 {
2678 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3124 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2679 }
2680 } 3125 }
3126
2681 } 3127 }
2682 } 3128 }
2683 3129
@@ -2690,6 +3136,17 @@ namespace OpenSim.Region.Framework.Scenes
2690 } 3136 }
2691 } 3137 }
2692 3138
3139
3140
3141 /// <summary>
3142 /// Gets the number of parts
3143 /// </summary>
3144 /// <returns></returns>
3145 public int GetPartCount()
3146 {
3147 return Children.Count;
3148 }
3149
2693 /// <summary> 3150 /// <summary>
2694 /// Get the parts of this scene object 3151 /// Get the parts of this scene object
2695 /// </summary> 3152 /// </summary>
@@ -2766,11 +3223,9 @@ namespace OpenSim.Region.Framework.Scenes
2766 scale.Y = m_scene.m_maxNonphys; 3223 scale.Y = m_scene.m_maxNonphys;
2767 if (scale.Z > m_scene.m_maxNonphys) 3224 if (scale.Z > m_scene.m_maxNonphys)
2768 scale.Z = m_scene.m_maxNonphys; 3225 scale.Z = m_scene.m_maxNonphys;
2769
2770 SceneObjectPart part = GetChildPart(localID); 3226 SceneObjectPart part = GetChildPart(localID);
2771 if (part != null) 3227 if (part != null)
2772 { 3228 {
2773 part.Resize(scale);
2774 if (part.PhysActor != null) 3229 if (part.PhysActor != null)
2775 { 3230 {
2776 if (part.PhysActor.IsPhysical) 3231 if (part.PhysActor.IsPhysical)
@@ -2785,7 +3240,7 @@ namespace OpenSim.Region.Framework.Scenes
2785 part.PhysActor.Size = scale; 3240 part.PhysActor.Size = scale;
2786 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 3241 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2787 } 3242 }
2788 //if (part.UUID != m_rootPart.UUID) 3243 part.Resize(scale);
2789 3244
2790 HasGroupChanged = true; 3245 HasGroupChanged = true;
2791 ScheduleGroupForFullUpdate(); 3246 ScheduleGroupForFullUpdate();
@@ -2807,7 +3262,6 @@ namespace OpenSim.Region.Framework.Scenes
2807 SceneObjectPart part = GetChildPart(localID); 3262 SceneObjectPart part = GetChildPart(localID);
2808 if (part != null) 3263 if (part != null)
2809 { 3264 {
2810 part.IgnoreUndoUpdate = true;
2811 if (scale.X > m_scene.m_maxNonphys) 3265 if (scale.X > m_scene.m_maxNonphys)
2812 scale.X = m_scene.m_maxNonphys; 3266 scale.X = m_scene.m_maxNonphys;
2813 if (scale.Y > m_scene.m_maxNonphys) 3267 if (scale.Y > m_scene.m_maxNonphys)
@@ -2827,94 +3281,100 @@ namespace OpenSim.Region.Framework.Scenes
2827 float y = (scale.Y / part.Scale.Y); 3281 float y = (scale.Y / part.Scale.Y);
2828 float z = (scale.Z / part.Scale.Z); 3282 float z = (scale.Z / part.Scale.Z);
2829 3283
2830 lock (m_parts) 3284 lockPartsForRead(true);
3285 if (x > 1.0f || y > 1.0f || z > 1.0f)
2831 { 3286 {
2832 if (x > 1.0f || y > 1.0f || z > 1.0f) 3287 foreach (SceneObjectPart obPart in m_parts.Values)
2833 { 3288 {
2834 foreach (SceneObjectPart obPart in m_parts.Values) 3289 if (obPart.UUID != m_rootPart.UUID)
2835 { 3290 {
2836 if (obPart.UUID != m_rootPart.UUID) 3291 Vector3 oldSize = new Vector3(obPart.Scale);
2837 { 3292 obPart.IgnoreUndoUpdate = true;
2838 obPart.IgnoreUndoUpdate = true;
2839 Vector3 oldSize = new Vector3(obPart.Scale);
2840 3293
2841 float f = 1.0f; 3294 float f = 1.0f;
2842 float a = 1.0f; 3295 float a = 1.0f;
2843 3296
2844 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3297 if (part.PhysActor != null && part.PhysActor.IsPhysical)
3298 {
3299 if (oldSize.X*x > m_scene.m_maxPhys)
2845 { 3300 {
2846 if (oldSize.X*x > m_scene.m_maxPhys) 3301 f = m_scene.m_maxPhys / oldSize.X;
2847 { 3302 a = f / x;
2848 f = m_scene.m_maxPhys / oldSize.X; 3303 x *= a;
2849 a = f / x; 3304 y *= a;
2850 x *= a; 3305 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 } 3306 }
2871 else 3307 if (oldSize.Y*y > m_scene.m_maxPhys)
3308 {
3309 f = m_scene.m_maxPhys / oldSize.Y;
3310 a = f / y;
3311 x *= a;
3312 y *= a;
3313 z *= a;
3314 }
3315 if (oldSize.Z*z > m_scene.m_maxPhys)
3316 {
3317 f = m_scene.m_maxPhys / oldSize.Z;
3318 a = f / z;
3319 x *= a;
3320 y *= a;
3321 z *= a;
3322 }
3323 }
3324 else
3325 {
3326 if (oldSize.X*x > m_scene.m_maxNonphys)
3327 {
3328 f = m_scene.m_maxNonphys / oldSize.X;
3329 a = f / x;
3330 x *= a;
3331 y *= a;
3332 z *= a;
3333 }
3334 if (oldSize.Y*y > m_scene.m_maxNonphys)
2872 { 3335 {
2873 if (oldSize.X*x > m_scene.m_maxNonphys) 3336 f = m_scene.m_maxNonphys / oldSize.Y;
2874 { 3337 a = f / y;
2875 f = m_scene.m_maxNonphys / oldSize.X; 3338 x *= a;
2876 a = f / x; 3339 y *= a;
2877 x *= a; 3340 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 } 3341 }
2898 obPart.IgnoreUndoUpdate = false; 3342 if (oldSize.Z*z > m_scene.m_maxNonphys)
2899 obPart.StoreUndoState(); 3343 {
3344 f = m_scene.m_maxNonphys / oldSize.Z;
3345 a = f / z;
3346 x *= a;
3347 y *= a;
3348 z *= a;
3349 }
3350
2900 } 3351 }
2901 } 3352 }
2902 } 3353 }
2903 } 3354 }
3355 lockPartsForRead(false);
2904 3356
2905 Vector3 prevScale = part.Scale; 3357 Vector3 prevScale = part.Scale;
2906 prevScale.X *= x; 3358 prevScale.X *= x;
2907 prevScale.Y *= y; 3359 prevScale.Y *= y;
2908 prevScale.Z *= z; 3360 prevScale.Z *= z;;
3361
3362 part.IgnoreUndoUpdate = false;
3363 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3364 part.IgnoreUndoUpdate = true;
2909 part.Resize(prevScale); 3365 part.Resize(prevScale);
3366 part.IgnoreUndoUpdate = false;
2910 3367
2911 lock (m_parts) 3368 lockPartsForRead(true);
2912 { 3369 {
2913 foreach (SceneObjectPart obPart in m_parts.Values) 3370 foreach (SceneObjectPart obPart in m_parts.Values)
2914 { 3371 {
2915 obPart.IgnoreUndoUpdate = true;
2916 if (obPart.UUID != m_rootPart.UUID) 3372 if (obPart.UUID != m_rootPart.UUID)
2917 { 3373 {
3374 obPart.IgnoreUndoUpdate = false;
3375 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3376 obPart.IgnoreUndoUpdate = true;
3377
2918 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3378 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2919 currentpos.X *= x; 3379 currentpos.X *= x;
2920 currentpos.Y *= y; 3380 currentpos.Y *= y;
@@ -2927,9 +3387,9 @@ namespace OpenSim.Region.Framework.Scenes
2927 obPart.UpdateOffSet(currentpos); 3387 obPart.UpdateOffSet(currentpos);
2928 } 3388 }
2929 obPart.IgnoreUndoUpdate = false; 3389 obPart.IgnoreUndoUpdate = false;
2930 obPart.StoreUndoState();
2931 } 3390 }
2932 } 3391 }
3392 lockPartsForRead(false);
2933 3393
2934 if (part.PhysActor != null) 3394 if (part.PhysActor != null)
2935 { 3395 {
@@ -2938,7 +3398,6 @@ namespace OpenSim.Region.Framework.Scenes
2938 } 3398 }
2939 3399
2940 part.IgnoreUndoUpdate = false; 3400 part.IgnoreUndoUpdate = false;
2941 part.StoreUndoState();
2942 HasGroupChanged = true; 3401 HasGroupChanged = true;
2943 ScheduleGroupForTerseUpdate(); 3402 ScheduleGroupForTerseUpdate();
2944 } 3403 }
@@ -2954,14 +3413,11 @@ namespace OpenSim.Region.Framework.Scenes
2954 /// <param name="pos"></param> 3413 /// <param name="pos"></param>
2955 public void UpdateGroupPosition(Vector3 pos) 3414 public void UpdateGroupPosition(Vector3 pos)
2956 { 3415 {
2957 foreach (SceneObjectPart part in Children.Values)
2958 {
2959 part.StoreUndoState();
2960 }
2961 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3416 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2962 { 3417 {
2963 if (IsAttachment) 3418 if (IsAttachment)
2964 { 3419 {
3420 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2965 m_rootPart.AttachedPos = pos; 3421 m_rootPart.AttachedPos = pos;
2966 } 3422 }
2967 if (RootPart.GetStatusSandbox()) 3423 if (RootPart.GetStatusSandbox())
@@ -2994,7 +3450,7 @@ namespace OpenSim.Region.Framework.Scenes
2994 SceneObjectPart part = GetChildPart(localID); 3450 SceneObjectPart part = GetChildPart(localID);
2995 foreach (SceneObjectPart parts in Children.Values) 3451 foreach (SceneObjectPart parts in Children.Values)
2996 { 3452 {
2997 parts.StoreUndoState(); 3453 parts.StoreUndoState(UndoType.STATE_PRIM_POSITION);
2998 } 3454 }
2999 if (part != null) 3455 if (part != null)
3000 { 3456 {
@@ -3019,7 +3475,7 @@ namespace OpenSim.Region.Framework.Scenes
3019 { 3475 {
3020 foreach (SceneObjectPart part in Children.Values) 3476 foreach (SceneObjectPart part in Children.Values)
3021 { 3477 {
3022 part.StoreUndoState(); 3478 part.StoreUndoState(UndoType.STATE_PRIM_POSITION);
3023 } 3479 }
3024 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3480 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3025 Vector3 oldPos = 3481 Vector3 oldPos =
@@ -3032,7 +3488,7 @@ namespace OpenSim.Region.Framework.Scenes
3032 axDiff *= Quaternion.Inverse(partRotation); 3488 axDiff *= Quaternion.Inverse(partRotation);
3033 diff = axDiff; 3489 diff = axDiff;
3034 3490
3035 lock (m_parts) 3491 lockPartsForRead(true);
3036 { 3492 {
3037 foreach (SceneObjectPart obPart in m_parts.Values) 3493 foreach (SceneObjectPart obPart in m_parts.Values)
3038 { 3494 {
@@ -3042,11 +3498,29 @@ namespace OpenSim.Region.Framework.Scenes
3042 } 3498 }
3043 } 3499 }
3044 } 3500 }
3501 lockPartsForRead(false);
3045 3502
3046 AbsolutePosition = newPos; 3503 //We have to set undoing here because otherwise an undo state will be saved
3504 if (!m_rootPart.Undoing)
3505 {
3506 m_rootPart.Undoing = true;
3507 AbsolutePosition = newPos;
3508 m_rootPart.Undoing = false;
3509 }
3510 else
3511 {
3512 AbsolutePosition = newPos;
3513 }
3047 3514
3048 HasGroupChanged = true; 3515 HasGroupChanged = true;
3049 ScheduleGroupForTerseUpdate(); 3516 if (m_rootPart.Undoing)
3517 {
3518 ScheduleGroupForFullUpdate();
3519 }
3520 else
3521 {
3522 ScheduleGroupForTerseUpdate();
3523 }
3050 } 3524 }
3051 3525
3052 public void OffsetForNewRegion(Vector3 offset) 3526 public void OffsetForNewRegion(Vector3 offset)
@@ -3066,7 +3540,7 @@ namespace OpenSim.Region.Framework.Scenes
3066 { 3540 {
3067 foreach (SceneObjectPart parts in Children.Values) 3541 foreach (SceneObjectPart parts in Children.Values)
3068 { 3542 {
3069 parts.StoreUndoState(); 3543 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3070 } 3544 }
3071 m_rootPart.UpdateRotation(rot); 3545 m_rootPart.UpdateRotation(rot);
3072 3546
@@ -3090,7 +3564,7 @@ namespace OpenSim.Region.Framework.Scenes
3090 { 3564 {
3091 foreach (SceneObjectPart parts in Children.Values) 3565 foreach (SceneObjectPart parts in Children.Values)
3092 { 3566 {
3093 parts.StoreUndoState(); 3567 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3094 } 3568 }
3095 m_rootPart.UpdateRotation(rot); 3569 m_rootPart.UpdateRotation(rot);
3096 3570
@@ -3117,7 +3591,7 @@ namespace OpenSim.Region.Framework.Scenes
3117 SceneObjectPart part = GetChildPart(localID); 3591 SceneObjectPart part = GetChildPart(localID);
3118 foreach (SceneObjectPart parts in Children.Values) 3592 foreach (SceneObjectPart parts in Children.Values)
3119 { 3593 {
3120 parts.StoreUndoState(); 3594 parts.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3121 } 3595 }
3122 if (part != null) 3596 if (part != null)
3123 { 3597 {
@@ -3145,15 +3619,24 @@ namespace OpenSim.Region.Framework.Scenes
3145 if (part.UUID == m_rootPart.UUID) 3619 if (part.UUID == m_rootPart.UUID)
3146 { 3620 {
3147 UpdateRootRotation(rot); 3621 UpdateRootRotation(rot);
3148 AbsolutePosition = pos; 3622 if (!m_rootPart.Undoing)
3623 {
3624 m_rootPart.Undoing = true;
3625 AbsolutePosition = pos;
3626 m_rootPart.Undoing = false;
3627 }
3628 else
3629 {
3630 AbsolutePosition = pos;
3631 }
3149 } 3632 }
3150 else 3633 else
3151 { 3634 {
3635 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3152 part.IgnoreUndoUpdate = true; 3636 part.IgnoreUndoUpdate = true;
3153 part.UpdateRotation(rot); 3637 part.UpdateRotation(rot);
3154 part.OffsetPosition = pos; 3638 part.OffsetPosition = pos;
3155 part.IgnoreUndoUpdate = false; 3639 part.IgnoreUndoUpdate = false;
3156 part.StoreUndoState();
3157 } 3640 }
3158 } 3641 }
3159 } 3642 }
@@ -3167,7 +3650,13 @@ namespace OpenSim.Region.Framework.Scenes
3167 Quaternion axRot = rot; 3650 Quaternion axRot = rot;
3168 Quaternion oldParentRot = m_rootPart.RotationOffset; 3651 Quaternion oldParentRot = m_rootPart.RotationOffset;
3169 3652
3170 m_rootPart.StoreUndoState(); 3653 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3654 bool cancelUndo = false;
3655 if (!m_rootPart.Undoing)
3656 {
3657 m_rootPart.Undoing = true;
3658 cancelUndo = true;
3659 }
3171 m_rootPart.UpdateRotation(rot); 3660 m_rootPart.UpdateRotation(rot);
3172 if (m_rootPart.PhysActor != null) 3661 if (m_rootPart.PhysActor != null)
3173 { 3662 {
@@ -3175,33 +3664,31 @@ namespace OpenSim.Region.Framework.Scenes
3175 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 3664 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
3176 } 3665 }
3177 3666
3178 lock (m_parts) 3667 lockPartsForRead(true);
3668
3669 foreach (SceneObjectPart prim in m_parts.Values)
3179 { 3670 {
3180 foreach (SceneObjectPart prim in m_parts.Values) 3671 if (prim.UUID != m_rootPart.UUID)
3181 { 3672 {
3182 if (prim.UUID != m_rootPart.UUID) 3673 prim.IgnoreUndoUpdate = true;
3183 { 3674 Vector3 axPos = prim.OffsetPosition;
3184 prim.IgnoreUndoUpdate = true; 3675 axPos *= oldParentRot;
3185 Vector3 axPos = prim.OffsetPosition; 3676 axPos *= Quaternion.Inverse(axRot);
3186 axPos *= oldParentRot; 3677 prim.OffsetPosition = axPos;
3187 axPos *= Quaternion.Inverse(axRot); 3678 Quaternion primsRot = prim.RotationOffset;
3188 prim.OffsetPosition = axPos; 3679 Quaternion newRot = primsRot * oldParentRot;
3189 Quaternion primsRot = prim.RotationOffset; 3680 newRot *= Quaternion.Inverse(axRot);
3190 Quaternion newRot = primsRot * oldParentRot; 3681 prim.RotationOffset = newRot;
3191 newRot *= Quaternion.Inverse(axRot); 3682 prim.ScheduleTerseUpdate();
3192 prim.RotationOffset = newRot; 3683 prim.IgnoreUndoUpdate = false;
3193 prim.ScheduleTerseUpdate();
3194 }
3195 } 3684 }
3196 } 3685 }
3197 foreach (SceneObjectPart childpart in Children.Values) 3686 if (cancelUndo == true)
3198 { 3687 {
3199 if (childpart != m_rootPart) 3688 m_rootPart.Undoing = false;
3200 {
3201 childpart.IgnoreUndoUpdate = false;
3202 childpart.StoreUndoState();
3203 }
3204 } 3689 }
3690 lockPartsForRead(false);
3691
3205 m_rootPart.ScheduleTerseUpdate(); 3692 m_rootPart.ScheduleTerseUpdate();
3206 } 3693 }
3207 3694
@@ -3323,7 +3810,7 @@ namespace OpenSim.Region.Framework.Scenes
3323 if (atTargets.Count > 0) 3810 if (atTargets.Count > 0)
3324 { 3811 {
3325 uint[] localids = new uint[0]; 3812 uint[] localids = new uint[0];
3326 lock (m_parts) 3813 lockPartsForRead(true);
3327 { 3814 {
3328 localids = new uint[m_parts.Count]; 3815 localids = new uint[m_parts.Count];
3329 int cntr = 0; 3816 int cntr = 0;
@@ -3333,6 +3820,7 @@ namespace OpenSim.Region.Framework.Scenes
3333 cntr++; 3820 cntr++;
3334 } 3821 }
3335 } 3822 }
3823 lockPartsForRead(false);
3336 3824
3337 for (int ctr = 0; ctr < localids.Length; ctr++) 3825 for (int ctr = 0; ctr < localids.Length; ctr++)
3338 { 3826 {
@@ -3351,7 +3839,7 @@ namespace OpenSim.Region.Framework.Scenes
3351 { 3839 {
3352 //trigger not_at_target 3840 //trigger not_at_target
3353 uint[] localids = new uint[0]; 3841 uint[] localids = new uint[0];
3354 lock (m_parts) 3842 lockPartsForRead(true);
3355 { 3843 {
3356 localids = new uint[m_parts.Count]; 3844 localids = new uint[m_parts.Count];
3357 int cntr = 0; 3845 int cntr = 0;
@@ -3361,7 +3849,8 @@ namespace OpenSim.Region.Framework.Scenes
3361 cntr++; 3849 cntr++;
3362 } 3850 }
3363 } 3851 }
3364 3852 lockPartsForRead(false);
3853
3365 for (int ctr = 0; ctr < localids.Length; ctr++) 3854 for (int ctr = 0; ctr < localids.Length; ctr++)
3366 { 3855 {
3367 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); 3856 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
@@ -3402,7 +3891,8 @@ namespace OpenSim.Region.Framework.Scenes
3402 if (atRotTargets.Count > 0) 3891 if (atRotTargets.Count > 0)
3403 { 3892 {
3404 uint[] localids = new uint[0]; 3893 uint[] localids = new uint[0];
3405 lock (m_parts) 3894 lockPartsForRead(true);
3895 try
3406 { 3896 {
3407 localids = new uint[m_parts.Count]; 3897 localids = new uint[m_parts.Count];
3408 int cntr = 0; 3898 int cntr = 0;
@@ -3412,6 +3902,10 @@ namespace OpenSim.Region.Framework.Scenes
3412 cntr++; 3902 cntr++;
3413 } 3903 }
3414 } 3904 }
3905 finally
3906 {
3907 lockPartsForRead(false);
3908 }
3415 3909
3416 for (int ctr = 0; ctr < localids.Length; ctr++) 3910 for (int ctr = 0; ctr < localids.Length; ctr++)
3417 { 3911 {
@@ -3430,7 +3924,8 @@ namespace OpenSim.Region.Framework.Scenes
3430 { 3924 {
3431 //trigger not_at_target 3925 //trigger not_at_target
3432 uint[] localids = new uint[0]; 3926 uint[] localids = new uint[0];
3433 lock (m_parts) 3927 lockPartsForRead(true);
3928 try
3434 { 3929 {
3435 localids = new uint[m_parts.Count]; 3930 localids = new uint[m_parts.Count];
3436 int cntr = 0; 3931 int cntr = 0;
@@ -3440,6 +3935,10 @@ namespace OpenSim.Region.Framework.Scenes
3440 cntr++; 3935 cntr++;
3441 } 3936 }
3442 } 3937 }
3938 finally
3939 {
3940 lockPartsForRead(false);
3941 }
3443 3942
3444 for (int ctr = 0; ctr < localids.Length; ctr++) 3943 for (int ctr = 0; ctr < localids.Length; ctr++)
3445 { 3944 {
@@ -3453,19 +3952,20 @@ namespace OpenSim.Region.Framework.Scenes
3453 public float GetMass() 3952 public float GetMass()
3454 { 3953 {
3455 float retmass = 0f; 3954 float retmass = 0f;
3456 lock (m_parts) 3955 lockPartsForRead(true);
3457 { 3956 {
3458 foreach (SceneObjectPart part in m_parts.Values) 3957 foreach (SceneObjectPart part in m_parts.Values)
3459 { 3958 {
3460 retmass += part.GetMass(); 3959 retmass += part.GetMass();
3461 } 3960 }
3462 } 3961 }
3962 lockPartsForRead(false);
3463 return retmass; 3963 return retmass;
3464 } 3964 }
3465 3965
3466 public void CheckSculptAndLoad() 3966 public void CheckSculptAndLoad()
3467 { 3967 {
3468 lock (m_parts) 3968 lockPartsForRead(true);
3469 { 3969 {
3470 if (!IsDeleted) 3970 if (!IsDeleted)
3471 { 3971 {
@@ -3490,6 +3990,7 @@ namespace OpenSim.Region.Framework.Scenes
3490 } 3990 }
3491 } 3991 }
3492 } 3992 }
3993 lockPartsForRead(false);
3493 } 3994 }
3494 3995
3495 protected void AssetReceived(string id, Object sender, AssetBase asset) 3996 protected void AssetReceived(string id, Object sender, AssetBase asset)
@@ -3510,7 +4011,7 @@ namespace OpenSim.Region.Framework.Scenes
3510 /// <param name="client"></param> 4011 /// <param name="client"></param>
3511 public void SetGroup(UUID GroupID, IClientAPI client) 4012 public void SetGroup(UUID GroupID, IClientAPI client)
3512 { 4013 {
3513 lock (m_parts) 4014 lockPartsForRead(true);
3514 { 4015 {
3515 foreach (SceneObjectPart part in m_parts.Values) 4016 foreach (SceneObjectPart part in m_parts.Values)
3516 { 4017 {
@@ -3520,6 +4021,7 @@ namespace OpenSim.Region.Framework.Scenes
3520 4021
3521 HasGroupChanged = true; 4022 HasGroupChanged = true;
3522 } 4023 }
4024 lockPartsForRead(false);
3523 4025
3524 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 4026 // 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. 4027 // for the same object with very different properties. The caller must schedule the update.
@@ -3541,11 +4043,12 @@ namespace OpenSim.Region.Framework.Scenes
3541 4043
3542 public void SetAttachmentPoint(byte point) 4044 public void SetAttachmentPoint(byte point)
3543 { 4045 {
3544 lock (m_parts) 4046 lockPartsForRead(true);
3545 { 4047 {
3546 foreach (SceneObjectPart part in m_parts.Values) 4048 foreach (SceneObjectPart part in m_parts.Values)
3547 part.SetAttachmentPoint(point); 4049 part.SetAttachmentPoint(point);
3548 } 4050 }
4051 lockPartsForRead(false);
3549 } 4052 }
3550 4053
3551 #region ISceneObject 4054 #region ISceneObject
@@ -3579,6 +4082,14 @@ namespace OpenSim.Region.Framework.Scenes
3579 SetFromItemID(uuid); 4082 SetFromItemID(uuid);
3580 } 4083 }
3581 4084
4085 public void ResetOwnerChangeFlag()
4086 {
4087 ForEachPart(delegate(SceneObjectPart part)
4088 {
4089 part.ResetOwnerChangeFlag();
4090 });
4091 }
4092
3582 #endregion 4093 #endregion
3583 } 4094 }
3584} 4095}