Reference Viewer behavior

See steps,

Basically just don’t like how it shows lingering dependency chains as if they were direct references, it is confusing.

Even when I delete the Mat Func asset, the confirm deletion window will show the MIC as a referencer.. when it absolutely is not.

Steps to Reproduce

  1. Create a regular Mat Func, a Material, and a MIC from that Material.
  2. Add the Mat Func into the Material and save all three assets.
  3. Check the reference viewer on the Mat Func with referencer depth set to 2, confirming that it shows the Mat and then the MIC
  4. Delete the Mat Func from the Material and save the Material.
  5. Check the reference viewer on the Mat Func with referencer depth set to 1, note how it is showing the MIC as a direct referencer when it is not and never was.

That does indeed sound like incorrect behavior.

I tried reproducing it on UE 5.4, 5.5, and 5.6 preview, but I can’t seem to reproduce it. These are my steps, can you see if they diverge from yours?

  1. Create a new empty Material and a new empty Material Function.
  2. Right click the Material and click “Create Material Instance”.
  3. Open the Material Function and put a Constant4Vector to have an output.
  4. In the Material, drag in the Material Function and connect it’s Output pin to the Base Color pin of the Material.
  5. Save the Material, the Material Function, and the Material Instance assets.
  6. Reference viewer shows Material Instance -> Material -> Material Function dependency chain.
  7. Delete the Material Function from the Material, save the Material.
  8. Reference viewer only shows Material Instance -> Material dependency chain, Material Function doesn’t have any dependencies or references.

If you’re deleting the material function outside of UE, like through version control or Windows Explorer, then it would explain this behavior.

An asset’s list of dependencies is saved into the asset itself when you save it. If you delete any of the other assets it depends on without resaving the asset itself, then its dependency list will remain unchanged.

In my case, I was removing the material function from the Material and then saving it, updating its dependencies list, which is why it worked for me. If you are deleting the material function asset itself, especially outside of UE, and expecting other assets who depend on it to update themselves, then that’s not how it works in UE. That’s why resaving the packages is fixing it in your case.

I will also mention that deleting assets while other assets are still depending on them, especially outside of UE, can in some cases produce crashes. It’s best to first make sure that you have removed all references to an asset before deleting it.

After your step 7 try restarting the editor and then try the reference viewer on it.

On my end, I can revert a deleted regular mat func asset, open the editor and do reference viewer on it and this is what it looks like:

[Image Removed]I will note that doing a package resave on these ‘referencers’ does clear out whatever is causing this.

Nope, as mentioned in the opening post, it was deleted inside of the editor with the content browser’s delete function.

Also the explanation doesn’t explain the problem because the problem was indirect referencers were being indicated as direct referencers in the reference viewer as shown in the picture.

In stock engine it is not possible for a MIC to directly reference a Regular Mat Func. It can only reference other asset types that can directly reference regular mat funcs (Materials, Layer/Blend Funcs).

Got it.

Yes, the MIC directly referencing the Material Function in your screenshot is indeed weird. I’m not able to get my MIC to show a direct reference like what is happening to you. Are you testing it with a mostly empty Material Function in the stock editor for the repro steps, like I’m doing? If we can get simple repro steps on the stock editor, then I’ll be able to see why it’s happening; otherwise, it’s something specific to your project, its assets, or potential engine modifications.

If we can’t get repro steps on an empty project in the stock editor, what you can do is to look into why the Material Function is being added as a dependency to the MIC in your project: add a breakpoint into `FPackageHarvester::TryHarvestImport`, save the MIC, and check the stack once it hits the breakpoint while trying to harvest the Material Function as an import.

Ok I made a repro setup for you. To use it, create a new 5.5.4 project, unzip this into it. Then you will have 2 assets in their original locations the function and a mic, run reference viewer on the func and you should see it repro.

Great, thank you. I can see that the reference to the Expand material function is indeed embedded in the MIC in your files. But because of how references get saved into assets (it’s just a list), it doesn’t tell me how it got there in the first place. That’s the part I would need to reproduce to catch it.

If I add the Expand function you provided to a new empty Material and create a MIC from that, it still doesn’t reproduce what you’re encountering for me.

In the repro steps in the initial post, you mentioned that you can reproduce this with a brand new Material, Material Function, and Material Instance. Can you attach those test files? That would be easiest.

If it does NOT work for new materials, then you can try creating a new MIC and see if it reproduces for that. If it doesn’t, then the Material might’ve been created in an earlier engine version and has since been fixed.

But if it happens also to the new MIC, it would lead me to believe that something in your Material is creating a dependency on the Expand function when a MIC of it is created. You could do a method of elimination by deleting nodes in the material, creating a new MIC, and see at which point it fixes itself. Then you’ll have the culprit. Or putting a breakpoint into `FPackageHarvester::TryHarvestImport` and seeing when the Expand function gets added as an import of the MIC when you save it.

“But because of how references get saved into assets (it’s just a list)”

Which is presumably a caching optimization? Does that list include indirect referencers?

“try creating a new MIC and see if it reproduces for that.”

Can’t, that function was removed from the base mats a long time ago.

" If it doesn’t, then the Material might’ve been created in an earlier engine version and has since been fixed."

Yah base material was probably created in 5.2 and we are on 5.5 now, the function was removed from it long time ago probably 5.4 or earlier.

Yes I couldn’t repro it again either, and remember I said that when I resave the MICs, the issue is cleared. So maybe it was an issue of a stale cache of referencers being naively used by the reference viewer, where the direct referencer is gone so it was only a list of irrelevant references left?

“Which is presumably a caching optimization?”

It’s a very performant way of doing it, yes. Going through a big BP graph for example, collecting references, can take a little while which isn’t noticeable during save time. But when you start UE, it needs to scan every single asset in the whole project and collect those references to populate the asset registry. For thousands of assets, any amount of time that isn’t as close to “instant” as possible will quickly turn into death by thousand cuts. So it needs to be as fast as possible.

“Does that list include indirect referencers?”

No, it doesn’t, so that’s why I think this is so weird. I believe the MIC somehow got the reference to the Material function serialized into it during save time or at the time of creation, but that’s not supposed to happen.

“So maybe it was an issue of a stale cache of referencers being naively used by the reference viewer, where the direct referencer is gone so it was only a list of irrelevant references left?”

I think it was definitely an incorrect reference saved into the asset, which automatically “fixes itself” when you resave the asset since it uses now the more up-to-date, and presumably fixed, way of collecting references.

Glad to hear that resaving the asset fixes the problem and that it isn’t occurring for new assets! One final advice I have is to resave all the assets in the project any time the team does a UE version upgrade (like from 5.4 to 5.5, no need to do it for patches like from 5.5.0 to 5.5.4). We have a commandlet that does it for you, you can check out this community resource on the ResavePackages commandlet for reference.

The ResavePackages commandlet has a bunch of parameters you might want to look into, for example having it check the files into version control for you, skip checked-out assets, only resaving assets in certain folders, etc. You can check out `UResavePackagesCommandlet::Main` in UnrealEd\Private\Commandlets\ContentCommandlets.cpp for the parameters it accepts.

“I believe the MIC somehow got the reference to the Material function serialized into it during save time or at the time of creation, but that’s not supposed to happen.”

I mean yah.. I don’t know how it can even happen when the class has no means to directly reference regular mat functions.

Like what you said in the previous post: “it would lead me to believe that something in your Material is creating a dependency on the Expand function when a MIC of it is created.”

The only thing a Material can have that can reference a Regular Mat Func is a Material Function Call Expression. But that cannot ‘induce a dependency’ on a MIC, its only ever an indirect dependency in the chain.

So at this point seems like we can only conclude it was a bug in the code at some point that introduced the incorrect reference list but has since been fixed apparently.

“The ResavePackages commandlet has a bunch of parameters you might want to look into”

Does it have an option to only resave packages that are not saved under the latest engine asset version?

Kinda. You can use -CHECKLICENSEEVER=x to only resave packages saved with licensee version x or lower.

There are alternatively the -MINVER=x and -MAXVER=x parameters, but those are not UE versions like 5.5.4, they are EUnrealEngineObjectUE5Version numbers which start with 1000 and are currently at 1013 for 5.5.4. We don’t update it when UE updates, we update it when the UObject serialization format changes.

I haven’t used it, and I don’t believe we use it here at Epic Games, so I can’t vouch for it or recommend it.

Ok thanks