Hi,
Thank you for the report and repro project. After looking into this, it seems like the issue doesn’t lie with replication but rather with how the default property values are being handled for the blueprint class.
After creating the BP class derived from BP_StaticEnvironmentActor and starting PIE, I can observe the constructor for the UDBPaintableComponent is passing in the expected value for the FastPaintList.PaintableComponent.
However, after the constructor is finished, FObjectInitializer::InitProperties changes the pointer to the BP archetype (BP_PaintableComp_GEN_VARIABLE), a value its getting from the DefaultData object. Here’s the callstack from when that happens:
UnrealEditor-DBSurfacePaint.dll!UE::CoreUObject::Private::Copy<FDBFastPaintList>(void * Dest, const void * Src, int ArrayDim) Line 1378 C++
[Inline Frame] UnrealEditor-CoreUObject.dll!UScriptStruct::ICppStructOps::Copy(void *) Line 1981 C++
UnrealEditor-CoreUObject.dll!UScriptStruct::CopyScriptStruct(void * InDest, const void * InSrc, int ArrayDim) Line 3707 C++
UnrealEditor-CoreUObject.dll!FStructProperty::CopyValuesInternal(void * Dest, const void * Src, int Count) Line 344 C++
[Inline Frame] UnrealEditor-CoreUObject.dll!FProperty::CopyCompleteValue(void *) Line 930 C++
[Inline Frame] UnrealEditor-CoreUObject.dll!FProperty::CopyCompleteValue_InContainer(void *) Line 936 C++
> UnrealEditor-CoreUObject.dll!FObjectInitializer::InitProperties(UObject * Obj, UClass * DefaultsClass, UObject * DefaultData, bool bCopyTransientsFromClassDefaults) Line 4560 C++
UnrealEditor-CoreUObject.dll!FObjectInitializer::PostConstructInit() Line 4240 C++
UnrealEditor-CoreUObject.dll!FObjectInitializer::~FObjectInitializer() Line 4112 C++
UnrealEditor-CoreUObject.dll!StaticConstructObject_Internal(const FStaticConstructObjectParameters & Params) Line 4845 C++
UnrealEditor-CoreUObject.dll!FDuplicateDataWriter::GetDuplicatedObject(UObject * Object, bool bCreateIfMissing) Line 184 C++
UnrealEditor-CoreUObject.dll!FDuplicateDataWriter::operator<<(UObject * & Object) Line 78 C++
[External Code]
[Inline Frame] UnrealEditor-Engine.dll!operator<<(FArchive &) Line 4350 C++
UnrealEditor-Engine.dll!AActor::Serialize(FArchive & Ar) Line 976 C++
UnrealEditor-CoreUObject.dll!StaticDuplicateObjectEx(FObjectDuplicationParameters & Parameters) Line 3066 C++
UnrealEditor-Engine.dll!UWorld::GetDuplicatedWorldForPIE(UWorld * InWorld, UPackage * InPIEackage, int PIEInstanceID) Line 4493 C++
UnrealEditor-Engine.dll!UWorld::DuplicateWorldForPIE(const FString & PackageName, UWorld * OwningWorld) Line 4565 C++
UnrealEditor-Engine.dll!UEngine::LoadMap(FWorldContext & WorldContext, FURL URL, UPendingNetGame * Pending, FString & Error) Line 16365 C++
UnrealEditor-Engine.dll!UEngine::TickWorldTravel(FWorldContext & Context, float DeltaSeconds) Line 16037 C++
UnrealEditor-UnrealEd.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 2157 C++
UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 546 C++
UnrealEditor.exe!FEngineLoop::Tick() Line 5977 C++
[Inline Frame] UnrealEditor.exe!EngineTick() Line 60 C++
UnrealEditor.exe!GuardedMain(const wchar_t * CmdLine) Line 190 C++
UnrealEditor.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) Line 266 C++
UnrealEditor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) Line 338 C++
[External Code]
After restarting the editor, the above still happens in InitProperties, but it appears as though the pointer is then later set back to the expected value when the actor component and its properties are serialized from StaticDuplicateObjectEx.
I’m not sure why this is only occurring for BP classes derived from a BP class, as well as why restarting the editor appears to fix the issue. To look into the problem further, I’ve opened a new issue, UE-380307, which should be visible in the public tracker in a day or so.
In the meanwhile, I believe you can try working around the issue by setting the FastPaintList.PaintableComponent pointer back to the correct value after the component’s constructor, such as in the component’s BeginPlay.
Thanks,
Alex
[Attachment Removed]