Loop Timer stops without reason

I set a timer loop using an actor. I don’t know why, but it stops calling the call-back function without any reasons and error messages.

I have a timeline object and create a timer function to loop the FTimeline.

/**
* UKTimelineObject holds a FTimeline.
* Events can be triggered at keyframes along the timeline.
* Floats, vectors, and colors are interpolated between keyframes along the timeline.
*/
UCLASS()
class UKTimelineObject : public UObject
{
	GENERATED_UCLASS_BODY()

public:

	/**
	 * @brief Initializes the timeline with a vector curve and set the tick and finish call-back functions.
	 *
	 * @param VectorCurve		   If non-null, the vector curve.
	 * @param TickFunc			   The function to call on every tick.
	 * @param FinishedFunc		   The finished function.
	 * @param InOwner			   The actor owner.
	 * @param InDeltaTime		   (Optional) the delta time between the play rate value. Default is 1.0
	 * @param InPlayRate		   (Optional) the play rate. Default is 1.0
	 * @param InLengthMode		   (Optional) the in length mode. Default is ETimelineLengthMode::TL_TimelineLength.
	 * @param InLength			   (Optional) the initial length. Default is 100.							   
	 * @param PropertyName		   (Optional) name of the property. Default is NAME_None.
	 */
	void Initialize(UCurveVector* VectorCurve, FOnTimelineVector TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime = 1.0f, float InPlayRate = 1.0f, ETimelineLengthMode InLengthMode = ETimelineLengthMode::TL_TimelineLength, const float InLength = 100.0f, FName PropertyName = NAME_None);

	/**
	* @brief Initializes the timeline with a float curve and set the tick and finish call-back functions.
	*
	* @param FloatCurve			   If non-null, the float curve.
	* @param TickFunc			   The function to call on every tick.
	* @param FinishedFunc		   The finished function.
	* @param InOwner			   The actor owner.
	* @param InDeltaTime		   (Optional) the delta time between the play rate value. Default is 1.0
	* @param InPlayRate			   (Optional) the play rate. Default is 1.0
	* @param InLengthMode		   (Optional) the in length mode. Default is ETimelineLengthMode::TL_TimelineLength.
	* @param InLength			   (Optional) the initial length. Default is 100.
	* @param PropertyName		   (Optional) name of the property. Default is NAME_None.
	*/
	void Initialize(UCurveFloat* FloatCurve, FOnTimelineFloat TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime = 1.0f, float InPlayRate = 1.0f, ETimelineLengthMode InLengthMode = ETimelineLengthMode::TL_TimelineLength, const float InLength = 100.0f, FName PropertyName = NAME_None);

	/**
	* @brief Initializes the timeline with a linear color curve and set the tick and finish call-back functions.
	*
	* @param LinearColorCurve	   If non-null, the linear color curve.
	* @param TickFunc			   The function to call on every tick.
	* @param FinishedFunc		   The finished function.
	* @param InOwner			   The actor owner.
	* @param InDeltaTime		   (Optional) the delta time between the play rate value. Default is 1.0
	* @param InPlayRate		       (Optional) the play rate. Default is 1.0
	* @param InLengthMode		   (Optional) the in length mode. Default is ETimelineLengthMode::TL_TimelineLength.
	* @param InLength			   (Optional) the initial length. Default is 100.
	* @param PropertyName		   (Optional) name of the property. Default is NAME_None.
	*/
	void Initialize(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime = 1.0f, float InPlayRate = 1.0f, ETimelineLengthMode InLengthMode = ETimelineLengthMode::TL_TimelineLength, const float InLength = 100.0f, FName PropertyName = NAME_None);

	/** Start playback of timeline */
	void Play();

	/** Start playback of timeline from the start */
	void PlayFromStart();

	/** Start playback of timeline in reverse */
	void Reverse();

	/** Start playback of timeline in reverse from the end */
	void ReverseFromEnd();

	/** Stop playback of timeline */
	void Stop();

	/** Get whether this timeline is playing or not. */
	bool IsPlaying() const;

	/** Get whether we are reversing or not */
	bool IsReversing() const;

	/** Jump to a position in the timeline. If bFireEvents is true, event functions will fire, otherwise will not. */
	void SetPlaybackPosition(float NewPosition, bool bFireEvents);

	/** Get the current playback position of the Timeline */
	float GetPlaybackPosition() const;

	/** true means we whould loop, false means we should not. */
	void SetLooping(bool bNewLooping);

	/** Get whether we are looping or not */
	bool IsLooping() const;

	/** Sets the new play rate for this timeline */
	void SetPlayRate(float NewRate);

	/** Get the current play rate for this timeline */
	float GetPlayRate() const;

	/**
	 * @brief Sets the delta time between play rate for this timeline.
	 * @param NewDeltaTime The new delta time.
	 */
	void SetDeltaTime(float NewDeltaTime);

	/** Get the current delta time between play rate for this timeline */
	float GetDeltaTime() const;

	/** Set the new playback position time to use */
	void SetNewTime(float NewTime);

	/** Get length of the timeline */
	float GetTimelineLength() const;

	/** Set length of the timeline */
	void SetTimelineLength(float NewLength);

	/** Sets the length mode of the timeline */
	void SetTimelineLengthMode(ETimelineLengthMode NewLengthMode);

	/** Get the initial length of the timeline */
	float GetInitialTimelineLength() const;

	/**
	 * @brief Sets initial timeline length.
	 * @param InLength The new initial time length.
	 */
	void SetInitialTimelineLength(const float InLength);

	/** @brief Sets back the timeline length to initial length. */
	void SetTimelineLengthToInitial();

	UFUNCTION()
	void OnRep_Timeline();

	/** Add a callback event to the timeline */
	void AddEvent(float Time, FOnTimelineEvent EventFunc);

	/** Add a vector interpolation to the timeline */
	void AddInterpVector(UCurveVector* VectorCurve, FOnTimelineVector InterpFunc, FName PropertyName = NAME_None);

	/** Add a float interpolation to the timeline */
	void AddInterpFloat(UCurveFloat* FloatCurve, FOnTimelineFloat InterpFunc, FName PropertyName = NAME_None);

	/** Add a linear color interpolation to the timeline */
	void AddInterpLinearColor(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor InterpFunc, FName PropertyName = NAME_None);

	/** Optionally provide an object to automatically update properties on */
	void SetPropertySetObject(UObject* NewPropertySetObject);

	/** Set the delegate to call after each timeline tick */
	void SetTimelinePostUpdateFunc(FOnTimelineEvent NewTimelinePostUpdateFunc);

	/** Set the delegate to call when timeline is finished */
	void SetTimelineFinishedFunc(FOnTimelineEvent NewTimelineFinishedFunc);

	/** Set the delegate to call when timeline is finished */
	void SetDirectionPropertyName(FName DirectionPropertyName);

	/** Get all curves used by the Timeline 
	void GetAllCurves(TSet<class UCurveBase*>& InOutCurves) const;
	*/

private:

	/**
	* @brief Activates the timer for ticking the timeline.
	*/
	void Activate();

	/**
	* @brief Deactivates the timer for ticking the timeline.
	*/
	void Deactivate();

	/**
	 * @brief Timer timeline on tick call-back.
	 */
	void TimerTimelineTick();

private:
	/** The actual timeline structure */
	UPROPERTY(ReplicatedUsing = OnRep_Timeline)
	FTimeline	TheTimeline;
	/** @brief The initial timeline length. */
	float InitialTimelineLength;
	/** @brief The delta time used for ticking the timeline. */
	float DeltaTime;
	/** @brief Handle of the timer for ticking the timeline. */
	FTimerHandle TimerTimelineHandle;
	/** @brief The actor owning this timeline object. Needed to access the GetWorlTimerManager(). */
	const AActor* TheActor;

};



UKTimelineObject::UKTimelineObject(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
	, InitialTimelineLength(5.0f)
	, DeltaTime(0.2f)
	, TheActor(nullptr)
{
}

void UKTimelineObject::Initialize(UCurveVector* VectorCurve, FOnTimelineVector TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime, float InPlayRate, ETimelineLengthMode InLengthMode, const float InLength, FName PropertyName)
{
	TheTimeline.AddInterpVector(VectorCurve, TickFunc, PropertyName);
	TheTimeline.SetTimelineFinishedFunc(FinishedFunc);
	TheTimeline.SetTimelineLengthMode(InLengthMode);

	DeltaTime = InDeltaTime;
	SetPlayRate(InPlayRate);
	TheActor = InOwner;
	SetInitialTimelineLength(InLength);
}

void UKTimelineObject::Initialize(UCurveFloat* FloatCurve, FOnTimelineFloat TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime, float InPlayRate, ETimelineLengthMode InLengthMode, const float InLength, FName PropertyName)
{
	TheTimeline.AddInterpFloat(FloatCurve, TickFunc, PropertyName);
	TheTimeline.SetTimelineFinishedFunc(FinishedFunc);
	TheTimeline.SetTimelineLengthMode(InLengthMode);

	DeltaTime = InDeltaTime;
	SetPlayRate(InPlayRate);
	TheActor = InOwner;
	SetInitialTimelineLength(InLength);
}

void UKTimelineObject::Initialize(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime, float InPlayRate, ETimelineLengthMode InLengthMode, const float InLength, FName PropertyName)
{
	TheTimeline.AddInterpLinearColor(LinearColorCurve, TickFunc, PropertyName);
	TheTimeline.SetTimelineFinishedFunc(FinishedFunc);
	TheTimeline.SetTimelineLengthMode(InLengthMode);

	DeltaTime = InDeltaTime;
	SetPlayRate(InPlayRate);
	TheActor = InOwner;
	SetInitialTimelineLength(InLength);
}


void UKTimelineObject::Activate()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Activate: DeltaTime=%f"), DeltaTime);
	if (TheActor && !TimerTimelineHandle.IsValid())
		TheActor->GetWorldTimerManager().SetTimer(TimerTimelineHandle, this, &UKTimelineObject::TimerTimelineTick, DeltaTime, true, 0.0f);
	else
	{
		UE_LOG(LogDebug, Warning, TEXT("UKTimelineObject::Activate: TimerTimelineHandle is already running"));
	}
}

void UKTimelineObject::Deactivate()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Deactivate: ClearTimer"));
	if (TheActor)
	{
		TheActor->GetWorldTimerManager().ClearTimer(TimerTimelineHandle);
	}
	TimerTimelineHandle.Invalidate();
}

void UKTimelineObject::TimerTimelineTick()
{
	if (TheTimeline.IsPlaying())
	{
		UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::TimerTimelineTick: GetTimelineLength=%f   GetPlayRate=%f   GetPosition=%f   DeltaTime=%f"), GetTimelineLength(), GetPlayRate(), GetPlaybackPosition(), GetDeltaTime());
		TheTimeline.TickTimeline(GetPlayRate());
	}
	else
	{
		UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::TimerTimelineTick: Deactivate"));
		Deactivate();
	}
}

void UKTimelineObject::Play()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Play"));
	Activate();
	TheTimeline.Play();
}

void UKTimelineObject::PlayFromStart()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::PlayFromStart"));
	Activate();
	TheTimeline.PlayFromStart();
}

void UKTimelineObject::Reverse()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Reverse"));
	Activate();
	TheTimeline.Reverse();
}

void UKTimelineObject::ReverseFromEnd()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::ReverseFromEnd"));
	Activate();
	TheTimeline.ReverseFromEnd();
}

void UKTimelineObject::Stop()
{
	UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Stop"));
	TheTimeline.Stop();
}

bool UKTimelineObject::IsPlaying() const
{
	return TheTimeline.IsPlaying();
}

void UKTimelineObject::AddEvent(float Time, FOnTimelineEvent Event)
{
	TheTimeline.AddEvent(Time, Event);
}

void UKTimelineObject::AddInterpVector(UCurveVector* VectorCurve, FOnTimelineVector InterpFunc, FName PropertyName)
{
	TheTimeline.AddInterpVector(VectorCurve, InterpFunc, PropertyName);
}

void UKTimelineObject::AddInterpFloat(UCurveFloat* FloatCurve, FOnTimelineFloat InterpFunc, FName PropertyName)
{
	TheTimeline.AddInterpFloat(FloatCurve, InterpFunc, PropertyName);
}

void UKTimelineObject::AddInterpLinearColor(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor InterpFunc, FName PropertyName)
{
	TheTimeline.AddInterpLinearColor(LinearColorCurve, InterpFunc, PropertyName);
}

void UKTimelineObject::SetPlaybackPosition(float NewPosition, bool bFireEvents)
{
	TheTimeline.SetPlaybackPosition(NewPosition, bFireEvents);
}

float UKTimelineObject::GetPlaybackPosition() const
{
	return TheTimeline.GetPlaybackPosition();
}

void UKTimelineObject::SetLooping(bool bNewLooping)
{
	TheTimeline.SetLooping(bNewLooping);
}

bool UKTimelineObject::IsLooping() const
{
	return TheTimeline.IsLooping();
}

bool UKTimelineObject::IsReversing() const
{
	return TheTimeline.IsReversing();
}

void UKTimelineObject::SetPlayRate(float NewRate)
{
	TheTimeline.SetPlayRate(NewRate);
}

float UKTimelineObject::GetPlayRate() const
{
	return TheTimeline.GetPlayRate();
}

void UKTimelineObject::SetDeltaTime(float NewDeltaTime)
{
	DeltaTime = NewDeltaTime;
}

float UKTimelineObject::GetDeltaTime() const
{
	return DeltaTime;
}

void UKTimelineObject::SetNewTime(float NewTime)
{
	TheTimeline.SetNewTime(NewTime);
}


float UKTimelineObject::GetTimelineLength() const
{
	return TheTimeline.GetTimelineLength();
}

void UKTimelineObject::SetTimelineLength(float NewLength)
{
	return TheTimeline.SetTimelineLength(NewLength);
}

void UKTimelineObject::SetTimelineLengthMode(ETimelineLengthMode NewLengthMode)
{
	TheTimeline.SetTimelineLengthMode(NewLengthMode);
}

float UKTimelineObject::GetInitialTimelineLength() const
{
	return InitialTimelineLength;
}

void UKTimelineObject::SetInitialTimelineLength(const float InLength)
{
	InitialTimelineLength = InLength;
	SetTimelineLengthToInitial();
}

void UKTimelineObject::SetTimelineLengthToInitial()
{
	SetTimelineLength(InitialTimelineLength);
}


void UKTimelineObject::SetPropertySetObject(UObject* NewPropertySetObject)
{
	TheTimeline.SetPropertySetObject(NewPropertySetObject);
}

void UKTimelineObject::SetTimelinePostUpdateFunc(FOnTimelineEvent NewTimelinePostUpdateFunc)
{
	TheTimeline.SetTimelinePostUpdateFunc(NewTimelinePostUpdateFunc);
}

void UKTimelineObject::SetTimelineFinishedFunc(FOnTimelineEvent NewTimelineFinishedFunc)
{
	TheTimeline.SetTimelineFinishedFunc(NewTimelineFinishedFunc);
}

void UKTimelineObject::SetDirectionPropertyName(FName DirectionPropertyName)
{
	TheTimeline.SetDirectionPropertyName(DirectionPropertyName);
}

/* Linker error. Can't find TheTimeline.GetAllCurves.
void UKTimelineObject::GetAllCurves(TSet<class UCurveBase*>& InOutCurves) const
{
	TheTimeline.GetAllCurves(InOutCurves);
}
*/

void UKTimelineObject::OnRep_Timeline()
{

}

void UKTimelineObject::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(UKTimelineObject, TheTimeline);
}

I initialize the object using the player character (AActor)

		UKTimelineObject* Timeline = NewObject<UKTimelineObject>(UKTimelineObject::StaticClass());
		Timeline->SetFlags(RF_MarkAsRootSet); // Not garbage collected

			if (TemporaryUpDownCurve)
			{
				FOnTimelineFloat OnTick;
				OnTick.BindUFunction(this, "TempEnergyDecayRateFactorTimelineTick");
				FOnTimelineEvent OnFinish;
				OnFinish.BindUFunction(this, "TempEnergyDecayRateFactorTimelineFinish");
				Timeline->Initialize(TemporaryUpDownCurve, OnTick, OnFinish, this);
				bCreated = true;
			}

When I start the object, it ticks several times (not always the same occurrences) and stops calling the UKTimelineObject::TimerTimelineTick()

I don’t know if someone faced the same problem with looping timer ?

Txs.
D.

Solved.
link text