Description

If an attempt to spawn an actor is made before the Level Editor Viewport is fully initialized (i.e. before it has had a chance to get rendered at least once), and that actor has no specific Factory associated with it, the engine crashes.

The spawning of the actor may be triggered, for example, by a Python script, by an Editor Utility Widget, or by simply using the "Place Actor" menu on the toolbar.

The actor can be of any type that does not provide a specific Factory. The bug was reproduced with a CineCameraActor. The linked UDN case also gives as examples a StaticMeshActor and any blueprint generated class. Examples that do not cause a crash include Actor, SpotLight, PointLight and CameraActor.

The viewport will not be fully initialized if the Editor was opened with a layout that does not show any part of any viewport (for example, by placing another tab alongside the viewport tab and having it showing instead of the viewport, or by simply not having any open viewports).

Note that, only when the viewport is first redrawn, the game thread calls FSceneViewport::OnDrawViewport() --> FSceneViewport::ResizeViewport() --> FSceneViewport::UpdateViewportRHI(). This will set the viewport dimensions from the default (0,0) to the appropriate values, and then call on the render thread FSceneViewport::InitRHI(), which initializes TArray<FSlateRenderTargetRHI*>FSceneViewport::BufferedSlateHandles.

On the crash path, the attempt to spawn the actor through the Place Actor menu will call FLevelEditorActionCallbacks::AddActor(). The attempt to spawn the actor using the Editor Actor Subsystem will call UEditorActorSubsystem::SpawnActorFromClass() or UEditorActorSubsystem::SpawnActorFromObject(). All of those end up calling FLevelEditorViewportClient::TryPlacingActorFromObject(). When no factory is found, this calls FActorPositioning::GetCurrentViewportPlacementTransform(), which is odd because we had transform information before, and now we are trying to use the mouse cursos position to get another transform. Anyway, this finally ends up calling FSceneViewport::EnqueueBeginRenderFrame(), where a division by zero happens:

[Runtime\Engine\Private\Slate\SceneViewport.cpp:1806]
NextBufferedTargetIndex = (CurrentBufferedTargetIndex + 1) % BufferedSlateHandles.Num();

Steps to Reproduce

1. Open the Editor, show the header for the Viewport Tab
2. Open another tab, like the Output Log, and place it alongside the Viewport Tab
3. Make sure the other tab is on top, then re-save the current level to make sure this layout will persist
4. Close and reopen the Editor. Make sure the viewport is not visible.

Option A:
5A. On the "Place Actors" menu on the toolbar, click Cinematic – CineCameraActor

Option B:
5B. Run the following Python script:
"unreal.get_editor_subsystem(unreal.EditorActorSubsystem).spawn_actor_from_class(unreal.CineCameraActor, unreal.Vector(0.0, 0.0, 0.0))"

Crash callstack for Option A:

UnrealEditor-Engine.dll!FSceneViewport::EnqueueBeginRenderFrame(const bool bShouldPresent) Line 1806
UnrealEditor-Engine.dll!FViewport::GetRawHitProxyData(UE::Math::TIntRect<int> InRect) Line 1950
UnrealEditor-Engine.dll!FViewport::GetHitProxyMap(UE::Math::TIntRect<int> InRect, TArray<HHitProxy *,TSizedDefaultAllocator<32>> & OutMap) Line 2023
UnrealEditor-Engine.dll!FViewport::GetHitProxy(int X, int Y) Line 2072
UnrealEditor-UnrealEd.dll!FActorPositioning::GetCurrentViewportPlacementTransform(const AActor & Actor, bool bSnap, const FViewportCursorLocation * InCursor) Line 169
UnrealEditor-UnrealEd.dll!FLevelEditorViewportClient::TryPlacingActorFromObject(ULevel * InLevel, UObject * ObjToUse, bool bSelectActors, EObjectFlags ObjectFlags, UActorFactory * FactoryToUse, const FName Name, const FViewportCursorLocation * Cursor) Line 248
UnrealEditor-UnrealEd.dll!UEditorEngine::UseActorFactory(UActorFactory * Factory, const FAssetData & AssetData, const UE::Math::TTransform<double> * InActorTransform, EObjectFlags InObjectFlags) Line 5024
UnrealEditor-LevelEditor.dll!FLevelEditorActionCallbacks::AddActor(UActorFactory * ActorFactory, const FAssetData & AssetData, const UE::Math::TTransform<double> * ActorTransform) Line 1581
UnrealEditor-PlacementMode.dll!SPlacementAssetMenuEntry::OnMouseButtonUp(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) Line 491
(...)

Crash callstack for Option B:

UnrealEditor-Engine.dll!FSceneViewport::EnqueueBeginRenderFrame(const bool bShouldPresent) Line 1806 C++
UnrealEditor-Engine.dll!FViewport::GetRawHitProxyData(UE::Math::TIntRect<int> InRect) Line 1950 C++
UnrealEditor-Engine.dll!FViewport::GetHitProxyMap(UE::Math::TIntRect<int> InRect, TArray<HHitProxy *,TSizedDefaultAllocator<32>> & OutMap) Line 2023 C++
UnrealEditor-Engine.dll!FViewport::GetHitProxy(int X, int Y) Line 2072 C++
UnrealEditor-UnrealEd.dll!FActorPositioning::GetCurrentViewportPlacementTransform(const AActor & Actor, bool bSnap, const FViewportCursorLocation * InCursor) Line 169 C++
UnrealEditor-UnrealEd.dll!FLevelEditorViewportClient::TryPlacingActorFromObject(ULevel * InLevel, UObject * ObjToUse, bool bSelectActors, EObjectFlags ObjectFlags, UActorFactory * FactoryToUse, const FName Name, const FViewportCursorLocation * Cursor) Line 248 C++
UnrealEditor-UnrealEd.dll!InternalActorUtilitiesSubsystemLibrary::SpawnActor(const wchar_t * MessageName, UObject * ObjToUse, UE::Math::TVector<double> Location, UE::Math::TRotator<double> Rotation, bool bTransient) Line 116 C++
UnrealEditor-UnrealEd.dll!UEditorActorSubsystem::SpawnActorFromClass(TSubclassOf<AActor> ActorClass, UE::Math::TVector<double> Location, UE::Math::TRotator<double> Rotation, bool bTransient) Line 502 C++
(...)

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-201004 in the post.

2
Login to Vote

Unresolved
ComponentUE - Editor - Workflow Systems
Affects Versions5.3
Target Fix5.4
CreatedNov 22, 2023
UpdatedJan 20, 2024