Hello.
Clean-ish solution to do that would require to modify the engine (FTimerManager class to be specific).You’d need to expose a function that either returns non-const pointer toFTimerData (and then call Execute on inner TimerDelegate) or does that for your without exposing such data - this would probably be safer solution.
As an ugly workaround without modifying the engine you’d have to duplicate some data from FTimerManager.
You’d have to have storage that would hold map timer handle → delegate, and custom functions for setting up/clearing/firing timers.
Storage would be something like this:
struct FStorageEntry
{
FStorageEntry(const FTimerHandle& InHandle, const FTimerDelegate& InDelegate)
: Handle(InHandle)
, Delegate(InDelegate)
{}
FTimerHandle Handle;
FTimerDelegate Delegate;
};
// TMap<FTimerHandle, FTimerDelegate> in most cases would be more efficient here
// but FTimerHandle cannot be used as key unfortunately.
TArray<FStorageEntry> Storage;
And setting up/execution functions:
void UCustomTimerManager::SetupTimer(FTimerHandle& OutTimwer)
{
if( GEngine )
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Yellow, TEXT("Setting up timer"));
}
UWorld* World = GetWorld();
if( !World ) return;
FTimerDelegate Delegate;
Delegate.BindUObject(this, &UCustomTimerManager::TimerFunction);
World->GetTimerManager().SetTimer(OutTimwer, Delegate, 10.f, false);
Storage.Add(FStorageEntry(OutTimwer, Delegate));
}
void UCustomTimerManager::ExecuteTimer(FTimerHandle& InOutTimerHandle)
{
if( GEngine )
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Yellow, TEXT("Executing timer"));
}
if( !InOutTimerHandle.IsValid() ) return;
UWorld* World = GetWorld(); // you should make sure this manager can actually reference to world
if( !World ) return;
for( int32 It = 0; It < Storage.Num(); ++It )
{
if( Storage[It].Handle == InOutTimerHandle )
{
Storage[It].Delegate.Execute();
Storage.RemoveAt(It);
World->GetTimerManager().ClearTimer(InOutTimerHandle);
break;
}
}
}
// Just for testing purposes
void UCustomTimerManager::TimerFunction()
{
if( GEngine )
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Yellow, TEXT("Timer function executed"));
}
}
This is not a complete solution ofc, but you should get the idea from that. Tested and works.
Personally, I’d prefer to modify the engine as 2nd solution is kind of ugly imo.
Cheers.