#Importing Content Archives during runtime

1 messages · Page 1 of 1 (latest)

echo snow
#

I'm kind of lost at how to import content archives during runtime. For reference, im not trying to specifically build an entities subscene.

I have a scene in Unity which im building using content archives which apparently builds 2 different bundles, one for the scene i pass into scenereferences and one for the assets i pass into obj references

in terms of importing i find myself a bit lost. initially i tried asset bundles but it only loads them with no dependency with the assets whatsoever, basically meaning the entire scene is pink (missing a few scripts, mats, textures, etc.)

I tried RemoteContentCatalog and RuntimeContentManager from entities but i run into an issue where nothing tries to load at all. I will post my scripts down below in this thread

What actually is the correct approach to importing my content archives in this sense

#
    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 = ContentArchiveBuildUtility.BuildContentArchives(
            BuildTarget.StandaloneWindows, // Use the appropriate BuildTarget
            objectRefs,
            sceneRefs,
            customContent,
            sceneName,
            outputPath,
            out buildResults,
            buildTasks,
            null
        );

This is how im currently building my scene

#
    public static void testLoadContentArchive(string pluginName)
    {
        string buildLocation = Path.Combine(Application.persistentDataPath, "build", pluginName);

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

        AssetBundleRequest allAssetsRequest = assetsBundle.LoadAllAssetsAsync();
        allAssetsRequest.completed += (operation) =>
        {
            AssetBundleCreateRequest sceneRequest = AssetBundle.LoadFromFileAsync(buildLocation + "/" + pluginName + "_Scene");
            AssetBundle scenesBundle = sceneRequest.assetBundle;

            string[] scenePath = scenesBundle.GetAllScenePaths();
            SceneManager.LoadScene(scenePath[0], LoadSceneMode.Single);
        };
    }

this loads the scene but with all the textures missing

#

thought i should raise this in the dots forum since i discovered contentarchives through looking at the entities docs and scripting api

echo snow
#

Thanks!! I will give that a shot :)

echo snow
#
public static void testLoadContentArchive(string pluginName)
{
    string buildLocation = Path.Combine(Application.persistentDataPath, "build", pluginName);

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

    AssetBundleRequest allAssetsRequest = assetsBundle.LoadAllAssetsAsync();
    allAssetsRequest.completed += (operation) =>
    {
        foreach (var asset in allAssetsRequest.allAssets)
        {
            AssetReference assetRef = new AssetReference();
            assetRef.SetEditorAsset(asset);

            if(asset is GameObject)
            {
                assetRef.LoadAssetAsync<GameObject>().Completed += (operation) =>
                {
                    assetRef.InstantiateAsync();
                };
            }
            else if(asset is Texture2D)
            {
                assetRef.LoadAssetAsync<Texture2D>().Completed += (operation) =>
                {
                    assetRef.InstantiateAsync();
                };
            }
            else if(asset is Material)
            {
                assetRef.LoadAssetAsync<Material>().Completed += (operation) =>
                {
                    assetRef.InstantiateAsync();
                };
            }
        }

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

        string[] scenePath = scenesBundle.GetAllScenePaths();
        SceneManager.LoadScene(scenePath[0], LoadSceneMode.Single);
    };
}

this is my current script using assetreferences, am i using it correctly? the docs say it should be a monobehaviour but the class im using is static i dont want it to be a monobehaviour. it gives the following error and warning for all textures and materials

UnityEngine.AddressableAssets.InvalidKeyException: Exception of type 'UnityEngine.AddressableAssets.InvalidKeyException' was thrown. No MergeMode is set to merge the multiple keys requested. Keys=, Type=UnityEngine.Texture2D
UnityEngine.AddressableAssets.AssetReference:LoadAssetAsync<UnityEngine.Texture2D> ()
V_PluginLoader/<>c__DisplayClass2_0:<testLoadContentArchive>b__0 (UnityEngine.AsyncOperation)
UnityEngine.AsyncOperation:InvokeCompletionEvent ()
Invalid object for AssetReference JusticeSword_MetallicSmoothness (UnityEngine.Texture2D).
UnityEngine.AddressableAssets.AssetReference:SetEditorAsset (UnityEngine.Object)
V_PluginLoader/<>c__DisplayClass2_0:<testLoadContentArchive>b__0 (UnityEngine.AsyncOperation)
UnityEngine.AsyncOperation:InvokeCompletionEvent ()
#

my scene loads but is missing all the textures and materials

pulsar flower
#

You seem to be mixing in addressables?

frosty bane
echo snow
#

Thanks! looking at those docs i am using RuntimeContentManager to Load in my assets however i run into yet another issue. my code at the moment is as follows

    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);
        }

    }

on several debugging it looks like when i get the contentDeliveryUPdate state, it is just set to None, even though im pointing it to the right path i've double checked. Another issue is when im loading in my asset file it gives the error

Asset file does not exist or does not contain LFID 0

on debugging i realise that my weak reference id is always set to 00000:0 (which im assuming is null) for every asset despite the asset being valid