// Copyright Epic Games, Inc. All Rights Reserved. #include "Sections/MovieSceneEventTriggerSection.h" #include "Channels/MovieSceneChannelProxy.h" #include "Tracks/MovieSceneEventTrack.h" #include "Systems/MovieSceneEventSystems.h" #include "MovieSceneTracksComponentTypes.h" #include "Evaluation/MovieSceneEvaluationField.h" #include "EntitySystem/MovieSceneEntityBuilder.h" #include "EntitySystem/MovieSceneInstanceRegistry.h" #include "EntitySystem/MovieSceneEntitySystemLinker.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(MovieSceneEventTriggerSection) UMovieSceneEventTriggerSection::UMovieSceneEventTriggerSection(const FObjectInitializer& ObjInit) : Super(ObjInit) { bSupportsInfiniteRange = true; SetRange(TRange::All()); #if WITH_EDITOR ChannelProxy = MakeShared(EventChannel, FMovieSceneChannelMetaData()); #endif } void UMovieSceneEventTriggerSection::ImportEntityImpl(UMovieSceneEntitySystemLinker* EntityLinker, const FEntityImportParams& Params, FImportedEntity* OutImportedEntity) { using namespace UE::MovieScene; const int32 EventIndex = static_cast(Params.EntityID); TArrayView Times = EventChannel.GetData().GetTimes(); TArrayView Events = EventChannel.GetData().GetValues(); if (!ensureMsgf(Events.IsValidIndex(EventIndex), TEXT("Attempting to import an event entity for an invalid index (Index: %d, Num: %d)"), EventIndex, Events.Num())) { return; } if (Events[EventIndex].Ptrs.Function == nullptr) { return; } UMovieSceneEventTrack* EventTrack = GetTypedOuter(); const FSequenceInstance& ThisInstance = EntityLinker->GetInstanceRegistry()->GetInstance(Params.Sequence.InstanceHandle); FMovieSceneContext Context = ThisInstance.GetContext(); // Don't allow events to fire when playback is in a stopped state. This can occur when stopping // playback and returning the current position to the start of playback. It's not desireable to have // all the events from the last playback position to the start of playback be fired. if (Context.GetStatus() == EMovieScenePlayerStatus::Stopped || Context.IsSilent()) { return; } else if (Context.GetDirection() == EPlayDirection::Forwards && !EventTrack->bFireEventsWhenForwards) { return; } else if (Context.GetDirection() == EPlayDirection::Backwards && !EventTrack->bFireEventsWhenBackwards) { return; } UMovieSceneEventSystem* EventSystem = nullptr; bool bMimicChanged = false; if (EventTrack->EventPosition == EFireEventsAtPosition::AtStartOfEvaluation) { bMimicChanged = true; EventSystem = EntityLinker->LinkSystem(); } else if (EventTrack->EventPosition == EFireEventsAtPosition::AfterSpawn) { bMimicChanged = true; EventSystem = EntityLinker->LinkSystem(); } else { EventSystem = EntityLinker->LinkSystem(); } TOptional RootTime = Context.GetSequenceToRootSequenceTransform().TryTransformTime(Times[EventIndex]); if (!RootTime) { return; } FMovieSceneEventTriggerData TriggerData = { Events[EventIndex].Ptrs, Params.GetObjectBindingID(), ThisInstance.GetSequenceID(), RootTime.GetValue() }; EventSystem->AddEvent(ThisInstance.GetRootInstanceHandle(), TriggerData); if (bMimicChanged) { // Mimic the structure changing in order to ensure that the instantiation phase runs EntityLinker->EntityManager.MimicStructureChanged(); } } bool UMovieSceneEventTriggerSection::PopulateEvaluationFieldImpl(const TRange& EffectiveRange, const FMovieSceneEvaluationFieldEntityMetaData& InMetaData, FMovieSceneEntityComponentFieldBuilder* OutFieldBuilder) { const int32 MetaDataIndex = OutFieldBuilder->AddMetaData(InMetaData); TArrayView Times = EventChannel.GetData().GetTimes(); for (int32 Index = 0; Index < Times.Num(); ++Index) { if (EffectiveRange.Contains(Times[Index])) { TRange Range(Times[Index]); OutFieldBuilder->AddOneShotEntity(Range, this, Index, MetaDataIndex); } } return true; }