You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Sequencer: Don't make cyclic inclusions with template sequences, fix a possible loop with template sequence track editor.
- Refactor the sub track editor to put `CanAddSubSequence` into a common place. - We don't need to auto-create the object binding when adding a template sequence section, because this can currently only be done via the object binidng's menu anyway. This solves a bug with a template sequence track to a template sequence that's currently itself in a template sequence track (are you following? :) ). The problem was that the template sequence's root binding would, at that point, be bound to a binding override, so trying to find the object binding for that object would fail in the template sequence. - Add warnings/notifications when adding a template sequence track that points to a template sequence with a different tick resolution. - When creating new template sequence sections, select them all in one go instead of one by one (and ending up with only the last one selected). #jira UE-89877 #jira UE-90372 #rb max.chen [CL 12117497 by ludovic chabant in 4.25 branch]
This commit is contained in:
+44
-15
@@ -355,24 +355,40 @@ FKeyPropertyResult FTemplateSequenceTrackEditor::AddKeyInternal(FFrameNumber Key
|
||||
{
|
||||
FKeyPropertyResult KeyPropertyResult;
|
||||
|
||||
bool bHandleCreated = false;
|
||||
bool bTrackCreated = false;
|
||||
bool bTrackModified = false;
|
||||
if (TemplateSequence->GetMovieScene()->GetPlaybackRange().IsEmpty())
|
||||
{
|
||||
FNotificationInfo Info(FText::Format(LOCTEXT("InvalidSequenceDuration", "Invalid template sequence {0}. The template sequence has no duration."), TemplateSequence->GetDisplayName()));
|
||||
Info.bUseLargeFont = false;
|
||||
FSlateNotificationManager::Get().AddNotification(Info);
|
||||
return KeyPropertyResult;
|
||||
}
|
||||
|
||||
if (!CanAddSubSequence(*TemplateSequence))
|
||||
{
|
||||
FNotificationInfo Info(FText::Format(LOCTEXT("InvalidSequenceCycle", "Invalid template sequence {0}. There could be a circular dependency."), TemplateSequence->GetDisplayName()));
|
||||
Info.bUseLargeFont = false;
|
||||
FSlateNotificationManager::Get().AddNotification(Info);
|
||||
return KeyPropertyResult;
|
||||
}
|
||||
|
||||
TArray<UMovieSceneSection*> NewSections;
|
||||
TSharedPtr<ISequencer> SequencerPtr = GetSequencer();
|
||||
if (SequencerPtr.IsValid())
|
||||
{
|
||||
const FFrameRate OuterTickResolution = SequencerPtr->GetFocusedTickResolution();
|
||||
const FFrameRate SubTickResolution = TemplateSequence->GetMovieScene()->GetTickResolution();
|
||||
if (SubTickResolution != OuterTickResolution)
|
||||
{
|
||||
FNotificationInfo Info(FText::Format(LOCTEXT("TickResolutionMismatch", "The parent sequence has a different tick resolution {0} than the newly added sequence {1}"), OuterTickResolution.ToPrettyText(), SubTickResolution.ToPrettyText()));
|
||||
Info.bUseLargeFont = false;
|
||||
FSlateNotificationManager::Get().AddNotification(Info);
|
||||
}
|
||||
|
||||
for (const FGuid& ObjectBindingGuid : ObjectBindings)
|
||||
{
|
||||
UObject* Object = SequencerPtr->FindSpawnedObjectOrTemplate(ObjectBindingGuid);
|
||||
|
||||
FFindOrCreateHandleResult HandleResult = FindOrCreateHandleToObject(Object);
|
||||
FGuid ObjectHandle = HandleResult.Handle;
|
||||
KeyPropertyResult.bHandleCreated |= HandleResult.bWasCreated;
|
||||
|
||||
if (ObjectHandle.IsValid())
|
||||
if (ObjectBindingGuid.IsValid())
|
||||
{
|
||||
FFindOrCreateTrackResult TrackResult = FindOrCreateTrackForObject(ObjectHandle, UTemplateSequenceTrack::StaticClass());
|
||||
FFindOrCreateTrackResult TrackResult = FindOrCreateTrackForObject(ObjectBindingGuid, UTemplateSequenceTrack::StaticClass());
|
||||
UMovieSceneTrack* Track = TrackResult.Track;
|
||||
KeyPropertyResult.bTrackCreated |= TrackResult.bWasCreated;
|
||||
|
||||
@@ -380,15 +396,22 @@ FKeyPropertyResult FTemplateSequenceTrackEditor::AddKeyInternal(FFrameNumber Key
|
||||
{
|
||||
UMovieSceneSection* NewSection = Cast<UTemplateSequenceTrack>(Track)->AddNewTemplateSequenceSection(KeyTime, TemplateSequence);
|
||||
KeyPropertyResult.bTrackModified = true;
|
||||
|
||||
GetSequencer()->EmptySelection();
|
||||
GetSequencer()->SelectSection(NewSection);
|
||||
GetSequencer()->ThrobSectionSelection();
|
||||
NewSections.Add(NewSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NewSections.Num() > 0)
|
||||
{
|
||||
GetSequencer()->EmptySelection();
|
||||
for (UMovieSceneSection* NewSection : NewSections)
|
||||
{
|
||||
GetSequencer()->SelectSection(NewSection);
|
||||
}
|
||||
GetSequencer()->ThrobSectionSelection();
|
||||
}
|
||||
|
||||
return KeyPropertyResult;
|
||||
}
|
||||
|
||||
@@ -397,6 +420,12 @@ FKeyPropertyResult FTemplateSequenceTrackEditor::AddLegacyCameraAnimKeyInternal(
|
||||
return FCameraAnimTrackEditorHelper::AddCameraAnimKey(*this, KeyTime, Objects, CameraAnim);
|
||||
}
|
||||
|
||||
bool FTemplateSequenceTrackEditor::CanAddSubSequence(const UMovieSceneSequence& Sequence) const
|
||||
{
|
||||
UMovieSceneSequence* FocusedSequence = GetSequencer()->GetFocusedMovieSceneSequence();
|
||||
return FSubTrackEditorUtil::CanAddSubSequence(FocusedSequence, Sequence);
|
||||
}
|
||||
|
||||
const UClass* FTemplateSequenceTrackEditor::AcquireObjectClassFromObjectGuid(const FGuid& Guid)
|
||||
{
|
||||
if (!Guid.IsValid())
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ private:
|
||||
FKeyPropertyResult AddKeyInternal(FFrameNumber KeyTime, TArray<FGuid> ObjectBindings, UTemplateSequence* TemplateSequence);
|
||||
FKeyPropertyResult AddLegacyCameraAnimKeyInternal(FFrameNumber KeyTime, const TArray<TWeakObjectPtr<UObject>> Objects, UCameraAnim* CameraAnim);
|
||||
|
||||
bool CanAddSubSequence(const UMovieSceneSequence& Sequence) const;
|
||||
const UClass* AcquireObjectClassFromObjectGuid(const FGuid& Guid);
|
||||
UCameraComponent* AcquireCameraComponentFromObjectGuid(const FGuid& Guid);
|
||||
|
||||
|
||||
@@ -480,35 +480,7 @@ bool FSubTrackEditor::CanAddSubSequence(const UMovieSceneSequence& Sequence) con
|
||||
{
|
||||
// prevent adding ourselves and ensure we have a valid movie scene
|
||||
UMovieSceneSequence* FocusedSequence = GetSequencer()->GetFocusedMovieSceneSequence();
|
||||
|
||||
if ((FocusedSequence == nullptr) || (FocusedSequence == &Sequence) || (FocusedSequence->GetMovieScene() == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure that the other sequence has a valid movie scene
|
||||
UMovieScene* SequenceMovieScene = Sequence.GetMovieScene();
|
||||
|
||||
if (SequenceMovieScene == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure we are not contained in the other sequence (circular dependency)
|
||||
// @todo sequencer: this check is not sufficient (does not prevent circular dependencies of 2+ levels)
|
||||
UMovieSceneSubTrack* SequenceSubTrack = SequenceMovieScene->FindMasterTrack<UMovieSceneSubTrack>();
|
||||
if (SequenceSubTrack && SequenceSubTrack->ContainsSequence(*FocusedSequence, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UMovieSceneCinematicShotTrack* SequenceCinematicTrack = SequenceMovieScene->FindMasterTrack<UMovieSceneCinematicShotTrack>();
|
||||
if (SequenceCinematicTrack && SequenceCinematicTrack->ContainsSequence(*FocusedSequence, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return FSubTrackEditorUtil::CanAddSubSequence(FocusedSequence, Sequence);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "TrackEditors/SubTrackEditorBase.h"
|
||||
#include "Tracks/MovieSceneCinematicShotTrack.h"
|
||||
#include "Tracks/MovieSceneSubTrack.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FSubTrackEditorBase"
|
||||
|
||||
@@ -344,4 +346,37 @@ FFrameNumber FSubSectionEditorUtil::SlipSection(FFrameNumber SlipTime)
|
||||
return SlipTime;
|
||||
}
|
||||
|
||||
bool FSubTrackEditorUtil::CanAddSubSequence(const UMovieSceneSequence* CurrentSequence, const UMovieSceneSequence& SubSequence)
|
||||
{
|
||||
// Prevent adding ourselves and ensure we have a valid movie scene.
|
||||
if ((CurrentSequence == nullptr) || (CurrentSequence == &SubSequence) || (CurrentSequence->GetMovieScene() == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure that the other sequence has a valid movie scene
|
||||
UMovieScene* SequenceMovieScene = SubSequence.GetMovieScene();
|
||||
|
||||
if (SequenceMovieScene == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure we are not contained in the other sequence (circular dependency)
|
||||
// @todo sequencer: this check is not sufficient (does not prevent circular dependencies of 2+ levels)
|
||||
UMovieSceneSubTrack* SequenceSubTrack = SequenceMovieScene->FindMasterTrack<UMovieSceneSubTrack>();
|
||||
if (SequenceSubTrack && SequenceSubTrack->ContainsSequence(*CurrentSequence, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UMovieSceneCinematicShotTrack* SequenceCinematicTrack = SequenceMovieScene->FindMasterTrack<UMovieSceneCinematicShotTrack>();
|
||||
if (SequenceCinematicTrack && SequenceCinematicTrack->ContainsSequence(*CurrentSequence, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
@@ -88,6 +88,21 @@ private:
|
||||
FFrameNumber InitialStartTimeDuringResize;
|
||||
};
|
||||
|
||||
class MOVIESCENETOOLS_API FSubTrackEditorUtil
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Check whether the given sequence can be added as a sub-sequence.
|
||||
*
|
||||
* The purpose of this method is to disallow circular references
|
||||
* between sub-sequences in the focused movie scene.
|
||||
*
|
||||
* @param Sequence The sequence to check.
|
||||
* @return true if the sequence can be added as a sub-sequence, false otherwise.
|
||||
*/
|
||||
static bool CanAddSubSequence(const UMovieSceneSequence* CurrentSequence, const UMovieSceneSequence& SubSequence);
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin class for sub-sequence section interfaces.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user