Hello [mention removed],
As far I’m aware, using Core Property Redirects (https://dev.epicgames.com/documentation/en-us/unreal-engine/core-redirects-in-unreal-engine) remains the official and recommended solution for handling edge cases when converting Blueprint variables to C++. That’s the safest way to prevent data loss during serialization and asset loading.
Using Metadata specifiers like only exists in the editor, and doesn’t affect serialization (https://dev.epicgames.com/documentation/en-us/unreal-engine/metadata-specifiers-in-unreal-engine). Epic itself indicates to not use it for final applications, just for Editor work. Data is saved based on internal UProperty name, so during reparenting, the variables will be lost unless there is a Property Redirect.
A possible solution I see, is to create and generate this property redirects entries from an Editor Tool. You could use an EditorUtilityWidget to speed up the process and use Unreal Reflection system (https://dev.epicgames.com/documentation/en\-us/unreal\-engine/reflection\-system\-in\-unreal\-engine) to relate the Blueprint and C++ variables, and generate this Property redirects.
Here are some of the code I’ve been using to check if this was possible:
1- Get CDO of the unreal class:
static UObject* ResolveToInstance(UObject* Object)
{
if (UBlueprint* BP = Cast<UBlueprint>(Object))
{
if (BP->GeneratedClass)
return BP->GeneratedClass->GetDefaultObject();
}
return Object;
}
2. Sanitize Property Names (Replace Ilegal characters):
static FString SanitizeCppIdentifier(const FString& In)
{
FString Out;
Out.Reserve(In.Len());
for (TCHAR C : In)
{
if (FChar::IsAlnum(C) || C == TEXT('_'))
Out.AppendChar(C);
else
Out.AppendChar(TEXT('_')); // replace illegal characters with underscore
}
while (Out.StartsWith(TEXT("_")))
Out.RightChopInline(1);
if (!Out.IsEmpty() && FChar::IsDigit(Out[0]))
Out = TEXT("N") + Out;
return Out;
}
3- Loop through Blueprint Properties:
for (TFieldIterator<FProperty> It(Class); It; ++It)
{
FProperty* Property = *It;
if (Property->GetOwnerClass() != Class)
continue;
FString RawName = Property->GetName();
FString Type = Property->GetClass()->GetName();
FString Display = Property->GetMetaData(TEXT("DisplayName"));
}
4. Detect Edge Cases
FString BaseName = Display.IsEmpty() ? RawName : Display;
FString Clean = SanitizeCppIdentifier(BaseName);
bool bIsEdgeCase = !Clean.Equals(BaseName);
if (bIsEdgeCase)
{
Result.Add(FString::Printf(TEXT("C++ Name: %s, Type: %s, Blueprint Name: %s"),
*RawName, *Type, *Display));
}
else
{
Result.Add(FString::Printf(TEXT("C++ Name: %s, Type: %s"),
*RawName, *Type));
}
5- Generate Core Property Redirects:
(Build sanitized OldName and NewName for .ini entries)
FString SafeOld = SanitizeCppIdentifier(RawName);
if (SafeOld.IsEmpty())
SafeOld = TEXT("RenamedProperty");
FString ClassName = Class->GetName();
FString OldFull = FString::Printf(TEXT("%s.%s"), *ClassName, *SafeOld);
FString NewFull = FString::Printf(TEXT("%s.%s"), *ClassName, *Clean);
FString Redirect = FString::Printf(TEXT("+PropertyRedirects=(OldName=\"%s\", NewName=\"%s\")"),
*OldFull, *NewFull);
RedirectOutput.Add(Redirect);
To integrate this within your Utility Widget, just plug the exposed InspectProperties(Object) function upon clicking a button in your Utility Widget, add an instance editable UObject variable (to specify which Blueprint Actor to scan), and print the output in a textbox of the Widget. You might also prefer to a TSubclass instead of the UObject*, that is what you prefer the most.
Here’s an example output with a variable using an illegal “$” character:
C++ Name: $TEST, Type: StrProperty, Blueprint Name: BP_TestActor_C.$TEST
----- Redirect Suggestions (For DefaultEngine.ini) -----
+PropertyRedirects=(OldName="BP_TestActor_C._TEST", NewName="BP_TestActor_C.TEST")
The suggested workflow would be to:
1- Carefully review the output with edge-case variables
2- Update illegal variables & resave blueprints
3- Copy redirects to DefaultEngine.ini
4- Rebuild the project.
Please let me know if this helps and don’t hesitate to ask if you need any further assistance.
Best,
Joan