void FSubMovieSceneTrackInstance::ClearInstance( IMovieScenePlayer& Player )
{
	TMap< TWeakObjectPtr<USubMovieSceneSection>, TSharedPtr<FMovieSceneSequenceInstance> >::TIterator It =  SubMovieSceneInstances.CreateIterator();
	for( ; It; ++It )
	{
		Player.RemoveMovieSceneInstance( *It.Key().Get(), It.Value().ToSharedRef() );
	}
}
void FMovieSceneSpawnTrackInstance::Update(EMovieSceneUpdateData& UpdateData, const TArray<TWeakObjectPtr<UObject>>& RuntimeObjects, IMovieScenePlayer& Player, FMovieSceneSequenceInstance& SequenceInstance)
{
	IMovieSceneSpawnRegister& SpawnRegister = Player.GetSpawnRegister();
	FMovieSceneSpawnable* Spawnable = SequenceInstance.GetSequence()->GetMovieScene()->FindSpawnable(Track->GetObjectId());

	TRange<float> Range = SequenceInstance.GetTimeRange();

	const bool bIsPreview = Player.IsPreview();

	// If we're evaluating outside of the instance's time range, and the sequence owns the spawnable, there's no reason to evaluate - it should already be destroyed
	if (Spawnable && Spawnable->GetSpawnOwnership() == ESpawnOwnership::InnerSequence && !Range.Contains(UpdateData.Position))
	{
		bool bDestroy = true;
#if WITH_EDITORONLY_DATA
		bDestroy = !Spawnable->ShouldIgnoreOwnershipInEditor();
		// Don't destroy cameras while previewing
		if (bIsPreview && MovieSceneHelpers::CameraComponentFromActor(Cast<AActor>(Spawnable->GetObjectTemplate())))
		{
			bDestroy = false;
		}
#endif
		if (bDestroy)
		{
			SpawnRegister.DestroySpawnedObject(Track->GetObjectId(), SequenceInstance, Player);
			return;
		}
	}

	bool bIsSpawned = false;
	if (Track->Eval(UpdateData.Position, UpdateData.LastPosition, bIsSpawned))
	{
		// Spawn the object if needed
		if (bIsSpawned && RuntimeObjects.Num() == 0)
		{
			SpawnRegister.SpawnObject(Track->GetObjectId(), SequenceInstance, Player);
		}

		// Destroy the object if needed
		if (!bIsSpawned && RuntimeObjects.Num() != 0)
		{
			SpawnRegister.DestroySpawnedObject(Track->GetObjectId(), SequenceInstance, Player);
		}
	}
}
void FMovieSceneShotTrackInstance::RefreshInstance( const TArray<UObject*>& RuntimeObjects, IMovieScenePlayer& Player )
{
    const TArray<UMovieSceneSection*>& ShotSections = SubMovieSceneTrack->GetAllSections();

    RuntimeCameraObjects.Empty( ShotSections.Num() );

    for( UMovieSceneSection* Section : ShotSections )
    {
        // @todo Sequencer - Sub-moviescenes: Get the cameras from the root movie scene instance.  We should support adding cameras for sub-moviescenes as shots
        TArray<UObject*> CameraObjects;
        Player.GetRuntimeObjects(Player.GetRootMovieSceneSequenceInstance(), CastChecked<UMovieSceneShotSection>( Section )->GetCameraGuid(), CameraObjects );
        if( CameraObjects.Num() == 1 )
        {
            RuntimeCameraObjects.Add( CameraObjects[0] );
        }
        else
        {
            // No valid camera object was found, take up space.  There should be one entry per section
            RuntimeCameraObjects.Add( nullptr );
        }
    }

    FSubMovieSceneTrackInstance::RefreshInstance( RuntimeObjects, Player );
}
void FMovieSceneSequenceInstance::UpdateObjectBinding(const FGuid& ObjectId, IMovieScenePlayer& Player)
{
	if(MovieSceneSequence.IsValid())
	{
		UMovieSceneSequence* Sequence = MovieSceneSequence.Get();
		auto* BindingInstance = ObjectBindingInstances.Find(ObjectId);

		if (!BindingInstance || !Sequence)
		{
			return;
		}

		// Update the runtime objects
		BindingInstance->RuntimeObjects.Reset();

		TWeakObjectPtr<UObject>* WeakSpawnedObject = SpawnedObjects.Find(ObjectId);
		if (WeakSpawnedObject)
		{
			UObject* SpawnedObject = WeakSpawnedObject->Get();
			if (SpawnedObject)
			{
				BindingInstance->RuntimeObjects.Add(SpawnedObject);
			}
		}
		else
		{
			Player.GetRuntimeObjects(SharedThis(this), BindingInstance->ObjectGuid, BindingInstance->RuntimeObjects);
		}

		const FMovieSceneBinding* ObjectBinding = Sequence->GetMovieScene()->GetBindings().FindByPredicate([&](const FMovieSceneBinding& In){
			return In.GetObjectGuid() == ObjectId;
		});

		// Refresh the instance map, if we found the binding itself
		if (ObjectBinding)
		{
			RefreshInstanceMap(ObjectBinding->GetTracks(), BindingInstance->RuntimeObjects, BindingInstance->TrackInstances, Player);
		}
	}
}
void FMovieSceneCinematicShotTrackInstance::RestoreState(const TArray<TWeakObjectPtr<UObject>>& RuntimeObjects, IMovieScenePlayer& Player, FMovieSceneSequenceInstance& SequenceInstance)
{
	FMovieSceneSubTrackInstance::RestoreState(RuntimeObjects, Player, SequenceInstance);

	Player.UpdateCameraCut(nullptr, nullptr);

	//@todo Need to manage how this interacts with the fade track
	/*
	// Reset editor preview/fade
	EMovieSceneViewportParams ViewportParams;
	ViewportParams.SetWhichViewportParam = (EMovieSceneViewportParams::SetViewportParam)(EMovieSceneViewportParams::SVP_FadeAmount | EMovieSceneViewportParams::SVP_FadeColor);
	ViewportParams.FadeAmount = 0.f;
	ViewportParams.FadeColor = FLinearColor::Black;

	TMap<FViewportClient*, EMovieSceneViewportParams> ViewportParamsMap;
	Player.GetViewportSettings(ViewportParamsMap);
	for (auto ViewportParamsPair : ViewportParamsMap)
	{
		ViewportParamsMap[ViewportParamsPair.Key] = ViewportParams;
	}
	Player.SetViewportSettings(ViewportParamsMap);
	*/
}
void FMovieSceneShotTrackInstance::ClearInstance( IMovieScenePlayer& Player )
{
    FSubMovieSceneTrackInstance::ClearInstance( Player );
    Player.UpdateCameraCut( nullptr, false );
}
void FMovieSceneSequenceInstance::RefreshInstance( IMovieScenePlayer& Player )
{
	if(MovieSceneSequence.IsValid())
	{
		UMovieScene* MovieScene = MovieSceneSequence->GetMovieScene();
		TimeRange = MovieScene->GetPlaybackRange();

		UMovieSceneTrack* CameraCutTrack = MovieScene->GetCameraCutTrack();

		if (CameraCutTrack != nullptr)
		{
			FMovieSceneInstanceMap CameraCutTrackInstanceMap;

			if (CameraCutTrackInstance.IsValid())
			{
				CameraCutTrackInstanceMap.Add(CameraCutTrack, CameraCutTrackInstance);
			}

			TArray<TWeakObjectPtr<UObject>> Objects;
			TArray<UMovieSceneTrack*> Tracks;
			Tracks.Add(CameraCutTrack);
			RefreshInstanceMap(Tracks, Objects, CameraCutTrackInstanceMap, Player);

			CameraCutTrackInstance = CameraCutTrackInstanceMap.FindRef(CameraCutTrack);
		}
		else if(CameraCutTrackInstance.IsValid())
		{
			CameraCutTrackInstance->ClearInstance(Player, *this);
			CameraCutTrackInstance.Reset();
		}

		// Get all the master tracks and create instances for them if needed
		const TArray<UMovieSceneTrack*>& MasterTracks = MovieScene->GetMasterTracks();
		TArray<TWeakObjectPtr<UObject>> Objects;
		RefreshInstanceMap( MasterTracks, Objects, MasterTrackInstances, Player );

		TSet< FGuid > FoundObjectBindings;
		// Get all tracks for each object binding and create instances for them if needed
		const TArray<FMovieSceneBinding>& ObjectBindings = MovieScene->GetBindings();
		for( int32 BindingIndex = 0; BindingIndex < ObjectBindings.Num(); ++BindingIndex )
		{
			const FMovieSceneBinding& ObjectBinding = ObjectBindings[BindingIndex];

			// Create an instance for this object binding
			FMovieSceneObjectBindingInstance& BindingInstance = ObjectBindingInstances.FindOrAdd( ObjectBinding.GetObjectGuid() );
			BindingInstance.ObjectGuid = ObjectBinding.GetObjectGuid();

			FoundObjectBindings.Add( ObjectBinding.GetObjectGuid() );

			// Populate the runtime objects for this instance of the binding.
			// @todo sequencer: SubSequences: We need to know which actors were removed and which actors were added so we know which saved actor state to restore/create
			BindingInstance.RuntimeObjects.Empty();
			Player.GetRuntimeObjects( SharedThis( this ), BindingInstance.ObjectGuid, BindingInstance.RuntimeObjects );

			// Refresh the instance's tracks
			const TArray<UMovieSceneTrack*>& Tracks = ObjectBinding.GetTracks();
			RefreshInstanceMap( Tracks, BindingInstance.RuntimeObjects, BindingInstance.TrackInstances, Player );
		}

		IMovieSceneSpawnRegister& SpawnRegister = Player.GetSpawnRegister();

		// Remove object binding instances which are no longer bound
		TMap<FGuid, FMovieSceneObjectBindingInstance>::TIterator It = ObjectBindingInstances.CreateIterator();
		for( ; It; ++It )
		{
			if( !FoundObjectBindings.Contains( It.Key() ) )
			{
				SpawnRegister.DestroySpawnedObject(It.Key(), *this, Player);

				// The instance no longer is bound to an existing guid
				It.RemoveCurrent();
			}
		}
	}
}
void FMovieSceneCinematicShotTrackInstance::ClearInstance(IMovieScenePlayer& Player, FMovieSceneSequenceInstance& SequenceInstance)
{
	FMovieSceneSubTrackInstance::ClearInstance(Player, SequenceInstance);

	Player.UpdateCameraCut(nullptr, nullptr);
}