Importing Content Archives during runtime

Im kind of lost in trying to import my Content Archives during runtime, i have looked at unity entities content management documents, successfully managed to build my content archives however im having issues importing them in at runtime. Below is my code on how im building my content Archives

   private void BuildContentArchivesForScene(string destinationFolder, string sceneName)
    {
        Scene currentScene = SceneManager.GetActiveScene();

        string outputPath = destinationFolder;

        // Step 3: Prepare scene references and object references
        var sceneRefs = new HashSet<UntypedWeakReferenceId>();
        var objectRefs = new HashSet<UntypedWeakReferenceId>();

        // Convert the scene path to a GUID and create a weak reference ID for the scene
        string sceneGUID = AssetDatabase.AssetPathToGUID(currentScene.path);
        var sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(currentScene.path);
        if (sceneAsset != null)
        {
            var sceneRef = UntypedWeakReferenceId.CreateFromObjectInstance(sceneAsset);
            if (!sceneRefs.Contains(sceneRef))
                sceneRefs.Add(sceneRef);
        }
        else
        {
            Debug.LogError("Failed to load scene asset.");
            return;
        }

        // Get dependencies for the scene (all assets the scene depends on)
        string[] dependencies = AssetDatabase.GetDependencies(scenePath, true);

        foreach (string dependency in dependencies)
        {
            if (!dependency.EndsWith(".unity") && dependency.StartsWith("Assets/YOUR_PLUGIN_HERE")) // Skip the scene itself
            {
                var asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(dependency);
                if (asset != null)
                {
                    var objectRef = UntypedWeakReferenceId.CreateFromObjectInstance(asset);
                    if (!objectRefs.Contains(objectRef))
                        objectRefs.Add(objectRef);
                }
            }
        }

        Debug.Log("Building....");
        Debug.Log("Scene refs: " + sceneRefs.Count);
        Debug.Log("Object refs: " + objectRefs.Count);

        foreach (var objectRef in objectRefs)
        {
            Debug.Log($"Object Reference: {objectRef}");
        }

        foreach (var sceneRef in sceneRefs)
        {
            Debug.Log($"Scene Reference: {sceneRef}");
        }

        // Step 4: Define the custom content (if any)
        var customContent = new List<CustomContent>();

        // Step 5: Prepare for the build
        IBundleBuildResults buildResults;
        var buildTasks = new List<IBuildTask>()
        {
            new BuildPlayerScripts(),

            // Calculate asset dependency data
            new CalculateAssetDependencyData(),

            //calculate scene dependency data
            new CalculateSceneDependencyData(),

            // Generate bundle maps
            new GenerateBundleMaps(),

            // Generate bundle packing layout
            new GenerateBundlePacking(),
          
            // Generate commands for writing the bundles
            new GenerateBundleCommands(),

            // Write the serialized asset files
            new WriteSerializedFiles(),

            // Archive and compress the bundles
            new ArchiveAndCompressBundles()
        };

        BuildCache.PurgeCache(true);

        // Step 6: Build the content archive
        var result = V_ContentArchiveBuildUtility.BuildContentArchives(
            BuildTarget.StandaloneWindows, // Use the appropriate BuildTarget
            objectRefs,
            sceneRefs,
            customContent,
            sceneName,
            outputPath,
            out buildResults,
            buildTasks,
            null
        );

        if (result == ReturnCode.Success)
        {
            var instance = DotsGlobalSettings.Instance;
            var playerGuid = instance.GetPlayerType() == DotsGlobalSettings.PlayerType.Client ? instance.GetClientGUID() : instance.GetServerGUID();
            if (!playerGuid.IsValid)
                throw new Exception("Invalid Player GUID");

            var subSceneGuids = new HashSet<Unity.Entities.Hash128>()
            {
                sceneRefs.First().GlobalId.AssetGUID
            };

            RemoteContentCatalogBuildUtility.BuildContent(subSceneGuids, playerGuid, BuildTarget.StandaloneWindows64, outputPath);

            var publishFolder = Path.Combine(outputPath, $"{sceneName}-RemoteContent");
            RemoteContentCatalogBuildUtility.PublishContent(outputPath, publishFolder, f => new string[] { "all" });
        }
    }

this builds my scene into 2 asset bundles, one with the assets and one with the scene (followed using the ContentArchivesBuildUtility scripting API) and then push a remote content update

However i am having issues in importing these files at runtime. The following is my code on how im doing it

   public static void LoadContentArchive(string pluginName)
    {
        string buildLocation = Path.Combine(Application.persistentDataPath, "build", pluginName);
        Uri fileUri = new Uri(buildLocation + "/" + pluginName + "-RemoteContent" + "/" + "catalogs.bin");
        RuntimeContentSystem.LoadContentCatalog(fileUri.ToString(), buildLocation + "/" + pluginName + "-cache", "all");

        RuntimeContentManager.Initialize();

        AssetBundleCreateRequest assetsRequest = AssetBundle.LoadFromFileAsync(buildLocation + "/" + pluginName + "_Assets");
        AssetBundle assetsBundle = assetsRequest.assetBundle;

        foreach (var asset in assetsBundle.LoadAllAssets())
        {
            if(asset != null)
            {
                UntypedWeakReferenceId obj = (UntypedWeakReferenceId.CreateFromObjectInstance(asset));
                RuntimeContentManager.LoadObjectAsync(obj);
            }
        }

        AssetBundleCreateRequest sceneRequest = AssetBundle.LoadFromFileAsync(buildLocation + "/" + pluginName + "_Scene");
        AssetBundle scenesBundle = sceneRequest.assetBundle;

        foreach (var scene in scenesBundle.LoadAllAssets())
        {
            UntypedWeakReferenceId sceneRef = (UntypedWeakReferenceId.CreateFromObjectInstance(scene));

            ContentSceneParameters sceneParams = new ContentSceneParameters()
            {
                loadSceneMode = LoadSceneMode.Single,
                localPhysicsMode = LocalPhysicsMode.None,
                autoIntegrate = true,
            };

            RuntimeContentManager.LoadSceneAsync(sceneRef, sceneParams);
        }

    }

When i do this on debugging i ran into some issues.
Firstly when I load my content catalog, the delivery update is always stuck to None, i have triple checked that it points to the correct file

Secondly, it throws the error of
Asset file does not exist or does not contain LFID 0
On debugging i find out that despite my asset is valid, the weakreferenceID is always set to 000000000000:0 and is valid to false.

Am i importing these archives correctly? is there an alternative approach i should take to importing them in?

1 Like