The Asset Registry: Finding and Iterating Through Assets with UE4 Python
One thing that you will want to do right away is iterate through a bank of existing assets or find assets in a build. In UE4, your main window into the ‘content browser’ is the ‘asset registry’. You can use it to find all kinds of assets, iterate through assets in a folder, etc.
Let’s go ahead and instance it to take a look, now would be a good time to open the unreal.AssetRegistryHelpers UE4 Python API docs in another tab! Also, I am running this in UE4 4.21 release, with the free Paragon asset Marketplace assets.
Walking Assets In A Directory
Let’s ask it for all the assets in a certain path.
asset_reg = unreal.AssetRegistryHelpers.get_asset_registry() assets = asset_reg.get_assets_by_path('/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes') |
The method to get the asset registry has returned an unreal.AssetRegistry class. If you look at this class, you can see some really useful calls, like get_assets_by_path, that I used on the next line.
Let’s take a look at the assets:
for asset in assets: print asset |
This yields:
LogPython: <Struct 'AssetData' (0x000001ADF8564560) {object_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh_Skeleton.Morigesh_Skeleton", package_name: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh_Skeleton", package_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes", asset_name: "Morigesh_Skeleton", as set_class: "Skeleton"}> LogPython: <Struct 'AssetData' (0x000001ADF8566A90) {object_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Orion_Proto_Retarget.Orion_Proto_Retarget", package_name: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Orion_Proto_Retarget", package_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes", asset_name: "Orion_Proto_R etarget", asset_class: "Rig"}> LogPython: <Struct 'AssetData' (0x000001ADF8564560) {object_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh_Cyl_Shadows.Morigesh_Cyl_Shadows", package_name: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh_Cyl_Shadows", package_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes", asset_name: "Morigesh_Cyl_ Shadows", asset_class: "PhysicsAsset"}> LogPython: <Struct 'AssetData' (0x000001ADF8566A90) {object_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh_Physics.Morigesh_Physics", package_name: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh_Physics", package_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes", asset_name: "Morigesh_Physics", asset_ class: "PhysicsAsset"}> LogPython: <Struct 'AssetData' (0x000001ADF85654B0) {object_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh.Morigesh", package_name: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh", package_path: "/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes", asset_name: "Morigesh", asset_class: "SkeletalMesh"}></code> |
It has returned Python Objects of ‘unreal.AssetData‘ type, this class has a lot of things we can query, like class type, name, full path, etc. Let’s print the class name for each:
for asset in assets: print asset.class |
Let’s only look at skeletal meshes and then let’s do something to them. In order to manipulate them, we need to load them, look at what the get_full_name function returns:
for asset in assets: #you could use isinstance unreal.SkeletalMesh, but let's build on what we learned if asset.asset_class == 'SkeletalMesh': print asset.get_full_name() #>SkeletalMesh'/Game/ParagonMorigesh/Characters/Heroes/Morigesh/Meshes/Morigesh.Morigesh' |
We need to split that output, then load the asset:
for asset in assets: if asset.asset_class == 'SkeletalMesh': full_name = asset.get_full_name() path = full_name.split(' ')[-1] skelmesh = unreal.load_asset(path) |
Now this returned an unreal.SkeletalMesh class and we can ask it for it’s skeleton:
skeleton = skelmesh.skeleton |
Finding Assets
Let’s say someone gives you a list of problematic assets, but they’re not long paths, just asset names! You want to be able to find the long path for all assets in the list so that you can do something with them. The AssetRegistry can help!
Let’s build a dictionary of all asets in the build, the keys will be the short names, and the values will be the long paths:
def get_asset_dict(asset_type=None): asset_list = None if asset_type: asset_list = unreal.AssetRegistryHelpers.get_asset_registry().get_assets_by_class(asset_type) else: asset_list = unreal.AssetRegistryHelpers.get_asset_registry().get_all_assets() asset_dict = {} for asset in asset_list: asset_name = str(asset.asset_name) obj_path = asset.object_path if asset_name not in asset_dict: asset_dict[asset_name] = [str(obj_path)] else: asset_dict[asset_name].append(str(obj_path)) return asset_dict |
This takes a second or two to build, but you now have an index of all assets by package name, that you can query their full path. It’s a bit faster if you query all assets of a certain type you know you’re looking for. You also will know when there is more than one asset with a name, because it’s list will have multiple entries. (That’s why we store what we find in a list, there could be multiple assets with the same name)
Awesome post. I was actually stuck with my code until I saw your use of AssetRegistryHelpers, so thank you for that.
However, I think I found a small typo you might want to correct to avoid other people getting confused. It’s in your 4th code snippet. The one that reads:
for asset in assets:
print asset.class
That second line needs to be “print asset.asset_class” in order to work.
Thank you for putting out such great and useful content. It’s been quite a few times already I’ve been trying to figure out how to code something a bit obscure for which there seem to be no examples in all of the web, when eventually my google explorations end up leading me to the answer in one of your posts.
Comment by Jorge — 2019/02/19 @ 1:07 PM
Hello Christopher.
I already posted a comment a few days ago, but I don’t see it appearing so I’m guessing it didn’t go through for some reason. But apologies if you get a similar message from me twice.
I just wanted to let you know that you seem to have a small typo in the example where you show how to print the class for every asset. So where it says
print asset.class
it should really say
print asset.asset_class
I know you know the correct expression as you use it in the if statement in the next example. But I thought you might want to correct it so that it doesn’t cause confusion to others.
Otherwise thank you for this, and all your other fantastic posts.
Jorge
Comment by Jorge — 2019/02/22 @ 7:23 PM
Thank you! This is great to see.
Here’s something I’m stuck on that’s related:
Get BP assets that have a certain Parent Class.
I can’t find anywhere in the python docs to check a BP’s parent class, just as they might appear in the Content Browser as “ParentClass”.
Any ideas?
Thanks!
Comment by Len — 2019/09/30 @ 10:12 PM