aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework
diff options
context:
space:
mode:
authorDan Lake2011-11-02 14:59:00 -0700
committerDan Lake2011-11-02 14:59:00 -0700
commite2c51a977d42822fe78ae0744117afb7bf509d35 (patch)
treebf145756d32fec7dc295510269447f458ccaf1ea /OpenSim/Region/Framework
parentRemoved redundant SceneContents property from Scene. It's the same as SceneGr... (diff)
downloadopensim-SC-e2c51a977d42822fe78ae0744117afb7bf509d35.zip
opensim-SC-e2c51a977d42822fe78ae0744117afb7bf509d35.tar.gz
opensim-SC-e2c51a977d42822fe78ae0744117afb7bf509d35.tar.bz2
opensim-SC-e2c51a977d42822fe78ae0744117afb7bf509d35.tar.xz
Changes UpdateFlag in SOP to an enumeration of NONE, TERSE and FULL.
UpdateFlag is now referenced/used only within SOP and SOG. Outsiders are using ScheduleFullUpdate, ScheduleTerseUpdate or ClearUpdateSchedule on SOP consistently now. Also started working toward eliminating those calls to ScheduleFullUpdate, ScheduleTerseUpdate or ClearUpdateSchedule from outside SOP in favor of just setting properties on SOP and let SOP decide if an update should be scheduled. This consolidates the update policy within SOP and the client rather than everywhere that makes changes to SOP. Some places forget to call update while others call it multiple times, "just to be sure". UpdateFlag and Schedule*Update will both be made private shortly. UpdateFlag is intended to be transient and internal to SOP so it has been removed from XML serializer for SOPs.
Diffstat (limited to 'OpenSim/Region/Framework')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs101
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs16
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs6
7 files changed, 66 insertions, 74 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 1af18e7..82ded28 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -1799,7 +1799,7 @@ namespace OpenSim.Region.Framework.Scenes
1799 newSet.RemoveAt(0); 1799 newSet.RemoveAt(0);
1800 1800
1801 foreach (SceneObjectPart newChild in newSet) 1801 foreach (SceneObjectPart newChild in newSet)
1802 newChild.UpdateFlag = 0; 1802 newChild.ClearUpdateSchedule();
1803 1803
1804 LinkObjects(newRoot, newSet); 1804 LinkObjects(newRoot, newSet);
1805 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1805 if (!affectedGroups.Contains(newRoot.ParentGroup))
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 2ea9854..a0a7344 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1157,7 +1157,7 @@ namespace OpenSim.Region.Framework.Scenes
1157 1157
1158 if (!silent) 1158 if (!silent)
1159 { 1159 {
1160 part.UpdateFlag = 0; 1160 part.ClearUpdateSchedule();
1161 if (part == m_rootPart) 1161 if (part == m_rootPart)
1162 { 1162 {
1163 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || 1163 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) ||
@@ -1735,13 +1735,13 @@ namespace OpenSim.Region.Framework.Scenes
1735 1735
1736 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) 1736 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
1737 { 1737 {
1738 m_rootPart.UpdateFlag = 1; 1738 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1739 lastPhysGroupPos = AbsolutePosition; 1739 lastPhysGroupPos = AbsolutePosition;
1740 } 1740 }
1741 1741
1742 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f)) 1742 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
1743 { 1743 {
1744 m_rootPart.UpdateFlag = 1; 1744 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
1745 lastPhysGroupRot = GroupRotation; 1745 lastPhysGroupRot = GroupRotation;
1746 } 1746 }
1747 1747
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index b68cc9f..44f822c 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -106,6 +106,13 @@ namespace OpenSim.Region.Framework.Scenes
106 SCULPT = 7 106 SCULPT = 7
107 } 107 }
108 108
109 public enum UpdateRequired : byte
110 {
111 NONE = 0,
112 TERSE = 1,
113 FULL = 2
114 }
115
109 #endregion Enumerations 116 #endregion Enumerations
110 117
111 public class SceneObjectPart : IScriptHost, ISceneEntity 118 public class SceneObjectPart : IScriptHost, ISceneEntity
@@ -254,15 +261,7 @@ namespace OpenSim.Region.Framework.Scenes
254 261
255 private bool m_passTouches; 262 private bool m_passTouches;
256 263
257 /// <summary> 264 private UpdateRequired m_updateFlag;
258 /// Only used internally to schedule client updates.
259 /// 0 - no update is scheduled
260 /// 1 - terse update scheduled
261 /// 2 - full update scheduled
262 ///
263 /// TODO - This should be an enumeration
264 /// </summary>
265 private byte m_updateFlag;
266 265
267 private PhysicsActor m_physActor; 266 private PhysicsActor m_physActor;
268 protected Vector3 m_acceleration; 267 protected Vector3 m_acceleration;
@@ -884,7 +883,15 @@ namespace OpenSim.Region.Framework.Scenes
884 } 883 }
885 } 884 }
886 885
887 /// <summary></summary> 886 /// <summary>Update angular velocity and schedule terse update.</summary>
887 public void UpdateAngularVelocity(Vector3 avel)
888 {
889 AngularVelocity = avel;
890 ScheduleTerseUpdate();
891 ParentGroup.HasGroupChanged = true;
892 }
893
894 /// <summary>Get or set angular velocity. Does not schedule update.</summary>
888 public Vector3 AngularVelocity 895 public Vector3 AngularVelocity
889 { 896 {
890 get 897 get
@@ -1023,8 +1030,8 @@ namespace OpenSim.Region.Framework.Scenes
1023 TriggerScriptChangedEvent(Changed.SCALE); 1030 TriggerScriptChangedEvent(Changed.SCALE);
1024 } 1031 }
1025 } 1032 }
1026 1033
1027 public byte UpdateFlag 1034 public UpdateRequired UpdateFlag
1028 { 1035 {
1029 get { return m_updateFlag; } 1036 get { return m_updateFlag; }
1030 set { m_updateFlag = value; } 1037 set { m_updateFlag = value; }
@@ -1309,9 +1316,9 @@ namespace OpenSim.Region.Framework.Scenes
1309 /// <summary> 1316 /// <summary>
1310 /// Clear all pending updates of parts to clients 1317 /// Clear all pending updates of parts to clients
1311 /// </summary> 1318 /// </summary>
1312 private void ClearUpdateSchedule() 1319 public void ClearUpdateSchedule()
1313 { 1320 {
1314 m_updateFlag = 0; 1321 UpdateFlag = UpdateRequired.NONE;
1315 } 1322 }
1316 1323
1317 /// <summary> 1324 /// <summary>
@@ -2829,7 +2836,7 @@ namespace OpenSim.Region.Framework.Scenes
2829 TimeStampFull = (uint)timeNow; 2836 TimeStampFull = (uint)timeNow;
2830 } 2837 }
2831 2838
2832 m_updateFlag = 2; 2839 UpdateFlag = UpdateRequired.FULL;
2833 2840
2834 // m_log.DebugFormat( 2841 // m_log.DebugFormat(
2835 // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", 2842 // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}",
@@ -2845,13 +2852,13 @@ namespace OpenSim.Region.Framework.Scenes
2845 if (m_parentGroup == null) 2852 if (m_parentGroup == null)
2846 return; 2853 return;
2847 2854
2848 if (m_updateFlag < 1) 2855 if (UpdateFlag == UpdateRequired.NONE)
2849 { 2856 {
2850 m_parentGroup.HasGroupChanged = true; 2857 m_parentGroup.HasGroupChanged = true;
2851 m_parentGroup.QueueForUpdateCheck(); 2858 m_parentGroup.QueueForUpdateCheck();
2852 2859
2853 TimeStampTerse = (uint) Util.UnixTimeSinceEpoch(); 2860 TimeStampTerse = (uint) Util.UnixTimeSinceEpoch();
2854 m_updateFlag = 1; 2861 UpdateFlag = UpdateRequired.TERSE;
2855 2862
2856 // m_log.DebugFormat( 2863 // m_log.DebugFormat(
2857 // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}", 2864 // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}",
@@ -3018,45 +3025,39 @@ namespace OpenSim.Region.Framework.Scenes
3018 const float POSITION_TOLERANCE = 0.05f; 3025 const float POSITION_TOLERANCE = 0.05f;
3019 const int TIME_MS_TOLERANCE = 3000; 3026 const int TIME_MS_TOLERANCE = 3000;
3020 3027
3021 if (m_updateFlag == 1) 3028 switch (UpdateFlag)
3022 { 3029 {
3023 // Throw away duplicate or insignificant updates 3030 case UpdateRequired.TERSE:
3024 if (!RotationOffset.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) ||
3025 !Acceleration.Equals(m_lastAcceleration) ||
3026 !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) ||
3027 Velocity.ApproxEquals(Vector3.Zero, VELOCITY_TOLERANCE) ||
3028 !AngularVelocity.ApproxEquals(m_lastAngularVelocity, VELOCITY_TOLERANCE) ||
3029 !OffsetPosition.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
3030 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE)
3031 { 3031 {
3032 AddTerseUpdateToAllAvatars(); 3032 // Throw away duplicate or insignificant updates
3033 ClearUpdateSchedule(); 3033 if (!RotationOffset.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) ||
3034 3034 !Acceleration.Equals(m_lastAcceleration) ||
3035 // This causes the Scene to 'poll' physical objects every couple of frames 3035 !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) ||
3036 // bad, so it's been replaced by an event driven method. 3036 Velocity.ApproxEquals(Vector3.Zero, VELOCITY_TOLERANCE) ||
3037 //if ((ObjectFlags & (uint)PrimFlags.Physics) != 0) 3037 !AngularVelocity.ApproxEquals(m_lastAngularVelocity, VELOCITY_TOLERANCE) ||
3038 //{ 3038 !OffsetPosition.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
3039 // Only send the constant terse updates on physical objects! 3039 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE)
3040 //ScheduleTerseUpdate(); 3040 {
3041 //} 3041 AddTerseUpdateToAllAvatars();
3042 3042 ClearUpdateSchedule();
3043 // Update the "last" values 3043
3044 m_lastPosition = OffsetPosition; 3044 // Update the "last" values
3045 m_lastRotation = RotationOffset; 3045 m_lastPosition = OffsetPosition;
3046 m_lastVelocity = Velocity; 3046 m_lastRotation = RotationOffset;
3047 m_lastAcceleration = Acceleration; 3047 m_lastVelocity = Velocity;
3048 m_lastAngularVelocity = AngularVelocity; 3048 m_lastAcceleration = Acceleration;
3049 m_lastTerseSent = Environment.TickCount; 3049 m_lastAngularVelocity = AngularVelocity;
3050 m_lastTerseSent = Environment.TickCount;
3051 }
3052 break;
3050 } 3053 }
3051 } 3054 case UpdateRequired.FULL:
3052 else
3053 {
3054 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes
3055 { 3055 {
3056 AddFullUpdateToAllAvatars(); 3056 AddFullUpdateToAllAvatars();
3057 ClearUpdateSchedule(); 3057 break;
3058 } 3058 }
3059 } 3059 }
3060
3060 ClearUpdateSchedule(); 3061 ClearUpdateSchedule();
3061 } 3062 }
3062 3063
@@ -3436,7 +3437,7 @@ namespace OpenSim.Region.Framework.Scenes
3436 _groupID = groupID; 3437 _groupID = groupID;
3437 if (client != null) 3438 if (client != null)
3438 SendPropertiesToClient(client); 3439 SendPropertiesToClient(client);
3439 m_updateFlag = 2; 3440 UpdateFlag = UpdateRequired.FULL;
3440 } 3441 }
3441 3442
3442 /// <summary> 3443 /// <summary>
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 29966f9..71c39b2 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -3211,7 +3211,7 @@ namespace OpenSim.Region.Framework.Scenes
3211 foreach (ISceneObject so in cAgent.AttachmentObjects) 3211 foreach (ISceneObject so in cAgent.AttachmentObjects)
3212 { 3212 {
3213 ((SceneObjectGroup)so).LocalId = 0; 3213 ((SceneObjectGroup)so).LocalId = 0;
3214 ((SceneObjectGroup)so).RootPart.UpdateFlag = 0; 3214 ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule();
3215 so.SetState(cAgent.AttachmentObjectStates[i++], m_scene); 3215 so.SetState(cAgent.AttachmentObjectStates[i++], m_scene);
3216 m_scene.IncomingCreateObject(so); 3216 m_scene.IncomingCreateObject(so);
3217 } 3217 }
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index e06a222..60cc788 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -316,7 +316,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
316 m_SOPXmlProcessors.Add("ClickAction", ProcessClickAction); 316 m_SOPXmlProcessors.Add("ClickAction", ProcessClickAction);
317 m_SOPXmlProcessors.Add("Shape", ProcessShape); 317 m_SOPXmlProcessors.Add("Shape", ProcessShape);
318 m_SOPXmlProcessors.Add("Scale", ProcessScale); 318 m_SOPXmlProcessors.Add("Scale", ProcessScale);
319 m_SOPXmlProcessors.Add("UpdateFlag", ProcessUpdateFlag);
320 m_SOPXmlProcessors.Add("SitTargetOrientation", ProcessSitTargetOrientation); 319 m_SOPXmlProcessors.Add("SitTargetOrientation", ProcessSitTargetOrientation);
321 m_SOPXmlProcessors.Add("SitTargetPosition", ProcessSitTargetPosition); 320 m_SOPXmlProcessors.Add("SitTargetPosition", ProcessSitTargetPosition);
322 m_SOPXmlProcessors.Add("SitTargetPositionLL", ProcessSitTargetPositionLL); 321 m_SOPXmlProcessors.Add("SitTargetPositionLL", ProcessSitTargetPositionLL);
@@ -584,11 +583,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
584 obj.Scale = Util.ReadVector(reader, "Scale"); 583 obj.Scale = Util.ReadVector(reader, "Scale");
585 } 584 }
586 585
587 private static void ProcessUpdateFlag(SceneObjectPart obj, XmlTextReader reader)
588 {
589 obj.UpdateFlag = (byte)reader.ReadElementContentAsInt("UpdateFlag", String.Empty);
590 }
591
592 private static void ProcessSitTargetOrientation(SceneObjectPart obj, XmlTextReader reader) 586 private static void ProcessSitTargetOrientation(SceneObjectPart obj, XmlTextReader reader)
593 { 587 {
594 obj.SitTargetOrientation = Util.ReadQuaternion(reader, "SitTargetOrientation"); 588 obj.SitTargetOrientation = Util.ReadQuaternion(reader, "SitTargetOrientation");
@@ -1187,7 +1181,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1187 WriteShape(writer, sop.Shape, options); 1181 WriteShape(writer, sop.Shape, options);
1188 1182
1189 WriteVector(writer, "Scale", sop.Scale); 1183 WriteVector(writer, "Scale", sop.Scale);
1190 writer.WriteElementString("UpdateFlag", sop.UpdateFlag.ToString());
1191 WriteQuaternion(writer, "SitTargetOrientation", sop.SitTargetOrientation); 1184 WriteQuaternion(writer, "SitTargetOrientation", sop.SitTargetOrientation);
1192 WriteVector(writer, "SitTargetPosition", sop.SitTargetPosition); 1185 WriteVector(writer, "SitTargetPosition", sop.SitTargetPosition);
1193 WriteVector(writer, "SitTargetPositionLL", sop.SitTargetPositionLL); 1186 WriteVector(writer, "SitTargetPositionLL", sop.SitTargetPositionLL);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
index 90cdd7b..a2332bb 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
@@ -70,8 +70,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
70 grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0)); 70 grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0));
71 71
72 // Required for linking 72 // Required for linking
73 grp1.RootPart.UpdateFlag = 0; 73 grp1.RootPart.ClearUpdateSchedule();
74 grp2.RootPart.UpdateFlag = 0; 74 grp2.RootPart.ClearUpdateSchedule();
75 75
76 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated. 76 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
77 grp1.LinkToGroup(grp2); 77 grp1.LinkToGroup(grp2);
@@ -164,10 +164,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
164 grp4.UpdateGroupRotationR(Quaternion.CreateFromEulers(0, 90 * Utils.DEG_TO_RAD, 0)); 164 grp4.UpdateGroupRotationR(Quaternion.CreateFromEulers(0, 90 * Utils.DEG_TO_RAD, 0));
165 165
166 // Required for linking 166 // Required for linking
167 grp1.RootPart.UpdateFlag = 0; 167 grp1.RootPart.ClearUpdateSchedule();
168 grp2.RootPart.UpdateFlag = 0; 168 grp2.RootPart.ClearUpdateSchedule();
169 grp3.RootPart.UpdateFlag = 0; 169 grp3.RootPart.ClearUpdateSchedule();
170 grp4.RootPart.UpdateFlag = 0; 170 grp4.RootPart.ClearUpdateSchedule();
171 171
172 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated. 172 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
173 grp1.LinkToGroup(grp2); 173 grp1.LinkToGroup(grp2);
@@ -198,8 +198,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
198 } 198 }
199 199
200 // Required for linking 200 // Required for linking
201 grp1.RootPart.UpdateFlag = 0; 201 grp1.RootPart.ClearUpdateSchedule();
202 grp3.RootPart.UpdateFlag = 0; 202 grp3.RootPart.ClearUpdateSchedule();
203 203
204 // root part should have no offset position or rotation 204 // root part should have no offset position or rotation
205 Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity, 205 Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity,
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs
index d34d8e5..860172c 100644
--- a/OpenSim/Region/Framework/Scenes/UndoState.cs
+++ b/OpenSim/Region/Framework/Scenes/UndoState.cs
@@ -158,6 +158,7 @@ namespace OpenSim.Region.Framework.Scenes
158 } 158 }
159 else 159 else
160 { 160 {
161 // Note: Updating these properties on sop automatically schedules an update if needed
161 if (Position != Vector3.Zero) 162 if (Position != Vector3.Zero)
162 { 163 {
163// m_log.DebugFormat( 164// m_log.DebugFormat(
@@ -181,8 +182,6 @@ namespace OpenSim.Region.Framework.Scenes
181 182
182 part.Resize(Scale); 183 part.Resize(Scale);
183 } 184 }
184
185 part.ScheduleTerseUpdate();
186 } 185 }
187 186
188 part.Undoing = false; 187 part.Undoing = false;
@@ -212,6 +211,7 @@ namespace OpenSim.Region.Framework.Scenes
212 } 211 }
213 else 212 else
214 { 213 {
214 // Note: Updating these properties on sop automatically schedules an update if needed
215 if (Position != Vector3.Zero) 215 if (Position != Vector3.Zero)
216 part.OffsetPosition = Position; 216 part.OffsetPosition = Position;
217 217
@@ -220,8 +220,6 @@ namespace OpenSim.Region.Framework.Scenes
220 220
221 if (Scale != Vector3.Zero) 221 if (Scale != Vector3.Zero)
222 part.Resize(Scale); 222 part.Resize(Scale);
223
224 part.ScheduleTerseUpdate();
225 } 223 }
226 224
227 part.Undoing = false; 225 part.Undoing = false;