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.cs1130
1 files changed, 820 insertions, 310 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index f9a8d41..3411d18 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -105,8 +105,113 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 105 /// since the group's last persistent backup
106 /// </summary> 106 /// </summary>
107 private bool m_hasGroupChanged = false; 107 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 108 private long timeFirstChanged = 0;
109 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 }
110 215
111 public bool HasGroupChanged 216 public bool HasGroupChanged
112 { 217 {
@@ -114,9 +219,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 219 {
115 if (value) 220 if (value)
116 { 221 {
222 if (m_isBackedUp)
223 {
224 m_scene.SceneGraph.FireChangeBackup(this);
225 }
117 timeLastChanged = DateTime.Now.Ticks; 226 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 227 if (!m_hasGroupChanged)
119 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 }
120 } 255 }
121 m_hasGroupChanged = value; 256 m_hasGroupChanged = value;
122 } 257 }
@@ -132,8 +267,19 @@ namespace OpenSim.Region.Framework.Scenes
132 return false; 267 return false;
133 if (m_scene.ShuttingDown) 268 if (m_scene.ShuttingDown)
134 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
135 long currentTime = DateTime.Now.Ticks; 277 long currentTime = DateTime.Now.Ticks;
136 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)
137 return true; 283 return true;
138 return false; 284 return false;
139 } 285 }
@@ -182,7 +328,7 @@ namespace OpenSim.Region.Framework.Scenes
182 328
183 private bool m_scriptListens_atRotTarget = false; 329 private bool m_scriptListens_atRotTarget = false;
184 private bool m_scriptListens_notAtRotTarget = false; 330 private bool m_scriptListens_notAtRotTarget = false;
185 331 public bool m_dupeInProgress = false;
186 internal Dictionary<UUID, string> m_savedScriptState = null; 332 internal Dictionary<UUID, string> m_savedScriptState = null;
187 333
188 #region Properties 334 #region Properties
@@ -222,7 +368,21 @@ namespace OpenSim.Region.Framework.Scenes
222 public virtual Quaternion Rotation 368 public virtual Quaternion Rotation
223 { 369 {
224 get { return m_rotation; } 370 get { return m_rotation; }
225 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 }
226 } 386 }
227 387
228 public Quaternion GroupRotation 388 public Quaternion GroupRotation
@@ -262,13 +422,16 @@ namespace OpenSim.Region.Framework.Scenes
262 set 422 set
263 { 423 {
264 m_regionHandle = value; 424 m_regionHandle = value;
265 lock (m_parts) 425 lockPartsForRead(true);
266 { 426 {
267 foreach (SceneObjectPart part in m_parts.Values) 427 foreach (SceneObjectPart part in m_parts.Values)
268 { 428 {
429
269 part.RegionHandle = m_regionHandle; 430 part.RegionHandle = m_regionHandle;
431
270 } 432 }
271 } 433 }
434 lockPartsForRead(false);
272 } 435 }
273 } 436 }
274 437
@@ -302,7 +465,12 @@ namespace OpenSim.Region.Framework.Scenes
302 { 465 {
303 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 466 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
304 } 467 }
305 468
469 lockPartsForRead(true);
470 foreach (SceneObjectPart part in m_parts.Values)
471 {
472 part.IgnoreUndoUpdate = true;
473 }
306 if (RootPart.GetStatusSandbox()) 474 if (RootPart.GetStatusSandbox())
307 { 475 {
308 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 476 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -310,15 +478,30 @@ namespace OpenSim.Region.Framework.Scenes
310 RootPart.ScriptSetPhysicsStatus(false); 478 RootPart.ScriptSetPhysicsStatus(false);
311 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), 479 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
312 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); 480 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
481 lockPartsForRead(false);
313 return; 482 return;
314 } 483 }
315 } 484 }
316 485 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
317 lock (m_parts) 486 lockPartsForRead(false);
487 foreach (SceneObjectPart part in parts)
318 { 488 {
319 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)
493 {
494 part.TriggerScriptChangedEvent(Changed.POSITION);
495 }
496 }
497 if (!m_dupeInProgress)
498 {
499 foreach (ScenePresence av in m_linkedAvatars)
320 { 500 {
321 part.GroupPosition = val; 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();
322 } 505 }
323 } 506 }
324 507
@@ -472,6 +655,7 @@ namespace OpenSim.Region.Framework.Scenes
472 /// </summary> 655 /// </summary>
473 public SceneObjectGroup() 656 public SceneObjectGroup()
474 { 657 {
658
475 } 659 }
476 660
477 /// <summary> 661 /// <summary>
@@ -488,7 +672,7 @@ namespace OpenSim.Region.Framework.Scenes
488 /// Constructor. This object is added to the scene later via AttachToScene() 672 /// Constructor. This object is added to the scene later via AttachToScene()
489 /// </summary> 673 /// </summary>
490 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 674 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
491 { 675 {
492 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 676 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
493 } 677 }
494 678
@@ -519,13 +703,16 @@ namespace OpenSim.Region.Framework.Scenes
519 703
520 public void SetFromItemID(UUID AssetId) 704 public void SetFromItemID(UUID AssetId)
521 { 705 {
522 lock (m_parts) 706 lockPartsForRead(true);
523 { 707 {
524 foreach (SceneObjectPart part in m_parts.Values) 708 foreach (SceneObjectPart part in m_parts.Values)
525 { 709 {
710
526 part.FromItemID = AssetId; 711 part.FromItemID = AssetId;
712
527 } 713 }
528 } 714 }
715 lockPartsForRead(false);
529 } 716 }
530 717
531 public UUID GetFromItemID() 718 public UUID GetFromItemID()
@@ -538,6 +725,9 @@ namespace OpenSim.Region.Framework.Scenes
538 /// </summary> 725 /// </summary>
539 public virtual void AttachToBackup() 726 public virtual void AttachToBackup()
540 { 727 {
728 if (IsAttachment) return;
729 m_scene.SceneGraph.FireAttachToBackup(this);
730
541 if (InSceneBackup) 731 if (InSceneBackup)
542 { 732 {
543 //m_log.DebugFormat( 733 //m_log.DebugFormat(
@@ -596,7 +786,7 @@ namespace OpenSim.Region.Framework.Scenes
596 Vector3 maxScale = Vector3.Zero; 786 Vector3 maxScale = Vector3.Zero;
597 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 787 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
598 788
599 lock (m_parts) 789 lockPartsForRead(true);
600 { 790 {
601 foreach (SceneObjectPart part in m_parts.Values) 791 foreach (SceneObjectPart part in m_parts.Values)
602 { 792 {
@@ -610,8 +800,11 @@ namespace OpenSim.Region.Framework.Scenes
610 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;
611 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;
612 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
613 } 804 }
614 } 805 }
806 lockPartsForRead(false);
807
615 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; 808 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
616 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; 809 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
617 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; 810 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
@@ -627,10 +820,11 @@ namespace OpenSim.Region.Framework.Scenes
627 820
628 EntityIntersection result = new EntityIntersection(); 821 EntityIntersection result = new EntityIntersection();
629 822
630 lock (m_parts) 823 lockPartsForRead(true);
631 { 824 {
632 foreach (SceneObjectPart part in m_parts.Values) 825 foreach (SceneObjectPart part in m_parts.Values)
633 { 826 {
827
634 // Temporary commented to stop compiler warning 828 // Temporary commented to stop compiler warning
635 //Vector3 partPosition = 829 //Vector3 partPosition =
636 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); 830 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
@@ -658,8 +852,10 @@ namespace OpenSim.Region.Framework.Scenes
658 result.distance = inter.distance; 852 result.distance = inter.distance;
659 } 853 }
660 } 854 }
855
661 } 856 }
662 } 857 }
858 lockPartsForRead(false);
663 return result; 859 return result;
664 } 860 }
665 861
@@ -678,10 +874,11 @@ namespace OpenSim.Region.Framework.Scenes
678 minY = 256f; 874 minY = 256f;
679 minZ = 8192f; 875 minZ = 8192f;
680 876
681 lock (m_parts) 877 lockPartsForRead(true);
682 { 878 {
683 foreach (SceneObjectPart part in m_parts.Values) 879 foreach (SceneObjectPart part in m_parts.Values)
684 { 880 {
881
685 Vector3 worldPos = part.GetWorldPosition(); 882 Vector3 worldPos = part.GetWorldPosition();
686 Vector3 offset = worldPos - AbsolutePosition; 883 Vector3 offset = worldPos - AbsolutePosition;
687 Quaternion worldRot; 884 Quaternion worldRot;
@@ -740,6 +937,8 @@ namespace OpenSim.Region.Framework.Scenes
740 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 937 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
741 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 938 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
742 939
940
941
743 //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);
744 //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);
745 //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);
@@ -911,6 +1110,7 @@ namespace OpenSim.Region.Framework.Scenes
911 minZ = backBottomLeft.Z; 1110 minZ = backBottomLeft.Z;
912 } 1111 }
913 } 1112 }
1113 lockPartsForRead(false);
914 } 1114 }
915 1115
916 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) 1116 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
@@ -946,21 +1146,29 @@ namespace OpenSim.Region.Framework.Scenes
946 1146
947 public void SaveScriptedState(XmlTextWriter writer) 1147 public void SaveScriptedState(XmlTextWriter writer)
948 { 1148 {
1149 SaveScriptedState(writer, false);
1150 }
1151
1152 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1153 {
949 XmlDocument doc = new XmlDocument(); 1154 XmlDocument doc = new XmlDocument();
950 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1155 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
951 1156
952 // Capture script state while holding the lock 1157 // Capture script state while holding the lock
953 lock (m_parts) 1158 lockPartsForRead(true);
954 { 1159 {
955 foreach (SceneObjectPart part in m_parts.Values) 1160 foreach (SceneObjectPart part in m_parts.Values)
956 { 1161 {
957 Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); 1162
1163 Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(oldIDs);
958 foreach (UUID itemid in pstates.Keys) 1164 foreach (UUID itemid in pstates.Keys)
959 { 1165 {
960 states.Add(itemid, pstates[itemid]); 1166 states.Add(itemid, pstates[itemid]);
961 } 1167 }
1168
962 } 1169 }
963 } 1170 }
1171 lockPartsForRead(false);
964 1172
965 if (states.Count > 0) 1173 if (states.Count > 0)
966 { 1174 {
@@ -978,6 +1186,118 @@ namespace OpenSim.Region.Framework.Scenes
978 } 1186 }
979 } 1187 }
980 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
981 public byte GetAttachmentPoint() 1301 public byte GetAttachmentPoint()
982 { 1302 {
983 return m_rootPart.Shape.State; 1303 return m_rootPart.Shape.State;
@@ -1069,13 +1389,16 @@ namespace OpenSim.Region.Framework.Scenes
1069 1389
1070 public override void UpdateMovement() 1390 public override void UpdateMovement()
1071 { 1391 {
1072 lock (m_parts) 1392 lockPartsForRead(true);
1073 { 1393 {
1074 foreach (SceneObjectPart part in m_parts.Values) 1394 foreach (SceneObjectPart part in m_parts.Values)
1075 { 1395 {
1396
1076 part.UpdateMovement(); 1397 part.UpdateMovement();
1398
1077 } 1399 }
1078 } 1400 }
1401 lockPartsForRead(false);
1079 } 1402 }
1080 1403
1081 public ushort GetTimeDilation() 1404 public ushort GetTimeDilation()
@@ -1118,7 +1441,7 @@ namespace OpenSim.Region.Framework.Scenes
1118 /// <param name="part"></param> 1441 /// <param name="part"></param>
1119 public void AddPart(SceneObjectPart part) 1442 public void AddPart(SceneObjectPart part)
1120 { 1443 {
1121 lock (m_parts) 1444 lockPartsForWrite(true);
1122 { 1445 {
1123 part.SetParent(this); 1446 part.SetParent(this);
1124 m_parts.Add(part.UUID, part); 1447 m_parts.Add(part.UUID, part);
@@ -1128,6 +1451,7 @@ namespace OpenSim.Region.Framework.Scenes
1128 if (part.LinkNum == 2 && RootPart != null) 1451 if (part.LinkNum == 2 && RootPart != null)
1129 RootPart.LinkNum = 1; 1452 RootPart.LinkNum = 1;
1130 } 1453 }
1454 lockPartsForWrite(false);
1131 } 1455 }
1132 1456
1133 /// <summary> 1457 /// <summary>
@@ -1135,28 +1459,33 @@ namespace OpenSim.Region.Framework.Scenes
1135 /// </summary> 1459 /// </summary>
1136 private void UpdateParentIDs() 1460 private void UpdateParentIDs()
1137 { 1461 {
1138 lock (m_parts) 1462 lockPartsForRead(true);
1139 { 1463 {
1140 foreach (SceneObjectPart part in m_parts.Values) 1464 foreach (SceneObjectPart part in m_parts.Values)
1141 { 1465 {
1466
1142 if (part.UUID != m_rootPart.UUID) 1467 if (part.UUID != m_rootPart.UUID)
1143 { 1468 {
1144 part.ParentID = m_rootPart.LocalId; 1469 part.ParentID = m_rootPart.LocalId;
1145 } 1470 }
1471
1146 } 1472 }
1147 } 1473 }
1474 lockPartsForRead(false);
1148 } 1475 }
1149 1476
1150 public void RegenerateFullIDs() 1477 public void RegenerateFullIDs()
1151 { 1478 {
1152 lock (m_parts) 1479 lockPartsForRead(true);
1153 { 1480 {
1154 foreach (SceneObjectPart part in m_parts.Values) 1481 foreach (SceneObjectPart part in m_parts.Values)
1155 { 1482 {
1483
1156 part.UUID = UUID.Random(); 1484 part.UUID = UUID.Random();
1157 1485
1158 } 1486 }
1159 } 1487 }
1488 lockPartsForRead(false);
1160 } 1489 }
1161 1490
1162 // helper provided for parts. 1491 // helper provided for parts.
@@ -1217,7 +1546,7 @@ namespace OpenSim.Region.Framework.Scenes
1217 1546
1218 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1547 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1219 { 1548 {
1220 part.StoreUndoState(); 1549 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1221 part.OnGrab(offsetPos, remoteClient); 1550 part.OnGrab(offsetPos, remoteClient);
1222 } 1551 }
1223 1552
@@ -1237,14 +1566,18 @@ namespace OpenSim.Region.Framework.Scenes
1237 /// <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>
1238 public void DeleteGroupFromScene(bool silent) 1567 public void DeleteGroupFromScene(bool silent)
1239 { 1568 {
1240 List<SceneObjectPart> parts; 1569 // We need to keep track of this state in case this group is still queued for backup.
1570 m_isDeleted = true;
1241 1571
1242 lock (m_parts) 1572 DetachFromBackup();
1243 parts = m_parts.Values.ToList(); 1573
1574 lockPartsForRead(true);
1575 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
1576 lockPartsForRead(false);
1244 1577
1245 foreach (SceneObjectPart part in parts) 1578 foreach (SceneObjectPart part in parts)
1246 { 1579 {
1247 Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1580 Scene.ForEachScenePresence(delegate (ScenePresence avatar)
1248 { 1581 {
1249 if (avatar.ParentID == LocalId) 1582 if (avatar.ParentID == LocalId)
1250 { 1583 {
@@ -1259,6 +1592,8 @@ namespace OpenSim.Region.Framework.Scenes
1259 } 1592 }
1260 }); 1593 });
1261 } 1594 }
1595
1596
1262 } 1597 }
1263 1598
1264 public void AddScriptLPS(int count) 1599 public void AddScriptLPS(int count)
@@ -1283,17 +1618,20 @@ namespace OpenSim.Region.Framework.Scenes
1283 1618
1284 scriptEvents aggregateScriptEvents = 0; 1619 scriptEvents aggregateScriptEvents = 0;
1285 1620
1286 lock (m_parts) 1621 lockPartsForRead(true);
1287 { 1622 {
1288 foreach (SceneObjectPart part in m_parts.Values) 1623 foreach (SceneObjectPart part in m_parts.Values)
1289 { 1624 {
1625
1290 if (part == null) 1626 if (part == null)
1291 continue; 1627 continue;
1292 if (part != RootPart) 1628 if (part != RootPart)
1293 part.Flags = objectflagupdate; 1629 part.Flags = objectflagupdate;
1294 aggregateScriptEvents |= part.AggregateScriptEvents; 1630 aggregateScriptEvents |= part.AggregateScriptEvents;
1631
1295 } 1632 }
1296 } 1633 }
1634 lockPartsForRead(false);
1297 1635
1298 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); 1636 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
1299 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); 1637 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
@@ -1335,42 +1673,52 @@ namespace OpenSim.Region.Framework.Scenes
1335 /// <param name="m_physicalPrim"></param> 1673 /// <param name="m_physicalPrim"></param>
1336 public void ApplyPhysics(bool m_physicalPrim) 1674 public void ApplyPhysics(bool m_physicalPrim)
1337 { 1675 {
1338 lock (m_parts) 1676 lockPartsForRead(true);
1677
1678 if (m_parts.Count > 1)
1339 { 1679 {
1340 if (m_parts.Count > 1) 1680 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1681 lockPartsForRead(false);
1682 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1683 foreach (SceneObjectPart part in values)
1341 { 1684 {
1342 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); 1685
1343 foreach (SceneObjectPart part in m_parts.Values) 1686 if (part.LocalId != m_rootPart.LocalId)
1344 { 1687 {
1345 if (part.LocalId != m_rootPart.LocalId) 1688 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1346 {
1347 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1348 }
1349 } 1689 }
1350 1690
1351 // Hack to get the physics scene geometries in the right spot
1352 ResetChildPrimPhysicsPositions();
1353 }
1354 else
1355 {
1356 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1357 } 1691 }
1692 // Hack to get the physics scene geometries in the right spot
1693 ResetChildPrimPhysicsPositions();
1694 }
1695 else
1696 {
1697 lockPartsForRead(false);
1698 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1358 } 1699 }
1359 } 1700 }
1360 1701
1361 public void SetOwnerId(UUID userId) 1702 public void SetOwnerId(UUID userId)
1362 { 1703 {
1363 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1704 ForEachPart(delegate(SceneObjectPart part)
1705 {
1706
1707 part.OwnerID = userId;
1708
1709 });
1364 } 1710 }
1365 1711
1366 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1712 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1367 { 1713 {
1368 lock (m_parts) 1714 lockPartsForRead(true);
1715 List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
1716 lockPartsForRead(false);
1717 foreach (SceneObjectPart part in values)
1369 { 1718 {
1370 foreach (SceneObjectPart part in m_parts.Values) 1719
1371 { 1720 whatToDo(part);
1372 whatToDo(part); 1721
1373 }
1374 } 1722 }
1375 } 1723 }
1376 1724
@@ -1400,7 +1748,10 @@ namespace OpenSim.Region.Framework.Scenes
1400 // any exception propogate upwards. 1748 // any exception propogate upwards.
1401 try 1749 try
1402 { 1750 {
1403 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1751 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1752 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1753 m_scene.LoadingPrims) // Land may not be valid yet
1754
1404 { 1755 {
1405 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1756 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1406 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1757 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1432,6 +1783,20 @@ namespace OpenSim.Region.Framework.Scenes
1432 // don't backup while it's selected or you're asking for changes mid stream. 1783 // don't backup while it's selected or you're asking for changes mid stream.
1433 if (isTimeToPersist() || forcedBackup) 1784 if (isTimeToPersist() || forcedBackup)
1434 { 1785 {
1786 if (m_rootPart.PhysActor != null &&
1787 (!m_rootPart.PhysActor.IsPhysical))
1788 {
1789 // Possible ghost prim
1790 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1791 {
1792 foreach (SceneObjectPart part in Children.Values)
1793 {
1794 // Re-set physics actor positions and
1795 // orientations
1796 part.GroupPosition = m_rootPart.GroupPosition;
1797 }
1798 }
1799 }
1435// m_log.DebugFormat( 1800// m_log.DebugFormat(
1436// "[SCENE]: Storing {0}, {1} in {2}", 1801// "[SCENE]: Storing {0}, {1} in {2}",
1437// Name, UUID, m_scene.RegionInfo.RegionName); 1802// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1476,15 +1841,17 @@ namespace OpenSim.Region.Framework.Scenes
1476 RootPart.SendFullUpdate( 1841 RootPart.SendFullUpdate(
1477 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); 1842 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
1478 1843
1479 lock (m_parts) 1844 lockPartsForRead(true);
1480 { 1845 {
1481 foreach (SceneObjectPart part in m_parts.Values) 1846 foreach (SceneObjectPart part in m_parts.Values)
1482 { 1847 {
1848
1483 if (part != RootPart) 1849 if (part != RootPart)
1484 part.SendFullUpdate( 1850 part.SendFullUpdate(
1485 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); 1851 remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
1486 } 1852 }
1487 } 1853 }
1854 lockPartsForRead(false);
1488 } 1855 }
1489 1856
1490 #region Copying 1857 #region Copying
@@ -1496,86 +1863,112 @@ namespace OpenSim.Region.Framework.Scenes
1496 /// <returns></returns> 1863 /// <returns></returns>
1497 public SceneObjectGroup Copy(bool userExposed) 1864 public SceneObjectGroup Copy(bool userExposed)
1498 { 1865 {
1499 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1866 SceneObjectGroup dupe;
1500 dupe.m_isBackedUp = false; 1867 try
1501 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>(); 1868 {
1869 m_dupeInProgress = true;
1870 dupe = (SceneObjectGroup)MemberwiseClone();
1871 dupe.m_isBackedUp = false;
1872 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
1502 1873
1503 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1874 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1504 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1875 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1505 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1876 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1506 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1877 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1507 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1878 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1508 // then restore it's attachment state 1879 // then restore it's attachment state
1509 1880
1510 // This is only necessary when userExposed is false! 1881 // This is only necessary when userExposed is false!
1511 1882
1512 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1883 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1513
1514 if (!userExposed)
1515 dupe.RootPart.IsAttachment = true;
1516 1884
1517 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1885 if (!userExposed)
1886 dupe.RootPart.IsAttachment = true;
1518 1887
1519 if (!userExposed) 1888 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1520 {
1521 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1522 }
1523 1889
1524 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1890 if (!userExposed)
1525 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1891 {
1892 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1893 }
1526 1894
1527 if (userExposed) 1895 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1528 dupe.m_rootPart.TrimPermissions(); 1896 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1529 1897
1530 List<SceneObjectPart> partList; 1898 if (userExposed)
1899 dupe.m_rootPart.TrimPermissions();
1531 1900
1532 lock (m_parts) 1901 /// may need to create a new Physics actor.
1533 { 1902 if (dupe.RootPart.PhysActor != null && userExposed)
1534 partList = new List<SceneObjectPart>(m_parts.Values);
1535 }
1536
1537 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1538 { 1903 {
1539 return p1.LinkNum.CompareTo(p2.LinkNum); 1904 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1905
1906 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1907 dupe.RootPart.Name,
1908 pbs,
1909 dupe.RootPart.AbsolutePosition,
1910 dupe.RootPart.Scale,
1911 dupe.RootPart.RotationOffset,
1912 dupe.RootPart.PhysActor.IsPhysical);
1913
1914 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1915 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1540 } 1916 }
1541 );
1542 1917
1543 foreach (SceneObjectPart part in partList) 1918 lockPartsForRead(true);
1544 { 1919
1545 if (part.UUID != m_rootPart.UUID) 1920 List<SceneObjectPart> partList;
1921
1922 partList = new List<SceneObjectPart>(m_parts.Values);
1923
1924 lockPartsForRead(false);
1925
1926 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1927 {
1928 return p1.LinkNum.CompareTo(p2.LinkNum);
1929 }
1930 );
1931
1932 foreach (SceneObjectPart part in partList)
1546 { 1933 {
1547 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1934 if (part.UUID != m_rootPart.UUID)
1548 newPart.LinkNum = part.LinkNum; 1935 {
1549 } 1936 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1937
1938 newPart.LinkNum = part.LinkNum;
1939 }
1550 1940
1551 // Need to duplicate the physics actor as well 1941 // Need to duplicate the physics actor as well
1552 if (part.PhysActor != null && userExposed) 1942 if (part.PhysActor != null && userExposed)
1943 {
1944 PrimitiveBaseShape pbs = part.Shape;
1945
1946 part.PhysActor
1947 = m_scene.PhysicsScene.AddPrimShape(
1948 part.Name,
1949 pbs,
1950 part.AbsolutePosition,
1951 part.Scale,
1952 part.RotationOffset,
1953 part.PhysActor.IsPhysical);
1954
1955 part.PhysActor.LocalID = part.LocalId;
1956 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1957 }
1958 }
1959 if (userExposed)
1553 { 1960 {
1554 PrimitiveBaseShape pbs = part.Shape; 1961 dupe.UpdateParentIDs();
1555 1962 dupe.HasGroupChanged = true;
1556 part.PhysActor 1963 dupe.AttachToBackup();
1557 = m_scene.PhysicsScene.AddPrimShape( 1964
1558 part.Name, 1965 ScheduleGroupForFullUpdate();
1559 pbs,
1560 part.AbsolutePosition,
1561 part.Scale,
1562 part.RotationOffset,
1563 part.PhysActor.IsPhysical);
1564
1565 part.PhysActor.LocalID = part.LocalId;
1566 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1567 } 1966 }
1568 } 1967 }
1569 1968 finally
1570 if (userExposed)
1571 { 1969 {
1572 dupe.UpdateParentIDs(); 1970 m_dupeInProgress = false;
1573 dupe.HasGroupChanged = true;
1574 dupe.AttachToBackup();
1575
1576 ScheduleGroupForFullUpdate();
1577 } 1971 }
1578
1579 return dupe; 1972 return dupe;
1580 } 1973 }
1581 1974
@@ -1766,13 +2159,40 @@ namespace OpenSim.Region.Framework.Scenes
1766 } 2159 }
1767 } 2160 }
1768 2161
2162 public void rotLookAt(Quaternion target, float strength, float damping)
2163 {
2164 SceneObjectPart rootpart = m_rootPart;
2165 if (rootpart != null)
2166 {
2167 if (IsAttachment)
2168 {
2169 /*
2170 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2171 if (avatar != null)
2172 {
2173 Rotate the Av?
2174 } */
2175 }
2176 else
2177 {
2178 if (rootpart.PhysActor != null)
2179 { // APID must be implemented in your physics system for this to function.
2180 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2181 rootpart.PhysActor.APIDStrength = strength;
2182 rootpart.PhysActor.APIDDamping = damping;
2183 rootpart.PhysActor.APIDActive = true;
2184 }
2185 }
2186 }
2187 }
2188
1769 public void stopLookAt() 2189 public void stopLookAt()
1770 { 2190 {
1771 SceneObjectPart rootpart = m_rootPart; 2191 SceneObjectPart rootpart = m_rootPart;
1772 if (rootpart != null) 2192 if (rootpart != null)
1773 { 2193 {
1774 if (rootpart.PhysActor != null) 2194 if (rootpart.PhysActor != null)
1775 { 2195 { // APID must be implemented in your physics system for this to function.
1776 rootpart.PhysActor.APIDActive = false; 2196 rootpart.PhysActor.APIDActive = false;
1777 } 2197 }
1778 } 2198 }
@@ -1837,14 +2257,14 @@ namespace OpenSim.Region.Framework.Scenes
1837 /// <param name="cGroupID"></param> 2257 /// <param name="cGroupID"></param>
1838 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2258 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1839 { 2259 {
1840 SceneObjectPart newPart = null; 2260 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1841 2261 newPart.SetParent(this);
1842 lock (m_parts) 2262
2263 lockPartsForWrite(true);
1843 { 2264 {
1844 newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1845 newPart.SetParent(this);
1846 m_parts.Add(newPart.UUID, newPart); 2265 m_parts.Add(newPart.UUID, newPart);
1847 } 2266 }
2267 lockPartsForWrite(false);
1848 2268
1849 SetPartAsNonRoot(newPart); 2269 SetPartAsNonRoot(newPart);
1850 2270
@@ -1908,6 +2328,8 @@ namespace OpenSim.Region.Framework.Scenes
1908 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) 2328 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1909 // return; 2329 // return;
1910 2330
2331 lockPartsForRead(true);
2332
1911 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2333 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1912 2334
1913 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) 2335 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
@@ -1923,8 +2345,7 @@ namespace OpenSim.Region.Framework.Scenes
1923 } 2345 }
1924 2346
1925 List<SceneObjectPart> partList = null; 2347 List<SceneObjectPart> partList = null;
1926 lock (m_parts) 2348 partList = new List<SceneObjectPart>(m_parts.Values);
1927 partList = new List<SceneObjectPart>(m_parts.Values);
1928 2349
1929 foreach (SceneObjectPart part in partList) 2350 foreach (SceneObjectPart part in partList)
1930 { 2351 {
@@ -1932,6 +2353,7 @@ namespace OpenSim.Region.Framework.Scenes
1932 part.UpdateLookAt(); 2353 part.UpdateLookAt();
1933 part.SendScheduledUpdates(); 2354 part.SendScheduledUpdates();
1934 } 2355 }
2356 lockPartsForRead(false);
1935 } 2357 }
1936 2358
1937 public void ScheduleFullUpdateToAvatar(ScenePresence presence) 2359 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
@@ -1940,27 +2362,29 @@ namespace OpenSim.Region.Framework.Scenes
1940 2362
1941 RootPart.AddFullUpdateToAvatar(presence); 2363 RootPart.AddFullUpdateToAvatar(presence);
1942 2364
1943 lock (m_parts) 2365 lockPartsForRead(true);
1944 { 2366 {
1945 foreach (SceneObjectPart part in m_parts.Values) 2367 foreach (SceneObjectPart part in m_parts.Values)
1946 { 2368 {
2369
1947 if (part != RootPart) 2370 if (part != RootPart)
1948 part.AddFullUpdateToAvatar(presence); 2371 part.AddFullUpdateToAvatar(presence);
2372
1949 } 2373 }
1950 } 2374 }
2375 lockPartsForRead(false);
1951 } 2376 }
1952 2377
1953 public void ScheduleTerseUpdateToAvatar(ScenePresence presence) 2378 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1954 { 2379 {
1955// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); 2380 lockPartsForRead(true);
1956 2381
1957 lock (m_parts) 2382 foreach (SceneObjectPart part in m_parts.Values)
1958 { 2383 {
1959 foreach (SceneObjectPart part in m_parts.Values) 2384 part.AddTerseUpdateToAvatar(presence);
1960 {
1961 part.AddTerseUpdateToAvatar(presence);
1962 }
1963 } 2385 }
2386
2387 lockPartsForRead(false);
1964 } 2388 }
1965 2389
1966 /// <summary> 2390 /// <summary>
@@ -1974,14 +2398,17 @@ namespace OpenSim.Region.Framework.Scenes
1974 checkAtTargets(); 2398 checkAtTargets();
1975 RootPart.ScheduleFullUpdate(); 2399 RootPart.ScheduleFullUpdate();
1976 2400
1977 lock (m_parts) 2401 lockPartsForRead(true);
1978 { 2402 {
1979 foreach (SceneObjectPart part in m_parts.Values) 2403 foreach (SceneObjectPart part in m_parts.Values)
1980 { 2404 {
2405
1981 if (part != RootPart) 2406 if (part != RootPart)
1982 part.ScheduleFullUpdate(); 2407 part.ScheduleFullUpdate();
2408
1983 } 2409 }
1984 } 2410 }
2411 lockPartsForRead(false);
1985 } 2412 }
1986 2413
1987 /// <summary> 2414 /// <summary>
@@ -1989,37 +2416,38 @@ namespace OpenSim.Region.Framework.Scenes
1989 /// </summary> 2416 /// </summary>
1990 public void ScheduleGroupForTerseUpdate() 2417 public void ScheduleGroupForTerseUpdate()
1991 { 2418 {
1992// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); 2419 lockPartsForRead(true);
1993 2420 foreach (SceneObjectPart part in m_parts.Values)
1994 lock (m_parts)
1995 { 2421 {
1996 foreach (SceneObjectPart part in m_parts.Values) 2422 part.ScheduleTerseUpdate();
1997 {
1998 part.ScheduleTerseUpdate();
1999 }
2000 } 2423 }
2424
2425 lockPartsForRead(false);
2001 } 2426 }
2002 2427
2003 /// <summary> 2428 /// <summary>
2004 /// Immediately send a full update for this scene object. 2429 /// Immediately send a full update for this scene object.
2005 /// </summary> 2430 /// </summary>
2006 public void SendGroupFullUpdate() 2431 public void SendGroupFullUpdate()
2007 { 2432 {
2008 if (IsDeleted) 2433 if (IsDeleted)
2009 return; 2434 return;
2010 2435
2011// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2436// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2012 2437
2013 RootPart.SendFullUpdateToAllClients(); 2438 RootPart.SendFullUpdateToAllClients();
2014 2439
2015 lock (m_parts) 2440 lockPartsForRead(true);
2016 { 2441 {
2017 foreach (SceneObjectPart part in m_parts.Values) 2442 foreach (SceneObjectPart part in m_parts.Values)
2018 { 2443 {
2444
2019 if (part != RootPart) 2445 if (part != RootPart)
2020 part.SendFullUpdateToAllClients(); 2446 part.SendFullUpdateToAllClients();
2447
2021 } 2448 }
2022 } 2449 }
2450 lockPartsForRead(false);
2023 } 2451 }
2024 2452
2025 /// <summary> 2453 /// <summary>
@@ -2051,14 +2479,15 @@ namespace OpenSim.Region.Framework.Scenes
2051 { 2479 {
2052 if (IsDeleted) 2480 if (IsDeleted)
2053 return; 2481 return;
2054 2482
2055 lock (m_parts) 2483 lockPartsForRead(true);
2056 { 2484 {
2057 foreach (SceneObjectPart part in m_parts.Values) 2485 foreach (SceneObjectPart part in m_parts.Values)
2058 { 2486 {
2059 part.SendTerseUpdateToAllClients(); 2487 part.SendTerseUpdateToAllClients();
2060 } 2488 }
2061 } 2489 }
2490 lockPartsForRead(false);
2062 } 2491 }
2063 2492
2064 #endregion 2493 #endregion
@@ -2072,16 +2501,18 @@ namespace OpenSim.Region.Framework.Scenes
2072 /// <returns>null if no child part with that linknum or child part</returns> 2501 /// <returns>null if no child part with that linknum or child part</returns>
2073 public SceneObjectPart GetLinkNumPart(int linknum) 2502 public SceneObjectPart GetLinkNumPart(int linknum)
2074 { 2503 {
2075 lock (m_parts) 2504 lockPartsForRead(true);
2076 { 2505 {
2077 foreach (SceneObjectPart part in m_parts.Values) 2506 foreach (SceneObjectPart part in m_parts.Values)
2078 { 2507 {
2079 if (part.LinkNum == linknum) 2508 if (part.LinkNum == linknum)
2080 { 2509 {
2510 lockPartsForRead(false);
2081 return part; 2511 return part;
2082 } 2512 }
2083 } 2513 }
2084 } 2514 }
2515 lockPartsForRead(false);
2085 2516
2086 return null; 2517 return null;
2087 } 2518 }
@@ -2107,17 +2538,19 @@ namespace OpenSim.Region.Framework.Scenes
2107 public SceneObjectPart GetChildPart(uint localID) 2538 public SceneObjectPart GetChildPart(uint localID)
2108 { 2539 {
2109 //m_log.DebugFormat("Entered looking for {0}", localID); 2540 //m_log.DebugFormat("Entered looking for {0}", localID);
2110 lock (m_parts) 2541 lockPartsForRead(true);
2111 { 2542 {
2112 foreach (SceneObjectPart part in m_parts.Values) 2543 foreach (SceneObjectPart part in m_parts.Values)
2113 { 2544 {
2114 //m_log.DebugFormat("Found {0}", part.LocalId); 2545 //m_log.DebugFormat("Found {0}", part.LocalId);
2115 if (part.LocalId == localID) 2546 if (part.LocalId == localID)
2116 { 2547 {
2548 lockPartsForRead(false);
2117 return part; 2549 return part;
2118 } 2550 }
2119 } 2551 }
2120 } 2552 }
2553 lockPartsForRead(false);
2121 2554
2122 return null; 2555 return null;
2123 } 2556 }
@@ -2148,17 +2581,19 @@ namespace OpenSim.Region.Framework.Scenes
2148 public bool HasChildPrim(uint localID) 2581 public bool HasChildPrim(uint localID)
2149 { 2582 {
2150 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); 2583 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
2151 lock (m_parts) 2584 lockPartsForRead(true);
2152 { 2585 {
2153 foreach (SceneObjectPart part in m_parts.Values) 2586 foreach (SceneObjectPart part in m_parts.Values)
2154 { 2587 {
2155 //m_log.DebugFormat("Found {0}", part.LocalId); 2588 //m_log.DebugFormat("Found {0}", part.LocalId);
2156 if (part.LocalId == localID) 2589 if (part.LocalId == localID)
2157 { 2590 {
2591 lockPartsForRead(false);
2158 return true; 2592 return true;
2159 } 2593 }
2160 } 2594 }
2161 } 2595 }
2596 lockPartsForRead(false);
2162 2597
2163 return false; 2598 return false;
2164 } 2599 }
@@ -2208,53 +2643,57 @@ namespace OpenSim.Region.Framework.Scenes
2208 if (m_rootPart.LinkNum == 0) 2643 if (m_rootPart.LinkNum == 0)
2209 m_rootPart.LinkNum = 1; 2644 m_rootPart.LinkNum = 1;
2210 2645
2211 lock (m_parts) 2646 lockPartsForWrite(true);
2212 { 2647
2213 m_parts.Add(linkPart.UUID, linkPart); 2648 m_parts.Add(linkPart.UUID, linkPart);
2649
2650 lockPartsForWrite(false);
2214 2651
2215 // Insert in terms of link numbers, the new links 2652 // Insert in terms of link numbers, the new links
2216 // before the current ones (with the exception of 2653 // before the current ones (with the exception of
2217 // the root prim. Shuffle the old ones up 2654 // the root prim. Shuffle the old ones up
2218 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) 2655 lockPartsForRead(true);
2656 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
2657 {
2658 if (kvp.Value.LinkNum != 1)
2219 { 2659 {
2220 if (kvp.Value.LinkNum != 1) 2660 // Don't update root prim link number
2221 { 2661 kvp.Value.LinkNum += objectGroup.PrimCount;
2222 // Don't update root prim link number
2223 kvp.Value.LinkNum += objectGroup.PrimCount;
2224 }
2225 } 2662 }
2663 }
2664 lockPartsForRead(false);
2226 2665
2227 linkPart.LinkNum = 2; 2666 linkPart.LinkNum = 2;
2228 2667
2229 linkPart.SetParent(this); 2668 linkPart.SetParent(this);
2230 linkPart.CreateSelected = true; 2669 linkPart.CreateSelected = true;
2231 2670
2232 //if (linkPart.PhysActor != null) 2671 //if (linkPart.PhysActor != null)
2233 //{ 2672 //{
2234 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2673 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2235 2674
2236 //linkPart.PhysActor = null; 2675 //linkPart.PhysActor = null;
2237 //} 2676 //}
2238 2677
2239 //TODO: rest of parts 2678 //TODO: rest of parts
2240 int linkNum = 3; 2679 int linkNum = 3;
2241 foreach (SceneObjectPart part in objectGroup.Children.Values) 2680 foreach (SceneObjectPart part in objectGroup.Children.Values)
2681 {
2682 if (part.UUID != objectGroup.m_rootPart.UUID)
2242 { 2683 {
2243 if (part.UUID != objectGroup.m_rootPart.UUID) 2684 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2244 {
2245 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2246 }
2247 part.ClearUndoState();
2248 } 2685 }
2686 part.ClearUndoState();
2249 } 2687 }
2250 2688
2251 m_scene.UnlinkSceneObject(objectGroup, true); 2689 m_scene.UnlinkSceneObject(objectGroup, true);
2252 objectGroup.m_isDeleted = true; 2690 objectGroup.m_isDeleted = true;
2691
2692 objectGroup.lockPartsForWrite(true);
2253 2693
2254 lock (objectGroup.m_parts) 2694 objectGroup.m_parts.Clear();
2255 { 2695
2256 objectGroup.m_parts.Clear(); 2696 objectGroup.lockPartsForWrite(false);
2257 }
2258 2697
2259 // Can't do this yet since backup still makes use of the root part without any synchronization 2698 // Can't do this yet since backup still makes use of the root part without any synchronization
2260// objectGroup.m_rootPart = null; 2699// objectGroup.m_rootPart = null;
@@ -2324,23 +2763,23 @@ namespace OpenSim.Region.Framework.Scenes
2324 Quaternion worldRot = linkPart.GetWorldRotation(); 2763 Quaternion worldRot = linkPart.GetWorldRotation();
2325 2764
2326 // Remove the part from this object 2765 // Remove the part from this object
2327 lock (m_parts) 2766 lockPartsForWrite(true);
2328 { 2767 {
2329 m_parts.Remove(linkPart.UUID); 2768 m_parts.Remove(linkPart.UUID);
2330 2769 }
2331 if (m_parts.Count == 1 && RootPart != null) //Single prim is left 2770 lockPartsForWrite(false);
2332 { 2771 lockPartsForRead(true);
2333 RootPart.LinkNum = 0; 2772 if (m_parts.Count == 1 && RootPart != null) //Single prim is left
2334 } 2773 RootPart.LinkNum = 0;
2335 else 2774 else
2775 {
2776 foreach (SceneObjectPart p in m_parts.Values)
2336 { 2777 {
2337 foreach (SceneObjectPart p in m_parts.Values) 2778 if (p.LinkNum > linkPart.LinkNum)
2338 { 2779 p.LinkNum--;
2339 if (p.LinkNum > linkPart.LinkNum)
2340 p.LinkNum--;
2341 }
2342 } 2780 }
2343 } 2781 }
2782 lockPartsForRead(false);
2344 2783
2345 linkPart.ParentID = 0; 2784 linkPart.ParentID = 0;
2346 linkPart.LinkNum = 0; 2785 linkPart.LinkNum = 0;
@@ -2384,6 +2823,8 @@ namespace OpenSim.Region.Framework.Scenes
2384 /// <param name="objectGroup"></param> 2823 /// <param name="objectGroup"></param>
2385 public virtual void DetachFromBackup() 2824 public virtual void DetachFromBackup()
2386 { 2825 {
2826 m_scene.SceneGraph.FireDetachFromBackup(this);
2827
2387 if (m_isBackedUp) 2828 if (m_isBackedUp)
2388 m_scene.EventManager.OnBackup -= ProcessBackup; 2829 m_scene.EventManager.OnBackup -= ProcessBackup;
2389 2830
@@ -2662,9 +3103,12 @@ namespace OpenSim.Region.Framework.Scenes
2662 3103
2663 if (selectionPart != null) 3104 if (selectionPart != null)
2664 { 3105 {
2665 lock (m_parts) 3106 lockPartsForRead(true);
3107 List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
3108 lockPartsForRead(false);
3109 foreach (SceneObjectPart part in parts)
2666 { 3110 {
2667 foreach (SceneObjectPart part in m_parts.Values) 3111 if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
2668 { 3112 {
2669 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || 3113 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax ||
2670 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || 3114 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax ||
@@ -2674,12 +3118,13 @@ namespace OpenSim.Region.Framework.Scenes
2674 break; 3118 break;
2675 } 3119 }
2676 } 3120 }
3121 }
2677 3122
2678 foreach (SceneObjectPart part in m_parts.Values) 3123 foreach (SceneObjectPart part in parts)
2679 { 3124 {
2680 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3125 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2681 }
2682 } 3126 }
3127
2683 } 3128 }
2684 } 3129 }
2685 3130
@@ -2692,6 +3137,17 @@ namespace OpenSim.Region.Framework.Scenes
2692 } 3137 }
2693 } 3138 }
2694 3139
3140
3141
3142 /// <summary>
3143 /// Gets the number of parts
3144 /// </summary>
3145 /// <returns></returns>
3146 public int GetPartCount()
3147 {
3148 return Children.Count;
3149 }
3150
2695 /// <summary> 3151 /// <summary>
2696 /// Get the parts of this scene object 3152 /// Get the parts of this scene object
2697 /// </summary> 3153 /// </summary>
@@ -2768,11 +3224,9 @@ namespace OpenSim.Region.Framework.Scenes
2768 scale.Y = m_scene.m_maxNonphys; 3224 scale.Y = m_scene.m_maxNonphys;
2769 if (scale.Z > m_scene.m_maxNonphys) 3225 if (scale.Z > m_scene.m_maxNonphys)
2770 scale.Z = m_scene.m_maxNonphys; 3226 scale.Z = m_scene.m_maxNonphys;
2771
2772 SceneObjectPart part = GetChildPart(localID); 3227 SceneObjectPart part = GetChildPart(localID);
2773 if (part != null) 3228 if (part != null)
2774 { 3229 {
2775 part.Resize(scale);
2776 if (part.PhysActor != null) 3230 if (part.PhysActor != null)
2777 { 3231 {
2778 if (part.PhysActor.IsPhysical) 3232 if (part.PhysActor.IsPhysical)
@@ -2787,7 +3241,7 @@ namespace OpenSim.Region.Framework.Scenes
2787 part.PhysActor.Size = scale; 3241 part.PhysActor.Size = scale;
2788 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 3242 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2789 } 3243 }
2790 //if (part.UUID != m_rootPart.UUID) 3244 part.Resize(scale);
2791 3245
2792 HasGroupChanged = true; 3246 HasGroupChanged = true;
2793 ScheduleGroupForFullUpdate(); 3247 ScheduleGroupForFullUpdate();
@@ -2809,7 +3263,6 @@ namespace OpenSim.Region.Framework.Scenes
2809 SceneObjectPart part = GetChildPart(localID); 3263 SceneObjectPart part = GetChildPart(localID);
2810 if (part != null) 3264 if (part != null)
2811 { 3265 {
2812 part.IgnoreUndoUpdate = true;
2813 if (scale.X > m_scene.m_maxNonphys) 3266 if (scale.X > m_scene.m_maxNonphys)
2814 scale.X = m_scene.m_maxNonphys; 3267 scale.X = m_scene.m_maxNonphys;
2815 if (scale.Y > m_scene.m_maxNonphys) 3268 if (scale.Y > m_scene.m_maxNonphys)
@@ -2829,94 +3282,100 @@ namespace OpenSim.Region.Framework.Scenes
2829 float y = (scale.Y / part.Scale.Y); 3282 float y = (scale.Y / part.Scale.Y);
2830 float z = (scale.Z / part.Scale.Z); 3283 float z = (scale.Z / part.Scale.Z);
2831 3284
2832 lock (m_parts) 3285 lockPartsForRead(true);
3286 if (x > 1.0f || y > 1.0f || z > 1.0f)
2833 { 3287 {
2834 if (x > 1.0f || y > 1.0f || z > 1.0f) 3288 foreach (SceneObjectPart obPart in m_parts.Values)
2835 { 3289 {
2836 foreach (SceneObjectPart obPart in m_parts.Values) 3290 if (obPart.UUID != m_rootPart.UUID)
2837 { 3291 {
2838 if (obPart.UUID != m_rootPart.UUID) 3292 Vector3 oldSize = new Vector3(obPart.Scale);
2839 { 3293 obPart.IgnoreUndoUpdate = true;
2840 obPart.IgnoreUndoUpdate = true;
2841 Vector3 oldSize = new Vector3(obPart.Scale);
2842 3294
2843 float f = 1.0f; 3295 float f = 1.0f;
2844 float a = 1.0f; 3296 float a = 1.0f;
2845 3297
2846 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3298 if (part.PhysActor != null && part.PhysActor.IsPhysical)
3299 {
3300 if (oldSize.X*x > m_scene.m_maxPhys)
2847 { 3301 {
2848 if (oldSize.X*x > m_scene.m_maxPhys) 3302 f = m_scene.m_maxPhys / oldSize.X;
2849 { 3303 a = f / x;
2850 f = m_scene.m_maxPhys / oldSize.X; 3304 x *= a;
2851 a = f / x; 3305 y *= a;
2852 x *= a; 3306 z *= a;
2853 y *= a;
2854 z *= a;
2855 }
2856 if (oldSize.Y*y > m_scene.m_maxPhys)
2857 {
2858 f = m_scene.m_maxPhys / oldSize.Y;
2859 a = f / y;
2860 x *= a;
2861 y *= a;
2862 z *= a;
2863 }
2864 if (oldSize.Z*z > m_scene.m_maxPhys)
2865 {
2866 f = m_scene.m_maxPhys / oldSize.Z;
2867 a = f / z;
2868 x *= a;
2869 y *= a;
2870 z *= a;
2871 }
2872 } 3307 }
2873 else 3308 if (oldSize.Y*y > m_scene.m_maxPhys)
3309 {
3310 f = m_scene.m_maxPhys / oldSize.Y;
3311 a = f / y;
3312 x *= a;
3313 y *= a;
3314 z *= a;
3315 }
3316 if (oldSize.Z*z > m_scene.m_maxPhys)
2874 { 3317 {
2875 if (oldSize.X*x > m_scene.m_maxNonphys) 3318 f = m_scene.m_maxPhys / oldSize.Z;
2876 { 3319 a = f / z;
2877 f = m_scene.m_maxNonphys / oldSize.X; 3320 x *= a;
2878 a = f / x; 3321 y *= a;
2879 x *= a; 3322 z *= a;
2880 y *= a;
2881 z *= a;
2882 }
2883 if (oldSize.Y*y > m_scene.m_maxNonphys)
2884 {
2885 f = m_scene.m_maxNonphys / oldSize.Y;
2886 a = f / y;
2887 x *= a;
2888 y *= a;
2889 z *= a;
2890 }
2891 if (oldSize.Z*z > m_scene.m_maxNonphys)
2892 {
2893 f = m_scene.m_maxNonphys / oldSize.Z;
2894 a = f / z;
2895 x *= a;
2896 y *= a;
2897 z *= a;
2898 }
2899 } 3323 }
2900 obPart.IgnoreUndoUpdate = false; 3324 }
2901 obPart.StoreUndoState(); 3325 else
3326 {
3327 if (oldSize.X*x > m_scene.m_maxNonphys)
3328 {
3329 f = m_scene.m_maxNonphys / oldSize.X;
3330 a = f / x;
3331 x *= a;
3332 y *= a;
3333 z *= a;
3334 }
3335 if (oldSize.Y*y > m_scene.m_maxNonphys)
3336 {
3337 f = m_scene.m_maxNonphys / oldSize.Y;
3338 a = f / y;
3339 x *= a;
3340 y *= a;
3341 z *= a;
3342 }
3343 if (oldSize.Z*z > m_scene.m_maxNonphys)
3344 {
3345 f = m_scene.m_maxNonphys / oldSize.Z;
3346 a = f / z;
3347 x *= a;
3348 y *= a;
3349 z *= a;
3350 }
3351
2902 } 3352 }
2903 } 3353 }
2904 } 3354 }
2905 } 3355 }
3356 lockPartsForRead(false);
2906 3357
2907 Vector3 prevScale = part.Scale; 3358 Vector3 prevScale = part.Scale;
2908 prevScale.X *= x; 3359 prevScale.X *= x;
2909 prevScale.Y *= y; 3360 prevScale.Y *= y;
2910 prevScale.Z *= z; 3361 prevScale.Z *= z;;
3362
3363 part.IgnoreUndoUpdate = false;
3364 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3365 part.IgnoreUndoUpdate = true;
2911 part.Resize(prevScale); 3366 part.Resize(prevScale);
3367 part.IgnoreUndoUpdate = false;
2912 3368
2913 lock (m_parts) 3369 lockPartsForRead(true);
2914 { 3370 {
2915 foreach (SceneObjectPart obPart in m_parts.Values) 3371 foreach (SceneObjectPart obPart in m_parts.Values)
2916 { 3372 {
2917 obPart.IgnoreUndoUpdate = true;
2918 if (obPart.UUID != m_rootPart.UUID) 3373 if (obPart.UUID != m_rootPart.UUID)
2919 { 3374 {
3375 obPart.IgnoreUndoUpdate = false;
3376 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3377 obPart.IgnoreUndoUpdate = true;
3378
2920 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3379 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2921 currentpos.X *= x; 3380 currentpos.X *= x;
2922 currentpos.Y *= y; 3381 currentpos.Y *= y;
@@ -2929,9 +3388,9 @@ namespace OpenSim.Region.Framework.Scenes
2929 obPart.UpdateOffSet(currentpos); 3388 obPart.UpdateOffSet(currentpos);
2930 } 3389 }
2931 obPart.IgnoreUndoUpdate = false; 3390 obPart.IgnoreUndoUpdate = false;
2932 obPart.StoreUndoState();
2933 } 3391 }
2934 } 3392 }
3393 lockPartsForRead(false);
2935 3394
2936 if (part.PhysActor != null) 3395 if (part.PhysActor != null)
2937 { 3396 {
@@ -2940,7 +3399,6 @@ namespace OpenSim.Region.Framework.Scenes
2940 } 3399 }
2941 3400
2942 part.IgnoreUndoUpdate = false; 3401 part.IgnoreUndoUpdate = false;
2943 part.StoreUndoState();
2944 HasGroupChanged = true; 3402 HasGroupChanged = true;
2945 ScheduleGroupForTerseUpdate(); 3403 ScheduleGroupForTerseUpdate();
2946 } 3404 }
@@ -2956,14 +3414,11 @@ namespace OpenSim.Region.Framework.Scenes
2956 /// <param name="pos"></param> 3414 /// <param name="pos"></param>
2957 public void UpdateGroupPosition(Vector3 pos) 3415 public void UpdateGroupPosition(Vector3 pos)
2958 { 3416 {
2959 foreach (SceneObjectPart part in Children.Values)
2960 {
2961 part.StoreUndoState();
2962 }
2963 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3417 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2964 { 3418 {
2965 if (IsAttachment) 3419 if (IsAttachment)
2966 { 3420 {
3421 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2967 m_rootPart.AttachedPos = pos; 3422 m_rootPart.AttachedPos = pos;
2968 } 3423 }
2969 if (RootPart.GetStatusSandbox()) 3424 if (RootPart.GetStatusSandbox())
@@ -2996,7 +3451,7 @@ namespace OpenSim.Region.Framework.Scenes
2996 SceneObjectPart part = GetChildPart(localID); 3451 SceneObjectPart part = GetChildPart(localID);
2997 foreach (SceneObjectPart parts in Children.Values) 3452 foreach (SceneObjectPart parts in Children.Values)
2998 { 3453 {
2999 parts.StoreUndoState(); 3454 parts.StoreUndoState(UndoType.STATE_PRIM_POSITION);
3000 } 3455 }
3001 if (part != null) 3456 if (part != null)
3002 { 3457 {
@@ -3021,7 +3476,7 @@ namespace OpenSim.Region.Framework.Scenes
3021 { 3476 {
3022 foreach (SceneObjectPart part in Children.Values) 3477 foreach (SceneObjectPart part in Children.Values)
3023 { 3478 {
3024 part.StoreUndoState(); 3479 part.StoreUndoState(UndoType.STATE_PRIM_POSITION);
3025 } 3480 }
3026 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3481 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3027 Vector3 oldPos = 3482 Vector3 oldPos =
@@ -3034,7 +3489,7 @@ namespace OpenSim.Region.Framework.Scenes
3034 axDiff *= Quaternion.Inverse(partRotation); 3489 axDiff *= Quaternion.Inverse(partRotation);
3035 diff = axDiff; 3490 diff = axDiff;
3036 3491
3037 lock (m_parts) 3492 lockPartsForRead(true);
3038 { 3493 {
3039 foreach (SceneObjectPart obPart in m_parts.Values) 3494 foreach (SceneObjectPart obPart in m_parts.Values)
3040 { 3495 {
@@ -3044,11 +3499,29 @@ namespace OpenSim.Region.Framework.Scenes
3044 } 3499 }
3045 } 3500 }
3046 } 3501 }
3502 lockPartsForRead(false);
3047 3503
3048 AbsolutePosition = newPos; 3504 //We have to set undoing here because otherwise an undo state will be saved
3505 if (!m_rootPart.Undoing)
3506 {
3507 m_rootPart.Undoing = true;
3508 AbsolutePosition = newPos;
3509 m_rootPart.Undoing = false;
3510 }
3511 else
3512 {
3513 AbsolutePosition = newPos;
3514 }
3049 3515
3050 HasGroupChanged = true; 3516 HasGroupChanged = true;
3051 ScheduleGroupForTerseUpdate(); 3517 if (m_rootPart.Undoing)
3518 {
3519 ScheduleGroupForFullUpdate();
3520 }
3521 else
3522 {
3523 ScheduleGroupForTerseUpdate();
3524 }
3052 } 3525 }
3053 3526
3054 public void OffsetForNewRegion(Vector3 offset) 3527 public void OffsetForNewRegion(Vector3 offset)
@@ -3068,7 +3541,7 @@ namespace OpenSim.Region.Framework.Scenes
3068 { 3541 {
3069 foreach (SceneObjectPart parts in Children.Values) 3542 foreach (SceneObjectPart parts in Children.Values)
3070 { 3543 {
3071 parts.StoreUndoState(); 3544 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3072 } 3545 }
3073 m_rootPart.UpdateRotation(rot); 3546 m_rootPart.UpdateRotation(rot);
3074 3547
@@ -3092,7 +3565,7 @@ namespace OpenSim.Region.Framework.Scenes
3092 { 3565 {
3093 foreach (SceneObjectPart parts in Children.Values) 3566 foreach (SceneObjectPart parts in Children.Values)
3094 { 3567 {
3095 parts.StoreUndoState(); 3568 parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
3096 } 3569 }
3097 m_rootPart.UpdateRotation(rot); 3570 m_rootPart.UpdateRotation(rot);
3098 3571
@@ -3119,7 +3592,7 @@ namespace OpenSim.Region.Framework.Scenes
3119 SceneObjectPart part = GetChildPart(localID); 3592 SceneObjectPart part = GetChildPart(localID);
3120 foreach (SceneObjectPart parts in Children.Values) 3593 foreach (SceneObjectPart parts in Children.Values)
3121 { 3594 {
3122 parts.StoreUndoState(); 3595 parts.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3123 } 3596 }
3124 if (part != null) 3597 if (part != null)
3125 { 3598 {
@@ -3147,15 +3620,24 @@ namespace OpenSim.Region.Framework.Scenes
3147 if (part.UUID == m_rootPart.UUID) 3620 if (part.UUID == m_rootPart.UUID)
3148 { 3621 {
3149 UpdateRootRotation(rot); 3622 UpdateRootRotation(rot);
3150 AbsolutePosition = pos; 3623 if (!m_rootPart.Undoing)
3624 {
3625 m_rootPart.Undoing = true;
3626 AbsolutePosition = pos;
3627 m_rootPart.Undoing = false;
3628 }
3629 else
3630 {
3631 AbsolutePosition = pos;
3632 }
3151 } 3633 }
3152 else 3634 else
3153 { 3635 {
3636 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3154 part.IgnoreUndoUpdate = true; 3637 part.IgnoreUndoUpdate = true;
3155 part.UpdateRotation(rot); 3638 part.UpdateRotation(rot);
3156 part.OffsetPosition = pos; 3639 part.OffsetPosition = pos;
3157 part.IgnoreUndoUpdate = false; 3640 part.IgnoreUndoUpdate = false;
3158 part.StoreUndoState();
3159 } 3641 }
3160 } 3642 }
3161 } 3643 }
@@ -3169,7 +3651,13 @@ namespace OpenSim.Region.Framework.Scenes
3169 Quaternion axRot = rot; 3651 Quaternion axRot = rot;
3170 Quaternion oldParentRot = m_rootPart.RotationOffset; 3652 Quaternion oldParentRot = m_rootPart.RotationOffset;
3171 3653
3172 m_rootPart.StoreUndoState(); 3654 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3655 bool cancelUndo = false;
3656 if (!m_rootPart.Undoing)
3657 {
3658 m_rootPart.Undoing = true;
3659 cancelUndo = true;
3660 }
3173 m_rootPart.UpdateRotation(rot); 3661 m_rootPart.UpdateRotation(rot);
3174 if (m_rootPart.PhysActor != null) 3662 if (m_rootPart.PhysActor != null)
3175 { 3663 {
@@ -3177,33 +3665,31 @@ namespace OpenSim.Region.Framework.Scenes
3177 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 3665 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
3178 } 3666 }
3179 3667
3180 lock (m_parts) 3668 lockPartsForRead(true);
3669
3670 foreach (SceneObjectPart prim in m_parts.Values)
3181 { 3671 {
3182 foreach (SceneObjectPart prim in m_parts.Values) 3672 if (prim.UUID != m_rootPart.UUID)
3183 { 3673 {
3184 if (prim.UUID != m_rootPart.UUID) 3674 prim.IgnoreUndoUpdate = true;
3185 { 3675 Vector3 axPos = prim.OffsetPosition;
3186 prim.IgnoreUndoUpdate = true; 3676 axPos *= oldParentRot;
3187 Vector3 axPos = prim.OffsetPosition; 3677 axPos *= Quaternion.Inverse(axRot);
3188 axPos *= oldParentRot; 3678 prim.OffsetPosition = axPos;
3189 axPos *= Quaternion.Inverse(axRot); 3679 Quaternion primsRot = prim.RotationOffset;
3190 prim.OffsetPosition = axPos; 3680 Quaternion newRot = primsRot * oldParentRot;
3191 Quaternion primsRot = prim.RotationOffset; 3681 newRot *= Quaternion.Inverse(axRot);
3192 Quaternion newRot = primsRot * oldParentRot; 3682 prim.RotationOffset = newRot;
3193 newRot *= Quaternion.Inverse(axRot); 3683 prim.ScheduleTerseUpdate();
3194 prim.RotationOffset = newRot; 3684 prim.IgnoreUndoUpdate = false;
3195 prim.ScheduleTerseUpdate();
3196 }
3197 } 3685 }
3198 } 3686 }
3199 foreach (SceneObjectPart childpart in Children.Values) 3687 if (cancelUndo == true)
3200 { 3688 {
3201 if (childpart != m_rootPart) 3689 m_rootPart.Undoing = false;
3202 {
3203 childpart.IgnoreUndoUpdate = false;
3204 childpart.StoreUndoState();
3205 }
3206 } 3690 }
3691 lockPartsForRead(false);
3692
3207 m_rootPart.ScheduleTerseUpdate(); 3693 m_rootPart.ScheduleTerseUpdate();
3208 } 3694 }
3209 3695
@@ -3325,7 +3811,7 @@ namespace OpenSim.Region.Framework.Scenes
3325 if (atTargets.Count > 0) 3811 if (atTargets.Count > 0)
3326 { 3812 {
3327 uint[] localids = new uint[0]; 3813 uint[] localids = new uint[0];
3328 lock (m_parts) 3814 lockPartsForRead(true);
3329 { 3815 {
3330 localids = new uint[m_parts.Count]; 3816 localids = new uint[m_parts.Count];
3331 int cntr = 0; 3817 int cntr = 0;
@@ -3335,6 +3821,7 @@ namespace OpenSim.Region.Framework.Scenes
3335 cntr++; 3821 cntr++;
3336 } 3822 }
3337 } 3823 }
3824 lockPartsForRead(false);
3338 3825
3339 for (int ctr = 0; ctr < localids.Length; ctr++) 3826 for (int ctr = 0; ctr < localids.Length; ctr++)
3340 { 3827 {
@@ -3353,7 +3840,7 @@ namespace OpenSim.Region.Framework.Scenes
3353 { 3840 {
3354 //trigger not_at_target 3841 //trigger not_at_target
3355 uint[] localids = new uint[0]; 3842 uint[] localids = new uint[0];
3356 lock (m_parts) 3843 lockPartsForRead(true);
3357 { 3844 {
3358 localids = new uint[m_parts.Count]; 3845 localids = new uint[m_parts.Count];
3359 int cntr = 0; 3846 int cntr = 0;
@@ -3363,7 +3850,8 @@ namespace OpenSim.Region.Framework.Scenes
3363 cntr++; 3850 cntr++;
3364 } 3851 }
3365 } 3852 }
3366 3853 lockPartsForRead(false);
3854
3367 for (int ctr = 0; ctr < localids.Length; ctr++) 3855 for (int ctr = 0; ctr < localids.Length; ctr++)
3368 { 3856 {
3369 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); 3857 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
@@ -3404,7 +3892,8 @@ namespace OpenSim.Region.Framework.Scenes
3404 if (atRotTargets.Count > 0) 3892 if (atRotTargets.Count > 0)
3405 { 3893 {
3406 uint[] localids = new uint[0]; 3894 uint[] localids = new uint[0];
3407 lock (m_parts) 3895 lockPartsForRead(true);
3896 try
3408 { 3897 {
3409 localids = new uint[m_parts.Count]; 3898 localids = new uint[m_parts.Count];
3410 int cntr = 0; 3899 int cntr = 0;
@@ -3414,6 +3903,10 @@ namespace OpenSim.Region.Framework.Scenes
3414 cntr++; 3903 cntr++;
3415 } 3904 }
3416 } 3905 }
3906 finally
3907 {
3908 lockPartsForRead(false);
3909 }
3417 3910
3418 for (int ctr = 0; ctr < localids.Length; ctr++) 3911 for (int ctr = 0; ctr < localids.Length; ctr++)
3419 { 3912 {
@@ -3432,7 +3925,8 @@ namespace OpenSim.Region.Framework.Scenes
3432 { 3925 {
3433 //trigger not_at_target 3926 //trigger not_at_target
3434 uint[] localids = new uint[0]; 3927 uint[] localids = new uint[0];
3435 lock (m_parts) 3928 lockPartsForRead(true);
3929 try
3436 { 3930 {
3437 localids = new uint[m_parts.Count]; 3931 localids = new uint[m_parts.Count];
3438 int cntr = 0; 3932 int cntr = 0;
@@ -3442,6 +3936,10 @@ namespace OpenSim.Region.Framework.Scenes
3442 cntr++; 3936 cntr++;
3443 } 3937 }
3444 } 3938 }
3939 finally
3940 {
3941 lockPartsForRead(false);
3942 }
3445 3943
3446 for (int ctr = 0; ctr < localids.Length; ctr++) 3944 for (int ctr = 0; ctr < localids.Length; ctr++)
3447 { 3945 {
@@ -3455,19 +3953,20 @@ namespace OpenSim.Region.Framework.Scenes
3455 public float GetMass() 3953 public float GetMass()
3456 { 3954 {
3457 float retmass = 0f; 3955 float retmass = 0f;
3458 lock (m_parts) 3956 lockPartsForRead(true);
3459 { 3957 {
3460 foreach (SceneObjectPart part in m_parts.Values) 3958 foreach (SceneObjectPart part in m_parts.Values)
3461 { 3959 {
3462 retmass += part.GetMass(); 3960 retmass += part.GetMass();
3463 } 3961 }
3464 } 3962 }
3963 lockPartsForRead(false);
3465 return retmass; 3964 return retmass;
3466 } 3965 }
3467 3966
3468 public void CheckSculptAndLoad() 3967 public void CheckSculptAndLoad()
3469 { 3968 {
3470 lock (m_parts) 3969 lockPartsForRead(true);
3471 { 3970 {
3472 if (!IsDeleted) 3971 if (!IsDeleted)
3473 { 3972 {
@@ -3492,6 +3991,7 @@ namespace OpenSim.Region.Framework.Scenes
3492 } 3991 }
3493 } 3992 }
3494 } 3993 }
3994 lockPartsForRead(false);
3495 } 3995 }
3496 3996
3497 protected void AssetReceived(string id, Object sender, AssetBase asset) 3997 protected void AssetReceived(string id, Object sender, AssetBase asset)
@@ -3512,7 +4012,7 @@ namespace OpenSim.Region.Framework.Scenes
3512 /// <param name="client"></param> 4012 /// <param name="client"></param>
3513 public void SetGroup(UUID GroupID, IClientAPI client) 4013 public void SetGroup(UUID GroupID, IClientAPI client)
3514 { 4014 {
3515 lock (m_parts) 4015 lockPartsForRead(true);
3516 { 4016 {
3517 foreach (SceneObjectPart part in m_parts.Values) 4017 foreach (SceneObjectPart part in m_parts.Values)
3518 { 4018 {
@@ -3522,6 +4022,7 @@ namespace OpenSim.Region.Framework.Scenes
3522 4022
3523 HasGroupChanged = true; 4023 HasGroupChanged = true;
3524 } 4024 }
4025 lockPartsForRead(false);
3525 4026
3526 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 4027 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
3527 // for the same object with very different properties. The caller must schedule the update. 4028 // for the same object with very different properties. The caller must schedule the update.
@@ -3543,11 +4044,12 @@ namespace OpenSim.Region.Framework.Scenes
3543 4044
3544 public void SetAttachmentPoint(byte point) 4045 public void SetAttachmentPoint(byte point)
3545 { 4046 {
3546 lock (m_parts) 4047 lockPartsForRead(true);
3547 { 4048 {
3548 foreach (SceneObjectPart part in m_parts.Values) 4049 foreach (SceneObjectPart part in m_parts.Values)
3549 part.SetAttachmentPoint(point); 4050 part.SetAttachmentPoint(point);
3550 } 4051 }
4052 lockPartsForRead(false);
3551 } 4053 }
3552 4054
3553 #region ISceneObject 4055 #region ISceneObject
@@ -3581,6 +4083,14 @@ namespace OpenSim.Region.Framework.Scenes
3581 SetFromItemID(uuid); 4083 SetFromItemID(uuid);
3582 } 4084 }
3583 4085
4086 public void ResetOwnerChangeFlag()
4087 {
4088 ForEachPart(delegate(SceneObjectPart part)
4089 {
4090 part.ResetOwnerChangeFlag();
4091 });
4092 }
4093
3584 #endregion 4094 #endregion
3585 } 4095 }
3586} 4096}