Hi!
We switched to 5.6 recently, and since then we experience that when a level is loaded using `ULevelStreamingDynamic::LoadLevelInstance`, when beeing streamned out, we receive calls to UnregisterComponent BEFORE receiving calls to EndPlay for actors belonging to that level.
If that can help, the callstack looks like this: cf Unregister BEFORE EndPlay.PNG
When that happens,the targeted level streaming state, as seen from `ULevelStreaming::UpdateStreamingState`, is `ELevelStreamingState::MakingInvisible`.
We were wondering if that was a bug, or if some assumptions we were having (order of calls to Register / Unregister and begin/endplay is reliable) have changed and are now false?
Steps to Reproduce
In a world, load another world using `ULevelStreamingDynamic::LoadLevelInstance`.
Observe that when actors of that level are streamed out, `UActorComponent::UnregisterComponent()` is called BEFORE `UActorComponent::EndPlay`.
Hello,
UActorComponent::UnregisterComponent can be called before UActorComponent::EndPlay when using incremental removal. Setting s.UnregisterComponentsTimeLimit to 0.0 can cause EndPlay to come before unregister. Do you know whether the cVar value changed for your project at some point?
Thanks,
Ryan
Hi Ryan!
Thanks for the answer.
So calling UnregisterComponent before EndPlay is an assumed behaviour?
About s.UnregisterComponentsTimeLimit, we did not change that value, it’s still 1 (the default value).
Do you think we should?
And to try to better understand how that appeared, do you know is all that changed recently (5.6)?
Yes, in UWorld::RemoveFromWorld, the components can be unregistered before the EndPlay is routed, and this has been the case even prior to 5.6. Can you step through the previous version you were using to see the code path it was going through?
It would probably be best not to rely on the order of the calls. I don’t recommend disabling s.UnregisterComponentsTimeLimit, as that can add more pressure to the game thread unless it’s a suitable temporary workaround for you.
-Ryan
Hi!
I’ll try this and will update here once done, thx for the reply.
Hi
I have finally been able to have the time to sync back before 5.6 and re-test.
Strangely, I could not repro the check we were having, which was the initial cause of the investigation (we were hitting `check(bRegistered);` from `UActorComponent::TickComponent`, related to how we unregister to the tick in EndPlay). I confirm that in that situation, Unregister is called BEFORE EndPlay.
For our bug to reproduce, Unregister needs to be called at least 1 frame before EndPlay will be called. That would i guess happen when the incremental unregister would not be able to unregister all actors (bFinishRemovingLevel
still false). During my latest tests, they were called on the same frame.
I guess this depends how many actors can be unregistered during the same frame, vs how many we have to… In my case today it could deal with all of them, which means EndPlay was sent in the same frame.
I can’t spend more time looking into this right now, so I guess we can close this ticket, but I would have been curious to understand it a bit more.
Thx for the help