CoreRedirects is not updating Blueprint variables (and decoupling C++ from Blueprints)

UE 5.2 on Windows

Problem Statement

I can’t get my CoreRedirects to change the references to my Enums and Structs in my Blueprints.

Root problem

The root problem is that I’m trying to convert a Blueprint class (“Pathfinding.cpp”) to C++, but it depends on existing code written in Blueprints (BaseGrid). I quickly discovered that I can’t access the variables/methods/Enums I’ve declared in my other Blueprints from C++. And I want to do this in a minimally invasive way so I don’t have to rewrite all of my existing Blueprints.

First I tried to create an C++ Interface for BaseGrid, but that did not allow me to declare variables. Then I tried to create an Abstract parent class, but I realized I would need to convert all of BaseGrid’s variables in C++. So now I am trying to decouple Pathfinding from BaseGrid by just passing in specific variables that it needs. Some of those variables are Enums and Structs, so in order to make those available to both the C++ code and the Blueprints I am trying to convert them to C++ as well. And that lead me to Core Redirects.

Current attempts

I have 3 Enums and a Struct to convert. I have the new ones declared in a TileDataTypes.h file. I have tried both leaving the Enum names as-is and renaming. I have also tried giving a single Enum its own file.

At the bottom of Config/DefaultEngine.ini file I have added a section like this:

[CoreRedirects]
+EnumRedirects=(OldName="E_TileType_Old",NewName="E_TileType",ValueChanges=(("None","Normal","Obstacle"),("None","Normal","Obstacle")))
+StructRedirects=(OldName="S_TileInfo",NewName="/Source/MyGamePrototype/Core/DataTypes/TileDataTypes.S_TileInfo")

Variant attempts:

; with file system path
+EnumRedirects=(OldName="E_TileType",NewName="/Source/MyGamePrototype/Core/DataTypes/E_TileType",ValueChanges=(("None","Normal","Obstacle"),("None","Normal","Obstacle")))

; with Module prefix
+EnumRedirects=(OldName="E_TileType_Old",NewName="/Source/MyGamePrototype/Core/DataTypes/TileDataTypes.E_TileType",ValueChanges=(("None","Normal","Obstacle"),("None","Normal","Obstacle")))

; with Script directory
+EnumRedirects=(OldName="E_TileType_Old",NewName="/Script/MyGamePrototype/Core/DataTypes/TileDataTypes.E_TileType",ValueChanges=(("None","Normal","Obstacle"),("None","Normal","Obstacle")))

; without subdirs (docs show it like this)
+EnumRedirects=(OldName="E_TileType_Old",NewName="/Script/TileDataTypes.E_TileType",ValueChanges=(("None","Normal","Obstacle"),("None","Normal","Obstacle")))

; with reference path on OldName
+EnumRedirects=(OldName="/Game/Blueprints/Core/Grid/GridUtils/E_TileType_Old",NewName="/Script/TileDataTypes.E_TileType",ValueChanges=(("None","Normal","Obstacle"),("None","Normal","Obstacle")))

I then compile and open UE and do a “Fix Up Redirectors” on the folder structure.

As far as I can tell, none of these have changed anything in my Blueprints, and when I try to delete the old Blueprint Enums, UE complains that there are still classes referring to them.

Questions

  1. Am I misunderstanding how CoreRedirects works? Does it only provide symlinks to the new Enums or will it update the actual references?
  2. a. What is the mysterious “Script” folder the documentation examples show? I only have a “Source” folder. It’s not very clear whether I should include my directory path based on these examples. I only found this from other forum posts.
  3. b. I got the “/Game/” path from the “Show References” window in UE, but where is this “Game” folder?
  4. If I ignore UE’s warnings and delete the old file anyway, will it corrupt my Blueprints (i.e. they won’t open for me to make the changes manually)?
  5. Is there a log output somewhere from CoreRedirects so I can see what it does/doesn’t do and/or errors or warnings?

/Script/ProjectName is a virtual package that contains all C++ declarations of your project. Since it’s virtual it has nothing to do with files on disk.

In your case I’m guessing it should look like

/Script/MyGamePrototype.E_TileType
/Script/MyGamePrototype.S_TileInfo

/Game/ is a virtual path that points to your project’s Content folder.
/Engine/ is a virtual path that points to Engine’s Content folder.

1 Like

Thank you for that! That helps my understanding significantly.

Update

While reviewing the “CoreRedirects” docs just now, I noticed the mention of BaseEngine.ini.

In that file, I found a way to show log output for CoreRedirects:

; The -DebugCoreRedirects command line parameter can be used to diagnose issues when adding new redirects

Debugging process

I’m going to leave my method here for posterity:

  1. I’m using VSCode. I found a post on stackoverflow that says you can add command line arguments via .vscode/launch.json

  2. In the list of configurations, I found the entry for "name": "Launch MyGamePrototypeEditor (Development)" (which I recognized from setting up VSCode with these instructions).

  3. Under args I added the parameter, and I also added a custom LOG file name (documented here – 4.26 but it still worked), which looks like this:


"args": [
  "C:\\{path_to_project}\\MyGamePrototype.uproject",
  "-DebugCoreRedirects",
  "LOG=MyLog.txt"
],

  1. I launched Unreal using VSCode “Run → Start Debugging”. After it finished loading my project, I simply closed it.

  2. I used a file system search to find the MyLog.txt file in my project directory, at C:\\{path_to_project}\\Saved\\Logs\\MyLog.txt

Results! …sort of

Okay, with that out of the way, I found this in the log file…

LogCoreRedirects: Error: ReadRedirectsFromIni(Engine) failed to parse ValueChanges for redirect (OldName=“/Game/E_TileType_Old”,NewName=“/Script/MyGamePrototype.E_TileType”,ValueChanges=((“None”,“Normal”,“Obstacle”),(“None”,“Normal”,“Obstacle”)))!

So I revisited the docs again and discovered what I missed (bold added)…

ValueChanges

List of String pairs

The first string in the pair is the old enumerated value, and the second string is the new value. If both values are in the same class, the old value must no longer exist in code.

I had written my ValueChanges thinking it was (fromA, fromB, fromC),(toA, toB, toC) which is wrong.

The correct way is (fromA, toA),(fromB, toB),(fromC, toC).

My new redirect looks like this:


[CoreRedirects]

+EnumRedirects=(OldName="E_TileType_Old",NewName="/Script/MyGamePrototype.E_TileType",ValueChanges=(("None","None"),("Normal","Normal"),("Obstacle","Obstacle")))

Now, this works… but broke my blueprints :frowning_face:

The references to Enum “E_TileType_Old” have been replaced by the type “Byte” with no inputs on the pins.

So I’m still missing something. I’m going to walk back the changes in version control and try again.

As an experiment, I tried giving the NewName something that is obviously wrong DoesNotExist2902903 and the result is the same as when I give it my declared Enum.

LogCoreRedirects: Verbose: RedirectNameAndValues(/Game/Blueprints/Core/Grid/GridUtils/E_TileType_Old.E_TileType_Old) replaced by /Script/MyGamePrototype.DoesNotExist2902903

And everything in the Editor is replaced with an empty byte.

I’ve also tried declaring my Enum in a different way (raw enum, vs enum class). It shows up in the Blueprint Editor for nodes, but unfortunately, I’ve not found any way to ask the Engine where it finds the declaration, so I cannot see if I’m using the correct one for my Redirect and the logs are not helpful there. The closest I’ve gotten here is the module list console command, but that only tells me that MyGamePrototype exists as a module, not what is in it.

And I’ve had no success with the StructRedirects either. The logs show:

LogCoreRedirects: ValidateRedirect(Type 4) can’t validate destination Struct for redirect from /Game/S_TileInfo to /Script/MyGamePrototype/S_TileInfo with unloaded package

…but it shows this for several built-in Unreal redirects as well.

…and with dot-delimiter NewName="/Script/MyGamePrototype.S_TileInfo" I get no log output for the Struct and no changes in the Editor.

At this point, I can only assume the feature is broken. If an Unreal tester finds this thread, perhaps they can validate on their end. Frustratingly, my only option is to do this manually :grimacing:

Epic does plenty of struct redirects from BP to C++ in their default ini, so it should work…

+StructRedirects=(OldName="S_TileInfo",NewName="/Script/MyGamePrototype.S_TileInfo")

How are you sure that it doesn’t work, what changes are you expecting ?

I was expecting that the feature would automatically update my Blueprints, such that any reference to the old enum E_TileType_Old (declared in Blueprints) would be changed to the new enum E_TileType (declared in C++), whilst remapping the values (or at the very least create something like a “symlink” to the new data type).

Instead, the closest I got was that it would replace the old enum with an empty Byte node.

I tried many different ways and could never get it to do that, so I gave up on it and went through the tedious process of doing this manually.

:thinking: One thought I had just now is that perhaps I missed something to do with “namespaces”. I haven’t declared a namespace for any of my modules and maybe that is needed for the feature to work. There is only one mention of this in the docs:

PropertyRedirects

The name of the new property. This name can be fully period-delimited like OldName, or it can be just the variable name if it exists in the same namespace as OldName.

And it doesn’t mention whether Blueprints would have a namespace or what that would be. The only mention is:

ClassRedirects

Specifies a change to the underlying class of the UCLASS. This is generally used to change a Blueprint class to a native class (/Script/CoreUObject.Class).

Hi there @tiberian
Did you ever find a resolution to this? I am having a nearly identical issue and using the -DebugCoreRedirects command-line argument gives me the same kind of feedback:
"LogCoreRedirects: ValidateRedirect(Type 4) can't validate destination Struct for redirect from /Game/Sponza/Blueprints/Flicker/ColorVarStruct to /Game/Blueprints/Flicker/ColorVarStruct with unloaded package"
For some reason it is not finding the destination struct which is bizarre because it’s sitting at that very path. If anything I was thinking it couldn’t find the source struct to replace.
Thanks!