Can't create custom TickFunction in any Object

Just like title says. I’\m trying to add custom Tick Function to ActorComponent (and Other objects), and this happen:

USTRUCT()
struct FAFMessageTick : public FTickFunction
{
	GENERATED_USTRUCT_BODY()
	/**  AActor  that is the target of this tick **/
	class UGAAbilitiesComponent* Target;

	/**
	* Abstract function actually execute the tick.
	* @param DeltaTime - frame time to advance, in seconds
	* @param TickType - kind of tick for this frame
	* @param CurrentThread - thread we are executing on, useful to pass along as new tasks are created
	* @param MyCompletionGraphEvent - completion event for this task. Useful for holding the completetion of this task until certain child tasks are complete.
	**/
	virtual void ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) override;
	/** Abstract function to describe this tick. Used to print messages about illegal cycles in the dependency graph **/
	virtual FString DiagnosticMessage() override;
};

void FAFMessageTick::ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{
	if (Target && !Target->IsPendingKillOrUnreachable() && Target->bRegistered)
	{
		if (TickType != LEVELTICK_ViewportsOnly || TickType == LEVELTICK_ViewportsOnly)
		{
			FScopeCycleCounterUObject ActorScope(Target);
			Target->TickMessageQueue(DeltaTime, TickType, *this);
		}
	}
}

FString FAFMessageTick::DiagnosticMessage()
{
	return Target->GetFullName() + TEXT("[TickAction]");
}


UPROPERTY()
	FAFMessageTick MessageQueueTick;


UGAAbilitiesComponent::UGAAbilitiesComponent(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	bWantsInitializeComponent = true;
	bIsAnyAbilityActive = false;
	bAutoActivate = true;
	//bAutoRegister = true;
	/*PrimaryComponentTick.bCanEverTick = false;
	PrimaryComponentTick.bStartWithTickEnabled = false;
	PrimaryComponentTick.bRunOnAnyThread = false;
	PrimaryComponentTick.bAllowTickOnDedicatedServer = true;
	PrimaryComponentTick.TickGroup = ETickingGroup::TG_PostUpdateWork;*/


	MessageQueueTick.bCanEverTick = true;
	MessageQueueTick.bRunOnAnyThread = false;
	MessageQueueTick.bAllowTickOnDedicatedServer = true;
	MessageQueueTick.TickGroup = ETickingGroup::TG_PrePhysics;
}
void UGAAbilitiesComponent::RegisterComponentTickFunctions(bool bRegister)
{
	Super::RegisterComponentTickFunctions(bRegister);

		SetupActorComponentTickFunction(&MessageQueueTick);
		MessageQueueTick.Target = this;
		MessageQueueTick.RegisterTickFunction(GetWorld()->PersistentLevel);
		MessageQueueTick.SetTickFunctionEnable(bRegister);
}

CallStack:

UE4Editor-Engine-Win64-Debug.dll!FTickTaskLevel::RemoveTickFunction(FTickFunction * TickFunction) Line 1204	C++
UE4Editor-Engine-Win64-Debug.dll!FTickTaskManager::RemoveTickFunction(FTickFunction * TickFunction) Line 1520	C++
UE4Editor-Engine-Win64-Debug.dll!FTickFunction::UnRegisterTickFunction() Line 1656	C++
UE4Editor-Engine-Win64-Debug.dll!FTickFunction::~FTickFunction() Line 1625	C++
UE4Editor-AbilityFramework-Win64-Debug.dll!UGAAbilitiesComponent::TickMessageQueue(float DeltaTime, ELevelTick TickType, FAFMessageTick TickFunction) Line 80	C++
UE4Editor-AbilityFramework-Win64-Debug.dll!FAFMessageTick::ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 36	C++
UE4Editor-Engine-Win64-Debug.dll!FTickFunctionTask::DoTask(ENamedThreads::Type CurrentThread, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 269	C++
UE4Editor-Engine-Win64-Debug.dll!TGraphTask<FTickFunctionTask>::ExecuteTask(TArray<FBaseGraphTask *,FDefaultAllocator> & NewTasks, ENamedThreads::Type CurrentThread) Line 885	C++
UE4Editor-Core-Win64-Debug.dll!FNamedTaskThread::ProcessTasksNamedThread(int QueueIndex, bool bAllowStall) Line 954	C++
UE4Editor-Core-Win64-Debug.dll!FNamedTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 701	C++
UE4Editor-Core-Win64-Debug.dll!FTaskGraphImplementation::ProcessThreadUntilRequestReturn(ENamedThreads::Type CurrentThread) Line 1748	C++
UE4Editor-Core-Win64-Debug.dll!FTaskGraphImplementation::WaitUntilTasksComplete(const TArray<TRefCountPtr<FGraphEvent>,TInlineAllocator<4,FDefaultAllocator> > & Tasks, ENamedThreads::Type CurrentThreadIfKnown) Line 1798	C++
UE4Editor-Engine-Win64-Debug.dll!FTickTaskSequencer::ReleaseTickGroup(ETickingGroup WorldTickGroup, bool bBlockTillComplete) Line 538	C++
UE4Editor-Engine-Win64-Debug.dll!FTickTaskManager::RunTickGroup(ETickingGroup Group, bool bBlockTillComplete) Line 1450	C++
UE4Editor-Engine-Win64-Debug.dll!UWorld::RunTickGroup(ETickingGroup Group, bool bBlockTillComplete) Line 758	C++
UE4Editor-Engine-Win64-Debug.dll!UWorld::Tick(ELevelTick TickType, float DeltaSeconds) Line 1373	C++
UE4Editor-UnrealEd-Win64-Debug.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 1634	C++
UE4Editor-UnrealEd-Win64-Debug.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 391	C++
UE4Editor-Win64-Debug.exe!FEngineLoop::Tick() Line 3061	C++
UE4Editor-Win64-Debug.exe!EngineTick() Line 63	C++
UE4Editor-Win64-Debug.exe!GuardedMain(const wchar_t * CmdLine, HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, int nCmdShow) Line 169	C++
UE4Editor-Win64-Debug.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 199	C++
[External Code]

Hi,

Sorry for the delay in responding to this issue. Would you be able to provide more information related to how you are setting this up? The code snippets that you provided do not appear to include all of the code necessary to reproduce this. What file(s) specifically are you adding this code into?

Hey

Here is minimal project (I removed starter content). All you need to do is to compile it, run and hit play in editor.

Tested on master branch.

Edit:
It also happens when adding tick function to classes derived directly from UObject (it, latent tasks in blueprint).

Hi,

I don’t think this is actually a bug. Looking at your implementation, it looks like you may have forgotten to include your own version of ExecuteTickHelper() in your FMyTickFunction struct. I added a slightly modified version of ExecuteTickHelper() to the struct and the custom tick function appeared to work fine after that. If you add a version of ExecuteTickHelper() to your struct, does it work for you?

I see, but ExecuteTickHelper only takes as argument ActorComponent. What if I want to use TickFunction on UObject ?

Edit:
I tried to wrap it like this (seen in other componenets):

void FMyTickFunction::ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{
	FActorComponentTickFunction::ExecuteTickHelper(Target,/*bTickInEditor=*/ false, DeltaTime, TickType, [this](float DilatedTime)
	{
		Target->MyTick(DilatedTime, *this);
	});
}

But it still doesn’t work.

Hi,

The modified version of ExecuteTickHelper() that I used was set to specifically take UMyActorComponent.

template < typename ExecuteTickLambda >
void FMyTickFunction::ExecuteMyTickHelper(UMyActorComponent* Target, bool bTickInEditor, float DeltaTime, ELevelTick TickType, const ExecuteTickLambda& ExecuteTickFunc)
{
	if (Target && !Target->IsPendingKillOrUnreachable() && Target->bRegistered)
	{
		FScopeCycleCounterUObject ComponentScope(Target);
		FScopeCycleCounterUObject AdditionalScope(Target->AdditionalStatObject());

		if (Target->bRegistered)
		{
			AActor* MyOwner = Target->GetOwner();
			if (TickType != LEVELTICK_ViewportsOnly ||
				(bTickInEditor && TickType == LEVELTICK_ViewportsOnly) ||
				(MyOwner && MyOwner->ShouldTickIfViewportsOnly())
				)
			{
				const float TimeDilation = (MyOwner ? MyOwner->CustomTimeDilation : 1.f);
				ExecuteTickFunc(DeltaTime * TimeDilation);
			}
		}
	}
}

Then I called it very similar to the method that you used:

void FMyTickFunction::ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{
	ExecuteMyTickHelper(Target, Target->bTickInEditor, DeltaTime, TickType, [this, TickType](float DilatedTime)
	{
		Target->MyTick(DilatedTime, TickType, this);
	});
}

That worked for me to call MyTick() without resulting in a crash, but only in the case where the Actor Component is attached to an Actor in the level. Getting a UObject to use a custom tick would require that it inherit from FTickableGameObject, which is an abstract class, so you would have to override several functions from that class, including the Tick() function. I am trying to find out if there is a way to attach the Actor Component to a UObject and get it to tick, which seems to be a little more difficult.

Hey

I finally got around trying it on latest master version, and unfortunetly it still crash exactly the same way as in my first post ;/.

Hello,

I just wanted to check and see if you are still having trouble with this issue, or if you have managed to get it to work. Were you able to get a UObject to tick by overriding the functions in FTickableGameObject?