Download

Timers causes the game to crash.

I have an enemy cpp class that uses timers, when ever I destroy the enemy in the middle of the game, and then restart the game, after a few seconds the game will crash and show the line where the timer is activated in the enemy class.
Even when the game was restarted it still running this timer someone .
I even tried to put in the enemy class:


void AEnemy_Character::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	GetWorldTimerManager().ClearAllTimersForObject(this);

        Super::EndPlay(EndPlayReason);
}


And also tried to destroy it, let it clear it’s timers with the function above, and then restart the level, I also tried the “open” node to start the current map instead of using “RestartLevel” on the console command node.

I’m using UE4.83

To use the timers i’m using a macro I’v made for myself:


#define SET_TIMER(lambda, time, loop) \
do \
{\
	FTimerHandle timer_handle;\
	FTimerDelegate timer_lambda;\
	timer_lambda.BindLambda(lambda);\
	GetWorld()->GetTimerManager().SetTimer(timer_handle, timer_lambda, time, loop); \
}\
while(false)

And this is an example of one of the calls:


SET_TIMER([this]
	{
		SET_TIMER([this]
		{
			if (````````)
				Go();
		},
		5.0f, true);
	},
	0.3f, false);

Edit: Also tried to open an other map that dose not have this enemy in it, and it still crashes.
Isn’t everything supposed to be restarted when I’m restarting or opening a new map?

Edit: And this is what I get in a packed game when I’m trying to restart a game after one of the enemies has started one of his timers:
f14705c377454eedda11fc1c02adba146b260718.jpeg

You’re running into this problem because of how you bind the function. When you call BindLambda you get a TBaseFunctorDelegateInstance. because of how functor delegates work this will never match for any object. You can verify this by looking at the code in TBaseFunctorDelegateInstance::HasSameObject(const void* UserObject). You can fix this by either using a different binding method or you can track the TimerHandles and use them to explicitly remove the timers with a call to FTimerManager::ClearTimer(FTimerHandle InHandle) for each handle.

Thanks! I’v solved it like this:

Now the macro looks like this:


#define SET_TIMER(lambda, time, loop) \
do \
{\
	FTimerHandle timer_handle;\
	FTimerDelegate timer_lambda;\
	timer_lambda.BindLambda(lambda);\
	GetWorld()->GetTimerManager().SetTimer(timer_handle, timer_lambda, time, loop); \
	all_timer_handles.Add(timer_handle);\
}\
while(false)

And I have this in my header:


TArray<FTimerHandle> all_timer_handles;

For clearing timers I used this:


void AEnemy_Character::Clear_All_Timers()
{
	for (auto i = 0; i < all_timer_handles.Num(); i++)
	{
		GetWorldTimerManager().ClearTimer(all_timer_handles*);
	}
}