We have found that in UE5.8 the behavior or FApp::IsGame while running a PIE world is inconsistent.
We have an automated test that captures some primitive data at an initial player location, then teleports to a new location to capture other primitive data. This is accomplished with a level Blueprint that runs in PIE. The problem occurs after the teleport, and stems from UPrimitiveComponent::OnRegister where we have added our own custom code to the end of the function which at one point branches when calling FApp::IsGame. Note, the reproduction steps show how to see the problem using unmodified UE5.8 while debugging as well.
At Position 1, FApp::IsGame returns True with this callstack on the GameThread:
EnlightenUtil::GetPrimitiveEnlightenId(const UPrimitiveComponent *)
FSystemAssignmentManager::OnPrimitiveRegister(UPrimitiveComponent *)
FEnlightenEngineSupport::OnPrimitiveRegister(UPrimitiveComponent *)
UPrimitiveComponent::OnRegister()
UStaticMeshComponent::OnRegister()
UInstancedStaticMeshComponent::OnRegister()
UActorComponent::ExecuteRegisterEvents(FRegisterComponentContext *)
UActorComponent::RegisterComponentWithWorld(UWorld *, FRegisterComponentContext *)
AActor::IncrementalRegisterComponents(int, FRegisterComponentContext *)
ULevel::IncrementalRegisterComponents(FRegisterComponentContext &)
ULevel::IncrementalUpdateComponents(int, bool, FRegisterComponentContext *)
UWorld::AddToWorld(ULevel *, const UE::Math::TTransform<double> &, bool, const TOptional<UE::FTimeout const> &, FNetLevelVisibilityTransactionId, ULevelStreaming *)
ULevelStreaming::UpdateStreamingState(bool &, bool &, const TOptional<UE::FTimeout const> &)
UWorld::UpdateLevelStreaming(const TOptional<UE::FTimeout const> &)
UWorld::FlushLevelStreaming::__l2::<lambda_1>::operator()()
UWorld::FlushLevelStreaming(EFlushLevelStreamingType)
UWorld::BlockTillLevelStreamingCompleted()
UEngine::BlockTillLevelStreamingCompleted(UWorld *)
UGameInstance::StartPlayInEditorGameInstance(ULocalPlayer *, const FGameInstancePIEParameters &)
UEditorEngine::CreateInnerProcessPIEGameInstance(FRequestPlaySessionParams &, const FGameInstancePIEParameters &, int)
UEditorEngine::OnLoginPIEComplete_Deferred(int, bool, FString, FPieLoginStruct)
UEditorEngine::CreateNewPlayInEditorInstance(FRequestPlaySessionParams &, const bool, const EPlayNetMode)
UEditorEngine::StartPlayInEditorSession(FRequestPlaySessionParams &)
Then after the teleport to Position 2 here is the callstack when FApp::IsGame returns False, also on the GameThread:
EnlightenUtil::GetPrimitiveEnlightenId(const UPrimitiveComponent *)
FSystemAssignmentManager::OnPrimitiveRegister(UPrimitiveComponent *)
FEnlightenEngineSupport::OnPrimitiveRegister(UPrimitiveComponent *)
UPrimitiveComponent::OnRegister()
UStaticMeshComponent::OnRegister()
UInstancedStaticMeshComponent::OnRegister()
UActorComponent::ExecuteRegisterEvents(FRegisterComponentContext *)
UActorComponent::RegisterComponentWithWorld(UWorld *, FRegisterComponentContext *)
AActor::IncrementalRegisterComponents(int, FRegisterComponentContext *)
ULevel::IncrementalRegisterComponents(FRegisterComponentContext &)
ULevel::IncrementalUpdateComponents(int, bool, FRegisterComponentContext *)
UWorld::AddToWorld(ULevel *, const UE::Math::TTransform<double> &, bool, const TOptional<UE::FTimeout const> &, FNetLevelVisibilityTransactionId, ULevelStreaming *)
ULevelStreaming::UpdateStreamingState(bool &, bool &, const TOptional<UE::FTimeout const> &)
UWorld::UpdateLevelStreaming(const TOptional<UE::FTimeout const> &)
According to the comments accompanying FApp::IsGame, it should return true on the GameThread (non-worker thread) while a normal PIE game is active.
We do have a temporary fix in place:
const UWorld* World = Component->GetWorld();
bool bIsRunningPlayInEditor = (World && World->IsPlayInEditor());
This returns True in the same code block where FApp::IsGame would return False.
However, it seems that there is a problem with FApp::IsGame, which we used in many places.
Thanks for your time and advice on the issue,
-Nate
[Attachment Removed]