x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Get all Actors from mounted .pak

To support modding, I create .pak files manually from our ModKit. Those .pak files may contain Material/StaticMeshes/Sounds/Actors/...

I am able to mount/unmount the .pak files at runtime and pass the mount path to the AssetRegistry to add the data.

  assetRegistry.ScanPathsSynchronous({ properContentDir }, true);

I'm able to get any Data-Asset using the AssetRegistry (Materials, Sounds, StaticMeshes, ...).

Trouble occours when going for blueprint generated actors. I found this tutorial for scanning a path for blueprint classes: http://kantandev.com/articles/finding-all-classes-blueprints-with-a-given-base

This works in editor and packaged build. However in a packaged build I'm only able to get Blueprint-Actors that are part of the main-pakfile. BlueprintGenerated actors from the runtime mounted pak are not returned from the asset registry. I opened the created .pak to make sure the BlueprintClasses are inside.

     FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
     IAssetRegistry& assetRegistry = AssetRegistryModule.Get();
 
     if (assetRegistry.IsLoadingAssets() || bScanPath)
     {
         TArray<FString> pathsToScan;
         pathsToScan.Add(*path);
         assetRegistry.ScanPathsSynchronous(pathsToScan, true);
     }
 
     FARFilter filter;
     filter.bRecursivePaths = bPathRecursive;
     filter.bRecursiveClasses = true;
     filter.PackagePaths.Add(*path);
     // Note: assetClass->IsInBlueprint() returns true, if the class was implemented in blueprint.
     // It will return false for classes that are native, like AActor.
     if (bBlueprintClass)
     {
         filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
     }
     else
     {
         filter.ClassNames.Add(*assetClass->GetClass()->GetName());
     }
     TArray<FAssetData> assetList;
     assetRegistry.GetAssets(filter, assetList);

assetList does not contain the actors from the mounted .pak, they are not known to the AssetRegistry.

Any idea why?

Product Version: UE 4.19
Tags:
more ▼

asked Oct 10 '18 at 04:13 PM in C++ Programming

avatar image

Rumbleball
287 8 20 22

avatar image StrangerGwenn Nov 12 '18 at 12:20 PM

Hey Rumbleball, we're trying to get mod support to work over here and face a similar issue : no DataAsset object we looked for was ever found by Asset Registry, though our valid PAK file was correctly mounted. DataAssets are basic UObjects, I have no idea if they're closer to Blueprints than they are to other resources. I've seen your answer and I'll definitely try it out, but this seems like an engine issue.

Did you ever find a more relevant solution ?

avatar image Rumbleball Nov 12 '18 at 03:20 PM

As long as you do not get anything, I would not assume you mounted correctly. Make sure the MountPoint in the package is correct ../../../GameName/... and you mount it to that mount point. In case you package from a different project (Different project name) you need to change the GameName in the mount point.

Then use

      FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
      IAssetRegistry& assetRegistry = AssetRegistryModule.Get();
 
          assetRegistry.ScanPathsSynchronous(pathsToScan, true);


After that you should be able to get the assets via the asset registry. This is valid for things links Materials, StaticMeshes, ... All assets that do not define a class.

Also make sure you actually mounted. Mounting a .pak is only possible in packaged game (Shipping/Development/Debug).

Also see my post here: https://answers.unrealengine.com/questions/131889/mounting-pak-files-at-runtime.html

avatar image StrangerGwenn Nov 12 '18 at 10:38 PM

Well, I haven't got the Pak file to mount in the packaged game by putting it in the "Paks" folder. I tried something close to the code you linked in that thread : https://pastebin.com/aqhsJv7c

The output confirms the validity of the pak file and the two assets I'm adding - material and data asset.

 Display: Target mount point ../../../HeliumRain/Mods/ExampleMod/
 Display: Mounted PakPlatformFile D:/Dock/SteamLibrary/SteamApps/workshop/content/681330/1560623971/Windows/ExampleMod.pak at ../../../HeliumRain/Mods/ExampleMod/
 Display: File ../../../HeliumRain/Mods/ExampleMod/AssetRegistry.bin
 Display: Dir ../../../HeliumRain/Mods/ExampleMod/Content
 Display: File ../../../HeliumRain/Mods/ExampleMod/Content/M_ModMaterial.uasset
 Display: File ../../../HeliumRain/Mods/ExampleMod/Content/M_ModMaterial.uexp
 Display: File ../../../HeliumRain/Mods/ExampleMod/Content/ModSector.uasset
 Display: File ../../../HeliumRain/Mods/ExampleMod/Content/ModSector.uexp
 Display: Dir ../../../HeliumRain/Mods/ExampleMod/Metadata
 Display: File ../../../HeliumRain/Mods/ExampleMod/Metadata/DevelopmentAssetRegistry.bin

Then I just search the asset registry...

     IAssetRegistry& Registry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
     Registry.SearchAllAssets(true);
 
     TArray<FAssetData> AssetList;
     Registry.GetAssetsByClass(UFlareSectorCatalogEntry::StaticClass()->GetFName(), AssetList);

Still can't get anything. Should I try using the AssetRegistry.bin file in the pak file ?

Thanks a lot for helping, there's really nothing out there that appears to work.

avatar image Rumbleball Nov 12 '18 at 11:21 PM

I had trouble letting unreal mount the PakFile automatically by placing it in the Content/Paks folder of the packaged game. It simply did not work out for me. (UE4.19)

Mounting manually works tough...

   IPlatformFile* ExistingPakPlatformFile = FPlatformFileManager::Get().FindPlatformFile(*PakFileName);

is wrong and must be

 IPlatformFile* existingPakPlatformFile = FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile"));

We are getting the PakPlatformFile here the engine already puts into the PlatformFile-Chain. The name of the PakPlatformFile is PakFile. You should not change anything about this line.

 if (!PakPlatformFile->Mount(*PakFileName, 0, *PakFile->GetMountPoint()))
     {
         FLOG("Failed to mount PakPlatformFile");
     }
     else
     {
         FLOGV("Mounted PakPlatformFile %s at %s", *PakFileName, *PakFile->GetMountPoint());
     }

You are not mouning a PakPlatformFile. You use the PakPlatformFile to mount your PakFile.

Instead of doing that stuff manually, you can also use:

 FCoreDelegates::OnMountPak.ExecuteIfBound(YOURPAKFILE, PAKORDER, nullptr)

The PakPlatformFile the engine creates binds to that delegate

 // Bound to FCoreDelegates::OnMountPak
 bool FPakPlatformFile::HandleMountPakDelegate(const FString& PakFilePath, uint32 PakOrder, IPlatformFile::FDirectoryVisitor* Visitor)

avatar image StrangerGwenn Nov 13 '18 at 04:34 AM

I've reverted the offending line, with no change. I've also tried the OnMountPak approach with exactly the same result - Pak mounts fine, all files present, no errors, still nothing found through AssetRegistry.

Basically my take here is that AssetRegistry is simply unable to find mod content at all. Did you get that in particular to work ? Or are you using something like SynchronousLoad instead ?

I've seen discussions here (https://answers.unrealengine.com/questions/587400/what-are-uexp-and-ubulk-files.html) about using FPaths::GameContentDir vs FPaths::EngineContentDir, does that ring any bell ? I've mounted my pak to PakFile->GetMountPoint() myself, which is "../../../HeliumRain/Mods/ExampleMod/".

avatar image Rumbleball Nov 20 '18 at 02:38 AM

You want to mount to GameContentDir as it is your content and not of engine.

"../../../HeliumRain/Mods/ExampleMod/". You missing content here. "../../../HeliumRain/Content/Mods/ExampleMod/".

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

Don't know why the AssetRegistry wouldn't find the classes. So I came up with a workaround.

This function makes use of some custom functions, but you get the idea. The function itself is expensive and should be run async.

 void GetBlueprintClassesInDirectory(const TSubclassOf<UObject> blueprintClass, const FString path, const bool bRecursive, TArray<UClass*>& blueprintClasses)
 {
     double startTime = FPlatformTime::Seconds();
 
     // Convert the content path to a full path to look for files.
     FString projectContentDir = FPaths::ProjectContentDir();
     FString properContentDir = MakeProperContentDir(path); // /Game/...
     FString contentRelativeDir = properContentDir;
     properContentDir.Split(TEXT("/Game"), nullptr, &contentRelativeDir);
     FString fullDir = projectContentDir + contentRelativeDir; // File system directory
 
     TArray<FString> foundFiles;
     UContentMountLibrary::GetAllFilesFoldersInDir(fullDir, FString("*"), true, false, foundFiles, true); // In a packaged game, files are returned multiple times.
 
     for (const FString& file : foundFiles)
     {
         if (file.EndsWith(TEXT(".uasset")))
         {
             // Convert the file path back to a content path.
             FString fileContentDir = FPaths::GetPath(file);
             FPaths::MakePathRelativeTo(fileContentDir, *projectContentDir);
             fileContentDir = FString(TEXT("/Game/")) + fileContentDir;
             fileContentDir.RemoveFromEnd(FString(TEXT("/")));
 
             FString fileName = FPaths::GetBaseFilename(file);
 
             FString classReference = FString::Printf(TEXT("%s/%s.%s_C"), *fileContentDir, *fileName, *fileName);
             UClass* loadedClass = LoadObject<UClass>(nullptr, *classReference);
             if (loadedClass && loadedClass->IsChildOf(blueprintClass))
             {
                 blueprintClasses.AddUnique(loadedClass); // NOTE we AddUnique as files are returned multiple times by file search function.
             }
         }
     }
 
     CM_LOG(Verbose, "GetBlueprintClassesInDirectory completed in %0.6f seconds", FPlatformTime::Seconds() - startTime);
 }
more ▼

answered Oct 15 '18 at 10:59 AM

avatar image

Rumbleball
287 8 20 22

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question