I have got a crash on packaged build with this message:
Fatal error: [File:D:\Build++UE4+Release-4.16+Compile\Sync\Engine\Source\Runtime\CoreUObject\Private\Serialization\AsyncLoading.cpp] [Line: 2936]
Missing Dependency, request for BillboardComponent but it hasn’t been created yet.
In my game BillboardComponent is an instance of UBillboardComponent which is used for debug purpose only and it is surrounded with define WITH_EDITORONLY_DATA, so I think in packaged build it shouldnt be included.
It is very easy to reproduce on template project. Add to any actor UBillboardComponent surrounded with WITH_EDITORONLY_DATA and try to package game for Windows x64 in debug mode. Next run packaged game and voilà.
That will have two effects: First, it will create the object with bRequired=false, so that it doesn’t crash if the object class is missing at runtime and it will also call MarkAsEditorOnlySubobject for you. MarkAsEditorOnlySubobject will set bIsEditorOnly = true so that during package save, the reference from your class to the component is tagged as OBJECTMARK_EditorOnly, which will cause the package generator to skip it during cooking https://github.com/EpicGames/UnrealEngine/blob/4.17/Engine/Source/Runtime/CoreUObject/Private/UObject/SavePackage.cpp#L2948
So if your deserialization is crashing because of the missing UPROPERTY, then the #if WITH_EDITORONLY_DATA is not detected correctly by the UnrealHeaderTool. If your deserialization is crashing because the class of your component cannot be loaded, then you probably used CreateDefaultSubobject where you should have used CreateEditorOnlyDefaultSubobject.
And lastly - as a side comment - you can also mark an UPROPERTY as Transient. That way, it just won’t get saved, no matter if you’re compiling for the editor or not. But unlike a regular C++ attribute, you can still edit transient UPROPERTYes in blueprint.That’s very helpful for effect objects which you create dynamically from a template, thus you don’t need to edit them in the editor and they will get re-created anyway. This can greatly improve loading times.
And since its kind of related, and yields the same error as your problem: Creating an object only on some platforms
Mark the UPROPERTY as transient, so that it doesn’t get saved. No #if around the UPROPERTY here, to keep memory layout the same on all platforms.
UPROPERTY(Transient)
class UDestructibleComponent* DestructibleComponent;
Create the object using NewObject in an #if, so that it doesn’t get marked as CDO and with Transient flag:
That way, the object will not be serialized into the cooked asset as CDO parameters (due to being created with NewObject and not CreateDefaultSubobject), and it won’t be saved itself (due to being transient) so that on platforms where you don’t create it, the Serializer doesn’t complain about its absence.