Fix stack overflow when using recursion with nested scene animations

#519
This commit is contained in:
Wojtek Figat
2021-07-30 14:29:40 +02:00
parent 563eecebda
commit 25487c17e3
5 changed files with 42 additions and 4 deletions

View File

@@ -26,6 +26,7 @@ namespace FlaxEditor.GUI.Timeline
private SceneAnimationPlayer _player; private SceneAnimationPlayer _player;
private bool _showSelected3dTrack = true; private bool _showSelected3dTrack = true;
internal Guid _id;
/// <summary> /// <summary>
/// Gets or sets the animation player actor used for the timeline preview. /// Gets or sets the animation player actor used for the timeline preview.

View File

@@ -2,6 +2,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.GUI.Timeline.Tracks namespace FlaxEditor.GUI.Timeline.Tracks
@@ -122,5 +123,22 @@ namespace FlaxEditor.GUI.Timeline.Tracks
: base(ref options) : base(ref options)
{ {
} }
/// <inheritdoc />
protected override void OnAssetChanged()
{
if (Asset)
{
var refs = Asset.GetReferences();
var id = ((SceneAnimationTimeline)Timeline)._id;
if (Asset.ID == id || refs.Contains(id))
{
Asset = null;
throw new Exception("Cannot use nested scene animation (recursion).");
}
}
base.OnAssetChanged();
}
} }
} }

View File

@@ -852,6 +852,7 @@ namespace FlaxEditor.Windows.Assets
_isWaitingForTimelineLoad = false; _isWaitingForTimelineLoad = false;
// Load timeline data from the asset // Load timeline data from the asset
_timeline._id = OriginalAsset.ID;
_timeline.Load(_asset); _timeline.Load(_asset);
// Setup // Setup

View File

@@ -192,7 +192,8 @@ void SceneAnimationPlayer::Tick(float dt)
_cameraCutCam = nullptr; _cameraCutCam = nullptr;
// Tick the animation // Tick the animation
Tick(anim, time, dt, 0); CallStack callStack;
Tick(anim, time, dt, 0, callStack);
#if !BUILD_RELEASE #if !BUILD_RELEASE
if (_tracksDataStack.Count() != 0) if (_tracksDataStack.Count() != 0)
{ {
@@ -486,9 +487,12 @@ bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexO
return true; return true;
} }
void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset) void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset, CallStack& callStack)
{ {
const float fps = anim->FramesPerSecond; const float fps = anim->FramesPerSecond;
#if !BUILD_RELEASE || USE_EDITOR
callStack.Add(anim);
#endif
// Update all tracks // Update all tracks
for (int32 j = 0; j < anim->Tracks.Count(); j++) for (int32 j = 0; j < anim->Tracks.Count(); j++)
@@ -546,7 +550,20 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
return; return;
} }
Tick(nestedAnim, mediaTime, dt, stateIndexOffset); #if !BUILD_RELEASE || USE_EDITOR
// Validate recursive call
if (callStack.Contains(nestedAnim))
{
LOG(Warning,
"Recursive nested scene animation. Animation {0} for nested track {1} on actor {2}.",
callStack.Last()->ToString(),
nestedAnim->ToString(),
ToString());
return;
}
#endif
Tick(nestedAnim, mediaTime, dt, stateIndexOffset, callStack);
} }
break; break;
} }

View File

@@ -202,7 +202,8 @@ private:
void Restore(SceneAnimation* anim, int32 stateIndexOffset); void Restore(SceneAnimation* anim, int32 stateIndexOffset);
bool TickPropertyTrack(int32 trackIndex, int32 stateIndexOffset, SceneAnimation* anim, float time, const SceneAnimation::Track& track, TrackInstance& state, void* target); bool TickPropertyTrack(int32 trackIndex, int32 stateIndexOffset, SceneAnimation* anim, float time, const SceneAnimation::Track& track, TrackInstance& state, void* target);
void Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset); typedef Array<SceneAnimation*, FixedAllocation<8>> CallStack;
void Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset, CallStack& callStack);
void Tick(); void Tick();
void OnAnimationModified(); void OnAnimationModified();
void ResetState(); void ResetState();