Description

When Simulating, or Playing-In-Editor and ejected, modifying an actor in the editor world causes the SIE/PIE runtime actor to recreate its blueprint added components via AActor::RerunConstructionScripts(). See the attached callstack.

This process recreates SCS components of the runtime actors by duplicating from their templates. Afterwards those runtime components have the latest default values, but in the process loses all runtime modifications including:

  • Functions bound to delegates are no longer bound
  • All properties are reset to their initial value

This causes a confusing workflow when simulating or testing in PIE. We should evaluate whether:

  • SCS components should not be recreated during SIE/PIE. Note: comments in AActor::PostEditChangeProperty() mention a necessity to recreate them for SIE.
  • Runtime modifications of the older runtime component should be migrated over to the new component, for example via CPFUO
Steps to Reproduce

Repro project was provided by reporter.

Setup repro steps

  • Create a native actor component class:
    • Make it a BlueprintSpawnableComponent
    • And give it a BlueprintAssignable DECLARE_DYNAMIC_MULTICAST_DELEGATE that's broadcasted on Tick
  • Create an actor blueprint BP_Repro that adds that component class in blueprint (SCS)
    • Bind an event with PrintString("Hello") to that delegate in the blueprint's event graph
    • Add a boolean variable ToggleMe
  • Place a BP_Repro in the map

Bug repro steps:

  • Start Simulating in editor, or start PIE and eject
  • Observe: The component's delegate fires per tick by design and the PrintString happens.
  • Select the BP_Repro in the Outliner
  • Change the value of the bool ToggleMe on the actor
  • (Note: this triggers AActor::RerunConstructionScripts())
  • Observe: The PrintString stops firing, despite that the component broadcasts its delegate every tick
  • Expected: The PrintString keeps firing, i.e. any events bound to the delegate should still be bound after AActor::RerunConstructionScripts().

 

Alternative repro steps:

  • Create a component class (BP or native):
    • Give it an integer variable MyInt
    • Print the value of MyInt on tick and increment it
  • Create an actor BP:
    • Adds that component (SCS)
    • Give it a bool property ToggleMe.
    • Place that in the level
  • Start PIE and Eject
  • Observe that MyInt increments per tick
  • Change the value of Toggle Me
  • Observe: the value of MyInt starts incrementing again from 0
  • Expected: the value of MyInt is retained when changing unrelated actor values
  •  
Callstack

This callstack is not a crash, but represents when a component gets reconstructed during SIE and Ejected-PIE and bindings to multicast delegates aren't copied over from the old component.

     UnrealEditor-UDN_DelegateBroke.dll!UMyComponent::Serialize(FArchive & Ar) Line 18    C++
     UnrealEditor-CoreUObject.dll!StaticDuplicateObjectEx(FObjectDuplicationParameters & Parameters) Line 3160    C++
     UnrealEditor-Engine.dll!AActor::CreateComponentFromTemplate(UActorComponent * Template, const FName InName) Line 1096    C++
     UnrealEditor-Engine.dll!USCS_Node::ExecuteNodeOnActor(AActor * Actor, USceneComponent * ParentComponent, const UE::Math::TTransform<double> * RootTransform, const FRotationConversionCache * RootRelativeRotationCache, bool bIsDefaultTransform, ESpawnActorScaleMethod TransformScaleMethod) Line 104    C++
     UnrealEditor-Engine.dll!USCS_Node::ExecuteNodeOnActor(AActor * Actor, USceneComponent * ParentComponent, const UE::Math::TTransform<double> * RootTransform, const FRotationConversionCache * RootRelativeRotationCache, bool bIsDefaultTransform, ESpawnActorScaleMethod TransformScaleMethod) Line 218    C++
     UnrealEditor-Engine.dll!USimpleConstructionScript::ExecuteScriptOnActor(AActor * Actor, const TInlineComponentArray<USceneComponent *,24> & NativeSceneComponents, const UE::Math::TTransform<double> & RootTransform, const FRotationConversionCache * RootRelativeRotationCache, bool bIsDefaultTransform, ESpawnActorScaleMethod TransformScaleMethod) Line 647    C++
     UnrealEditor-Engine.dll!AActor::ExecuteConstruction(const UE::Math::TTransform<double> & Transform, const FRotationConversionCache * TransformRotationCache, const FComponentInstanceDataCache * InstanceDataCache, bool bIsDefaultTransform, ESpawnActorScaleMethod TransformScaleMethod) Line 871    C++
>    UnrealEditor-Engine.dll!AActor::RerunConstructionScripts() Line 588    C++
     UnrealEditor-Engine.dll!AActor::PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) Line 235    C++
     UnrealEditor-CoreUObject.dll!UObject::PostEditChangeChainProperty(FPropertyChangedChainEvent & PropertyChangedEvent) Line 577    C++
     [Inline Frame] UnrealEditor-PropertyEditor.dll!FPropertyNode::NotifyPostChange::__l14::<lambda_1>::operator()(UObject *) Line 3230    C++
     UnrealEditor-PropertyEditor.dll!FPropertyNode::NotifyPostChange(FPropertyChangedEvent & InPropertyChangedEvent, FNotifyHook * InNotifyHook) Line 3234    C++
     UnrealEditor-PropertyEditor.dll!FPropertyValueImpl::ImportText(const TArray<FObjectBaseAddress,TSizedDefaultAllocator<32>> & InObjects, const TArray<FString,TSizedDefaultAllocator<32>> & InValues, FPropertyNode * InPropertyNode, unsigned int Flags) Line 565    C++
     UnrealEditor-PropertyEditor.dll!FPropertyValueImpl::ImportText(const FString & InValue, FPropertyNode * InPropertyNode, unsigned int Flags) Line 251    C++
     UnrealEditor-PropertyEditor.dll!FPropertyValueImpl::ImportText(const FString & InValue, unsigned int Flags) Line 158    C++
     UnrealEditor-PropertyEditor.dll!FPropertyHandleBool::SetValue(const bool & NewValue, unsigned int Flags) Line 3895    C++
     UnrealEditor-PropertyEditor.dll!SPropertyEditorBool::OnCheckStateChanged(ECheckBoxState InNewState) Line 96    C++
     [Inline Frame] UnrealEditor-PropertyEditor.dll!Invoke(void(SPropertyEditorBool::*)(ECheckBoxState)) Line 66    C++
     [Inline Frame] UnrealEditor-PropertyEditor.dll!UE::Core::Private::Tuple::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(SPropertyEditorBool::*)(ECheckBoxState) &) Line 317    C++
     UnrealEditor-PropertyEditor.dll!TBaseSPMethodDelegateInstance<0,SPropertyEditorBool,1,void __cdecl(enum ECheckBoxState),FDefaultDelegateUserPolicy>::ExecuteIfSafe(ECheckBoxState <Params_0>) Line 299    C++
     UnrealEditor-Slate.dll!TDelegate<void __cdecl(enum ECheckBoxState),FDefaultDelegateUserPolicy>::ExecuteIfBound<void,0>(ECheckBoxState <Params_0>) Line 635    C++
     UnrealEditor-Slate.dll!SCheckBox::ToggleCheckedState() Line 388    C++
     UnrealEditor-Slate.dll!SCheckBox::OnMouseButtonUp(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) Line 250    C++
     [Inline Frame] UnrealEditor-Slate.dll!FSlateApplication::RoutePointerUpEvent::__l8::<lambda_2>::operator()(const FArrangedWidget &) Line 5317    C++
     UnrealEditor-Slate.dll!FEventRouter::Route<FReply,FEventRouter::FToLeafmostPolicy,FPointerEvent,`FSlateApplication::RoutePointerUpEvent'::`8'::<lambda_2>>(FSlateApplication * ThisApplication, FEventRouter::FToLeafmostPolicy RoutingPolicy, FPointerEvent EventCopy, const FSlateApplication::RoutePointerUpEvent::__l8::<lambda_2> & Lambda, ESlateDebuggingInputEvent DebuggingInputEvent) Line 448    C++
     UnrealEditor-Slate.dll!FSlateApplication::RoutePointerUpEvent(const FWidgetPath & WidgetsUnderPointer, const FPointerEvent & PointerEvent) Line 5303    C++
     UnrealEditor-Slate.dll!FSlateApplication::ProcessMouseButtonUpEvent(const FPointerEvent & MouseEvent) Line 5888    C++
     UnrealEditor-Slate.dll!FSlateApplication::OnMouseUp(const EMouseButtons::Type Button, const UE::Math::TVector2<double> CursorPos) Line 5844    C++
     UnrealEditor-ApplicationCore.dll!FWindowsApplication::ProcessDeferredMessage(const FDeferredWindowsMessage & DeferredMessage) Line 2253    C++
     UnrealEditor-ApplicationCore.dll!FWindowsApplication::DeferMessage(TSharedPtr<FWindowsWindow,1> & NativeWindow, HWND__ * InHWnd, unsigned int InMessage, unsigned __int64 InWParam, __int64 InLParam, int MouseX, int MouseY, unsigned int RawInputFlags) Line 2765    C++
     UnrealEditor-ApplicationCore.dll!FWindowsApplication::ProcessMessage(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 1926    C++
     [Inline Frame] UnrealEditor-ApplicationCore.dll!WindowsApplication_WndProc(HWND__ *) Line 930    C++
     UnrealEditor-ApplicationCore.dll!FWindowsApplication::AppWndProc(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 936    C++
     [External Code]    
     [Inline Frame] UnrealEditor-ApplicationCore.dll!WinPumpMessages() Line 116    C++
     UnrealEditor-ApplicationCore.dll!FWindowsPlatformApplicationMisc::PumpMessages(bool bFromMainLoop) Line 145    C++
     UnrealEditor.exe!FEngineLoop::Tick() Line 5773    C++
     [Inline Frame] UnrealEditor.exe!EngineTick() Line 69    C++

Have Comments or More Details?

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

0
Login to Vote

Unresolved
ComponentUE - Gameplay - Blueprint Runtime
Affects Versions5.45.25.3
Target Fix5.6
CreatedSep 6, 2024
UpdatedSep 6, 2024
View Jira Issue