// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. #include "NiagaraEffectViewModel.h" #include "NiagaraEffect.h" #include "NiagaraEmitterHandle.h" #include "NiagaraEmitterProperties.h" #include "NiagaraScriptSource.h" #include "NiagaraEditorUtilities.h" #include "NiagaraEmitterHandleViewModel.h" #include "NiagaraEmitterViewModel.h" #include "NiagaraEffectScriptViewModel.h" #include "NiagaraScriptInputCollectionViewModel.h" #include "NiagaraSequence.h" #include "MovieSceneNiagaraEmitterTrack.h" #include "MovieSceneNiagaraEmitterSection.h" #include "NiagaraEffectInstance.h" #include "Editor.h" #include "ScopedTransaction.h" #include "MovieScene.h" #include "ISequencerModule.h" #include "EditorSupportDelegates.h" #include "ModuleManager.h" #include "TNiagaraViewModelManager.h" #define LOCTEXT_NAMESPACE "NiagaraEffectViewModel" template<> TMap> TNiagaraViewModelManager::ObjectsToViewModels{}; FNiagaraEffectViewModel::FNiagaraEffectViewModel(UNiagaraEffect& InEffect, FNiagaraEffectViewModelOptions InOptions) : Effect(InEffect) , ParameterEditMode(InOptions.ParameterEditMode) , PreviewComponent(nullptr) , EffectScriptViewModel(MakeShareable(new FNiagaraEffectScriptViewModel(Effect))) , NiagaraSequence(nullptr) , bCanRemoveEmittersFromTimeline(InOptions.bCanRemoveEmittersFromTimeline) , bCanRenameEmittersFromTimeline(InOptions.bCanRenameEmittersFromTimeline) , bUpdatingFromSequencerDataChange(false) { EffectScriptViewModel->GetInputCollectionViewModel()->OnParameterValueChanged().AddRaw(this, &FNiagaraEffectViewModel::EffectParameterValueChanged); EffectScriptViewModel->GetInputCollectionViewModel()->OnCollectionChanged().AddRaw(this, &FNiagaraEffectViewModel::EffectParameterCollectionChanged); EffectScriptViewModel->OnParameterBindingsChanged().AddRaw(this, &FNiagaraEffectViewModel::EffectParameterBindingsChanged); EffectScriptViewModel->GetInputCollectionViewModel()->GetSelection().OnSelectedObjectsChanged().AddRaw(this, &FNiagaraEffectViewModel::ParameterSelectionChanged); SetupPreviewComponentAndInstance(); SetupSequencer(); RefreshAll(); GEditor->RegisterForUndo(this); RegisteredHandle = RegisterViewModelWithMap(&InEffect, this); } FNiagaraEffectViewModel::~FNiagaraEffectViewModel() { CurveOwner.EmptyCurves(); if (EffectInstance.IsValid()) { EffectInstance->OnInitialized().RemoveAll(this); } GEditor->UnregisterForUndo(this); // Make sure that we clear out all of our event handlers UnregisterViewModelWithMap(RegisteredHandle); UE_LOG(LogNiagaraEditor, Warning, TEXT("Deleting effect view model %p"), this); EffectScriptViewModel->GetInputCollectionViewModel()->OnParameterValueChanged().RemoveAll(this); EffectScriptViewModel->GetInputCollectionViewModel()->OnCollectionChanged().RemoveAll(this); EffectScriptViewModel->OnParameterBindingsChanged().RemoveAll(this); for (TSharedRef& HandleRef : EmitterHandleViewModels) { HandleRef->OnPropertyChanged().RemoveAll(this); HandleRef->GetEmitterViewModel()->OnPropertyChanged().RemoveAll(this); HandleRef->GetEmitterViewModel()->OnParameterValueChanged().RemoveAll(this); HandleRef->GetEmitterViewModel()->OnScriptCompiled().RemoveAll(this); HandleRef->GetEmitterViewModel()->GetSpawnScriptViewModel()->GetInputCollectionViewModel()-> GetSelection().OnSelectedObjectsChanged().RemoveAll(this); HandleRef->GetEmitterViewModel()->GetUpdateScriptViewModel()->GetInputCollectionViewModel()-> GetSelection().OnSelectedObjectsChanged().RemoveAll(this); } EmitterHandleViewModels.Empty(); EffectInstance.Reset(); } const TArray>& FNiagaraEffectViewModel::GetEmitterHandleViewModels() { return EmitterHandleViewModels; } TSharedRef FNiagaraEffectViewModel::GetEffectScriptViewModel() { return EffectScriptViewModel; } UNiagaraComponent* FNiagaraEffectViewModel::GetPreviewComponent() { return PreviewComponent; } TSharedPtr FNiagaraEffectViewModel::GetSequencer() { return Sequencer; } FNiagaraCurveOwner& FNiagaraEffectViewModel::GetCurveOwner() { return CurveOwner; } void FNiagaraEffectViewModel::AddEmitterFromAssetData(const FAssetData& AssetData) { UNiagaraEmitterProperties* Emitter = Cast(AssetData.GetAsset()); if (Emitter != nullptr) { const FScopedTransaction Transaction(LOCTEXT("AddEmitter", "Add emitter")); TSet EmitterHandleNames; for (const FNiagaraEmitterHandle& EmitterHandle : Effect.GetEmitterHandles()) { EmitterHandleNames.Add(EmitterHandle.GetName()); } Effect.Modify(); FNiagaraEmitterHandle EmitterHandle = Effect.AddEmitterHandle(*Emitter, FNiagaraEditorUtilities::GetUniqueName(Emitter->GetFName(), EmitterHandleNames)); if (Effect.GetNumEmitters() == 1) { // When adding a new emitter to an empty effect reset the playback and start playing. Sequencer->SetGlobalTime(0); Sequencer->SetPlaybackStatus(EMovieScenePlayerStatus::Playing); } RefreshAll(); } } void FNiagaraEffectViewModel::DuplicateEmitter(TSharedRef EmitterHandleToDuplicate) { if (EmitterHandleToDuplicate->GetEmitterHandle() == nullptr) { return; } const FScopedTransaction DuplicateTransaction(LOCTEXT("DuplicateEmitter", "Duplicate emitter")); TSet EmitterHandleNames; for (const FNiagaraEmitterHandle& EmitterHandle : Effect.GetEmitterHandles()) { EmitterHandleNames.Add(EmitterHandle.GetName()); } Effect.Modify(); FNiagaraEmitterHandle EmitterHandle = Effect.DuplicateEmitterHandle(*EmitterHandleToDuplicate->GetEmitterHandle(), FNiagaraEditorUtilities::GetUniqueName(EmitterHandleToDuplicate->GetEmitterHandle()->GetName(), EmitterHandleNames)); // When adding a new emitter reset the playback and start playing. Sequencer->SetGlobalTime(0); Sequencer->SetPlaybackStatus(EMovieScenePlayerStatus::Playing); RefreshAll(); } void FNiagaraEffectViewModel::DeleteEmitter(TSharedRef EmitterHandleToDelete) { const FScopedTransaction DeleteTransaction(LOCTEXT("DeleteEmitter", "Delete emitter")); Effect.Modify(); if (EmitterHandleToDelete->GetEmitterHandle()) { Effect.RemoveEmitterHandle(*EmitterHandleToDelete->GetEmitterHandle()); } RefreshAll(); } FNiagaraEffectViewModel::FOnEmitterHandleViewModelsChanged& FNiagaraEffectViewModel::OnEmitterHandleViewModelsChanged() { return OnEmitterHandleViewModelsChangedDelegate; } FNiagaraEffectViewModel::FOnCurveOwnerChanged& FNiagaraEffectViewModel::OnCurveOwnerChanged() { return OnCurveOwnerChangedDelegate; } void FNiagaraEffectViewModel::AddReferencedObjects(FReferenceCollector& Collector) { if (PreviewComponent != nullptr) { Collector.AddReferencedObject(PreviewComponent); } if (NiagaraSequence != nullptr) { Collector.AddReferencedObject(NiagaraSequence); } } void FNiagaraEffectViewModel::PostUndo(bool bSuccess) { RefreshAll(); } void FNiagaraEffectViewModel::SetupPreviewComponentAndInstance() { PreviewComponent = NewObject(GetTransientPackage(), NAME_None, RF_Transient); PreviewComponent->SetAsset(&Effect); EffectInstance = PreviewComponent->GetEffectInstance(); EffectInstance->SetAgeUpdateMode(FNiagaraEffectInstance::EAgeUpdateMode::DesiredAge); EffectInstance->OnInitialized().AddRaw(this, &FNiagaraEffectViewModel::EffectInstanceInitialized); } void FNiagaraEffectViewModel::RefreshAll() { ReinitEffectInstances(); RefreshEmitterHandleViewModels(); RefreshSequencerTracks(); EffectScriptViewModel->RefreshEmitterNodes(); } void FNiagaraEffectViewModel::ReinitEffectInstances() { // Make sure the emitters are compiled and then setup the effect instance. for (int32 i = 0; i < Effect.GetNumEmitters(); ++i) { FNiagaraEmitterHandle& EmitterHandle = Effect.GetEmitterHandle(i); FString ErrorMessages; //Cast(EmitterHandle.GetInstance()->SpawnScriptProps.Script->Source)->Compile(ErrorMessages); //Cast(EmitterHandle.GetInstance()->UpdateScriptProps.Script->Source)->Compile(ErrorMessages); EmitterHandle.GetInstance()->UpdateScriptProps.InitDataSetAccess(); } for (TObjectIterator ComponentIt; ComponentIt; ++ComponentIt) { UNiagaraComponent* Component = *ComponentIt; if (Component->GetAsset() == &Effect) { Component->GetEffectInstance()->Init(Component->GetAsset()); } } } void FNiagaraEffectViewModel::RefreshEmitterHandleViewModels() { TArray> OldViewModels = EmitterHandleViewModels; EmitterHandleViewModels.Empty(); // Map existing view models to the real instances that now exist. Reuse if we can. Create a new one if we cannot. int32 i; for (i = 0; i < Effect.GetNumEmitters(); ++i) { FNiagaraEmitterHandle* EmitterHandle = &Effect.GetEmitterHandle(i); FNiagaraSimulation* Simulation = EffectInstance->GetSimulationForHandle(*EmitterHandle); bool bAdd = OldViewModels.Num() <= i; if (bAdd) { TSharedRef ViewModel = MakeShareable(new FNiagaraEmitterHandleViewModel(EmitterHandle, Simulation, Effect, ParameterEditMode)); // Since we're adding fresh, we need to register all the event handlers. ViewModel->OnPropertyChanged().AddRaw(this, &FNiagaraEffectViewModel::EmitterHandlePropertyChanged, ViewModel); ViewModel->GetEmitterViewModel()->OnPropertyChanged().AddRaw(this, &FNiagaraEffectViewModel::EmitterPropertyChanged, ViewModel); ViewModel->GetEmitterViewModel()->OnParameterValueChanged().AddRaw(this, &FNiagaraEffectViewModel::EmitterParameterValueChanged); ViewModel->GetEmitterViewModel()->OnScriptCompiled().AddRaw(this, &FNiagaraEffectViewModel::ScriptCompiled); ViewModel->GetEmitterViewModel()->GetSpawnScriptViewModel()->GetInputCollectionViewModel()-> GetSelection().OnSelectedObjectsChanged().AddRaw(this, &FNiagaraEffectViewModel::ParameterSelectionChanged); ViewModel->GetEmitterViewModel()->GetUpdateScriptViewModel()->GetInputCollectionViewModel()-> GetSelection().OnSelectedObjectsChanged().AddRaw(this, &FNiagaraEffectViewModel::ParameterSelectionChanged); EmitterHandleViewModels.Add(ViewModel); } else { TSharedRef ViewModel = OldViewModels[i]; ViewModel->Set(EmitterHandle, Simulation, Effect, ParameterEditMode); EmitterHandleViewModels.Add(ViewModel); } } check(EmitterHandleViewModels.Num() == Effect.GetNumEmitters()); // Clear out any old view models that may still be left around. for (; i < OldViewModels.Num(); i++) { TSharedRef ViewModel = OldViewModels[i]; ViewModel->OnPropertyChanged().RemoveAll(this); ViewModel->GetEmitterViewModel()->OnPropertyChanged().RemoveAll(this); ViewModel->GetEmitterViewModel()->OnParameterValueChanged().RemoveAll(this); ViewModel->GetEmitterViewModel()->OnScriptCompiled().RemoveAll(this); ViewModel->GetEmitterViewModel()->GetSpawnScriptViewModel()->GetInputCollectionViewModel()-> GetSelection().OnSelectedObjectsChanged().RemoveAll(this); ViewModel->GetEmitterViewModel()->GetUpdateScriptViewModel()->GetInputCollectionViewModel()-> GetSelection().OnSelectedObjectsChanged().RemoveAll(this); ViewModel->Set(nullptr, nullptr, Effect, ParameterEditMode); } OnEmitterHandleViewModelsChangedDelegate.Broadcast(); } float SequencerTimeRangePadding = 0.1f; float SequencerEmitterEndPadding = 5.0f; void FNiagaraEffectViewModel::RefreshSequencerTracks() { TArray MasterTracks = NiagaraSequence->GetMovieScene()->GetMasterTracks(); for (UMovieSceneTrack* MasterTrack : MasterTracks) { if (MasterTrack != nullptr) { NiagaraSequence->GetMovieScene()->RemoveMasterTrack(*MasterTrack); } } float MaxEmitterTime = 0; for (TSharedRef EmitterHandleViewModel : EmitterHandleViewModels) { UMovieSceneNiagaraEmitterTrack* EmitterTrack = Cast(NiagaraSequence->GetMovieScene()->AddMasterTrack(UMovieSceneNiagaraEmitterTrack::StaticClass())); EmitterTrack->SetEmitterHandle(EmitterHandleViewModel); RefreshSequencerTrack(EmitterTrack); MaxEmitterTime = FMath::Max(MaxEmitterTime, EmitterHandleViewModel->GetEmitterViewModel()->GetEndTime()); } TRange CurrentPlaybackRange = NiagaraSequence->MovieScene->GetPlaybackRange(); TRange CurrentWorkingRange = NiagaraSequence->MovieScene->GetEditorData().WorkingRange; NiagaraSequence->MovieScene->SetPlaybackRange(0, FMath::Max(MaxEmitterTime + SequencerEmitterEndPadding, CurrentPlaybackRange.GetUpperBoundValue())); NiagaraSequence->MovieScene->GetEditorData().WorkingRange = TRange( FMath::Min(-SequencerTimeRangePadding, CurrentWorkingRange.GetLowerBoundValue()), FMath::Max(NiagaraSequence->MovieScene->GetPlaybackRange().GetUpperBoundValue() + SequencerTimeRangePadding, CurrentWorkingRange.GetUpperBoundValue())); Sequencer->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::MovieSceneStructureItemsChanged); } UMovieSceneNiagaraEmitterTrack* FNiagaraEffectViewModel::GetTrackForHandleViewModel(TSharedRef EmitterHandleViewModel) { for (UMovieSceneTrack* Track : NiagaraSequence->GetMovieScene()->GetMasterTracks()) { UMovieSceneNiagaraEmitterTrack* EmitterTrack = CastChecked(Track); if (EmitterTrack->GetEmitterHandle() == EmitterHandleViewModel) { return EmitterTrack; } } return nullptr; } void FNiagaraEffectViewModel::RefreshSequencerTrack(UMovieSceneNiagaraEmitterTrack* EmitterTrack) { if(EmitterTrack != nullptr) { TSharedPtr EmitterHandleViewModel = EmitterTrack->GetEmitterHandle(); UNiagaraEmitterProperties* Emitter = EmitterHandleViewModel->GetEmitterViewModel()->GetEmitter(); TArray Sections = EmitterTrack->GetAllSections(); UMovieSceneNiagaraEmitterSection* EmitterSection = Cast(Sections.Num() == 1 ? Sections[0] : nullptr); if (EmitterSection != nullptr && Emitter != nullptr) { EmitterTrack->SetDisplayName(EmitterHandleViewModel->GetNameText()); bool bIsInfinite = EmitterHandleViewModel->GetEmitterViewModel()->GetStartTime() == 0 && EmitterHandleViewModel->GetEmitterViewModel()->GetEndTime() == 0; float StartTime; float EndTime; if (bIsInfinite && Emitter->Bursts.Num() > 0) { StartTime = TNumericLimits::Max(); EndTime = TNumericLimits::Lowest(); for (const FNiagaraEmitterBurst& Burst : Emitter->Bursts) { StartTime = FMath::Min(StartTime, Burst.Time); EndTime = FMath::Max(EndTime, Burst.Time); } } else { StartTime = EmitterHandleViewModel->GetEmitterViewModel()->GetStartTime(); EndTime = EmitterHandleViewModel->GetEmitterViewModel()->GetEndTime(); } EmitterSection->SetEmitterHandle(EmitterHandleViewModel.ToSharedRef()); EmitterSection->SetIsActive(EmitterHandleViewModel->GetIsEnabled()); EmitterSection->SetStartTime(StartTime); EmitterSection->SetEndTime(EndTime); EmitterSection->SetIsInfinite(bIsInfinite); TSharedPtr BurstCurve = EmitterSection->GetBurstCurve(); if (BurstCurve.IsValid()) { BurstCurve->Reset(); for (const FNiagaraEmitterBurst& Burst : Emitter->Bursts) { FMovieSceneBurstKey BurstKey; BurstKey.TimeRange = Burst.TimeRange; BurstKey.SpawnMinimum = Burst.SpawnMinimum; BurstKey.SpawnMaximum = Burst.SpawnMaximum; BurstCurve->AddKeyValue(Burst.Time, BurstKey); } } } } } TRange SequencerDefaultTimeRange(0, 10); void FNiagaraEffectViewModel::SetupSequencer() { NiagaraSequence = NewObject(GetTransientPackage()); NiagaraSequence->MovieScene = NewObject(NiagaraSequence, FName("Niagara Effect MovieScene"), RF_Transactional); NiagaraSequence->MovieScene->SetPlaybackRange(SequencerDefaultTimeRange.GetLowerBoundValue(), SequencerDefaultTimeRange.GetUpperBoundValue()); NiagaraSequence->MovieScene->GetEditorData().ViewRange =TRange( SequencerDefaultTimeRange.GetLowerBoundValue() - SequencerTimeRangePadding, SequencerDefaultTimeRange.GetUpperBoundValue() + SequencerTimeRangePadding); NiagaraSequence->MovieScene->GetEditorData().WorkingRange = NiagaraSequence->MovieScene->GetEditorData().ViewRange; FSequencerViewParams ViewParams(TEXT("NiagaraSequencerSettings")); { ViewParams.InitialScrubPosition = 0; ViewParams.UniqueName = "NiagaraSequenceEditor"; } FSequencerInitParams SequencerInitParams; { SequencerInitParams.ViewParams = ViewParams; SequencerInitParams.RootSequence = NiagaraSequence; SequencerInitParams.bEditWithinLevelEditor = false; SequencerInitParams.ToolkitHost = nullptr; } ISequencerModule &SequencerModule = FModuleManager::LoadModuleChecked< ISequencerModule >("Sequencer"); Sequencer = SequencerModule.CreateSequencer(SequencerInitParams); Sequencer->OnMovieSceneDataChanged().AddRaw(this, &FNiagaraEffectViewModel::SequencerDataChanged); Sequencer->OnGlobalTimeChanged().AddRaw(this, &FNiagaraEffectViewModel::SequencerTimeChanged); Sequencer->SetPlaybackStatus(Effect.GetNumEmitters() > 0 ? EMovieScenePlayerStatus::Playing : EMovieScenePlayerStatus::Stopped); } void FNiagaraEffectViewModel::ResetEffect() { EffectInstance->Reset(FNiagaraEffectInstance::EResetMode::DeferredReset); if (Sequencer->GetPlaybackStatus() == EMovieScenePlayerStatus::Playing) { Sequencer->SetGlobalTime(0.0f); } for (TObjectIterator ComponentIt; ComponentIt; ++ComponentIt) { UNiagaraComponent* Component = *ComponentIt; if (Component->GetAsset() == &Effect) { Component->SynchronizeWithSourceEffect(); Component->GetEffectInstance()->Reset(FNiagaraEffectInstance::EResetMode::DeferredReset); } } SynchronizeEffectDrivenParametersUI(); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); } void FNiagaraEffectViewModel::ReInitializeEffect() { if (EffectInstance.IsValid()) { EffectInstance->Reset(FNiagaraEffectInstance::EResetMode::DeferredReInit); } if (Sequencer.IsValid() && Sequencer->GetPlaybackStatus() == EMovieScenePlayerStatus::Playing) { Sequencer->SetGlobalTime(0.0f); } for (TObjectIterator ComponentIt; ComponentIt; ++ComponentIt) { UNiagaraComponent* Component = *ComponentIt; if (Component->GetAsset() == &Effect) { Component->SynchronizeWithSourceEffect(); Component->GetEffectInstance()->Reset(FNiagaraEffectInstance::EResetMode::DeferredReInit); } } SynchronizeEffectDrivenParametersUI(); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); } struct FParameterCurveData { FRichCurve* Curve; FName Name; FLinearColor Color; UObject* Owner; FGuid ParameterId; TSharedPtr ParameterCollection; }; void GetParameterCurveData(FName EmitterName, FString ScriptName, TSharedPtr ParameterCollection, TArray& OutParameterCurveData) { for (TSharedRef SelectedParameterViewModel : ParameterCollection->GetSelection().GetSelectedObjects()) { UNiagaraDataInterfaceCurveBase* CurveDataInterface = Cast(SelectedParameterViewModel->GetDefaultValueObject()); if (CurveDataInterface != nullptr) { TArray CurveData; CurveDataInterface->GetCurveData(CurveData); for (UNiagaraDataInterfaceCurveBase::FCurveData CurveDataItem : CurveData) { FParameterCurveData ParameterCurveData; ParameterCurveData.Curve = CurveDataItem.Curve; ParameterCurveData.Color = CurveDataItem.Color; ParameterCurveData.Owner = CurveDataInterface; FString EmitterPrefix = EmitterName == NAME_None ? FString() : EmitterName.ToString() + "."; FString ScriptPrefix = ScriptName + "."; FString ParameterName = CurveDataItem.Name == NAME_None ? SelectedParameterViewModel->GetName().ToString() : SelectedParameterViewModel->GetName().ToString() + "."; FString DataName = CurveDataItem.Name == NAME_None ? FString() : CurveDataItem.Name.ToString(); ParameterCurveData.Name = *(EmitterPrefix + ScriptPrefix + ParameterName + DataName); ParameterCurveData.ParameterId = SelectedParameterViewModel->GetId(); ParameterCurveData.ParameterCollection = ParameterCollection; OutParameterCurveData.Add(ParameterCurveData); } } } } void FNiagaraEffectViewModel::ResetCurveData() { CurveOwner.EmptyCurves(); TArray ParameterCurveData; GetParameterCurveData( NAME_None, TEXT("Effect"), EffectScriptViewModel->GetInputCollectionViewModel(), ParameterCurveData); for (TSharedRef EmitterHandleViewModel : EmitterHandleViewModels) { GetParameterCurveData( EmitterHandleViewModel->GetName(), TEXT("Spawn"), EmitterHandleViewModel->GetEmitterViewModel()->GetSpawnScriptViewModel()->GetInputCollectionViewModel(), ParameterCurveData); GetParameterCurveData( EmitterHandleViewModel->GetName(), TEXT("Update"), EmitterHandleViewModel->GetEmitterViewModel()->GetUpdateScriptViewModel()->GetInputCollectionViewModel(), ParameterCurveData); } for (FParameterCurveData& ParameterCurveDataItem : ParameterCurveData) { CurveOwner.AddCurve( *ParameterCurveDataItem.Curve, ParameterCurveDataItem.Name, ParameterCurveDataItem.Color, *ParameterCurveDataItem.Owner, FNiagaraCurveOwner::FNotifyCurveChanged::CreateRaw(this, &FNiagaraEffectViewModel::CurveChanged, ParameterCurveDataItem.ParameterCollection, ParameterCurveDataItem.ParameterId)); } OnCurveOwnerChangedDelegate.Broadcast(); } void FNiagaraEffectViewModel::EmitterHandlePropertyChanged(TSharedRef EmitterHandleViewModel) { // When the emitter handle changes, refresh the effect scripts emitter nodes just in cast the // property that changed was the handles emitter. EffectScriptViewModel->RefreshEmitterNodes(); if (bUpdatingFromSequencerDataChange == false) { RefreshSequencerTrack(GetTrackForHandleViewModel(EmitterHandleViewModel)); } ReInitializeEffect(); } void FNiagaraEffectViewModel::EffectParameterCollectionChanged() { ResetEffect(); } void FNiagaraEffectViewModel::EmitterPropertyChanged(TSharedRef EmitterHandleViewModel) { if (bUpdatingFromSequencerDataChange == false) { RefreshSequencerTrack(GetTrackForHandleViewModel(EmitterHandleViewModel)); } ResetEffect(); } void FNiagaraEffectViewModel::EmitterParameterValueChanged(FGuid ParamterId) { ResetEffect(); } void FNiagaraEffectViewModel::ParameterSelectionChanged() { ResetCurveData(); } void FNiagaraEffectViewModel::EffectParameterValueChanged(FGuid ParamterId) { ResetEffect(); } void FNiagaraEffectViewModel::EffectParameterBindingsChanged() { ReInitializeEffect(); } void FNiagaraEffectViewModel::ScriptCompiled() { ReInitializeEffect(); } void FNiagaraEffectViewModel::CurveChanged(TSharedPtr CollectionViewModel, FGuid ParameterId) { CollectionViewModel->NotifyParameterChangedExternally(ParameterId); } void FNiagaraEffectViewModel::SynchronizeEffectDrivenParametersUI() { for (TSharedRef& EmitterHandleVM : EmitterHandleViewModels) { TSharedRef EmitterVM = EmitterHandleVM->GetEmitterViewModel(); TSharedRef SpawnVM = EmitterVM->GetSpawnScriptViewModel(); TSharedRef UpdateVM = EmitterVM->GetUpdateScriptViewModel(); TSharedRef SpawnInputCollectionVM = SpawnVM->GetInputCollectionViewModel(); TSharedRef UpdateInputCollectionVM = UpdateVM->GetInputCollectionViewModel(); FNiagaraEmitterHandle* EmitterHandle = EmitterHandleVM->GetEmitterHandle(); if (EmitterHandle != nullptr) { SpawnInputCollectionVM->SetAllParametersEditingEnabled(true); UpdateInputCollectionVM->SetAllParametersEditingEnabled(true); SpawnInputCollectionVM->SetAllParametersTooltipOverrides(FText::FromString(FString())); UpdateInputCollectionVM->SetAllParametersTooltipOverrides(FText::FromString(FString())); FText OverrideTextFormat = LOCTEXT("NiagaraEffectTooltipOverride", "Parameter {0} is driven by the effect graph."); const TArray Bindings = Effect.GetParameterBindings(); for (const FNiagaraParameterBinding& Binding : Bindings) { if (Binding.GetDestinationEmitterId() == EmitterHandle->GetId()) { TSharedPtr ParamVM = SpawnInputCollectionVM->GetParameterViewModel(Binding.GetDestinationParameterId()); if (ParamVM.IsValid()) { ParamVM->SetEditingEnabled(false); ParamVM->SetTooltipOverride(FText::Format(OverrideTextFormat, FText::FromName(ParamVM->GetName()))); } ParamVM = UpdateInputCollectionVM->GetParameterViewModel(Binding.GetDestinationParameterId()); if (ParamVM.IsValid()) { ParamVM->SetEditingEnabled(false); ParamVM->SetTooltipOverride(FText::Format(OverrideTextFormat, FText::FromName(ParamVM->GetName()))); } } } const TArray DataInterfaceBindings = Effect.GetDataInterfaceBindings(); for (const FNiagaraParameterBinding& Binding : DataInterfaceBindings) { if (Binding.GetDestinationEmitterId() == EmitterHandle->GetId()) { TSharedPtr ParamVM = SpawnInputCollectionVM->GetParameterViewModel(Binding.GetDestinationParameterId()); if (ParamVM.IsValid()) { ParamVM->SetEditingEnabled(false); ParamVM->SetTooltipOverride(FText::Format(OverrideTextFormat, FText::FromName(ParamVM->GetName()))); } ParamVM = UpdateInputCollectionVM->GetParameterViewModel(Binding.GetDestinationParameterId()); if (ParamVM.IsValid()) { ParamVM->SetEditingEnabled(false); ParamVM->SetTooltipOverride(FText::Format(OverrideTextFormat, FText::FromName(ParamVM->GetName()))); } } } } } } void FNiagaraEffectViewModel::SequencerDataChanged() { bUpdatingFromSequencerDataChange = true; TSet VaildTrackEmitterHandleIds; for (UMovieSceneTrack* Track : NiagaraSequence->GetMovieScene()->GetMasterTracks()) { UMovieSceneNiagaraEmitterTrack* EmitterTrack = CastChecked(Track); TArray Sections = EmitterTrack->GetAllSections(); UMovieSceneNiagaraEmitterSection* EmitterSection = Cast(Sections.Num() == 1 ? Sections[0] : nullptr); if (EmitterSection != nullptr) { VaildTrackEmitterHandleIds.Add(EmitterTrack->GetEmitterHandle()->GetId()); TSharedPtr EmitterHandleViewModel = EmitterTrack->GetEmitterHandle(); if (bCanRenameEmittersFromTimeline) { EmitterHandleViewModel->SetName(*EmitterTrack->GetDisplayName().ToString()); } else { EmitterTrack->SetDisplayName(EmitterHandleViewModel->GetNameText()); } EmitterHandleViewModel->SetIsEnabled(EmitterSection->IsActive()); TSharedPtr EmitterViewModel = EmitterTrack->GetEmitterHandle()->GetEmitterViewModel(); if (EmitterSection->IsInfinite() == false) { EmitterViewModel->SetStartTime(EmitterSection->GetStartTime()); EmitterViewModel->SetEndTime(EmitterSection->GetEndTime()); } TSharedPtr BurstCurve = EmitterSection->GetBurstCurve(); if (BurstCurve.IsValid()) { UNiagaraEmitterProperties* Emitter = EmitterViewModel->GetEmitter(); if (Emitter) { Emitter->Bursts.Empty(); } TArray KeyHandles; for (TKeyTimeIterator KeyIterator = BurstCurve->IterateKeys(); KeyIterator; ++KeyIterator) { KeyHandles.Add(KeyIterator.GetKeyHandle()); } for (const FKeyHandle& KeyHandle : KeyHandles) { auto Key = BurstCurve->GetKey(KeyHandle).GetValue(); FNiagaraEmitterBurst Burst; Burst.Time = Key.Time; Burst.TimeRange = Key.Value.TimeRange; Burst.SpawnMinimum = Key.Value.SpawnMinimum; Burst.SpawnMaximum = Key.Value.SpawnMaximum; if (Emitter) { Emitter->Bursts.Add(Burst); } } } } bUpdatingFromSequencerDataChange = false; } TSet AllEmitterHandleIds; for (TSharedRef EmitterHandleViewModel : EmitterHandleViewModels) { AllEmitterHandleIds.Add(EmitterHandleViewModel->GetId()); } TSet RemovedHandles = AllEmitterHandleIds.Difference(VaildTrackEmitterHandleIds); if (RemovedHandles.Num() > 0) { if (bCanRemoveEmittersFromTimeline) { Effect.RemoveEmitterHandlesById(RemovedHandles); RefreshAll(); } else { RefreshSequencerTracks(); } } EffectInstance->Reset(FNiagaraEffectInstance::EResetMode::DeferredReset); } void FNiagaraEffectViewModel::SequencerTimeChanged() { // Skip the first update after going from stopped to playing because snapping in sequencer may have made the time // reverse by a small amount, and sending that update to the effect will reset it unnecessarily. * EMovieScenePlayerStatus::Type CurrentStatus = Sequencer->GetPlaybackStatus(); bool bStartedPlaying = PreviousStatus == EMovieScenePlayerStatus::Stopped && CurrentStatus == EMovieScenePlayerStatus::Playing; if (CurrentStatus != EMovieScenePlayerStatus::Stopped && bStartedPlaying == false) { EffectInstance->SetDesiredAge(FMath::Max(Sequencer->GetGlobalTime(), 0.0f)); } PreviousStatus = CurrentStatus; } void FNiagaraEffectViewModel::EffectInstanceInitialized() { for (TSharedRef EmitterHandleViewModel : EmitterHandleViewModels) { if (EmitterHandleViewModel->GetEmitterHandle()) { EmitterHandleViewModel->SetSimulation(EffectInstance->GetSimulationForHandle(*EmitterHandleViewModel->GetEmitterHandle())); } } } void FNiagaraEffectViewModel::ResynchronizeAllHandles() { Effect.ResynchronizeAllHandles(); RefreshAll(); } #undef LOCTEXT_NAMESPACE // NiagaraEffectViewModel