Is is possible to create a redirector from a blueprint variable to a uproperty defined in code?

I want to move a field from an inherited blueprint class to its code base class. Is it possible to use a redirector to fix all of the blueprint reads/writes to reference the new field now defined in code?

It is possible. Let’s say I have a blueprint class named MyActor that is a child of Actor and a variable named Foo and I want to redirect it to a variable named Bar. Let’s start with the case where both Foo and Bar are on MyActor. The redirector would look like this:

+PropertyRedirects=(OldName=“/Game/BP_MyActor.SKEL_BP_MyActor_C.Foo”,NewName=“/Game/BP_MyActor.SKEL_BP_MyActor_C.Bar”)

If both Foo and Bar were members of AActor then your redirector would look like this:

+PropertyRedirects=(OldName=“/Script/Engine.Actor.Foo”,NewName=“/Script/Engine.Actor.Bar”)

Finally, for the case you’re interested in, we have Foo on MyActor and Bar on AActor. Because the package doesn’t match in the old and new names we can’t specify the outer in the old name so our redirector would look like:

+PropertyRedirects=(OldName=“/Game/BP_MyActor.Foo”,NewName=“/Script/Engine.Actor.Bar”)

There isn’t current support for redirecting blueprint enums. I believe the original intention was for any redirection to happen through the editor similar to other assets. That won’t help in your case though. I’ve added support for this in CL 3808541. In case you can’t see it and want to add the change to your codebase just add the following code near the bottom of FCoreRedirects::GetFlagsForTypeName

if (TypeName == NAME_UserDefinedEnum)
{
	return ECoreRedirectFlags::Type_Enum;
}

You’ll also need to update UnrealNames.inl to support the new NAME_UserDefinedEnum constant.

The redirectors for using this are a bit unusual so I’ll walk through an example after explaining what you’ll need to do. Your redirector will need an OverrideClassName or else you’ll end up with a byte as the new type instead of an enum. You’ll also need to provide ValueChanges for each of the enum values even if they’re the same names in both. The names in your old enum don’t matter. The old names you use in the redirector will be NewEnumerator# where # is the index of the value in the enum starting at 0.

Let’s say I have a blueprint enum, called EMyBPEnum, that I’m replacing with a code enum, called EMyCodeEnum, and they both contain Value1 and Value2. My final redirector would look like this:

+EnumRedirects=(OldName=“/Game/EMyBPEnum.EMyBPEnum”,NewName=“/Script/Engine.EMyCodeEnum”, ValueChanges=((“NewEnumerator0”,“EMyCodeEnum::Value1”), (“NewEnumerator1”,“EMyCodeEnum::Value2”)), OverrideClassName=“/Script/CoreUObject.Enum”)

Thanks for finding that Jon. It’s working now quite nicely.

One issue I did come across though is that due to editing the order of the original Blueprint enumerators the values NewEnumeratorN (N - 0, 1, …) no longer matched the code enumerator values even though they were displayed in the same order. This meant that I had get the actual enumerators to values from UUserDefinedEnum::SetEnums and map those to the correct code enumerators in the redirector. No big deal, but a gotcha to be aware of.

Thanks Fred!

Hi,

just to follow up on this I’m attempting to redirect a enum declared in Blueprint to a code defined enum with a different name, but the same enum value names. E.g.

MyBPEnum
{
Value1,
Value2
}

MyCodeEnum
{
Value1,
Value2
}

I’ve setup the redirector as follows in DefaultEngine.ini:

[CoreRedirects]
+EnumRedirects(OldName=“/Game/MyFolder1/MFolder2/MyBPEnum.MyBPEnum”,NewName=“/Script/MyCodeModule.MyCodeEnum”)

I’ve verfied that FCoreRedirects::RedirectNameAndValues redirects the name correctly, however, BP variables of type MyBPEnum remain unchanged instead of being redirected to MyCodeEnum.

Any ideas?

Thanks,

-David

Thanks Fred. This almost did the trick. Unfortunately, it failed to correctly update enumerator references in BP. Instead those got redirected to NewEnumeratorX.
I also tried using the actual enumerator names and they were still redirected to NewEnumeratorX.

Any ideas?

-David

Here’s the redirector I’m using in DefaultEngine.ini:

[CoreRedirects]
+EnumRedirects=(OldName=“/Game/GlobalData/Enums/Enum_AI_CombatStates.Enum_AI_CombatStates”,NewName=“/Script/RsGameTechRT.ERsCombatState”, ValueChanges=((“NewEnumerator0”,“ERsCombatState::Neutral”), (“NewEnumerator1”,“ERsCombatState::Attacking”)), (“NewEnumerator2”,“ERsCombatState::Reaction”)), (“NewEnumerator3”,“ERsCombatState::Blocking”)), (“NewEnumerator4”,“ERsCombatState::Parrying”)), (“NewEnumerator5”,“ERsCombatState::Evading”)), (“NewEnumerator6”,“ERsCombatState::Stunned”)), (“NewEnumerator7”,“ERsCombatState::Telekinesis”)), OverrideClassName=“/Script/CoreUObject.Enum”)

FEnumEditorUtils::UpdateAfterPathChanged is returning Enum_AI_CombatStates::NewEnumeratorX (where X is 0, 1, 2 etc). I tried using Enum_AI_CombatStates::NewEnumeratorX in the redirector and still no luck.

Here’s the updated redirector:

[CoreRedirects]
+EnumRedirects=(OldName=“/Game/GlobalData/Enums/Enum_AI_CombatStates.Enum_AI_CombatStates”,NewName=“/Script/RsGameTechRT.ERsCombatState”, ValueChanges=((“Enum_AI_CombatStates::NewEnumerator0”,“ERsCombatState::Neutral”),(“Enum_AI_CombatStates::NewEnumerator1”,“ERsCombatState::Attacking”)),(“Enum_AI_CombatStates::NewEnumerator2”,“ERsCombatState::Reaction”)),(“Enum_AI_CombatStates::NewEnumerator3”,“ERsCombatState::Blocking”)),(“Enum_AI_CombatStates::NewEnumerator4”,“ERsCombatState::Parrying”)),(“Enum_AI_CombatStates::NewEnumerator5”,“ERsCombatState::Evading”)),(“Enum_AI_CombatStates::NewEnumerator6”,“ERsCombatState::Stunned”)),(“Enum_AI_CombatStates::NewEnumerator7”,“ERsCombatState::Telekinesis”)),OverrideClassName=“/Script/CoreUObject.Enum”)

I’ve attached a screenshot of what I’m seeing in VS for FCoreRedirects::GetValueRedirects.

I tried using both:
/Game/GlobalData/Enums/Enum_AI_CombatStates.Enum_AI_CombatStates::NewEnumerator1

and

/Game/GlobalData/Enums/Enum_AI_CombatStates::NewEnumerator1

Both caused the redirector to no longer work.

Thanks for the info Fred.

I’ve verified that the enum type itself is redirected correctly and RedirectNameAndValues finds the correct enum value changes.

However, after digging into this a bit further I’m unable to see where it actually does the enumerator name redirection. It only calls FCoreRedirects::GetValueRedirects once for my enum from UUserDefinedEnum::SetEnums. That fails to find _MAX so adds it to the Names map and then adds the unredirected names to the master list.

No worries, I’ve been out for the holidays.

I did the test case you recommended and got max enum value for the value and *_MAX name for the string value for all enum values. So no, the enum values are not being redirected to the values assigned in C++.

Thanks for finding that Jon. It’s working now quite nicely.

One issue I did come across though is that due to editing the order of the original Blueprint enumerators the values NewEnumeratorN (N - 0, 1, …) no longer matched the code enumerator values even though they were displayed in the same order. This meant that I had get the actual enumerators to values from UUserDefinedEnum::SetEnums and map those to the correct code enumerators in the redirector. No big deal, but a gotcha to be aware of.

Thanks for finding that Jon. It’s working now quite nicely.

One issue I did come across though is that due to editing the order of the original Blueprint enumerators the values NewEnumeratorN (N - 0, 1, …) no longer matched the code enumerator values even though they were displayed in the same order. This meant that I had get the actual enumerators to values from UUserDefinedEnum::SetEnums and map those to the correct code enumerators in the redirector. No big deal, but a gotcha to be aware of.

Hi,

I’ve run into an issue with Enum redirection. We have a blueprint enumerator Enum_BPExample. I setup a redirector to a code Enum_Code. Everything works. There is an interface blueprint BP_Interface, that has a function that takes Enum_BPExample as a paramter. It correctly shows up as Enum_Code. However, when I check for find references to Enum_BPExample, BP_Interface shows up as referencing the original blueprint version (nothing else does).

Some animation notifies were referencing Enum_BPExample (but correctly show up as Enum_Code). If I compile and save the interface BP_Interface, with or without any changes, it appears to work correctly, but when I restart the editor, all the values for Enum_Code in the animation notifies have been reset to the first enum value of Enum_Code.

Any ideas?
Thanks

Jiesang

I mentioned that in my answer. You need to include ValueChanges in the redirector to go from NewEnumeratorX to your new values. Is that not working for you?

I’m not sure why that isn’t working for you. One thing you could try doing is putting a breakpoint inside FEnumEditorUtils::UpdateAfterPathsChanged and loading your blueprint that uses the enum. You should be able to see what names it’s expecting inside that function. You could also try using the long form of the names (eg “Enum_AI_CombatStates::NewEnumerator0”)

That looks correct to me. It’s possible that there is something else going on with the enum value names that wasn’t there in my simple test example. The next thing I’d recommend trying is putting a breakpoint inside FCoreRedirects::GetValueRedirects. You should see a call with UK2Node::PostReconstructNode further up the callstack. Seeing what name it’s trying to use here may be helpful.

There are a couple potential things that could be happening. Are you getting a non-null result in FoundRedirect after the call to RedirectNameAndValues? If not, it’s either not finding the redirector at all or the redirector doesn’t have the values associated with it. You should be able to figure out which by stepping in a few times until you hit FCoreRedirects::GetMatchingRedirects. You might need to inspect the RedirectsForName array to make sure your type is there and matches the object name you’re looking for.

If you’re finding the redirector but the value changes aren’t associated with it you should probably check the data in the redirects map anyways in case your data is there but not being returned for some reason.

If you’re sure you’re getting the right redirector and there are no values you should throw a breakpoint in FCoreRedirects::ReadRedirectsFromIni to see why they aren’t being stored. If you are getting value redirects then it should just be a matter of looking at the value being passed into GetIndexByNameString and making sure it matches what you have in the ini.

David,

I’m very sorry for the delay in response. I will be investigating this further early next week.

Any additional info on your setup would be helpful. From the previous responses, I think I have a decent understanding of what you’re doing here.

Out of curiosity, are the enum values at least being directed? E.G.:

BPEnum { Value1 = 1; Value2 = 2; … }
CPPEnum { Value1 = 10; Value2 = 20; … }

Would casting the value of BPEnum::Value1 and printing it display 1 or 10 for you? Have you tested this sort of case?

Thanks,
Jon N.