My custom tick function in component doesn't work.

Tl;dr when trying to spawn pawn with this component (player), editor crashes.
At this point I really don’t know what to do with, since, this implementation is I think no different than SkeletalMeshComponent, and yet it doesn’t work.

Implementation:



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]");
}


In Component:



	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]	



is Target a valid object?

edit/ But no access error, so i guess it is.

I think you have to handle both bRegister == true and false cases in RegisterComponentTickFunctions. When I added custom tick functions, my RegisterComponentTickFunctions looked basically like this:


if (bRegister)
		{
			if (SetupActorComponentTickFunction(&AutoJumpObstaclesTickFunction))
			{
				AutoJumpObstaclesTickFunction.Target = this;
			}
		}
		else
		{
			if (AutoJumpObstaclesTickFunction.IsTickFunctionRegistered())
			{
				AutoJumpObstaclesTickFunction.UnRegisterTickFunction();
			}
		}

And the only other difference I see at the moment is that I check the TickType in ExecuteTick before I do anything else with Target. So maybe Target isn’t valid yet in your case or something:



if ((TickType == LEVELTICK_All) && Target && !Target->IsPendingKillOrUnreachable())
	{
		FScopeCycleCounterUObject ComponentScope(Target);
		FScopeCycleCounterUObject AdditionalScope(Target->AdditionalStatObject());
		Target->AutoJumpObstaclesTick(DeltaTime, *this);
	}


Hey thanks for reply.
Unfortuently it still doesn’t work. At this point I would consider it a bug.