Physics - Async Ticking Crash
(Sorry, I’m not entirely sure if this is a bug report, question, discussion etc.)
Looks like my game is crashing when an actor that is async ticking is streamed out by the world partition. I did not found anything official about this, but there was a discussion about it:
I think this is still present (at least in my 5.4 game). I also realized that Unreal added a check for this in 5.5 in PhysScene_Chaos.cpp
for(AActor* Actor : AsyncPhysicsTickActors)
{
check(Actor)
FScopeCycleCounterUObject ActorScope(Actor);
Actor->AsyncPhysicsTickActor(DeltaTime, SimTime);
}
First of all, this is a raw pointer, so I’m not sure what’s the point of the check since its not null anyways - its quite unreliable.
Also, according to the discussions above Id have to implement the unregister per actor in my custom class. Why don’t we have a simple UnregisterAsyncPhysicsTickActor call on EndPlay in Actor.cpp (just like we have a RegisterAsyncPhysicsTickActor in BeginPlay, called RegisterAllActorTickFunctions). Wouldn’t it be safe to say that if the actor is bAsyncPhysicsTickEnabled, then it should try to unregister itself on EndPlay?
We do unregister it when you call Destroy() on the actor, but looks like the world streaming does not call that, it only calls RouteEndPlay, and seemingly that does not care about async physic ticking.
I don’t get it how isn’t it a prominent issue, or why cant I find anything about it from Epic side? Am I missing something?
TLDR shouldnt we have an EndPlay in Actor.cpp similar to this
void AActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (ActorHasBegunPlay == EActorBeginPlayState::HasBegunPlay)
{
TRACE_OBJECT_LIFETIME_END(this);
ActorHasBegunPlay = EActorBeginPlayState::HasNotBegunPlay;
#if UE_WITH_IRIS
// This must be called otherwise the ReplicationSystem will keep a reference to the actor forever.
EndReplication(EndPlayReason);
#endif
// Dispatch the blueprint events
ReceiveEndPlay(EndPlayReason);
OnEndPlay.Broadcast(this, EndPlayReason);
TInlineComponentArray<UActorComponent*> Components;
GetComponents(Components);
for (UActorComponent* Component : Components)
{
if (Component->HasBegunPlay())
{
Component->EndPlay(EndPlayReason);
ensureMsgf(Component->HasBegunPlay() == false, TEXT("EndPlay on %s failed. Make sure to call Super::EndPlay() in the override function in class %s."), *Component->GetName(), *Component->GetClass()->GetName());
}
}
/* Updated part - unregistering async ticking*/
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(GetWorld()->GetPhysicsScene()))
{
if (bAsyncPhysicsTickEnabled)
{
Scene->UnregisterAsyncPhysicsTickActor(this);
}
}
}
}