u/Fir0x_

(HELP) AssetRegistryState loading for improved scan time

Hi, I am trying to improve the asset registry scan time by loading pre-serialized version of it, but it doesn't work at all so far.

For context, in our project we have pak files that are stored on a remote server. They have to stay there and cannot be copied to a local disk. The paks are already big, and will be even bigger in the future. Because of that, the call to `IAssetRegistry::ScanPathsSynchronous` takes multiple seconds.

The idea is to produce a serialized version of the registry for each pak containing only the assets with the corresponding chunk ID, with hope that it will be faster.

I wrote a commandlet that takes the `DevelopmentAssetRegistry.bin` generated during cooking, and tried to split it. However, the application crashes during deserialization of my "handmade" registries due to an out of bound index. From what I understand, it seems the content of the file is not what is expected.

Here is the splitting code:

bool GeneratePaksAssetRegistries(const FString& BasePath)
{
  FAssetRegistryState AssetRegistryState;
   if (!FAssetRegistryState::LoadFromDisk(\*(BasePath / "DevelopmentAssetRegistry.bin"), {}, AssetRegistryState))
  {
    return false;
  }

  TSet<int32> ChunkIds;
  AssetRegistryState.EnumerateAllAssets(\[&ChunkIds\](const FAssetData& AssetData)
  {
    for (const int32 ChunkId : AssetData.GdtChunkIDs())
    {
      ChunkIds.Add(ChunkId);
    }
  });

  for (const int32 ChunkId : ChunkIds)
  {
    FAssetRegistryState ChunkState;
    ChunkState.InitializeFromExistingAndPrune(AssetRegistryState, {}, {}, { ChunkId }, {});

    const FString Filename = FString::Printf("AssetRegistry\_pakchunk%d-Windows.bin"), ChunkId);
    const FString FullPath = BasePath / Filename;

    if (FArchive\* Writer = IFileManager::Get().CreateFileWriter(\*FullPath))
    {
      FAssetRegistrySerializationOptions SerializationOptions{};
      SerializationOptions.bSerializeAssetRegistry = true;
      SerializationOptions.bSerializeDependencies = true;
      SerializationOptions.bSerializePackageData = true;
      ChunkState.Save(\*Writer, SerializationOptions);
      Writer->Close();
    }
    else
    {
      return false;
    }
  }

  return true;
}

And here is the snippet of the loading code:

IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();

FAssetRegistryState CachedState;
FAssetRegistryState LoadOptions{};
LoadOptions.bLoadDependencies = true;
LoadOptions.bLoadPackageData = true;

if (FAssetRegistryState::LoadFromDisk(\*CachedAsserRegistryPath, LoadOptions, CschedState)) // Crash here
{
  AssetRegistry.AppendState(CachedState);
}

I tried the different serialization/deserialization options, but the index is always out of bound.

It may be because because a packaged application cannot read serialized asset registries produced from cooking data. So, I also tried to do the scan the first time the packaged application starts, and then split and serialize the registry so that future launch will be faster. However, all `.bin` files produced with this method have the same size, which is abnormal considering the number of assets in each pak is not the same at all. The post-cook commandlet does not have this issue.

I am completely stuck at the moment. Is it even possible to cache the asset registry for faster launch time of a packaged application?

reddit.com
u/Fir0x_ — 6 days ago