From ef6e007a4c7301dbd7a1a0392a07664e7034201b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 28 Aug 2012 03:21:03 +0100 Subject: [PATCH 1/3] [possible still very broken] mess around keyframes. timer events threads overlaps, some null objects exceptions, region crossing... --- OpenSim/Data/MySQL/MySQLSimulationData.cs | 2 +- .../EntityTransfer/EntityTransferModule.cs | 12 +- .../Region/Framework/Scenes/KeyframeMotion.cs | 384 +++++++++++++----- OpenSim/Region/Framework/Scenes/Scene.cs | 6 + .../Framework/Scenes/SceneObjectGroup.cs | 29 +- .../Framework/Scenes/SceneObjectPart.cs | 5 +- .../Serialization/SceneObjectSerializer.cs | 2 +- .../Shared/Api/Implementation/LSL_Api.cs | 2 +- 8 files changed, 319 insertions(+), 123 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 4d7c0c937c..3b90c854c9 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -1698,7 +1698,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl); if (prim.KeyframeMotion != null) - cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize()); + cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize(true)); else cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]); diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 560f807167..9ffb851bbc 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1855,6 +1855,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (grp.RootPart.PhysActor != null) grp.RootPart.PhysActor.CrossingFailure(); + if (grp.RootPart.KeyframeMotion != null) + grp.RootPart.KeyframeMotion.CrossingFailure(); + grp.ScheduleGroupForFullUpdate(); } @@ -1910,8 +1913,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer grp, e); } } +/* + * done on caller ( not in attachments crossing for now) else { + if (!grp.IsDeleted) { PhysicsActor pa = grp.RootPart.PhysActor; @@ -1920,15 +1926,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer pa.CrossingFailure(); if (grp.RootPart.KeyframeMotion != null) { - grp.RootPart.Velocity = Vector3.Zero; + // moved to KeyframeMotion.CrossingFailure +// grp.RootPart.Velocity = Vector3.Zero; grp.RootPart.KeyframeMotion.CrossingFailure(); - grp.SendGroupRootTerseUpdate(); +// grp.SendGroupRootTerseUpdate(); } } } m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); } + */ } else { diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 6ee09b712a..4e6425fea1 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -58,12 +58,31 @@ namespace OpenSim.Region.Framework.Scenes private Vector3 m_serializedPosition; private Keyframe m_currentFrame; + private List m_frames = new List(); private Keyframe[] m_keyframes; [NonSerialized()] - protected Timer m_timer = new Timer(); + protected Timer m_timer = null; + + // timer lock + [NonSerialized()] + private object m_onTimerLock; + + // timer overrun detect + // prevents overlap or timer events threads frozen on the lock + [NonSerialized()] + private bool m_inOnTimer; + + // skip timer events. + //timer.stop doesn't assure there aren't event threads still being fired + [NonSerialized()] + private bool m_skipOnTimer; + + // retry position for cross fail + [NonSerialized()] + private Vector3 m_nextPosition; [NonSerialized()] private SceneObjectGroup m_group; @@ -88,7 +107,7 @@ namespace OpenSim.Region.Framework.Scenes { set { - if (value) + if (!value) { // Once we're let go, recompute positions if (m_selected) @@ -100,7 +119,8 @@ namespace OpenSim.Region.Framework.Scenes if (!m_selected) m_serializedPosition = m_group.AbsolutePosition; } - m_selected = value; } + m_selected = value; + } } public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) @@ -111,31 +131,65 @@ namespace OpenSim.Region.Framework.Scenes KeyframeMotion newMotion = (KeyframeMotion)fmt.Deserialize(ms); +/* + * create timer in start() + * this was creating unneeded timers + // This will be started when position is updated + newMotion.m_timer = new Timer(); newMotion.m_timer.Interval = (int)timerInterval; newMotion.m_timer.AutoReset = true; newMotion.m_timer.Elapsed += newMotion.OnTimer; +*/ + newMotion.m_group = grp; + if (grp != null && grp.IsSelected) + newMotion.m_selected = true; + + newMotion.m_onTimerLock = new object(); + newMotion.m_skipOnTimer = false; + newMotion.m_inOnTimer = false; return newMotion; } public void UpdateSceneObject(SceneObjectGroup grp) { - m_group = grp; - Vector3 offset = grp.AbsolutePosition - m_serializedPosition; - - m_basePosition += offset; - m_currentFrame.Position += offset; - for (int i = 0 ; i < m_frames.Count ; i++) +// lock (m_onTimerLock) { - Keyframe k = m_frames[i]; - k.Position += offset; - m_frames[i] = k; - } + m_skipOnTimer = true; + if (m_timer != null) + m_timer.Stop(); - if (m_running) - Start(); + m_group = grp; + Vector3 grppos = grp.AbsolutePosition; + Vector3 offset = grppos - m_serializedPosition; + // avoid doing it more than once + // current this will happen draging a prim to other region + m_serializedPosition = grppos; + + m_basePosition += offset; + m_currentFrame.Position += offset; + + m_nextPosition += offset; +/* + for (int i = 0; i < m_frames.Count; i++) + { + Keyframe k = m_frames[i]; + k.Position += offset; + m_frames[i] = k; + } +*/ + for (int i = 0; i < m_frames.Count; i++) + { + Keyframe k = m_frames[i]; + k.Position += offset; + m_frames[i]=k; + } + + if (m_running) + Start(); + } } public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) @@ -143,13 +197,16 @@ namespace OpenSim.Region.Framework.Scenes m_mode = mode; m_data = data; + m_onTimerLock = new object(); + m_group = grp; m_basePosition = grp.AbsolutePosition; m_baseRotation = grp.GroupRotation; - +/* m_timer.Interval = (int)timerInterval; m_timer.AutoReset = true; m_timer.Elapsed += OnTimer; + */ } public void SetKeyframes(Keyframe[] frames) @@ -157,19 +214,63 @@ namespace OpenSim.Region.Framework.Scenes m_keyframes = frames; } + public void Delete() + { + m_skipOnTimer = true; + m_frames.Clear(); + m_keyframes = null; + m_running = false; + + if (m_timer == null) + return; + + m_timer.Stop(); + m_timer.Elapsed -= OnTimer; + m_timer = null; + } + public void Start() { if (m_keyframes.Length > 0) + { + if (m_timer == null) + { + m_timer = new Timer(); + m_timer.Interval = (int)timerInterval; + m_timer.AutoReset = true; + m_timer.Elapsed += OnTimer; + } + + m_skipOnTimer = false; + m_inOnTimer = false; + m_timer.Start(); - m_running = true; + m_running = true; + } + else + { + m_running = false; + m_skipOnTimer = true; + if (m_timer != null) + { + m_timer.Stop(); + m_timer.Elapsed -= OnTimer; + m_timer = null; + } + } } public void Stop() { + m_skipOnTimer = true; + // Failed object creation if (m_timer == null) return; + m_timer.Stop(); + m_timer.Elapsed -= OnTimer; + m_timer = null; m_basePosition = m_group.AbsolutePosition; m_baseRotation = m_group.GroupRotation; @@ -184,6 +285,8 @@ namespace OpenSim.Region.Framework.Scenes public void Pause() { + m_skipOnTimer = true; + m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); m_group.SendGroupRootTerseUpdate(); @@ -284,138 +387,197 @@ namespace OpenSim.Region.Framework.Scenes protected void OnTimer(object sender, ElapsedEventArgs e) { - if (m_frames.Count == 0) + if (m_inOnTimer) { - GetNextList(); - - if (m_frames.Count == 0) - { - Stop(); - return; - } - - m_currentFrame = m_frames[0]; - } - - if (m_selected) - { - if (m_group.RootPart.Velocity != Vector3.Zero) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); - } + m_log.Error("[KeyFrame]: timer overrun"); return; } - // Do the frame processing - double steps = (double)m_currentFrame.TimeMS / timerInterval; - float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; - - if (steps <= 1.0) +// lock (m_onTimerLock) { - m_currentFrame.TimeMS = 0; + if (m_skipOnTimer) + return; - m_group.AbsolutePosition = (Vector3)m_currentFrame.Position; - m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); - } - else - { - Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; - Vector3 motionThisFrame = v / (float)steps; - v = v * 1000 / m_currentFrame.TimeMS; - - bool update = false; - - if (Vector3.Mag(motionThisFrame) >= 0.05f) + m_inOnTimer = true; + try { - m_group.AbsolutePosition += motionThisFrame; - m_group.RootPart.Velocity = v; - update = true; - } - - if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) - { - Quaternion current = m_group.GroupRotation; - - Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); - - float angle = 0; - - float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; - float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; - float aa_bb = aa * bb; - - if (aa_bb == 0) + if (m_frames.Count == 0) { - angle = 0; + GetNextList(); + + if (m_frames.Count == 0) + { + Stop(); + m_inOnTimer = false; + return; + } + + m_currentFrame = m_frames[0]; + } + + if (m_selected) + { + if (m_group.RootPart.Velocity != Vector3.Zero) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); + } + m_inOnTimer = false; + return; + } + + // Do the frame processing + double steps = (double)m_currentFrame.TimeMS / timerInterval; + float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; + + if (steps <= 1.0) + { + m_currentFrame.TimeMS = 0; + + // m_group.AbsolutePosition = (Vector3)m_currentFrame.Position; + m_nextPosition = (Vector3)m_currentFrame.Position; + m_group.AbsolutePosition = m_nextPosition; + + m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); } else { - float ab = current.X * step.X + - current.Y * step.Y + - current.Z * step.Z + - current.W * step.W; - float q = (ab * ab) / aa_bb; + Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; + Vector3 motionThisFrame = v / (float)steps; + v = v * 1000 / m_currentFrame.TimeMS; - if (q > 1.0f) + bool update = false; + + if (Vector3.Mag(motionThisFrame) >= 0.05f) { - angle = 0; + // m_group.AbsolutePosition += motionThisFrame; + m_nextPosition = m_group.AbsolutePosition + motionThisFrame; + m_group.AbsolutePosition = m_nextPosition; + + m_group.RootPart.Velocity = v; + update = true; } - else + + if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) { - angle = (float)Math.Acos(2 * q - 1); + Quaternion current = m_group.GroupRotation; + + Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); + + float angle = 0; + + float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; + float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; + float aa_bb = aa * bb; + + if (aa_bb == 0) + { + angle = 0; + } + else + { + float ab = current.X * step.X + + current.Y * step.Y + + current.Z * step.Z + + current.W * step.W; + float q = (ab * ab) / aa_bb; + + if (q > 1.0f) + { + angle = 0; + } + else + { + angle = (float)Math.Acos(2 * q - 1); + } + } + + if (angle > 0.01f) + { + m_group.UpdateGroupRotationR(step); + //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); + update = true; + } } + + if (update) + m_group.SendGroupRootTerseUpdate(); } - if (angle > 0.01f) + m_currentFrame.TimeMS -= (int)timerInterval; + + if (m_currentFrame.TimeMS <= 0) { - m_group.UpdateGroupRotationR(step); - //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); - update = true; + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); + m_group.SendGroupRootTerseUpdate(); + + m_frames.RemoveAt(0); + if (m_frames.Count > 0) + m_currentFrame = m_frames[0]; } } - - if (update) - m_group.SendGroupRootTerseUpdate(); - } - - m_currentFrame.TimeMS -= (int)timerInterval; - - if (m_currentFrame.TimeMS <= 0) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); - m_group.SendGroupRootTerseUpdate(); - - m_frames.RemoveAt(0); - if (m_frames.Count > 0) - m_currentFrame = m_frames[0]; + finally + { + m_inOnTimer = false; + } } } - public Byte[] Serialize() + public Byte[] Serialize(bool StopMoveTimer) { MemoryStream ms = new MemoryStream(); - m_timer.Stop(); + if (StopMoveTimer && m_timer != null) + { + m_skipOnTimer = true; + m_timer.Stop(); + } - BinaryFormatter fmt = new BinaryFormatter(); - SceneObjectGroup tmp = m_group; - m_group = null; - m_serializedPosition = tmp.AbsolutePosition; - fmt.Serialize(ms, this); - m_group = tmp; - return ms.ToArray(); +// lock (m_onTimerLock) + { + BinaryFormatter fmt = new BinaryFormatter(); + SceneObjectGroup tmp = m_group; + m_group = null; + if(!m_selected) + m_serializedPosition = tmp.AbsolutePosition; + fmt.Serialize(ms, this); + m_group = tmp; + return ms.ToArray(); + } + } + + public void StartCrossingCheck() + { + m_skipOnTimer = true; + if (m_timer != null) + m_timer.Stop(); + + if (m_group.RootPart.Velocity != Vector3.Zero) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); + } } public void CrossingFailure() { // The serialization has stopped the timer, so let's wait a moment // then retry the crossing. We'll get back here if it fails. + // if it is a open border there is no serialization + // so make sure timer is actually stopped + + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); + Util.FireAndForget(delegate (object x) { Thread.Sleep(60000); if (m_running) + { + m_skipOnTimer = false; m_timer.Start(); + m_group.AbsolutePosition = m_nextPosition; + } }); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 57fcf51f9e..0237021251 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2346,6 +2346,12 @@ namespace OpenSim.Region.Framework.Scenes foreach (SceneObjectPart part in partList) { + if (part.KeyframeMotion != null) + { + part.KeyframeMotion.Delete(); + part.KeyframeMotion = null; + } + if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) { PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index eee53d75ec..65a1da2f94 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -509,6 +509,9 @@ namespace OpenSim.Region.Framework.Scenes Vector3 newpos = Vector3.Zero; OpenSim.Services.Interfaces.GridRegion destination = null; + if (m_rootPart.KeyframeMotion != null) + m_rootPart.KeyframeMotion.StartCrossingCheck(); + bool canCross = true; foreach (ScenePresence av in m_linkedAvatars) { @@ -551,7 +554,7 @@ namespace OpenSim.Region.Framework.Scenes av.ParentID = 0; } -// m_linkedAvatars.Clear(); + // m_linkedAvatars.Clear(); m_scene.CrossPrimGroupIntoNewRegion(val, this, true); // Normalize @@ -599,11 +602,16 @@ namespace OpenSim.Region.Framework.Scenes avsToCross.Clear(); } - else if (RootPart.PhysActor != null) + else { - RootPart.PhysActor.CrossingFailure(); - } + if (m_rootPart.KeyframeMotion != null) + m_rootPart.KeyframeMotion.CrossingFailure(); + if (RootPart.PhysActor != null) + { + RootPart.PhysActor.CrossingFailure(); + } + } Vector3 oldp = AbsolutePosition; val.X = Util.Clamp(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f); val.Y = Util.Clamp(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f); @@ -2058,8 +2066,8 @@ namespace OpenSim.Region.Framework.Scenes { if (part.KeyframeMotion != null) { - part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize()); - part.KeyframeMotion.UpdateSceneObject(this); + part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize(false)); +// part.KeyframeMotion.UpdateSceneObject(this); } }); @@ -4407,6 +4415,15 @@ namespace OpenSim.Region.Framework.Scenes public virtual ISceneObject CloneForNewScene() { SceneObjectGroup sog = Copy(false); + sog.ForEachPart(delegate(SceneObjectPart part) + { + if (part.KeyframeMotion != null) + { + part.KeyframeMotion = KeyframeMotion.FromData(sog, part.KeyframeMotion.Serialize(true)); + // this is called later +// part.KeyframeMotion.UpdateSceneObject(this); + } + }); sog.IsDeleted = false; return sog; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ed626d0e87..bf5fc992a8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -769,7 +769,7 @@ namespace OpenSim.Region.Framework.Scenes { m_groupPosition = value; PhysicsActor actor = PhysActor; - if (actor != null) + if (actor != null && ParentGroup.Scene.PhysicsScene != null) { try { @@ -3408,6 +3408,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendTerseUpdateToAllClients() { + if (ParentGroup == null || ParentGroup.Scene == null) + return; + ParentGroup.Scene.ForEachClient(delegate(IClientAPI client) { SendTerseUpdateToClient(client); diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 134bd9dca9..1c756078e7 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1241,7 +1241,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization if (sog.RootPart.KeyframeMotion != null) { - Byte[] data = sog.RootPart.KeyframeMotion.Serialize(); + Byte[] data = sog.RootPart.KeyframeMotion.Serialize(true); writer.WriteStartElement(String.Empty, "KeyframeMotion", String.Empty); writer.WriteBase64(data, 0, data.Length); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index d8ef772246..207d0621a6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -12963,7 +12963,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (frames.Data.Length > 0) // We are getting a new motion { if (group.RootPart.KeyframeMotion != null) - group.RootPart.KeyframeMotion.Stop(); + group.RootPart.KeyframeMotion.Delete(); group.RootPart.KeyframeMotion = null; int idx = 0; From 72ac0665b207f7f840b861086b3a620a9942775f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 29 Aug 2012 00:35:06 +0100 Subject: [PATCH 2/3] [Potentially broken] keyframes changes.. since it's there, use timer for crossing retries and not still another thread, etc... --- .../Region/Framework/Scenes/KeyframeMotion.cs | 280 +++++++++++------- 1 file changed, 165 insertions(+), 115 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 4e6425fea1..5333177d79 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -53,9 +53,9 @@ namespace OpenSim.Region.Framework.Scenes public Vector3 AngularVelocity; }; + private Vector3 m_serializedPosition; private Vector3 m_basePosition; private Quaternion m_baseRotation; - private Vector3 m_serializedPosition; private Keyframe m_currentFrame; @@ -78,7 +78,13 @@ namespace OpenSim.Region.Framework.Scenes // skip timer events. //timer.stop doesn't assure there aren't event threads still being fired [NonSerialized()] - private bool m_skipOnTimer; + private bool m_timerStopped; + + [NonSerialized()] + private bool m_crossing; + + [NonSerialized()] + private int m_crossFailcntr; // retry position for cross fail [NonSerialized()] @@ -107,6 +113,8 @@ namespace OpenSim.Region.Framework.Scenes { set { + m_crossing = false; + m_crossFailcntr = 0; if (!value) { // Once we're let go, recompute positions @@ -117,39 +125,58 @@ namespace OpenSim.Region.Framework.Scenes { // Save selection position in case we get moved if (!m_selected) + { + StopTimer(); m_serializedPosition = m_group.AbsolutePosition; + } } m_selected = value; } } + private void StartTimer() + { + if (m_timer == null) + return; + m_timerStopped = false; + m_timer.Start(); + } + + private void StopTimer() + { + if (m_timer == null || m_timerStopped) + return; + m_timerStopped = true; + m_timer.Stop(); + } + public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) { - MemoryStream ms = new MemoryStream(data); + KeyframeMotion newMotion = null; - BinaryFormatter fmt = new BinaryFormatter(); + try + { + MemoryStream ms = new MemoryStream(data); + BinaryFormatter fmt = new BinaryFormatter(); - KeyframeMotion newMotion = (KeyframeMotion)fmt.Deserialize(ms); + newMotion = (KeyframeMotion)fmt.Deserialize(ms); -/* - * create timer in start() - * this was creating unneeded timers + newMotion.m_group = grp; - // This will be started when position is updated + if (grp != null && grp.IsSelected) + newMotion.m_selected = true; - newMotion.m_timer = new Timer(); - newMotion.m_timer.Interval = (int)timerInterval; - newMotion.m_timer.AutoReset = true; - newMotion.m_timer.Elapsed += newMotion.OnTimer; -*/ - newMotion.m_group = grp; + newMotion.m_onTimerLock = new object(); + newMotion.m_timerStopped = false; + newMotion.m_inOnTimer = false; + newMotion.m_crossing = false; + newMotion.m_crossFailcntr = 0; + } + catch + { + newMotion = null; + } - if (grp != null && grp.IsSelected) - newMotion.m_selected = true; - - newMotion.m_onTimerLock = new object(); - newMotion.m_skipOnTimer = false; - newMotion.m_inOnTimer = false; return newMotion; } @@ -157,9 +184,9 @@ namespace OpenSim.Region.Framework.Scenes { // lock (m_onTimerLock) { - m_skipOnTimer = true; - if (m_timer != null) - m_timer.Stop(); + m_crossing = false; + m_crossFailcntr = 0; + StopTimer(); m_group = grp; Vector3 grppos = grp.AbsolutePosition; @@ -172,14 +199,7 @@ namespace OpenSim.Region.Framework.Scenes m_currentFrame.Position += offset; m_nextPosition += offset; -/* - for (int i = 0; i < m_frames.Count; i++) - { - Keyframe k = m_frames[i]; - k.Position += offset; - m_frames[i] = k; - } -*/ + for (int i = 0; i < m_frames.Count; i++) { Keyframe k = m_frames[i]; @@ -202,11 +222,8 @@ namespace OpenSim.Region.Framework.Scenes m_group = grp; m_basePosition = grp.AbsolutePosition; m_baseRotation = grp.GroupRotation; -/* - m_timer.Interval = (int)timerInterval; - m_timer.AutoReset = true; - m_timer.Elapsed += OnTimer; - */ + m_crossing = false; + m_crossFailcntr = 0; } public void SetKeyframes(Keyframe[] frames) @@ -216,21 +233,23 @@ namespace OpenSim.Region.Framework.Scenes public void Delete() { - m_skipOnTimer = true; + m_running = false; + m_crossing = false; + m_crossFailcntr = 0; + StopTimer(); m_frames.Clear(); m_keyframes = null; - m_running = false; if (m_timer == null) return; - - m_timer.Stop(); m_timer.Elapsed -= OnTimer; m_timer = null; } public void Start() { + m_crossing = false; + m_crossFailcntr = 0; if (m_keyframes.Length > 0) { if (m_timer == null) @@ -241,19 +260,16 @@ namespace OpenSim.Region.Framework.Scenes m_timer.Elapsed += OnTimer; } - m_skipOnTimer = false; m_inOnTimer = false; - - m_timer.Start(); + StartTimer(); m_running = true; } else { m_running = false; - m_skipOnTimer = true; if (m_timer != null) { - m_timer.Stop(); + StopTimer(); m_timer.Elapsed -= OnTimer; m_timer = null; } @@ -262,13 +278,11 @@ namespace OpenSim.Region.Framework.Scenes public void Stop() { - m_skipOnTimer = true; + m_running = false; + m_crossing = false; + m_crossFailcntr = 0; - // Failed object creation - if (m_timer == null) - return; - - m_timer.Stop(); + StopTimer(); m_timer.Elapsed -= OnTimer; m_timer = null; @@ -280,19 +294,17 @@ namespace OpenSim.Region.Framework.Scenes m_group.SendGroupRootTerseUpdate(); m_frames.Clear(); - m_running = false; } public void Pause() { - m_skipOnTimer = true; + m_running = false; + m_crossFailcntr = 0; + StopTimer(); m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); m_group.SendGroupRootTerseUpdate(); - - m_timer.Stop(); - m_running = false; } private void GetNextList() @@ -325,9 +337,16 @@ namespace OpenSim.Region.Framework.Scenes Keyframe k = m_keyframes[i]; if (k.Position.HasValue) - k.Position = (k.Position * direction) + pos; + { + k.Position = (k.Position * direction); +// k.Velocity = (Vector3)k.Position / (k.TimeMS / 1000.0f); + k.Position += pos; + } else + { k.Position = pos; +// k.Velocity = Vector3.Zero; + } k.StartRotation = rot; if (k.Rotation.HasValue) @@ -341,6 +360,8 @@ namespace OpenSim.Region.Framework.Scenes k.Rotation = rot; } +/* ang vel not in use for now + float angle = 0; float aa = k.StartRotation.X * k.StartRotation.X + k.StartRotation.Y * k.StartRotation.Y + k.StartRotation.Z * k.StartRotation.Z + k.StartRotation.W * k.StartRotation.W; @@ -370,6 +391,7 @@ namespace OpenSim.Region.Framework.Scenes } k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000)); + */ k.TimeTotal = k.TimeMS; m_frames.Add(k); @@ -387,20 +409,56 @@ namespace OpenSim.Region.Framework.Scenes protected void OnTimer(object sender, ElapsedEventArgs e) { - if (m_inOnTimer) + if (m_timerStopped) // trap events still in air even after a timer.stop + return; + + if (m_inOnTimer) // don't let overruns to happen { - m_log.Error("[KeyFrame]: timer overrun"); + m_log.Warn("[KeyFrame]: timer overrun"); return; } + if (m_group == null) + return; + // lock (m_onTimerLock) { - if (m_skipOnTimer) - return; m_inOnTimer = true; + + bool update = false; + try { + if (m_selected) + { + if (m_group.RootPart.Velocity != Vector3.Zero) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); + } + m_inOnTimer = false; + return; + } + + if (m_crossing) + { + // if crossing and timer running then cross failed + // wait some time then + // retry to set the position that evtually caused the outbound + // if still outside region this will call startCrossing below + m_crossing = false; + m_group.AbsolutePosition = m_nextPosition; + if (!m_crossing) + { + StopTimer(); + m_timer.Interval = timerInterval; + StartTimer(); + } + m_inOnTimer = false; + return; + } + if (m_frames.Count == 0) { GetNextList(); @@ -413,41 +471,41 @@ namespace OpenSim.Region.Framework.Scenes } m_currentFrame = m_frames[0]; + m_currentFrame.TimeMS += (int)timerInterval; + + //force a update on a keyframe transition + update = true; } - if (m_selected) - { - if (m_group.RootPart.Velocity != Vector3.Zero) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); - } - m_inOnTimer = false; - return; - } + m_currentFrame.TimeMS -= (int)timerInterval; // Do the frame processing double steps = (double)m_currentFrame.TimeMS / timerInterval; - float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; - if (steps <= 1.0) + if (steps <= 0.0) { - m_currentFrame.TimeMS = 0; + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); - // m_group.AbsolutePosition = (Vector3)m_currentFrame.Position; m_nextPosition = (Vector3)m_currentFrame.Position; m_group.AbsolutePosition = m_nextPosition; m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); + + m_frames.RemoveAt(0); + if (m_frames.Count > 0) + m_currentFrame = m_frames[0]; + + update = true; } else { + float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; + Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; Vector3 motionThisFrame = v / (float)steps; v = v * 1000 / m_currentFrame.TimeMS; - bool update = false; - if (Vector3.Mag(motionThisFrame) >= 0.05f) { // m_group.AbsolutePosition += motionThisFrame; @@ -463,8 +521,8 @@ namespace OpenSim.Region.Framework.Scenes Quaternion current = m_group.GroupRotation; Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); - - float angle = 0; +/* use simpler change detection + * float angle = 0; float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; @@ -493,6 +551,12 @@ namespace OpenSim.Region.Framework.Scenes } if (angle > 0.01f) + */ + if(Math.Abs(step.X -current.X) > 0.001f + || Math.Abs(step.Y -current.Y) > 0.001f + || Math.Abs(step.Z -current.Z) > 0.001f) + // assuming w is a dependente var + { m_group.UpdateGroupRotationR(step); //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); @@ -500,25 +564,22 @@ namespace OpenSim.Region.Framework.Scenes } } - if (update) - m_group.SendGroupRootTerseUpdate(); } - m_currentFrame.TimeMS -= (int)timerInterval; - - if (m_currentFrame.TimeMS <= 0) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); + if (update) m_group.SendGroupRootTerseUpdate(); - m_frames.RemoveAt(0); - if (m_frames.Count > 0) - m_currentFrame = m_frames[0]; - } } + catch ( Exception ex) + { + // still happening sometimes + // lets try to see what + m_log.Warn("[KeyFrame]: timer overrun" + ex.Message); + } + finally { + // make sure we do not let this frozen m_inOnTimer = false; } } @@ -528,10 +589,7 @@ namespace OpenSim.Region.Framework.Scenes { MemoryStream ms = new MemoryStream(); if (StopMoveTimer && m_timer != null) - { - m_skipOnTimer = true; - m_timer.Stop(); - } + StopTimer(); // lock (m_onTimerLock) { @@ -548,10 +606,9 @@ namespace OpenSim.Region.Framework.Scenes public void StartCrossingCheck() { - m_skipOnTimer = true; - if (m_timer != null) - m_timer.Stop(); - + StopTimer(); + m_crossing = true; +// to remove / retune to smoth crossings if (m_group.RootPart.Velocity != Vector3.Zero) { m_group.RootPart.Velocity = Vector3.Zero; @@ -561,24 +618,17 @@ namespace OpenSim.Region.Framework.Scenes public void CrossingFailure() { - // The serialization has stopped the timer, so let's wait a moment - // then retry the crossing. We'll get back here if it fails. - // if it is a open border there is no serialization - // so make sure timer is actually stopped - - m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); - - Util.FireAndForget(delegate (object x) + if (m_group != null) { - Thread.Sleep(60000); - if (m_running) + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); + + if (m_running && m_timer != null) { - m_skipOnTimer = false; - m_timer.Start(); - m_group.AbsolutePosition = m_nextPosition; + m_timer.Interval = 60000; + StartTimer(); } - }); + } } } } From 2e54c3cc8f4caf6b6d056ae04419b171942a17d7 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 29 Aug 2012 03:19:47 +0100 Subject: [PATCH 3/3] A few more changes to keyframes --- OpenSim/Data/MySQL/MySQLSimulationData.cs | 2 +- .../Region/Framework/Scenes/KeyframeMotion.cs | 174 ++++++++++++------ .../Framework/Scenes/SceneObjectGroup.cs | 4 +- .../Serialization/SceneObjectSerializer.cs | 2 +- 4 files changed, 117 insertions(+), 65 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 3b90c854c9..4d7c0c937c 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -1698,7 +1698,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl); if (prim.KeyframeMotion != null) - cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize(true)); + cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize()); else cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]); diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 5333177d79..42e3860fde 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -81,10 +81,10 @@ namespace OpenSim.Region.Framework.Scenes private bool m_timerStopped; [NonSerialized()] - private bool m_crossing; + private bool m_isCrossing; [NonSerialized()] - private int m_crossFailcntr; + private bool m_waitingCrossing; // retry position for cross fail [NonSerialized()] @@ -112,9 +112,7 @@ namespace OpenSim.Region.Framework.Scenes public bool Selected { set - { - m_crossing = false; - m_crossFailcntr = 0; + { if (!value) { // Once we're let go, recompute positions @@ -130,6 +128,8 @@ namespace OpenSim.Region.Framework.Scenes m_serializedPosition = m_group.AbsolutePosition; } } + m_isCrossing = false; + m_waitingCrossing = false; m_selected = value; } } @@ -150,6 +150,17 @@ namespace OpenSim.Region.Framework.Scenes m_timer.Stop(); } + private void RemoveTimer() + { + if (m_timer == null) + return; + m_timerStopped = true; + m_timer.Stop(); + m_timer.Elapsed -= OnTimer; + m_timer = null; + } + + public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) { KeyframeMotion newMotion = null; @@ -169,8 +180,8 @@ namespace OpenSim.Region.Framework.Scenes newMotion.m_onTimerLock = new object(); newMotion.m_timerStopped = false; newMotion.m_inOnTimer = false; - newMotion.m_crossing = false; - newMotion.m_crossFailcntr = 0; + newMotion.m_isCrossing = false; + newMotion.m_waitingCrossing = false; } catch { @@ -184,8 +195,8 @@ namespace OpenSim.Region.Framework.Scenes { // lock (m_onTimerLock) { - m_crossing = false; - m_crossFailcntr = 0; + m_isCrossing = false; + m_waitingCrossing = false; StopTimer(); m_group = grp; @@ -220,10 +231,13 @@ namespace OpenSim.Region.Framework.Scenes m_onTimerLock = new object(); m_group = grp; - m_basePosition = grp.AbsolutePosition; - m_baseRotation = grp.GroupRotation; - m_crossing = false; - m_crossFailcntr = 0; + if (grp != null) + { + m_basePosition = grp.AbsolutePosition; + m_baseRotation = grp.GroupRotation; + } + m_isCrossing = false; + m_waitingCrossing = false; } public void SetKeyframes(Keyframe[] frames) @@ -231,34 +245,74 @@ namespace OpenSim.Region.Framework.Scenes m_keyframes = frames; } + public KeyframeMotion Copy(SceneObjectGroup newgrp) + { + StopTimer(); + + KeyframeMotion newmotion = new KeyframeMotion(newgrp, m_mode, m_data); + + if (newgrp != null && newgrp.IsSelected) + newmotion.m_selected = true; + + if (m_keyframes != null) + m_keyframes.CopyTo(newmotion.m_keyframes, 0); + + newmotion.m_frames = new List(m_frames); + newmotion.m_currentFrame = m_currentFrame; + + newmotion.m_nextPosition = m_nextPosition; + if (m_selected) + newmotion.m_serializedPosition = m_serializedPosition; + else + { + if (m_group != null) + newmotion.m_serializedPosition = m_group.AbsolutePosition; + else + newmotion.m_serializedPosition = m_serializedPosition; + } + + newmotion.m_iterations = m_iterations; + + newmotion.m_onTimerLock = new object(); + newmotion.m_timerStopped = false; + newmotion.m_inOnTimer = false; + newmotion.m_isCrossing = false; + newmotion.m_waitingCrossing = false; + + if (m_running && !m_waitingCrossing) + StartTimer(); + + return newmotion; + } + public void Delete() { m_running = false; - m_crossing = false; - m_crossFailcntr = 0; - StopTimer(); + RemoveTimer(); + m_isCrossing = false; + m_waitingCrossing = false; m_frames.Clear(); m_keyframes = null; - - if (m_timer == null) - return; - m_timer.Elapsed -= OnTimer; - m_timer = null; } public void Start() { - m_crossing = false; - m_crossFailcntr = 0; + m_isCrossing = false; + m_waitingCrossing = false; if (m_keyframes.Length > 0) { if (m_timer == null) { m_timer = new Timer(); - m_timer.Interval = (int)timerInterval; + m_timer.Interval = timerInterval; m_timer.AutoReset = true; m_timer.Elapsed += OnTimer; } + else + { + StopTimer(); + m_timer.Interval = timerInterval; + } m_inOnTimer = false; StartTimer(); @@ -267,24 +321,17 @@ namespace OpenSim.Region.Framework.Scenes else { m_running = false; - if (m_timer != null) - { - StopTimer(); - m_timer.Elapsed -= OnTimer; - m_timer = null; - } + RemoveTimer(); } } public void Stop() { m_running = false; - m_crossing = false; - m_crossFailcntr = 0; + m_isCrossing = false; + m_waitingCrossing = false; - StopTimer(); - m_timer.Elapsed -= OnTimer; - m_timer = null; + RemoveTimer(); m_basePosition = m_group.AbsolutePosition; m_baseRotation = m_group.GroupRotation; @@ -299,8 +346,7 @@ namespace OpenSim.Region.Framework.Scenes public void Pause() { m_running = false; - m_crossFailcntr = 0; - StopTimer(); + RemoveTimer(); m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.UpdateAngularVelocity(Vector3.Zero); @@ -421,7 +467,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_group == null) return; -// lock (m_onTimerLock) + lock (m_onTimerLock) { m_inOnTimer = true; @@ -441,15 +487,15 @@ namespace OpenSim.Region.Framework.Scenes return; } - if (m_crossing) + if (m_isCrossing) { // if crossing and timer running then cross failed // wait some time then // retry to set the position that evtually caused the outbound // if still outside region this will call startCrossing below - m_crossing = false; + m_isCrossing = false; m_group.AbsolutePosition = m_nextPosition; - if (!m_crossing) + if (!m_isCrossing) { StopTimer(); m_timer.Interval = timerInterval; @@ -552,9 +598,9 @@ namespace OpenSim.Region.Framework.Scenes if (angle > 0.01f) */ - if(Math.Abs(step.X -current.X) > 0.001f - || Math.Abs(step.Y -current.Y) > 0.001f - || Math.Abs(step.Z -current.Z) > 0.001f) + if(Math.Abs(step.X - current.X) > 0.001f + || Math.Abs(step.Y - current.Y) > 0.001f + || Math.Abs(step.Z - current.Z) > 0.001f) // assuming w is a dependente var { @@ -563,7 +609,6 @@ namespace OpenSim.Region.Framework.Scenes update = true; } } - } if (update) @@ -573,7 +618,7 @@ namespace OpenSim.Region.Framework.Scenes catch ( Exception ex) { // still happening sometimes - // lets try to see what + // lets try to see where m_log.Warn("[KeyFrame]: timer overrun" + ex.Message); } @@ -585,29 +630,34 @@ namespace OpenSim.Region.Framework.Scenes } } - public Byte[] Serialize(bool StopMoveTimer) + public Byte[] Serialize() { + StopTimer(); MemoryStream ms = new MemoryStream(); - if (StopMoveTimer && m_timer != null) - StopTimer(); -// lock (m_onTimerLock) - { - BinaryFormatter fmt = new BinaryFormatter(); - SceneObjectGroup tmp = m_group; - m_group = null; - if(!m_selected) - m_serializedPosition = tmp.AbsolutePosition; - fmt.Serialize(ms, this); - m_group = tmp; - return ms.ToArray(); - } + BinaryFormatter fmt = new BinaryFormatter(); + SceneObjectGroup tmp = m_group; + m_group = null; + if (!m_selected && tmp != null) + m_serializedPosition = tmp.AbsolutePosition; + fmt.Serialize(ms, this); + m_group = tmp; + if (m_running && !m_waitingCrossing) + StartTimer(); + + return ms.ToArray(); } public void StartCrossingCheck() { + // timer will be restart by crossingFailure + // or never since crossing worked and this + // should be deleted StopTimer(); - m_crossing = true; + + m_isCrossing = true; + m_waitingCrossing = true; + // to remove / retune to smoth crossings if (m_group.RootPart.Velocity != Vector3.Zero) { @@ -618,6 +668,8 @@ namespace OpenSim.Region.Framework.Scenes public void CrossingFailure() { + m_waitingCrossing = false; + if (m_group != null) { m_group.RootPart.Velocity = Vector3.Zero; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 65a1da2f94..834d27b7ac 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2066,7 +2066,7 @@ namespace OpenSim.Region.Framework.Scenes { if (part.KeyframeMotion != null) { - part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize(false)); + part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize()); // part.KeyframeMotion.UpdateSceneObject(this); } }); @@ -4419,7 +4419,7 @@ namespace OpenSim.Region.Framework.Scenes { if (part.KeyframeMotion != null) { - part.KeyframeMotion = KeyframeMotion.FromData(sog, part.KeyframeMotion.Serialize(true)); + part.KeyframeMotion = KeyframeMotion.FromData(sog, part.KeyframeMotion.Serialize()); // this is called later // part.KeyframeMotion.UpdateSceneObject(this); } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 1c756078e7..123c158e2c 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1241,7 +1241,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization if (sog.RootPart.KeyframeMotion != null) { - Byte[] data = sog.RootPart.KeyframeMotion.Serialize(true); + Byte[] data = sog.RootPart.KeyframeMotion.Serialize(); writer.WriteStartElement(String.Empty, "KeyframeMotion", String.Empty); writer.WriteBase64(data, 0, data.Length);