FTimeline SetPlaybackPosition InterpFuncStatic is cleared

FTimeline SetPlaybackPosition InterpFuncStatic is cleared

Hi,

I think there is a bug in the void FTimeline::SetPlaybackPosition(float NewPosition, bool bFireEvents).

I have in my class

/**
* @brief The energy data curve when the event EnergyUp is called.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Curves")
UCurveFloat* EnergyUpCurve;

UFUNCTION()
void EnergyLevelTimelineTick(float value);

/** @brief The energy level timeline. */
FTimeline	EnergyLevelTimeline;

/** @brief The energy level timeline tick function callback. */
FOnTimelineFloatStatic	EnergyLevelTimelineTickFunction;

In the cpp, I do initialization and works.

void AKPlayerCharacter::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	if (EnergyUpCurve)
	{
		EnergyLevelTimeline = FTimeline();
		EnergyLevelTimelineTickFunction.BindUFunction(this, "EnergyLevelTimelineTick");
		EnergyLevelTimeline.AddInterpFloat(EnergyUpCurve, EnergyLevelTimelineTickFunction);
	}
	...
}

The EnergyLevelTimeline.AddInterpFloat add correctly my call - back.

void FTimeline::AddInterpLinearColor(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColorStatic InterpFunc)
{
 	FTimelineLinearColorTrack NewEntry;
 	NewEntry.LinearColorCurve = LinearColorCurve;
  	NewEntry.InterpFuncStatic = InterpFunc;
    
  	InterpLinearColors.Add(NewEntry);
}

I checked the array and everything is fine.

When I Play the timeline EnergyLevelTimeline.PlayFromStart();
The function

void FTimeline::SetPlaybackPosition(float NewPosition, bool bFireEvents) is called during the loop.
...
// Iterate over each float interpolation
for (int32 InterpIdx = 0; InterpIdx<InterpFloats.Num(); InterpIdx++)
{
	FTimelineFloatTrack& FloatEntry = InterpFloats[InterpIdx];
	if (FloatEntry.FloatCurve && (FloatEntry.InterpFunc.IsBound() || FloatEntry.FloatPropertyName != NAME_None || FloatEntry.InterpFuncStatic.IsBound()))
	{
		// Get float from func
		const float Val = FloatEntry.FloatCurve->GetFloatValue(Position);

		// Pass float to specified function
		FloatEntry.InterpFunc.ExecuteIfBound(Val);

		// Set float property
		if (PropSetObject)
		{
			if (FloatEntry.FloatProperty == NULL)
			{
				FloatEntry.FloatProperty = FindField<UFloatProperty>(PropSetObject->GetClass(), FloatEntry.FloatPropertyName);
				if (FloatEntry.FloatProperty == NULL)
				{
					UE_LOG(LogTimeline, Log, TEXT("SetPlaybackPosition: No float property '%s' in '%s'"), *FloatEntry.FloatPropertyName.ToString(), *PropSetObject->GetName());
				}
			}
			if (FloatEntry.FloatProperty)
			{
				FloatEntry.FloatProperty->SetPropertyValue_InContainer(PropSetObject, Val);
			}
		}
		// Pass float to non-dynamic version of the specified function
		FloatEntry.InterpFuncStatic.ExecuteIfBound(Val);
	}
}
...

The first time, my function is called, FloatEntry.InterpFuncStatic is correct.

But just after the call, InterpFuncStatic member var is cleared.

That’s why my call-back function is never called from the SetPlaybackPosition.
Is there a way to avoid the SetPlaybackPosition to clear the InterpFuncStatic member var ?

Have nice day,
Dominique

In fact I didn’t understood the FTimeLine struct.
TickTimeline(float DeltaTime) function must be called using a timer or from a Tick() function.

If you do that, then all call-back functions are called.

Dominique