diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 883 |
1 files changed, 632 insertions, 251 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 17275d0..dbf493c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -104,8 +104,104 @@ namespace OpenSim.Region.Framework.Scenes | |||
104 | /// since the group's last persistent backup | 104 | /// since the group's last persistent backup |
105 | /// </summary> | 105 | /// </summary> |
106 | private bool m_hasGroupChanged = false; | 106 | private bool m_hasGroupChanged = false; |
107 | private long timeFirstChanged; | 107 | private long timeFirstChanged = 0; |
108 | private long timeLastChanged; | 108 | private long timeLastChanged = 0; |
109 | private long m_maxPersistTime = 0; | ||
110 | private long m_minPersistTime = 0; | ||
111 | private Random m_rand; | ||
112 | private bool m_suspendUpdates; | ||
113 | private System.Threading.ReaderWriterLockSlim m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
114 | private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>(); | ||
115 | |||
116 | public bool areUpdatesSuspended | ||
117 | { | ||
118 | get | ||
119 | { | ||
120 | return m_suspendUpdates; | ||
121 | } | ||
122 | set | ||
123 | { | ||
124 | m_suspendUpdates = value; | ||
125 | if (!value) | ||
126 | { | ||
127 | QueueForUpdateCheck(); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | public void lockPartsForRead(bool locked) | ||
133 | { | ||
134 | if (locked) | ||
135 | { | ||
136 | if (m_partsLock.RecursiveReadCount > 0) | ||
137 | { | ||
138 | 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."); | ||
139 | try | ||
140 | { | ||
141 | m_partsLock.ExitReadLock(); | ||
142 | } | ||
143 | catch { } // Ignore errors, to allow resync | ||
144 | } | ||
145 | if (m_partsLock.RecursiveWriteCount > 0) | ||
146 | { | ||
147 | 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."); | ||
148 | try | ||
149 | { | ||
150 | m_partsLock.ExitWriteLock(); | ||
151 | } | ||
152 | catch { } | ||
153 | |||
154 | } | ||
155 | |||
156 | while (!m_partsLock.TryEnterReadLock(60000)) | ||
157 | { | ||
158 | 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."); | ||
159 | if (m_partsLock.IsWriteLockHeld) | ||
160 | { | ||
161 | m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | if (m_partsLock.RecursiveReadCount > 0) | ||
168 | { | ||
169 | m_partsLock.ExitReadLock(); | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | public void lockPartsForWrite(bool locked) | ||
174 | { | ||
175 | if (locked) | ||
176 | { | ||
177 | if (m_partsLock.RecursiveReadCount > 0) | ||
178 | { | ||
179 | 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."); | ||
180 | m_partsLock.ExitReadLock(); | ||
181 | } | ||
182 | if (m_partsLock.RecursiveWriteCount > 0) | ||
183 | { | ||
184 | m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed."); | ||
185 | m_partsLock.ExitWriteLock(); | ||
186 | } | ||
187 | |||
188 | while (!m_partsLock.TryEnterWriteLock(60000)) | ||
189 | { | ||
190 | 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."); | ||
191 | if (m_partsLock.IsWriteLockHeld) | ||
192 | { | ||
193 | m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | if (m_partsLock.RecursiveWriteCount > 0) | ||
200 | { | ||
201 | m_partsLock.ExitWriteLock(); | ||
202 | } | ||
203 | } | ||
204 | } | ||
109 | 205 | ||
110 | public bool HasGroupChanged | 206 | public bool HasGroupChanged |
111 | { | 207 | { |
@@ -113,9 +209,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
113 | { | 209 | { |
114 | if (value) | 210 | if (value) |
115 | { | 211 | { |
212 | if (m_isBackedUp) | ||
213 | { | ||
214 | m_scene.SceneGraph.FireChangeBackup(this); | ||
215 | } | ||
116 | timeLastChanged = DateTime.Now.Ticks; | 216 | timeLastChanged = DateTime.Now.Ticks; |
117 | if (!m_hasGroupChanged) | 217 | if (!m_hasGroupChanged) |
118 | timeFirstChanged = DateTime.Now.Ticks; | 218 | timeFirstChanged = DateTime.Now.Ticks; |
219 | if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null) | ||
220 | { | ||
221 | if (m_rand == null) | ||
222 | { | ||
223 | byte[] val = new byte[16]; | ||
224 | m_rootPart.UUID.ToBytes(val, 0); | ||
225 | m_rand = new Random(BitConverter.ToInt32(val, 0)); | ||
226 | } | ||
227 | |||
228 | if (m_scene.GetRootAgentCount() == 0) | ||
229 | { | ||
230 | //If the region is empty, this change has been made by an automated process | ||
231 | //and thus we delay the persist time by a random amount between 1.5 and 2.5. | ||
232 | |||
233 | float factor = 1.5f + (float)(m_rand.NextDouble()); | ||
234 | m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor); | ||
235 | m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | //If the region is not empty, we want to obey the minimum and maximum persist times | ||
240 | //but add a random factor so we stagger the object persistance a little | ||
241 | m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5 | ||
242 | m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0 | ||
243 | } | ||
244 | } | ||
119 | } | 245 | } |
120 | m_hasGroupChanged = value; | 246 | m_hasGroupChanged = value; |
121 | } | 247 | } |
@@ -131,8 +257,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
131 | return false; | 257 | return false; |
132 | if (m_scene.ShuttingDown) | 258 | if (m_scene.ShuttingDown) |
133 | return true; | 259 | return true; |
260 | |||
261 | if (m_minPersistTime == 0 || m_maxPersistTime == 0) | ||
262 | { | ||
263 | m_maxPersistTime = m_scene.m_persistAfter; | ||
264 | m_minPersistTime = m_scene.m_dontPersistBefore; | ||
265 | } | ||
266 | |||
134 | long currentTime = DateTime.Now.Ticks; | 267 | long currentTime = DateTime.Now.Ticks; |
135 | if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) | 268 | |
269 | if (timeLastChanged == 0) timeLastChanged = currentTime; | ||
270 | if (timeFirstChanged == 0) timeFirstChanged = currentTime; | ||
271 | |||
272 | if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime) | ||
136 | return true; | 273 | return true; |
137 | return false; | 274 | return false; |
138 | } | 275 | } |
@@ -221,7 +358,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
221 | public virtual Quaternion Rotation | 358 | public virtual Quaternion Rotation |
222 | { | 359 | { |
223 | get { return m_rotation; } | 360 | get { return m_rotation; } |
224 | set { m_rotation = value; } | 361 | set { |
362 | lockPartsForRead(true); | ||
363 | try | ||
364 | { | ||
365 | foreach(SceneObjectPart p in m_parts.Values) | ||
366 | { | ||
367 | p.StoreUndoState(UndoType.STATE_GROUP_ROTATION); | ||
368 | } | ||
369 | } | ||
370 | finally | ||
371 | { | ||
372 | lockPartsForRead(false); | ||
373 | } | ||
374 | m_rotation = value; | ||
375 | } | ||
225 | } | 376 | } |
226 | 377 | ||
227 | public Quaternion GroupRotation | 378 | public Quaternion GroupRotation |
@@ -258,13 +409,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
258 | set | 409 | set |
259 | { | 410 | { |
260 | m_regionHandle = value; | 411 | m_regionHandle = value; |
261 | lock (m_parts) | 412 | lockPartsForRead(true); |
262 | { | 413 | { |
263 | foreach (SceneObjectPart part in m_parts.Values) | 414 | foreach (SceneObjectPart part in m_parts.Values) |
264 | { | 415 | { |
416 | |||
265 | part.RegionHandle = m_regionHandle; | 417 | part.RegionHandle = m_regionHandle; |
418 | |||
266 | } | 419 | } |
267 | } | 420 | } |
421 | lockPartsForRead(false); | ||
268 | } | 422 | } |
269 | } | 423 | } |
270 | 424 | ||
@@ -298,6 +452,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
298 | { | 452 | { |
299 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | 453 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); |
300 | } | 454 | } |
455 | |||
456 | lockPartsForRead(true); | ||
457 | foreach (SceneObjectPart part in m_parts.Values) | ||
458 | { | ||
459 | part.IgnoreUndoUpdate = true; | ||
460 | } | ||
301 | if (RootPart.GetStatusSandbox()) | 461 | if (RootPart.GetStatusSandbox()) |
302 | { | 462 | { |
303 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) | 463 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) |
@@ -305,16 +465,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
305 | RootPart.ScriptSetPhysicsStatus(false); | 465 | RootPart.ScriptSetPhysicsStatus(false); |
306 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), | 466 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), |
307 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); | 467 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); |
468 | lockPartsForRead(false); | ||
308 | return; | 469 | return; |
309 | } | 470 | } |
310 | } | 471 | } |
311 | lock (m_parts) | 472 | foreach (SceneObjectPart part in m_parts.Values) |
312 | { | 473 | { |
313 | foreach (SceneObjectPart part in m_parts.Values) | 474 | part.IgnoreUndoUpdate = false; |
314 | { | 475 | part.StoreUndoState(UndoType.STATE_GROUP_POSITION); |
315 | part.GroupPosition = val; | 476 | part.GroupPosition = val; |
316 | } | ||
317 | } | 477 | } |
478 | lockPartsForRead(false); | ||
318 | 479 | ||
319 | //if (m_rootPart.PhysActor != null) | 480 | //if (m_rootPart.PhysActor != null) |
320 | //{ | 481 | //{ |
@@ -457,6 +618,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
457 | /// </summary> | 618 | /// </summary> |
458 | public SceneObjectGroup() | 619 | public SceneObjectGroup() |
459 | { | 620 | { |
621 | |||
460 | } | 622 | } |
461 | 623 | ||
462 | /// <summary> | 624 | /// <summary> |
@@ -473,7 +635,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
473 | /// Constructor. This object is added to the scene later via AttachToScene() | 635 | /// Constructor. This object is added to the scene later via AttachToScene() |
474 | /// </summary> | 636 | /// </summary> |
475 | public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) | 637 | public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) |
476 | { | 638 | { |
477 | SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); | 639 | SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); |
478 | } | 640 | } |
479 | 641 | ||
@@ -504,13 +666,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
504 | 666 | ||
505 | public void SetFromItemID(UUID AssetId) | 667 | public void SetFromItemID(UUID AssetId) |
506 | { | 668 | { |
507 | lock (m_parts) | 669 | lockPartsForRead(true); |
508 | { | 670 | { |
509 | foreach (SceneObjectPart part in m_parts.Values) | 671 | foreach (SceneObjectPart part in m_parts.Values) |
510 | { | 672 | { |
673 | |||
511 | part.FromItemID = AssetId; | 674 | part.FromItemID = AssetId; |
675 | |||
512 | } | 676 | } |
513 | } | 677 | } |
678 | lockPartsForRead(false); | ||
514 | } | 679 | } |
515 | 680 | ||
516 | public UUID GetFromItemID() | 681 | public UUID GetFromItemID() |
@@ -523,6 +688,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
523 | /// </summary> | 688 | /// </summary> |
524 | public virtual void AttachToBackup() | 689 | public virtual void AttachToBackup() |
525 | { | 690 | { |
691 | if (IsAttachment) return; | ||
692 | m_scene.SceneGraph.FireAttachToBackup(this); | ||
693 | |||
526 | if (InSceneBackup) | 694 | if (InSceneBackup) |
527 | { | 695 | { |
528 | //m_log.DebugFormat( | 696 | //m_log.DebugFormat( |
@@ -579,7 +747,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
579 | Vector3 maxScale = Vector3.Zero; | 747 | Vector3 maxScale = Vector3.Zero; |
580 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); | 748 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); |
581 | 749 | ||
582 | lock (m_parts) | 750 | lockPartsForRead(true); |
583 | { | 751 | { |
584 | foreach (SceneObjectPart part in m_parts.Values) | 752 | foreach (SceneObjectPart part in m_parts.Values) |
585 | { | 753 | { |
@@ -593,8 +761,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
593 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; | 761 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; |
594 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; | 762 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; |
595 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; | 763 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; |
764 | |||
596 | } | 765 | } |
597 | } | 766 | } |
767 | lockPartsForRead(false); | ||
768 | |||
598 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; | 769 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; |
599 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; | 770 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; |
600 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; | 771 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; |
@@ -610,10 +781,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
610 | 781 | ||
611 | EntityIntersection result = new EntityIntersection(); | 782 | EntityIntersection result = new EntityIntersection(); |
612 | 783 | ||
613 | lock (m_parts) | 784 | lockPartsForRead(true); |
614 | { | 785 | { |
615 | foreach (SceneObjectPart part in m_parts.Values) | 786 | foreach (SceneObjectPart part in m_parts.Values) |
616 | { | 787 | { |
788 | |||
617 | // Temporary commented to stop compiler warning | 789 | // Temporary commented to stop compiler warning |
618 | //Vector3 partPosition = | 790 | //Vector3 partPosition = |
619 | // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); | 791 | // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); |
@@ -641,8 +813,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
641 | result.distance = inter.distance; | 813 | result.distance = inter.distance; |
642 | } | 814 | } |
643 | } | 815 | } |
816 | |||
644 | } | 817 | } |
645 | } | 818 | } |
819 | lockPartsForRead(false); | ||
646 | return result; | 820 | return result; |
647 | } | 821 | } |
648 | 822 | ||
@@ -661,10 +835,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
661 | minY = 256f; | 835 | minY = 256f; |
662 | minZ = 8192f; | 836 | minZ = 8192f; |
663 | 837 | ||
664 | lock(m_parts); | 838 | lockPartsForRead(true); |
665 | { | 839 | { |
666 | foreach (SceneObjectPart part in m_parts.Values) | 840 | foreach (SceneObjectPart part in m_parts.Values) |
667 | { | 841 | { |
842 | |||
668 | Vector3 worldPos = part.GetWorldPosition(); | 843 | Vector3 worldPos = part.GetWorldPosition(); |
669 | Vector3 offset = worldPos - AbsolutePosition; | 844 | Vector3 offset = worldPos - AbsolutePosition; |
670 | Quaternion worldRot; | 845 | Quaternion worldRot; |
@@ -723,6 +898,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
723 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); | 898 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); |
724 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); | 899 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); |
725 | 900 | ||
901 | |||
902 | |||
726 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | 903 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); |
727 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | 904 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); |
728 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | 905 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); |
@@ -894,6 +1071,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
894 | minZ = backBottomLeft.Z; | 1071 | minZ = backBottomLeft.Z; |
895 | } | 1072 | } |
896 | } | 1073 | } |
1074 | lockPartsForRead(false); | ||
897 | } | 1075 | } |
898 | 1076 | ||
899 | public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) | 1077 | public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) |
@@ -929,21 +1107,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
929 | 1107 | ||
930 | public void SaveScriptedState(XmlTextWriter writer) | 1108 | public void SaveScriptedState(XmlTextWriter writer) |
931 | { | 1109 | { |
1110 | SaveScriptedState(writer, false); | ||
1111 | } | ||
1112 | |||
1113 | public void SaveScriptedState(XmlTextWriter writer, bool oldIDs) | ||
1114 | { | ||
932 | XmlDocument doc = new XmlDocument(); | 1115 | XmlDocument doc = new XmlDocument(); |
933 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); | 1116 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); |
934 | 1117 | ||
935 | // Capture script state while holding the lock | 1118 | // Capture script state while holding the lock |
936 | lock (m_parts) | 1119 | lockPartsForRead(true); |
937 | { | 1120 | { |
938 | foreach (SceneObjectPart part in m_parts.Values) | 1121 | foreach (SceneObjectPart part in m_parts.Values) |
939 | { | 1122 | { |
940 | Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); | 1123 | |
1124 | Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(oldIDs); | ||
941 | foreach (UUID itemid in pstates.Keys) | 1125 | foreach (UUID itemid in pstates.Keys) |
942 | { | 1126 | { |
943 | states.Add(itemid, pstates[itemid]); | 1127 | states.Add(itemid, pstates[itemid]); |
944 | } | 1128 | } |
1129 | |||
945 | } | 1130 | } |
946 | } | 1131 | } |
1132 | lockPartsForRead(false); | ||
947 | 1133 | ||
948 | if (states.Count > 0) | 1134 | if (states.Count > 0) |
949 | { | 1135 | { |
@@ -962,6 +1148,47 @@ namespace OpenSim.Region.Framework.Scenes | |||
962 | } | 1148 | } |
963 | 1149 | ||
964 | /// <summary> | 1150 | /// <summary> |
1151 | /// Add the avatar to this linkset (avatar is sat). | ||
1152 | /// </summary> | ||
1153 | /// <param name="agentID"></param> | ||
1154 | public void AddAvatar(UUID agentID) | ||
1155 | { | ||
1156 | ScenePresence presence; | ||
1157 | if (m_scene.TryGetScenePresence(agentID, out presence)) | ||
1158 | { | ||
1159 | if (!m_linkedAvatars.Contains(presence)) | ||
1160 | { | ||
1161 | m_linkedAvatars.Add(presence); | ||
1162 | } | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | /// <summary> | ||
1167 | /// Delete the avatar from this linkset (avatar is unsat). | ||
1168 | /// </summary> | ||
1169 | /// <param name="agentID"></param> | ||
1170 | public void DeleteAvatar(UUID agentID) | ||
1171 | { | ||
1172 | ScenePresence presence; | ||
1173 | if (m_scene.TryGetScenePresence(agentID, out presence)) | ||
1174 | { | ||
1175 | if (m_linkedAvatars.Contains(presence)) | ||
1176 | { | ||
1177 | m_linkedAvatars.Remove(presence); | ||
1178 | } | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | /// <summary> | ||
1183 | /// Returns the list of linked presences (avatars sat on this group) | ||
1184 | /// </summary> | ||
1185 | /// <param name="agentID"></param> | ||
1186 | public List<ScenePresence> GetLinkedAvatars() | ||
1187 | { | ||
1188 | return m_linkedAvatars; | ||
1189 | } | ||
1190 | |||
1191 | /// <summary> | ||
965 | /// Attach this scene object to the given avatar. | 1192 | /// Attach this scene object to the given avatar. |
966 | /// </summary> | 1193 | /// </summary> |
967 | /// <param name="agentID"></param> | 1194 | /// <param name="agentID"></param> |
@@ -1112,13 +1339,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1112 | 1339 | ||
1113 | public override void UpdateMovement() | 1340 | public override void UpdateMovement() |
1114 | { | 1341 | { |
1115 | lock (m_parts) | 1342 | lockPartsForRead(true); |
1116 | { | 1343 | { |
1117 | foreach (SceneObjectPart part in m_parts.Values) | 1344 | foreach (SceneObjectPart part in m_parts.Values) |
1118 | { | 1345 | { |
1346 | |||
1119 | part.UpdateMovement(); | 1347 | part.UpdateMovement(); |
1348 | |||
1120 | } | 1349 | } |
1121 | } | 1350 | } |
1351 | lockPartsForRead(false); | ||
1122 | } | 1352 | } |
1123 | 1353 | ||
1124 | public ushort GetTimeDilation() | 1354 | public ushort GetTimeDilation() |
@@ -1162,7 +1392,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1162 | /// <param name="part"></param> | 1392 | /// <param name="part"></param> |
1163 | public void AddPart(SceneObjectPart part) | 1393 | public void AddPart(SceneObjectPart part) |
1164 | { | 1394 | { |
1165 | lock (m_parts) | 1395 | lockPartsForWrite(true); |
1166 | { | 1396 | { |
1167 | part.SetParent(this); | 1397 | part.SetParent(this); |
1168 | m_parts.Add(part.UUID, part); | 1398 | m_parts.Add(part.UUID, part); |
@@ -1172,6 +1402,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1172 | if (part.LinkNum == 2 && RootPart != null) | 1402 | if (part.LinkNum == 2 && RootPart != null) |
1173 | RootPart.LinkNum = 1; | 1403 | RootPart.LinkNum = 1; |
1174 | } | 1404 | } |
1405 | lockPartsForWrite(false); | ||
1175 | } | 1406 | } |
1176 | 1407 | ||
1177 | /// <summary> | 1408 | /// <summary> |
@@ -1179,28 +1410,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
1179 | /// </summary> | 1410 | /// </summary> |
1180 | private void UpdateParentIDs() | 1411 | private void UpdateParentIDs() |
1181 | { | 1412 | { |
1182 | lock (m_parts) | 1413 | lockPartsForRead(true); |
1183 | { | 1414 | { |
1184 | foreach (SceneObjectPart part in m_parts.Values) | 1415 | foreach (SceneObjectPart part in m_parts.Values) |
1185 | { | 1416 | { |
1417 | |||
1186 | if (part.UUID != m_rootPart.UUID) | 1418 | if (part.UUID != m_rootPart.UUID) |
1187 | { | 1419 | { |
1188 | part.ParentID = m_rootPart.LocalId; | 1420 | part.ParentID = m_rootPart.LocalId; |
1189 | } | 1421 | } |
1422 | |||
1190 | } | 1423 | } |
1191 | } | 1424 | } |
1425 | lockPartsForRead(false); | ||
1192 | } | 1426 | } |
1193 | 1427 | ||
1194 | public void RegenerateFullIDs() | 1428 | public void RegenerateFullIDs() |
1195 | { | 1429 | { |
1196 | lock (m_parts) | 1430 | lockPartsForRead(true); |
1197 | { | 1431 | { |
1198 | foreach (SceneObjectPart part in m_parts.Values) | 1432 | foreach (SceneObjectPart part in m_parts.Values) |
1199 | { | 1433 | { |
1434 | |||
1200 | part.UUID = UUID.Random(); | 1435 | part.UUID = UUID.Random(); |
1201 | 1436 | ||
1202 | } | 1437 | } |
1203 | } | 1438 | } |
1439 | lockPartsForRead(false); | ||
1204 | } | 1440 | } |
1205 | 1441 | ||
1206 | // helper provided for parts. | 1442 | // helper provided for parts. |
@@ -1261,7 +1497,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1261 | 1497 | ||
1262 | public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) | 1498 | public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) |
1263 | { | 1499 | { |
1264 | part.StoreUndoState(); | 1500 | part.StoreUndoState(UndoType.STATE_PRIM_ALL); |
1265 | part.OnGrab(offsetPos, remoteClient); | 1501 | part.OnGrab(offsetPos, remoteClient); |
1266 | } | 1502 | } |
1267 | 1503 | ||
@@ -1281,27 +1517,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
1281 | 1517 | ||
1282 | DetachFromBackup(); | 1518 | DetachFromBackup(); |
1283 | 1519 | ||
1284 | lock (m_parts) | 1520 | lockPartsForRead(true); |
1521 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | ||
1522 | lockPartsForRead(false); | ||
1523 | |||
1524 | foreach (SceneObjectPart part in values) | ||
1285 | { | 1525 | { |
1286 | foreach (SceneObjectPart part in m_parts.Values) | ||
1287 | { | ||
1288 | // part.Inventory.RemoveScriptInstances(); | 1526 | // part.Inventory.RemoveScriptInstances(); |
1289 | Scene.ForEachScenePresence(delegate(ScenePresence avatar) | 1527 | |
1528 | Scene.ForEachScenePresence(delegate (ScenePresence sp) | ||
1529 | { | ||
1530 | if (sp.ParentID == LocalId) | ||
1290 | { | 1531 | { |
1291 | if (avatar.ParentID == LocalId) | 1532 | sp.StandUp(); |
1292 | { | 1533 | } |
1293 | avatar.StandUp(); | ||
1294 | } | ||
1295 | 1534 | ||
1296 | if (!silent) | 1535 | if (!silent) |
1297 | { | 1536 | { |
1298 | part.UpdateFlag = 0; | 1537 | part.UpdateFlag = 0; |
1299 | if (part == m_rootPart) | 1538 | if (part == m_rootPart) |
1300 | avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); | 1539 | sp.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); |
1301 | } | 1540 | } |
1302 | }); | 1541 | }); |
1303 | } | 1542 | |
1304 | } | 1543 | } |
1544 | |||
1545 | |||
1305 | } | 1546 | } |
1306 | 1547 | ||
1307 | public void AddScriptLPS(int count) | 1548 | public void AddScriptLPS(int count) |
@@ -1326,17 +1567,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1326 | 1567 | ||
1327 | scriptEvents aggregateScriptEvents=0; | 1568 | scriptEvents aggregateScriptEvents=0; |
1328 | 1569 | ||
1329 | lock (m_parts) | 1570 | lockPartsForRead(true); |
1330 | { | 1571 | { |
1331 | foreach (SceneObjectPart part in m_parts.Values) | 1572 | foreach (SceneObjectPart part in m_parts.Values) |
1332 | { | 1573 | { |
1574 | |||
1333 | if (part == null) | 1575 | if (part == null) |
1334 | continue; | 1576 | continue; |
1335 | if (part != RootPart) | 1577 | if (part != RootPart) |
1336 | part.ObjectFlags = objectflagupdate; | 1578 | part.ObjectFlags = objectflagupdate; |
1337 | aggregateScriptEvents |= part.AggregateScriptEvents; | 1579 | aggregateScriptEvents |= part.AggregateScriptEvents; |
1580 | |||
1338 | } | 1581 | } |
1339 | } | 1582 | } |
1583 | lockPartsForRead(false); | ||
1340 | 1584 | ||
1341 | m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); | 1585 | m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); |
1342 | m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); | 1586 | m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); |
@@ -1378,42 +1622,52 @@ namespace OpenSim.Region.Framework.Scenes | |||
1378 | /// <param name="m_physicalPrim"></param> | 1622 | /// <param name="m_physicalPrim"></param> |
1379 | public void ApplyPhysics(bool m_physicalPrim) | 1623 | public void ApplyPhysics(bool m_physicalPrim) |
1380 | { | 1624 | { |
1381 | lock (m_parts) | 1625 | lockPartsForRead(true); |
1626 | |||
1627 | if (m_parts.Count > 1) | ||
1382 | { | 1628 | { |
1383 | if (m_parts.Count > 1) | 1629 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); |
1630 | lockPartsForRead(false); | ||
1631 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1632 | foreach (SceneObjectPart part in values) | ||
1384 | { | 1633 | { |
1385 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | 1634 | |
1386 | foreach (SceneObjectPart part in m_parts.Values) | 1635 | if (part.LocalId != m_rootPart.LocalId) |
1387 | { | 1636 | { |
1388 | if (part.LocalId != m_rootPart.LocalId) | 1637 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); |
1389 | { | ||
1390 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); | ||
1391 | } | ||
1392 | } | 1638 | } |
1393 | 1639 | ||
1394 | // Hack to get the physics scene geometries in the right spot | ||
1395 | ResetChildPrimPhysicsPositions(); | ||
1396 | } | ||
1397 | else | ||
1398 | { | ||
1399 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1400 | } | 1640 | } |
1641 | // Hack to get the physics scene geometries in the right spot | ||
1642 | ResetChildPrimPhysicsPositions(); | ||
1643 | } | ||
1644 | else | ||
1645 | { | ||
1646 | lockPartsForRead(false); | ||
1647 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1401 | } | 1648 | } |
1402 | } | 1649 | } |
1403 | 1650 | ||
1404 | public void SetOwnerId(UUID userId) | 1651 | public void SetOwnerId(UUID userId) |
1405 | { | 1652 | { |
1406 | ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); | 1653 | ForEachPart(delegate(SceneObjectPart part) |
1654 | { | ||
1655 | |||
1656 | part.OwnerID = userId; | ||
1657 | |||
1658 | }); | ||
1407 | } | 1659 | } |
1408 | 1660 | ||
1409 | public void ForEachPart(Action<SceneObjectPart> whatToDo) | 1661 | public void ForEachPart(Action<SceneObjectPart> whatToDo) |
1410 | { | 1662 | { |
1411 | lock (m_parts) | 1663 | lockPartsForRead(true); |
1664 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | ||
1665 | lockPartsForRead(false); | ||
1666 | foreach (SceneObjectPart part in values) | ||
1412 | { | 1667 | { |
1413 | foreach (SceneObjectPart part in m_parts.Values) | 1668 | |
1414 | { | 1669 | whatToDo(part); |
1415 | whatToDo(part); | 1670 | |
1416 | } | ||
1417 | } | 1671 | } |
1418 | } | 1672 | } |
1419 | 1673 | ||
@@ -1436,7 +1690,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1436 | 1690 | ||
1437 | try | 1691 | try |
1438 | { | 1692 | { |
1439 | if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart | 1693 | if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart |
1694 | m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things | ||
1695 | m_scene.LoadingPrims) // Land may not be valid yet | ||
1696 | |||
1440 | { | 1697 | { |
1441 | ILandObject parcel = m_scene.LandChannel.GetLandObject( | 1698 | ILandObject parcel = m_scene.LandChannel.GetLandObject( |
1442 | m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); | 1699 | m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); |
@@ -1511,15 +1768,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1511 | RootPart.SendFullUpdate( | 1768 | RootPart.SendFullUpdate( |
1512 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); | 1769 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); |
1513 | 1770 | ||
1514 | lock (m_parts) | 1771 | lockPartsForRead(true); |
1515 | { | 1772 | { |
1516 | foreach (SceneObjectPart part in m_parts.Values) | 1773 | foreach (SceneObjectPart part in m_parts.Values) |
1517 | { | 1774 | { |
1775 | |||
1518 | if (part != RootPart) | 1776 | if (part != RootPart) |
1519 | part.SendFullUpdate( | 1777 | part.SendFullUpdate( |
1520 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); | 1778 | remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); |
1521 | } | 1779 | } |
1522 | } | 1780 | } |
1781 | lockPartsForRead(false); | ||
1523 | } | 1782 | } |
1524 | 1783 | ||
1525 | #region Copying | 1784 | #region Copying |
@@ -1580,10 +1839,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1580 | 1839 | ||
1581 | List<SceneObjectPart> partList; | 1840 | List<SceneObjectPart> partList; |
1582 | 1841 | ||
1583 | lock (m_parts) | 1842 | lockPartsForRead(true); |
1584 | { | 1843 | |
1585 | partList = new List<SceneObjectPart>(m_parts.Values); | 1844 | partList = new List<SceneObjectPart>(m_parts.Values); |
1586 | } | 1845 | |
1846 | lockPartsForRead(false); | ||
1587 | 1847 | ||
1588 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) | 1848 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) |
1589 | { | 1849 | { |
@@ -1800,13 +2060,40 @@ namespace OpenSim.Region.Framework.Scenes | |||
1800 | } | 2060 | } |
1801 | } | 2061 | } |
1802 | 2062 | ||
2063 | public void rotLookAt(Quaternion target, float strength, float damping) | ||
2064 | { | ||
2065 | SceneObjectPart rootpart = m_rootPart; | ||
2066 | if (rootpart != null) | ||
2067 | { | ||
2068 | if (IsAttachment) | ||
2069 | { | ||
2070 | /* | ||
2071 | ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); | ||
2072 | if (avatar != null) | ||
2073 | { | ||
2074 | Rotate the Av? | ||
2075 | } */ | ||
2076 | } | ||
2077 | else | ||
2078 | { | ||
2079 | if (rootpart.PhysActor != null) | ||
2080 | { // APID must be implemented in your physics system for this to function. | ||
2081 | rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W); | ||
2082 | rootpart.PhysActor.APIDStrength = strength; | ||
2083 | rootpart.PhysActor.APIDDamping = damping; | ||
2084 | rootpart.PhysActor.APIDActive = true; | ||
2085 | } | ||
2086 | } | ||
2087 | } | ||
2088 | } | ||
2089 | |||
1803 | public void stopLookAt() | 2090 | public void stopLookAt() |
1804 | { | 2091 | { |
1805 | SceneObjectPart rootpart = m_rootPart; | 2092 | SceneObjectPart rootpart = m_rootPart; |
1806 | if (rootpart != null) | 2093 | if (rootpart != null) |
1807 | { | 2094 | { |
1808 | if (rootpart.PhysActor != null) | 2095 | if (rootpart.PhysActor != null) |
1809 | { | 2096 | { // APID must be implemented in your physics system for this to function. |
1810 | rootpart.PhysActor.APIDActive = false; | 2097 | rootpart.PhysActor.APIDActive = false; |
1811 | } | 2098 | } |
1812 | } | 2099 | } |
@@ -1874,10 +2161,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1874 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); | 2161 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); |
1875 | newPart.SetParent(this); | 2162 | newPart.SetParent(this); |
1876 | 2163 | ||
1877 | lock (m_parts) | 2164 | lockPartsForWrite(true); |
1878 | { | 2165 | { |
1879 | m_parts.Add(newPart.UUID, newPart); | 2166 | m_parts.Add(newPart.UUID, newPart); |
1880 | } | 2167 | } |
2168 | lockPartsForWrite(false); | ||
1881 | 2169 | ||
1882 | SetPartAsNonRoot(newPart); | 2170 | SetPartAsNonRoot(newPart); |
1883 | 2171 | ||
@@ -1940,7 +2228,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1940 | //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) | 2228 | //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) |
1941 | // return; | 2229 | // return; |
1942 | 2230 | ||
1943 | lock (m_parts) | 2231 | lockPartsForRead(true); |
1944 | { | 2232 | { |
1945 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 2233 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); |
1946 | 2234 | ||
@@ -1960,9 +2248,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1960 | { | 2248 | { |
1961 | if (!IsSelected) | 2249 | if (!IsSelected) |
1962 | part.UpdateLookAt(); | 2250 | part.UpdateLookAt(); |
2251 | |||
1963 | part.SendScheduledUpdates(); | 2252 | part.SendScheduledUpdates(); |
2253 | |||
1964 | } | 2254 | } |
1965 | } | 2255 | } |
2256 | lockPartsForRead(false); | ||
1966 | } | 2257 | } |
1967 | 2258 | ||
1968 | public void ScheduleFullUpdateToAvatar(ScenePresence presence) | 2259 | public void ScheduleFullUpdateToAvatar(ScenePresence presence) |
@@ -1971,27 +2262,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
1971 | 2262 | ||
1972 | RootPart.AddFullUpdateToAvatar(presence); | 2263 | RootPart.AddFullUpdateToAvatar(presence); |
1973 | 2264 | ||
1974 | lock (m_parts) | 2265 | lockPartsForRead(true); |
1975 | { | 2266 | { |
1976 | foreach (SceneObjectPart part in m_parts.Values) | 2267 | foreach (SceneObjectPart part in m_parts.Values) |
1977 | { | 2268 | { |
2269 | |||
1978 | if (part != RootPart) | 2270 | if (part != RootPart) |
1979 | part.AddFullUpdateToAvatar(presence); | 2271 | part.AddFullUpdateToAvatar(presence); |
2272 | |||
1980 | } | 2273 | } |
1981 | } | 2274 | } |
2275 | lockPartsForRead(false); | ||
1982 | } | 2276 | } |
1983 | 2277 | ||
1984 | public void ScheduleTerseUpdateToAvatar(ScenePresence presence) | 2278 | public void ScheduleTerseUpdateToAvatar(ScenePresence presence) |
1985 | { | 2279 | { |
1986 | // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); | 2280 | lockPartsForRead(true); |
1987 | 2281 | ||
1988 | lock (m_parts) | 2282 | foreach (SceneObjectPart part in m_parts.Values) |
1989 | { | 2283 | { |
1990 | foreach (SceneObjectPart part in m_parts.Values) | 2284 | part.AddTerseUpdateToAvatar(presence); |
1991 | { | ||
1992 | part.AddTerseUpdateToAvatar(presence); | ||
1993 | } | ||
1994 | } | 2285 | } |
2286 | |||
2287 | lockPartsForRead(false); | ||
1995 | } | 2288 | } |
1996 | 2289 | ||
1997 | /// <summary> | 2290 | /// <summary> |
@@ -1999,20 +2292,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
1999 | /// </summary> | 2292 | /// </summary> |
2000 | public void ScheduleGroupForFullUpdate() | 2293 | public void ScheduleGroupForFullUpdate() |
2001 | { | 2294 | { |
2002 | if (IsAttachment) | 2295 | //if (IsAttachment) |
2003 | m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); | 2296 | // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); |
2004 | 2297 | ||
2005 | checkAtTargets(); | 2298 | checkAtTargets(); |
2006 | RootPart.ScheduleFullUpdate(); | 2299 | RootPart.ScheduleFullUpdate(); |
2007 | 2300 | ||
2008 | lock (m_parts) | 2301 | lockPartsForRead(true); |
2009 | { | 2302 | { |
2010 | foreach (SceneObjectPart part in m_parts.Values) | 2303 | foreach (SceneObjectPart part in m_parts.Values) |
2011 | { | 2304 | { |
2305 | |||
2012 | if (part != RootPart) | 2306 | if (part != RootPart) |
2013 | part.ScheduleFullUpdate(); | 2307 | part.ScheduleFullUpdate(); |
2308 | |||
2014 | } | 2309 | } |
2015 | } | 2310 | } |
2311 | lockPartsForRead(false); | ||
2016 | } | 2312 | } |
2017 | 2313 | ||
2018 | /// <summary> | 2314 | /// <summary> |
@@ -2020,37 +2316,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
2020 | /// </summary> | 2316 | /// </summary> |
2021 | public void ScheduleGroupForTerseUpdate() | 2317 | public void ScheduleGroupForTerseUpdate() |
2022 | { | 2318 | { |
2023 | // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); | 2319 | lockPartsForRead(true); |
2024 | 2320 | foreach (SceneObjectPart part in m_parts.Values) | |
2025 | lock (m_parts) | ||
2026 | { | 2321 | { |
2027 | foreach (SceneObjectPart part in m_parts.Values) | 2322 | part.ScheduleTerseUpdate(); |
2028 | { | ||
2029 | part.ScheduleTerseUpdate(); | ||
2030 | } | ||
2031 | } | 2323 | } |
2324 | |||
2325 | lockPartsForRead(false); | ||
2032 | } | 2326 | } |
2033 | 2327 | ||
2034 | /// <summary> | 2328 | /// <summary> |
2035 | /// Immediately send a full update for this scene object. | 2329 | /// Immediately send a full update for this scene object. |
2036 | /// </summary> | 2330 | /// </summary> |
2037 | public void SendGroupFullUpdate() | 2331 | public void SendGroupFullUpdate() |
2038 | { | 2332 | { |
2039 | if (IsDeleted) | 2333 | if (IsDeleted) |
2040 | return; | 2334 | return; |
2041 | 2335 | ||
2042 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); | 2336 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); |
2043 | 2337 | ||
2044 | RootPart.SendFullUpdateToAllClients(); | 2338 | RootPart.SendFullUpdateToAllClients(); |
2045 | 2339 | ||
2046 | lock (m_parts) | 2340 | lockPartsForRead(true); |
2047 | { | 2341 | { |
2048 | foreach (SceneObjectPart part in m_parts.Values) | 2342 | foreach (SceneObjectPart part in m_parts.Values) |
2049 | { | 2343 | { |
2344 | |||
2050 | if (part != RootPart) | 2345 | if (part != RootPart) |
2051 | part.SendFullUpdateToAllClients(); | 2346 | part.SendFullUpdateToAllClients(); |
2347 | |||
2052 | } | 2348 | } |
2053 | } | 2349 | } |
2350 | lockPartsForRead(false); | ||
2054 | } | 2351 | } |
2055 | 2352 | ||
2056 | /// <summary> | 2353 | /// <summary> |
@@ -2082,14 +2379,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
2082 | { | 2379 | { |
2083 | if (IsDeleted) | 2380 | if (IsDeleted) |
2084 | return; | 2381 | return; |
2085 | 2382 | ||
2086 | lock (m_parts) | 2383 | lockPartsForRead(true); |
2087 | { | 2384 | { |
2088 | foreach (SceneObjectPart part in m_parts.Values) | 2385 | foreach (SceneObjectPart part in m_parts.Values) |
2089 | { | 2386 | { |
2090 | part.SendTerseUpdateToAllClients(); | 2387 | part.SendTerseUpdateToAllClients(); |
2091 | } | 2388 | } |
2092 | } | 2389 | } |
2390 | lockPartsForRead(false); | ||
2093 | } | 2391 | } |
2094 | 2392 | ||
2095 | #endregion | 2393 | #endregion |
@@ -2103,16 +2401,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
2103 | /// <returns>null if no child part with that linknum or child part</returns> | 2401 | /// <returns>null if no child part with that linknum or child part</returns> |
2104 | public SceneObjectPart GetLinkNumPart(int linknum) | 2402 | public SceneObjectPart GetLinkNumPart(int linknum) |
2105 | { | 2403 | { |
2106 | lock (m_parts) | 2404 | lockPartsForRead(true); |
2107 | { | 2405 | { |
2108 | foreach (SceneObjectPart part in m_parts.Values) | 2406 | foreach (SceneObjectPart part in m_parts.Values) |
2109 | { | 2407 | { |
2110 | if (part.LinkNum == linknum) | 2408 | if (part.LinkNum == linknum) |
2111 | { | 2409 | { |
2410 | lockPartsForRead(false); | ||
2112 | return part; | 2411 | return part; |
2113 | } | 2412 | } |
2114 | } | 2413 | } |
2115 | } | 2414 | } |
2415 | lockPartsForRead(false); | ||
2116 | 2416 | ||
2117 | return null; | 2417 | return null; |
2118 | } | 2418 | } |
@@ -2140,17 +2440,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2140 | public SceneObjectPart GetChildPart(uint localID) | 2440 | public SceneObjectPart GetChildPart(uint localID) |
2141 | { | 2441 | { |
2142 | //m_log.DebugFormat("Entered looking for {0}", localID); | 2442 | //m_log.DebugFormat("Entered looking for {0}", localID); |
2143 | lock (m_parts) | 2443 | lockPartsForRead(true); |
2144 | { | 2444 | { |
2145 | foreach (SceneObjectPart part in m_parts.Values) | 2445 | foreach (SceneObjectPart part in m_parts.Values) |
2146 | { | 2446 | { |
2147 | //m_log.DebugFormat("Found {0}", part.LocalId); | 2447 | //m_log.DebugFormat("Found {0}", part.LocalId); |
2148 | if (part.LocalId == localID) | 2448 | if (part.LocalId == localID) |
2149 | { | 2449 | { |
2450 | lockPartsForRead(false); | ||
2150 | return part; | 2451 | return part; |
2151 | } | 2452 | } |
2152 | } | 2453 | } |
2153 | } | 2454 | } |
2455 | lockPartsForRead(false); | ||
2154 | 2456 | ||
2155 | return null; | 2457 | return null; |
2156 | } | 2458 | } |
@@ -2180,17 +2482,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2180 | public bool HasChildPrim(uint localID) | 2482 | public bool HasChildPrim(uint localID) |
2181 | { | 2483 | { |
2182 | //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); | 2484 | //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); |
2183 | lock (m_parts) | 2485 | lockPartsForRead(true); |
2184 | { | 2486 | { |
2185 | foreach (SceneObjectPart part in m_parts.Values) | 2487 | foreach (SceneObjectPart part in m_parts.Values) |
2186 | { | 2488 | { |
2187 | //m_log.DebugFormat("Found {0}", part.LocalId); | 2489 | //m_log.DebugFormat("Found {0}", part.LocalId); |
2188 | if (part.LocalId == localID) | 2490 | if (part.LocalId == localID) |
2189 | { | 2491 | { |
2492 | lockPartsForRead(false); | ||
2190 | return true; | 2493 | return true; |
2191 | } | 2494 | } |
2192 | } | 2495 | } |
2193 | } | 2496 | } |
2497 | lockPartsForRead(false); | ||
2194 | 2498 | ||
2195 | return false; | 2499 | return false; |
2196 | } | 2500 | } |
@@ -2240,53 +2544,57 @@ namespace OpenSim.Region.Framework.Scenes | |||
2240 | if (m_rootPart.LinkNum == 0) | 2544 | if (m_rootPart.LinkNum == 0) |
2241 | m_rootPart.LinkNum = 1; | 2545 | m_rootPart.LinkNum = 1; |
2242 | 2546 | ||
2243 | lock (m_parts) | 2547 | lockPartsForWrite(true); |
2244 | { | 2548 | |
2245 | m_parts.Add(linkPart.UUID, linkPart); | 2549 | m_parts.Add(linkPart.UUID, linkPart); |
2246 | 2550 | ||
2247 | // Insert in terms of link numbers, the new links | 2551 | lockPartsForWrite(false); |
2248 | // before the current ones (with the exception of | 2552 | |
2249 | // the root prim. Shuffle the old ones up | 2553 | // Insert in terms of link numbers, the new links |
2250 | foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) | 2554 | // before the current ones (with the exception of |
2555 | // the root prim. Shuffle the old ones up | ||
2556 | lockPartsForRead(true); | ||
2557 | foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) | ||
2558 | { | ||
2559 | if (kvp.Value.LinkNum != 1) | ||
2251 | { | 2560 | { |
2252 | if (kvp.Value.LinkNum != 1) | 2561 | // Don't update root prim link number |
2253 | { | 2562 | kvp.Value.LinkNum += objectGroup.PrimCount; |
2254 | // Don't update root prim link number | ||
2255 | kvp.Value.LinkNum += objectGroup.PrimCount; | ||
2256 | } | ||
2257 | } | 2563 | } |
2564 | } | ||
2565 | lockPartsForRead(false); | ||
2258 | 2566 | ||
2259 | linkPart.LinkNum = 2; | 2567 | linkPart.LinkNum = 2; |
2260 | 2568 | ||
2261 | linkPart.SetParent(this); | 2569 | linkPart.SetParent(this); |
2262 | linkPart.CreateSelected = true; | 2570 | linkPart.CreateSelected = true; |
2263 | 2571 | ||
2264 | //if (linkPart.PhysActor != null) | 2572 | //if (linkPart.PhysActor != null) |
2265 | //{ | 2573 | //{ |
2266 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); | 2574 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); |
2267 | 2575 | ||
2268 | //linkPart.PhysActor = null; | 2576 | //linkPart.PhysActor = null; |
2269 | //} | 2577 | //} |
2270 | 2578 | ||
2271 | //TODO: rest of parts | 2579 | //TODO: rest of parts |
2272 | int linkNum = 3; | 2580 | int linkNum = 3; |
2273 | foreach (SceneObjectPart part in objectGroup.Children.Values) | 2581 | foreach (SceneObjectPart part in objectGroup.Children.Values) |
2582 | { | ||
2583 | if (part.UUID != objectGroup.m_rootPart.UUID) | ||
2274 | { | 2584 | { |
2275 | if (part.UUID != objectGroup.m_rootPart.UUID) | 2585 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); |
2276 | { | ||
2277 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | ||
2278 | } | ||
2279 | part.ClearUndoState(); | ||
2280 | } | 2586 | } |
2587 | part.ClearUndoState(); | ||
2281 | } | 2588 | } |
2282 | 2589 | ||
2283 | m_scene.UnlinkSceneObject(objectGroup.UUID, true); | 2590 | m_scene.UnlinkSceneObject(objectGroup.UUID, true); |
2284 | objectGroup.m_isDeleted = true; | 2591 | objectGroup.m_isDeleted = true; |
2592 | |||
2593 | objectGroup.lockPartsForWrite(true); | ||
2285 | 2594 | ||
2286 | lock (objectGroup.m_parts) | 2595 | objectGroup.m_parts.Clear(); |
2287 | { | 2596 | |
2288 | objectGroup.m_parts.Clear(); | 2597 | objectGroup.lockPartsForWrite(false); |
2289 | } | ||
2290 | 2598 | ||
2291 | // Can't do this yet since backup still makes use of the root part without any synchronization | 2599 | // Can't do this yet since backup still makes use of the root part without any synchronization |
2292 | // objectGroup.m_rootPart = null; | 2600 | // objectGroup.m_rootPart = null; |
@@ -2356,11 +2664,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2356 | Quaternion worldRot = linkPart.GetWorldRotation(); | 2664 | Quaternion worldRot = linkPart.GetWorldRotation(); |
2357 | 2665 | ||
2358 | // Remove the part from this object | 2666 | // Remove the part from this object |
2359 | lock (m_parts) | 2667 | lockPartsForWrite(true); |
2360 | { | 2668 | { |
2361 | m_parts.Remove(linkPart.UUID); | 2669 | m_parts.Remove(linkPart.UUID); |
2362 | } | 2670 | } |
2363 | 2671 | lockPartsForWrite(false); | |
2672 | lockPartsForRead(true); | ||
2364 | if (m_parts.Count == 1 && RootPart != null) //Single prim is left | 2673 | if (m_parts.Count == 1 && RootPart != null) //Single prim is left |
2365 | RootPart.LinkNum = 0; | 2674 | RootPart.LinkNum = 0; |
2366 | else | 2675 | else |
@@ -2371,6 +2680,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2371 | p.LinkNum--; | 2680 | p.LinkNum--; |
2372 | } | 2681 | } |
2373 | } | 2682 | } |
2683 | lockPartsForRead(false); | ||
2374 | 2684 | ||
2375 | linkPart.ParentID = 0; | 2685 | linkPart.ParentID = 0; |
2376 | linkPart.LinkNum = 0; | 2686 | linkPart.LinkNum = 0; |
@@ -2414,6 +2724,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2414 | /// <param name="objectGroup"></param> | 2724 | /// <param name="objectGroup"></param> |
2415 | public virtual void DetachFromBackup() | 2725 | public virtual void DetachFromBackup() |
2416 | { | 2726 | { |
2727 | m_scene.SceneGraph.FireDetachFromBackup(this); | ||
2728 | |||
2417 | if (m_isBackedUp) | 2729 | if (m_isBackedUp) |
2418 | m_scene.EventManager.OnBackup -= ProcessBackup; | 2730 | m_scene.EventManager.OnBackup -= ProcessBackup; |
2419 | 2731 | ||
@@ -2692,9 +3004,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2692 | 3004 | ||
2693 | if (selectionPart != null) | 3005 | if (selectionPart != null) |
2694 | { | 3006 | { |
2695 | lock (m_parts) | 3007 | lockPartsForRead(true); |
3008 | List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values); | ||
3009 | lockPartsForRead(false); | ||
3010 | foreach (SceneObjectPart part in parts) | ||
2696 | { | 3011 | { |
2697 | foreach (SceneObjectPart part in m_parts.Values) | 3012 | if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0) |
2698 | { | 3013 | { |
2699 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || | 3014 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || |
2700 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || | 3015 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || |
@@ -2704,12 +3019,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2704 | break; | 3019 | break; |
2705 | } | 3020 | } |
2706 | } | 3021 | } |
3022 | } | ||
2707 | 3023 | ||
2708 | foreach (SceneObjectPart part in m_parts.Values) | 3024 | foreach (SceneObjectPart part in parts) |
2709 | { | 3025 | { |
2710 | part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 3026 | part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
2711 | } | ||
2712 | } | 3027 | } |
3028 | |||
2713 | } | 3029 | } |
2714 | } | 3030 | } |
2715 | 3031 | ||
@@ -2722,6 +3038,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2722 | } | 3038 | } |
2723 | } | 3039 | } |
2724 | 3040 | ||
3041 | |||
3042 | |||
3043 | /// <summary> | ||
3044 | /// Gets the number of parts | ||
3045 | /// </summary> | ||
3046 | /// <returns></returns> | ||
3047 | public int GetPartCount() | ||
3048 | { | ||
3049 | return Children.Count; | ||
3050 | } | ||
3051 | |||
2725 | /// <summary> | 3052 | /// <summary> |
2726 | /// Get the parts of this scene object | 3053 | /// Get the parts of this scene object |
2727 | /// </summary> | 3054 | /// </summary> |
@@ -2795,11 +3122,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2795 | scale.Y = m_scene.m_maxNonphys; | 3122 | scale.Y = m_scene.m_maxNonphys; |
2796 | if (scale.Z > m_scene.m_maxNonphys) | 3123 | if (scale.Z > m_scene.m_maxNonphys) |
2797 | scale.Z = m_scene.m_maxNonphys; | 3124 | scale.Z = m_scene.m_maxNonphys; |
2798 | |||
2799 | SceneObjectPart part = GetChildPart(localID); | 3125 | SceneObjectPart part = GetChildPart(localID); |
2800 | if (part != null) | 3126 | if (part != null) |
2801 | { | 3127 | { |
2802 | part.Resize(scale); | ||
2803 | if (part.PhysActor != null) | 3128 | if (part.PhysActor != null) |
2804 | { | 3129 | { |
2805 | if (part.PhysActor.IsPhysical) | 3130 | if (part.PhysActor.IsPhysical) |
@@ -2814,7 +3139,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2814 | part.PhysActor.Size = scale; | 3139 | part.PhysActor.Size = scale; |
2815 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); | 3140 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); |
2816 | } | 3141 | } |
2817 | //if (part.UUID != m_rootPart.UUID) | 3142 | part.Resize(scale); |
2818 | 3143 | ||
2819 | HasGroupChanged = true; | 3144 | HasGroupChanged = true; |
2820 | ScheduleGroupForFullUpdate(); | 3145 | ScheduleGroupForFullUpdate(); |
@@ -2836,7 +3161,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2836 | SceneObjectPart part = GetChildPart(localID); | 3161 | SceneObjectPart part = GetChildPart(localID); |
2837 | if (part != null) | 3162 | if (part != null) |
2838 | { | 3163 | { |
2839 | part.IgnoreUndoUpdate = true; | ||
2840 | if (scale.X > m_scene.m_maxNonphys) | 3164 | if (scale.X > m_scene.m_maxNonphys) |
2841 | scale.X = m_scene.m_maxNonphys; | 3165 | scale.X = m_scene.m_maxNonphys; |
2842 | if (scale.Y > m_scene.m_maxNonphys) | 3166 | if (scale.Y > m_scene.m_maxNonphys) |
@@ -2856,94 +3180,100 @@ namespace OpenSim.Region.Framework.Scenes | |||
2856 | float y = (scale.Y / part.Scale.Y); | 3180 | float y = (scale.Y / part.Scale.Y); |
2857 | float z = (scale.Z / part.Scale.Z); | 3181 | float z = (scale.Z / part.Scale.Z); |
2858 | 3182 | ||
2859 | lock (m_parts) | 3183 | lockPartsForRead(true); |
3184 | if (x > 1.0f || y > 1.0f || z > 1.0f) | ||
2860 | { | 3185 | { |
2861 | if (x > 1.0f || y > 1.0f || z > 1.0f) | 3186 | foreach (SceneObjectPart obPart in m_parts.Values) |
2862 | { | 3187 | { |
2863 | foreach (SceneObjectPart obPart in m_parts.Values) | 3188 | if (obPart.UUID != m_rootPart.UUID) |
2864 | { | 3189 | { |
2865 | if (obPart.UUID != m_rootPart.UUID) | 3190 | Vector3 oldSize = new Vector3(obPart.Scale); |
2866 | { | 3191 | obPart.IgnoreUndoUpdate = true; |
2867 | obPart.IgnoreUndoUpdate = true; | ||
2868 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
2869 | 3192 | ||
2870 | float f = 1.0f; | 3193 | float f = 1.0f; |
2871 | float a = 1.0f; | 3194 | float a = 1.0f; |
2872 | 3195 | ||
2873 | if (part.PhysActor != null && part.PhysActor.IsPhysical) | 3196 | if (part.PhysActor != null && part.PhysActor.IsPhysical) |
3197 | { | ||
3198 | if (oldSize.X*x > m_scene.m_maxPhys) | ||
2874 | { | 3199 | { |
2875 | if (oldSize.X*x > m_scene.m_maxPhys) | 3200 | f = m_scene.m_maxPhys / oldSize.X; |
2876 | { | 3201 | a = f / x; |
2877 | f = m_scene.m_maxPhys / oldSize.X; | 3202 | x *= a; |
2878 | a = f / x; | 3203 | y *= a; |
2879 | x *= a; | 3204 | z *= a; |
2880 | y *= a; | ||
2881 | z *= a; | ||
2882 | } | ||
2883 | if (oldSize.Y*y > m_scene.m_maxPhys) | ||
2884 | { | ||
2885 | f = m_scene.m_maxPhys / oldSize.Y; | ||
2886 | a = f / y; | ||
2887 | x *= a; | ||
2888 | y *= a; | ||
2889 | z *= a; | ||
2890 | } | ||
2891 | if (oldSize.Z*z > m_scene.m_maxPhys) | ||
2892 | { | ||
2893 | f = m_scene.m_maxPhys / oldSize.Z; | ||
2894 | a = f / z; | ||
2895 | x *= a; | ||
2896 | y *= a; | ||
2897 | z *= a; | ||
2898 | } | ||
2899 | } | 3205 | } |
2900 | else | 3206 | if (oldSize.Y*y > m_scene.m_maxPhys) |
3207 | { | ||
3208 | f = m_scene.m_maxPhys / oldSize.Y; | ||
3209 | a = f / y; | ||
3210 | x *= a; | ||
3211 | y *= a; | ||
3212 | z *= a; | ||
3213 | } | ||
3214 | if (oldSize.Z*z > m_scene.m_maxPhys) | ||
3215 | { | ||
3216 | f = m_scene.m_maxPhys / oldSize.Z; | ||
3217 | a = f / z; | ||
3218 | x *= a; | ||
3219 | y *= a; | ||
3220 | z *= a; | ||
3221 | } | ||
3222 | } | ||
3223 | else | ||
3224 | { | ||
3225 | if (oldSize.X*x > m_scene.m_maxNonphys) | ||
3226 | { | ||
3227 | f = m_scene.m_maxNonphys / oldSize.X; | ||
3228 | a = f / x; | ||
3229 | x *= a; | ||
3230 | y *= a; | ||
3231 | z *= a; | ||
3232 | } | ||
3233 | if (oldSize.Y*y > m_scene.m_maxNonphys) | ||
3234 | { | ||
3235 | f = m_scene.m_maxNonphys / oldSize.Y; | ||
3236 | a = f / y; | ||
3237 | x *= a; | ||
3238 | y *= a; | ||
3239 | z *= a; | ||
3240 | } | ||
3241 | if (oldSize.Z*z > m_scene.m_maxNonphys) | ||
2901 | { | 3242 | { |
2902 | if (oldSize.X*x > m_scene.m_maxNonphys) | 3243 | f = m_scene.m_maxNonphys / oldSize.Z; |
2903 | { | 3244 | a = f / z; |
2904 | f = m_scene.m_maxNonphys / oldSize.X; | 3245 | x *= a; |
2905 | a = f / x; | 3246 | y *= a; |
2906 | x *= a; | 3247 | z *= a; |
2907 | y *= a; | ||
2908 | z *= a; | ||
2909 | } | ||
2910 | if (oldSize.Y*y > m_scene.m_maxNonphys) | ||
2911 | { | ||
2912 | f = m_scene.m_maxNonphys / oldSize.Y; | ||
2913 | a = f / y; | ||
2914 | x *= a; | ||
2915 | y *= a; | ||
2916 | z *= a; | ||
2917 | } | ||
2918 | if (oldSize.Z*z > m_scene.m_maxNonphys) | ||
2919 | { | ||
2920 | f = m_scene.m_maxNonphys / oldSize.Z; | ||
2921 | a = f / z; | ||
2922 | x *= a; | ||
2923 | y *= a; | ||
2924 | z *= a; | ||
2925 | } | ||
2926 | } | 3248 | } |
2927 | obPart.IgnoreUndoUpdate = false; | 3249 | |
2928 | obPart.StoreUndoState(); | ||
2929 | } | 3250 | } |
2930 | } | 3251 | } |
2931 | } | 3252 | } |
2932 | } | 3253 | } |
3254 | lockPartsForRead(false); | ||
2933 | 3255 | ||
2934 | Vector3 prevScale = part.Scale; | 3256 | Vector3 prevScale = part.Scale; |
2935 | prevScale.X *= x; | 3257 | prevScale.X *= x; |
2936 | prevScale.Y *= y; | 3258 | prevScale.Y *= y; |
2937 | prevScale.Z *= z; | 3259 | prevScale.Z *= z;; |
3260 | |||
3261 | part.IgnoreUndoUpdate = false; | ||
3262 | part.StoreUndoState(UndoType.STATE_GROUP_SCALE); | ||
3263 | part.IgnoreUndoUpdate = true; | ||
2938 | part.Resize(prevScale); | 3264 | part.Resize(prevScale); |
3265 | part.IgnoreUndoUpdate = false; | ||
2939 | 3266 | ||
2940 | lock (m_parts) | 3267 | lockPartsForRead(true); |
2941 | { | 3268 | { |
2942 | foreach (SceneObjectPart obPart in m_parts.Values) | 3269 | foreach (SceneObjectPart obPart in m_parts.Values) |
2943 | { | 3270 | { |
2944 | obPart.IgnoreUndoUpdate = true; | ||
2945 | if (obPart.UUID != m_rootPart.UUID) | 3271 | if (obPart.UUID != m_rootPart.UUID) |
2946 | { | 3272 | { |
3273 | obPart.IgnoreUndoUpdate = false; | ||
3274 | obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE); | ||
3275 | obPart.IgnoreUndoUpdate = true; | ||
3276 | |||
2947 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); | 3277 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); |
2948 | currentpos.X *= x; | 3278 | currentpos.X *= x; |
2949 | currentpos.Y *= y; | 3279 | currentpos.Y *= y; |
@@ -2956,9 +3286,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2956 | obPart.UpdateOffSet(currentpos); | 3286 | obPart.UpdateOffSet(currentpos); |
2957 | } | 3287 | } |
2958 | obPart.IgnoreUndoUpdate = false; | 3288 | obPart.IgnoreUndoUpdate = false; |
2959 | obPart.StoreUndoState(); | ||
2960 | } | 3289 | } |
2961 | } | 3290 | } |
3291 | lockPartsForRead(false); | ||
2962 | 3292 | ||
2963 | if (part.PhysActor != null) | 3293 | if (part.PhysActor != null) |
2964 | { | 3294 | { |
@@ -2967,7 +3297,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2967 | } | 3297 | } |
2968 | 3298 | ||
2969 | part.IgnoreUndoUpdate = false; | 3299 | part.IgnoreUndoUpdate = false; |
2970 | part.StoreUndoState(); | ||
2971 | HasGroupChanged = true; | 3300 | HasGroupChanged = true; |
2972 | ScheduleGroupForTerseUpdate(); | 3301 | ScheduleGroupForTerseUpdate(); |
2973 | } | 3302 | } |
@@ -2983,14 +3312,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2983 | /// <param name="pos"></param> | 3312 | /// <param name="pos"></param> |
2984 | public void UpdateGroupPosition(Vector3 pos) | 3313 | public void UpdateGroupPosition(Vector3 pos) |
2985 | { | 3314 | { |
2986 | foreach (SceneObjectPart part in Children.Values) | ||
2987 | { | ||
2988 | part.StoreUndoState(); | ||
2989 | } | ||
2990 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) | 3315 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) |
2991 | { | 3316 | { |
2992 | if (IsAttachment) | 3317 | if (IsAttachment) |
2993 | { | 3318 | { |
3319 | m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION); | ||
2994 | m_rootPart.AttachedPos = pos; | 3320 | m_rootPart.AttachedPos = pos; |
2995 | } | 3321 | } |
2996 | if (RootPart.GetStatusSandbox()) | 3322 | if (RootPart.GetStatusSandbox()) |
@@ -3023,7 +3349,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3023 | SceneObjectPart part = GetChildPart(localID); | 3349 | SceneObjectPart part = GetChildPart(localID); |
3024 | foreach (SceneObjectPart parts in Children.Values) | 3350 | foreach (SceneObjectPart parts in Children.Values) |
3025 | { | 3351 | { |
3026 | parts.StoreUndoState(); | 3352 | parts.StoreUndoState(UndoType.STATE_PRIM_POSITION); |
3027 | } | 3353 | } |
3028 | if (part != null) | 3354 | if (part != null) |
3029 | { | 3355 | { |
@@ -3048,7 +3374,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3048 | { | 3374 | { |
3049 | foreach (SceneObjectPart part in Children.Values) | 3375 | foreach (SceneObjectPart part in Children.Values) |
3050 | { | 3376 | { |
3051 | part.StoreUndoState(); | 3377 | part.StoreUndoState(UndoType.STATE_PRIM_POSITION); |
3052 | } | 3378 | } |
3053 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | 3379 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); |
3054 | Vector3 oldPos = | 3380 | Vector3 oldPos = |
@@ -3061,7 +3387,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3061 | axDiff *= Quaternion.Inverse(partRotation); | 3387 | axDiff *= Quaternion.Inverse(partRotation); |
3062 | diff = axDiff; | 3388 | diff = axDiff; |
3063 | 3389 | ||
3064 | lock (m_parts) | 3390 | lockPartsForRead(true); |
3065 | { | 3391 | { |
3066 | foreach (SceneObjectPart obPart in m_parts.Values) | 3392 | foreach (SceneObjectPart obPart in m_parts.Values) |
3067 | { | 3393 | { |
@@ -3071,11 +3397,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
3071 | } | 3397 | } |
3072 | } | 3398 | } |
3073 | } | 3399 | } |
3400 | lockPartsForRead(false); | ||
3074 | 3401 | ||
3075 | AbsolutePosition = newPos; | 3402 | //We have to set undoing here because otherwise an undo state will be saved |
3403 | if (!m_rootPart.Undoing) | ||
3404 | { | ||
3405 | m_rootPart.Undoing = true; | ||
3406 | AbsolutePosition = newPos; | ||
3407 | m_rootPart.Undoing = false; | ||
3408 | } | ||
3409 | else | ||
3410 | { | ||
3411 | AbsolutePosition = newPos; | ||
3412 | } | ||
3076 | 3413 | ||
3077 | HasGroupChanged = true; | 3414 | HasGroupChanged = true; |
3078 | ScheduleGroupForTerseUpdate(); | 3415 | if (m_rootPart.Undoing) |
3416 | { | ||
3417 | ScheduleGroupForFullUpdate(); | ||
3418 | } | ||
3419 | else | ||
3420 | { | ||
3421 | ScheduleGroupForTerseUpdate(); | ||
3422 | } | ||
3079 | } | 3423 | } |
3080 | 3424 | ||
3081 | public void OffsetForNewRegion(Vector3 offset) | 3425 | public void OffsetForNewRegion(Vector3 offset) |
@@ -3095,7 +3439,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3095 | { | 3439 | { |
3096 | foreach (SceneObjectPart parts in Children.Values) | 3440 | foreach (SceneObjectPart parts in Children.Values) |
3097 | { | 3441 | { |
3098 | parts.StoreUndoState(); | 3442 | parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
3099 | } | 3443 | } |
3100 | m_rootPart.UpdateRotation(rot); | 3444 | m_rootPart.UpdateRotation(rot); |
3101 | 3445 | ||
@@ -3119,7 +3463,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3119 | { | 3463 | { |
3120 | foreach (SceneObjectPart parts in Children.Values) | 3464 | foreach (SceneObjectPart parts in Children.Values) |
3121 | { | 3465 | { |
3122 | parts.StoreUndoState(); | 3466 | parts.StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
3123 | } | 3467 | } |
3124 | m_rootPart.UpdateRotation(rot); | 3468 | m_rootPart.UpdateRotation(rot); |
3125 | 3469 | ||
@@ -3146,7 +3490,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3146 | SceneObjectPart part = GetChildPart(localID); | 3490 | SceneObjectPart part = GetChildPart(localID); |
3147 | foreach (SceneObjectPart parts in Children.Values) | 3491 | foreach (SceneObjectPart parts in Children.Values) |
3148 | { | 3492 | { |
3149 | parts.StoreUndoState(); | 3493 | parts.StoreUndoState(UndoType.STATE_PRIM_ROTATION); |
3150 | } | 3494 | } |
3151 | if (part != null) | 3495 | if (part != null) |
3152 | { | 3496 | { |
@@ -3174,15 +3518,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
3174 | if (part.UUID == m_rootPart.UUID) | 3518 | if (part.UUID == m_rootPart.UUID) |
3175 | { | 3519 | { |
3176 | UpdateRootRotation(rot); | 3520 | UpdateRootRotation(rot); |
3177 | AbsolutePosition = pos; | 3521 | if (!m_rootPart.Undoing) |
3522 | { | ||
3523 | m_rootPart.Undoing = true; | ||
3524 | AbsolutePosition = pos; | ||
3525 | m_rootPart.Undoing = false; | ||
3526 | } | ||
3527 | else | ||
3528 | { | ||
3529 | AbsolutePosition = pos; | ||
3530 | } | ||
3178 | } | 3531 | } |
3179 | else | 3532 | else |
3180 | { | 3533 | { |
3534 | part.StoreUndoState(UndoType.STATE_PRIM_ROTATION); | ||
3181 | part.IgnoreUndoUpdate = true; | 3535 | part.IgnoreUndoUpdate = true; |
3182 | part.UpdateRotation(rot); | 3536 | part.UpdateRotation(rot); |
3183 | part.OffsetPosition = pos; | 3537 | part.OffsetPosition = pos; |
3184 | part.IgnoreUndoUpdate = false; | 3538 | part.IgnoreUndoUpdate = false; |
3185 | part.StoreUndoState(); | ||
3186 | } | 3539 | } |
3187 | } | 3540 | } |
3188 | } | 3541 | } |
@@ -3196,7 +3549,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3196 | Quaternion axRot = rot; | 3549 | Quaternion axRot = rot; |
3197 | Quaternion oldParentRot = m_rootPart.RotationOffset; | 3550 | Quaternion oldParentRot = m_rootPart.RotationOffset; |
3198 | 3551 | ||
3199 | m_rootPart.StoreUndoState(); | 3552 | m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION); |
3553 | bool cancelUndo = false; | ||
3554 | if (!m_rootPart.Undoing) | ||
3555 | { | ||
3556 | m_rootPart.Undoing = true; | ||
3557 | cancelUndo = true; | ||
3558 | } | ||
3200 | m_rootPart.UpdateRotation(rot); | 3559 | m_rootPart.UpdateRotation(rot); |
3201 | if (m_rootPart.PhysActor != null) | 3560 | if (m_rootPart.PhysActor != null) |
3202 | { | 3561 | { |
@@ -3204,33 +3563,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
3204 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | 3563 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); |
3205 | } | 3564 | } |
3206 | 3565 | ||
3207 | lock (m_parts) | 3566 | lockPartsForRead(true); |
3567 | |||
3568 | foreach (SceneObjectPart prim in m_parts.Values) | ||
3208 | { | 3569 | { |
3209 | foreach (SceneObjectPart prim in m_parts.Values) | 3570 | if (prim.UUID != m_rootPart.UUID) |
3210 | { | 3571 | { |
3211 | if (prim.UUID != m_rootPart.UUID) | 3572 | prim.IgnoreUndoUpdate = true; |
3212 | { | 3573 | Vector3 axPos = prim.OffsetPosition; |
3213 | prim.IgnoreUndoUpdate = true; | 3574 | axPos *= oldParentRot; |
3214 | Vector3 axPos = prim.OffsetPosition; | 3575 | axPos *= Quaternion.Inverse(axRot); |
3215 | axPos *= oldParentRot; | 3576 | prim.OffsetPosition = axPos; |
3216 | axPos *= Quaternion.Inverse(axRot); | 3577 | Quaternion primsRot = prim.RotationOffset; |
3217 | prim.OffsetPosition = axPos; | 3578 | Quaternion newRot = primsRot * oldParentRot; |
3218 | Quaternion primsRot = prim.RotationOffset; | 3579 | newRot *= Quaternion.Inverse(axRot); |
3219 | Quaternion newRot = primsRot * oldParentRot; | 3580 | prim.RotationOffset = newRot; |
3220 | newRot *= Quaternion.Inverse(axRot); | 3581 | prim.ScheduleTerseUpdate(); |
3221 | prim.RotationOffset = newRot; | 3582 | prim.IgnoreUndoUpdate = false; |
3222 | prim.ScheduleTerseUpdate(); | ||
3223 | } | ||
3224 | } | 3583 | } |
3225 | } | 3584 | } |
3226 | foreach (SceneObjectPart childpart in Children.Values) | 3585 | if (cancelUndo == true) |
3227 | { | 3586 | { |
3228 | if (childpart != m_rootPart) | 3587 | m_rootPart.Undoing = false; |
3229 | { | ||
3230 | childpart.IgnoreUndoUpdate = false; | ||
3231 | childpart.StoreUndoState(); | ||
3232 | } | ||
3233 | } | 3588 | } |
3589 | lockPartsForRead(false); | ||
3590 | |||
3234 | m_rootPart.ScheduleTerseUpdate(); | 3591 | m_rootPart.ScheduleTerseUpdate(); |
3235 | } | 3592 | } |
3236 | 3593 | ||
@@ -3352,7 +3709,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3352 | if (atTargets.Count > 0) | 3709 | if (atTargets.Count > 0) |
3353 | { | 3710 | { |
3354 | uint[] localids = new uint[0]; | 3711 | uint[] localids = new uint[0]; |
3355 | lock (m_parts) | 3712 | lockPartsForRead(true); |
3356 | { | 3713 | { |
3357 | localids = new uint[m_parts.Count]; | 3714 | localids = new uint[m_parts.Count]; |
3358 | int cntr = 0; | 3715 | int cntr = 0; |
@@ -3362,6 +3719,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3362 | cntr++; | 3719 | cntr++; |
3363 | } | 3720 | } |
3364 | } | 3721 | } |
3722 | lockPartsForRead(false); | ||
3365 | 3723 | ||
3366 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3724 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3367 | { | 3725 | { |
@@ -3380,7 +3738,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3380 | { | 3738 | { |
3381 | //trigger not_at_target | 3739 | //trigger not_at_target |
3382 | uint[] localids = new uint[0]; | 3740 | uint[] localids = new uint[0]; |
3383 | lock (m_parts) | 3741 | lockPartsForRead(true); |
3384 | { | 3742 | { |
3385 | localids = new uint[m_parts.Count]; | 3743 | localids = new uint[m_parts.Count]; |
3386 | int cntr = 0; | 3744 | int cntr = 0; |
@@ -3390,7 +3748,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3390 | cntr++; | 3748 | cntr++; |
3391 | } | 3749 | } |
3392 | } | 3750 | } |
3393 | 3751 | lockPartsForRead(false); | |
3752 | |||
3394 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3753 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3395 | { | 3754 | { |
3396 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); | 3755 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); |
@@ -3431,7 +3790,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3431 | if (atRotTargets.Count > 0) | 3790 | if (atRotTargets.Count > 0) |
3432 | { | 3791 | { |
3433 | uint[] localids = new uint[0]; | 3792 | uint[] localids = new uint[0]; |
3434 | lock (m_parts) | 3793 | lockPartsForRead(true); |
3794 | try | ||
3435 | { | 3795 | { |
3436 | localids = new uint[m_parts.Count]; | 3796 | localids = new uint[m_parts.Count]; |
3437 | int cntr = 0; | 3797 | int cntr = 0; |
@@ -3441,6 +3801,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3441 | cntr++; | 3801 | cntr++; |
3442 | } | 3802 | } |
3443 | } | 3803 | } |
3804 | finally | ||
3805 | { | ||
3806 | lockPartsForRead(false); | ||
3807 | } | ||
3444 | 3808 | ||
3445 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3809 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3446 | { | 3810 | { |
@@ -3459,7 +3823,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3459 | { | 3823 | { |
3460 | //trigger not_at_target | 3824 | //trigger not_at_target |
3461 | uint[] localids = new uint[0]; | 3825 | uint[] localids = new uint[0]; |
3462 | lock (m_parts) | 3826 | lockPartsForRead(true); |
3827 | try | ||
3463 | { | 3828 | { |
3464 | localids = new uint[m_parts.Count]; | 3829 | localids = new uint[m_parts.Count]; |
3465 | int cntr = 0; | 3830 | int cntr = 0; |
@@ -3469,6 +3834,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3469 | cntr++; | 3834 | cntr++; |
3470 | } | 3835 | } |
3471 | } | 3836 | } |
3837 | finally | ||
3838 | { | ||
3839 | lockPartsForRead(false); | ||
3840 | } | ||
3472 | 3841 | ||
3473 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3842 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3474 | { | 3843 | { |
@@ -3482,19 +3851,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
3482 | public float GetMass() | 3851 | public float GetMass() |
3483 | { | 3852 | { |
3484 | float retmass = 0f; | 3853 | float retmass = 0f; |
3485 | lock (m_parts) | 3854 | lockPartsForRead(true); |
3486 | { | 3855 | { |
3487 | foreach (SceneObjectPart part in m_parts.Values) | 3856 | foreach (SceneObjectPart part in m_parts.Values) |
3488 | { | 3857 | { |
3489 | retmass += part.GetMass(); | 3858 | retmass += part.GetMass(); |
3490 | } | 3859 | } |
3491 | } | 3860 | } |
3861 | lockPartsForRead(false); | ||
3492 | return retmass; | 3862 | return retmass; |
3493 | } | 3863 | } |
3494 | 3864 | ||
3495 | public void CheckSculptAndLoad() | 3865 | public void CheckSculptAndLoad() |
3496 | { | 3866 | { |
3497 | lock (m_parts) | 3867 | lockPartsForRead(true); |
3498 | { | 3868 | { |
3499 | if (!IsDeleted) | 3869 | if (!IsDeleted) |
3500 | { | 3870 | { |
@@ -3519,6 +3889,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3519 | } | 3889 | } |
3520 | } | 3890 | } |
3521 | } | 3891 | } |
3892 | lockPartsForRead(false); | ||
3522 | } | 3893 | } |
3523 | 3894 | ||
3524 | protected void AssetReceived(string id, Object sender, AssetBase asset) | 3895 | protected void AssetReceived(string id, Object sender, AssetBase asset) |
@@ -3539,7 +3910,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3539 | /// <param name="client"></param> | 3910 | /// <param name="client"></param> |
3540 | public void SetGroup(UUID GroupID, IClientAPI client) | 3911 | public void SetGroup(UUID GroupID, IClientAPI client) |
3541 | { | 3912 | { |
3542 | lock (m_parts) | 3913 | lockPartsForRead(true); |
3543 | { | 3914 | { |
3544 | foreach (SceneObjectPart part in m_parts.Values) | 3915 | foreach (SceneObjectPart part in m_parts.Values) |
3545 | { | 3916 | { |
@@ -3549,6 +3920,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3549 | 3920 | ||
3550 | HasGroupChanged = true; | 3921 | HasGroupChanged = true; |
3551 | } | 3922 | } |
3923 | lockPartsForRead(false); | ||
3552 | 3924 | ||
3553 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled | 3925 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled |
3554 | // for the same object with very different properties. The caller must schedule the update. | 3926 | // for the same object with very different properties. The caller must schedule the update. |
@@ -3570,11 +3942,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3570 | 3942 | ||
3571 | public void SetAttachmentPoint(byte point) | 3943 | public void SetAttachmentPoint(byte point) |
3572 | { | 3944 | { |
3573 | lock (m_parts) | 3945 | lockPartsForRead(true); |
3574 | { | 3946 | { |
3575 | foreach (SceneObjectPart part in m_parts.Values) | 3947 | foreach (SceneObjectPart part in m_parts.Values) |
3576 | part.SetAttachmentPoint(point); | 3948 | part.SetAttachmentPoint(point); |
3577 | } | 3949 | } |
3950 | lockPartsForRead(false); | ||
3578 | } | 3951 | } |
3579 | 3952 | ||
3580 | #region ISceneObject | 3953 | #region ISceneObject |
@@ -3608,6 +3981,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3608 | SetFromItemID(uuid); | 3981 | SetFromItemID(uuid); |
3609 | } | 3982 | } |
3610 | 3983 | ||
3984 | public void ResetOwnerChangeFlag() | ||
3985 | { | ||
3986 | ForEachPart(delegate(SceneObjectPart part) | ||
3987 | { | ||
3988 | part.ResetOwnerChangeFlag(); | ||
3989 | }); | ||
3990 | } | ||
3991 | |||
3611 | #endregion | 3992 | #endregion |
3612 | } | 3993 | } |
3613 | } | 3994 | } |