There is currently no simple way to do a deprecated variable fixup on native variables that are set by a blueprint class. For a simple variable rename, CoreRedirects can be used and will work properly. However for a more complex fixup the general procedure is to set up a custom version (or a class-specific version which has the same problem) and add fixup logic to PostLoad. This will work properly for native classes that are placed or blueprint classes that are not placed or inherited, but it the deprecation behavior will be inconsistent for blueprint classes that are placed or inherited.
The primary reason this does not work consistently is that the timing of PostLoad depends on the order that assets are loaded. If the blueprint is loaded before the map as in step 13, the deprecation logic in PostLoad on the blueprint happens before the instance is loaded and it works properly. However if the map and blueprint are loaded at the same time like in step 11, the PostLoad on the blueprint will happen after the instance has already been partially loaded so it will load in with the incorrect value.
There are several work arounds for this problem but they do not cover all cases. One option is to move the deprecation fixup to Serialize instead of PostLoad, and this works for most cases but is not guaranteed to work for blueprint inheritance because blueprint CDOs do not call properly call Serialize for historical reasons. Another option is to call the fixup logic from PostCDOCompiled instead of PostLoad, but that is complex and requires checking the bIsRegeneratingOnLoad flag before running the fixup as the linker version will be incorrect for compiles without that flag.
Data refactoring would be easier if there was a simple and reliable method for upgrading deprecated blueprint-exposed variables.
This repro uses EngineTest but you can modify it for any game:
UPROPERTY() int32 IntegerProperty_DEPRECATED; UPROPERTY(EditAnywhere, Interp, BlueprintReadWrite, Category = "General") int32 NewIntegerProperty; virtual PostLoad() override; virtual void Serialize(FArchive& Ar) override;
struct FTestVersion { enum Type { BeforeCustomVersionWasAdded = 0, NewIntegerProperty = 1, VersionPlusOne, LatestVersion = VersionPlusOne - 1 }; const static FGuid GUID; }; const FGuid FTestVersion::GUID(0x11310AED, 0x2E554D61, 0xAF679AA3, 0xC5A1083C); FCustomVersionRegistration GRegisterReproCustomVersion(FTestVersion::GUID, FTestVersion::LatestVersion, TEXT("TestVersion")); void AEngineTestPropertiesActor::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar.UsingCustomVersion(FTestVersion::GUID); } void AEngineTestPropertiesActor::PostLoad() { Super::PostLoad(); const int32 TestVersion = GetLinkerCustomVersion(FTestVersion::GUID); if (TestVersion < FTestVersion::NewIntegerProperty) { NewIntegerProperty = IntegerProperty_DEPRECATED; } if (TestVersion >= FTestVersion::NewIntegerProperty) { IntegerProperty_DEPRECATED = NewIntegerProperty; } }
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-209248 in the post.
0 |
Component | UE - Gameplay - Blueprint |
---|---|
Affects Versions | 5.0, 5.5 |
Target Fix | 5.6 |
Created | Mar 7, 2024 |
---|---|
Updated | Oct 1, 2024 |