Download

Timers going off after level change

Basically what the title says. Is this supposed to happen? The level has already changed and the timers are going off on invalidated actors from the previous level.

Have you tried clearing the timers in question on the actors as and when they are getting destroyed (i.e. override BeginDestroy/Destroyed on your actor)?

How can the timers be going off if those actors don’t exist anymore? It sounds like the level is still loaded somewhere…

AFAIK the World Timer Manager is bound to a world, so gets destroyed when the world is shut down.

Yea it’s odd. I’m specifically loading a different map with this call


UGameplayStatics::OpenLevel(this, TEXT("/Game/Maps/SwatterSelection"));

The objects that the timers go off on seem to be in different states of destruction. Ex: where I recently had a fatal error while debugging, which happened in SpawnActorDeferred, while looking at the watch list, Owner had


0x000000001d606080 (Name=0x0000000002b364d0 "None")

and even worse, “this” had


0x00000000005edb40 (Name=Invalid)

Which, AFAIK, indicates that the object is trying to be destroyed but hasn’t finished because it’s still being referenced.

I’m still debugging right now to find out what’s going on. I’ll try to see if the timer manager is actually getting destroyed along with the world.

While it is true that the UWorld does have a TimerManager member which is assigned (new’d) in the constructor and delete’d in FinishDestroy, calling UWorld::GetTimerManager will actually return the TimerManager of your GameInstance given that the GameInstance is valid non-Null (which it probably is if you haven’t set the GameInstanceClass to ‘None’). So in reality you are likely using the TimerManager of the GameInstance which is an entirely different instance and survives level loading. In that case the timers won’t be removed automatically.

The above is based on the 4.11 version of the engine (so it may have changed already). The same also applies to the LatentActionManager by the way.

In any case my suggestion above should still work. Even if it means more work as you have to manually clear the timers again.

Yea i was just about to post, I had found that the GameInstance TimerManager was the one being used. Didn’t realize that there were two TimerManagers that could be picked.

Hmm. The issue I’m having now is that there are some cases where I set up timers with delegates using BindLambda, which, AFAIK, doesn’t inherently have an object related to the delegate. So my solution would be one of two things:

  1. Find out how to clear timers with lambdas binded to their delegates.
  2. Make sure no GameInstance class is instantiated.

Is there any way of doing either of these things? I tried #2 by setting the class as None in DefaultEngine.ini, but it created it anyway.

It looks like you cannot clear the GameInstanceClass (set it to none, not even via the Project Settings -> Project -> Maps & Modes -> Game Instance -> Game Instance Class setting). However when you call FTimerManager::SetTimer the first argument FTimerHandle can be used to either call FTimerManager::ClearTimer or FTimerManager::SetTimer with a Rate <= 0.0f


UWorld* World = GetWorld();
if (World)
{
	FTimerHandle TimerHandle;
	World->GetTimerManager().SetTimer(TimerHandle, /* other params */);

	//...

	World->GetTimerManager().ClearTimer(TimerHandle);
	//or World->GetTimerManager().SetTimer(TimerHandle, 0.0f, /* other params */);
}

Yeah. Well, i guess new rule for me is, keep references to all your handles, lol. Didn’t think it would come to that, but ah well. Thanks for the help guys.