Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question WebGL build with Streamed Asset Bundle containing external package

Discussion in 'WebGL' started by codecrafter2004, Jun 8, 2023.

  1. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    I have been stumped by this issue for a while now.

    My project (Unity 2022.2.13) consists of a script that makes a UnityWebRequest to an asset bundle stored at localhost on my computer. The asset bundle contains a scene and its associated assets, including a Cinemachine Camera Dolly. The asset bundle is unpacked, then the scene is loaded by the script. This process works flawlessly through the Unity Editor and through a Windows build of Unity but fails on WebGL. Upon loading the scene, the editor throws many warnings/errors, most declaring that "The referenced script x on this behaviour is missing!"

    upload_2023-6-7_17-35-31.png

    On previous builds without assets containing Cinemachine scripts, there were no such warnings. Therefore, there has to be some conflict between the assets in the scene containing Cinemachine and the Unity WebGL builder. Any ideas on how this can be resolved? Thanks.
     
  2. unityruba

    unityruba

    Unity Technologies

    Joined:
    Nov 6, 2020
    Posts:
    233
    Could you share the code snippet where you make the UnityWebRequest call?
     
  3. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    Code (CSharp):
    1. // Loads in the scene from the asset bundle and sends out events to other GameObjects once loaded
    2.     IEnumerator LoadAssetBundle(string bundleURL)
    3.     {
    4.         print("Making request...");
    5.         UnityWebRequest request = UnityWebRequest.Get(bundleURL);
    6.         yield return request.SendWebRequest();
    7.  
    8.         if (request.result == UnityWebRequest.Result.Success)
    9.         {
    10.             print("Downloading...");
    11.             byte[] bundleData = request.downloadHandler.data;
    12.             AssetBundle assetBundle = AssetBundle.LoadFromMemory(bundleData);
    13.             print("Success! Loading scene...");
    14.  
    15.             // Load the scene from the AssetBundle
    16.            
    17.             string[] scenePaths = assetBundle.GetAllScenePaths();
    18.             AsyncOperation loadOperation = SceneManager.LoadSceneAsync(scenePaths[0], LoadSceneMode.Single);
    19.             yield return loadOperation;
    20.  
    21.             startingSound.Play(); // play beginning sound as start of game to create excitement
    22.             assetBundle.Unload(false);
    23.             SceneLoaded?.Invoke();
    24.            
    25.  
    26.             // only invoke scene loaded event once camera has come to a stop
    27.             yield return new WaitForSeconds(3);
    28.             Camera camera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
    29.             Vector3 prev = camera.velocity;
    30.             yield return new WaitForSeconds(0.2f);
    31.             while (camera.velocity != prev)
    32.             {
    33.                 prev = camera.velocity;
    34.                 yield return new WaitForSeconds(0.2f);
    35.             }
    36.             GameStart?.Invoke();
    37.  
    38.         }
    39.         else
    40.         {
    41.             Debug.LogError("Failed to load AssetBundle: " + request.error);
    42.         }
    43.     }
     
  4. unityruba

    unityruba

    Unity Technologies

    Joined:
    Nov 6, 2020
    Posts:
    233
    Do you set the asset bundle manifest path? per our docs https://docs.unity3d.com/2020.3/Documentation/Manual/webgl-assetbundles.html
    If you set that path, then the asset bundles won't be stripped during the build process.
     
  5. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    I set the asset bundle manifest path, but it unfortunately did not solve the problem. That being said, I'm not entirely sure if I am using it correctly. Is this implementation correct?
    Code (CSharp):
    1. using UnityEditor.Build.Reporting;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. public class BuildWebGL : MonoBehaviour
    6. {
    7.     [MenuItem("Build/Build WebGL")]
    8.     public static void MyBuild()
    9.     {
    10.         BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
    11.         buildPlayerOptions.scenes = new[] { "Assets/Scenes/SampleScene.unity"};
    12.         buildPlayerOptions.locationPathName = "C:\\Users\\gilre\\Documents\\Unity\\export\\Passport proof-of-concept";
    13.         buildPlayerOptions.target = BuildTarget.WebGL;
    14.         buildPlayerOptions.options = BuildOptions.None;
    15.         buildPlayerOptions.assetBundleManifestPath = "C:\\Users\\gilre\\Documents\\Unity\\Passport-Proof-of-Concept\\loadables\\scene.manifest";
    16.  
    17.         BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
    18.         BuildSummary summary = report.summary;
    19.  
    20.         if (summary.result == BuildResult.Succeeded)
    21.         {
    22.             Debug.Log("Build succeeded: " + summary.totalSize + " bytes");
    23.         }
    24.  
    25.         if (summary.result == BuildResult.Failed)
    26.         {
    27.             Debug.Log("Build failed");
    28.         }
    29.     }
    30. }
    31.  
    Regarding code stripping, I have already disabled it due to causing numerous "could not produce class with ID x" errors.
     
  6. unityruba

    unityruba

    Unity Technologies

    Joined:
    Nov 6, 2020
    Posts:
    233
  7. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    That is what I did, but even with the manifest file pointed to in assetBundleManifestPath the scene is not imported properly in WebGL. What else can I try?
     
  8. unityruba

    unityruba

    Unity Technologies

    Joined:
    Nov 6, 2020
    Posts:
    233
    Edit: better phrasing :)

    Is there another manifest file generated that matches the parent directory of your project?

    From the updated docs: https://docs.unity3d.com/Manual/AssetBundles-Building.html
    When you call BuildPipeline.BuildAssetBundles to create your AssetBundles, Unity will also generate a manifest file with a filename matching the parent directory name and ".manifest" as its extension. You can assign the path to this manifest file to assetBundleManifestPath to ensure that a player build does not strip any types used in the AssetBundles that you built.

    You do not need to set this property when you use link.xml files, or if you generate AssetBundles using the Addressables package.
     
  9. unityruba

    unityruba

    Unity Technologies

    Joined:
    Nov 6, 2020
    Posts:
    233
  10. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    Just realized there was another .manifest file in the AssetBundle output. Unfortunately, this one did not work either, same error.

    Interestingly enough, I opened up both .manifest files only to discover that neither one listed any dependencies. Should I manually add them in myself?
     
  11. AndrewSkow

    AndrewSkow

    Unity Technologies

    Joined:
    Nov 17, 2020
    Posts:
    72
    Hi! I agree with unityruba that the .manifest file should fix code stripping problems. And the file path that is expected is the .manifest file that matches the build directory name.

    e.g. if you build to C:\myassetbundles it would be C:\myassetbundles\myassetbundles.manifest.

    Note: We calling Unity APIs with paths I almost always use "/" as the path separator. I think that "\" should be accepted on Windows but mention it just because i notice that in the way the path is specified when building the player.

    That main .manifest file will list the other AssetBundles that were built and inside those individual AssetBundles manifest files there are the ClassTypes section which lists the things that the AssetBundle uses. This help avoid code stripping from removing those required types.

    Some more info about the output of the build: https://docs.unity3d.com/2023.2/Documentation/Manual/AssetBundles-Building.html

    unityruba is also correct that a link.xml can be used as another way to disable stripping. And some users also make a small use of the referenced feature somewhere inside their player build content as another way to prevent stripping.

    Also - I think there are some Player settings for controlling the code stripping. It might be helpful to disable all code stripping temporarily, just to confirm if that fixes the problem. If it does then its a question of correctly specifying the path.

    I hope this helps!
     
  12. AndrewSkow

    AndrewSkow

    Unity Technologies

    Joined:
    Nov 17, 2020
    Posts:
    72
    Another point:

    If you want to understand what types are mentioned in the "ClassTypes" section of your .manifest files then this reference can help decipher the numeric values:

    https://docs.unity3d.com/Manual/ClassIDReference.html

    And in the case of scripting dependency the ClassTypes section will have entries for each script type that look like this:

    - Class: 114
    Script: {fileID: 11500000, guid: 534d3d861f3f94e4ab70f8be380bed98, type: 3}


    * Class 114 means MonoBehaviour (which also covers ScriptableObject-derived classes)
    * the guid is the Asset guid for the script file or assembly that contains the class definition.


    Hopefully it is going to be rare that anyone needs to look at the dependency information down to this low level detail, but I thought it could be helpful to explain a bit more of how Unity extracts the type dependency information from these .manifest files.

    Rather than incorrect content the more likely problem usually is that the wrong manifest file is specified. We've added a better error message for that case in 2023.2.
     
    Last edited: Jun 9, 2023
  13. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    In that case, I need to figure out why my asset bundle manifest files are being generated incorrectly, then. Could it be because I'm using the Unity Asset Bundle Browser for builds, which is no longer supported?
     
  14. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    I'm pretty lost right now. Is this what the .manifest file (the one listed as the output folder) is supposed to look like for an Asset Bundle using an external package like Cinemachine? Shouldn't the external package be listed here under dependencies?

    ManifestFileVersion: 0
    CRC: 1144967610
    AssetBundleManifest:
    AssetBundleInfos:
    Info_0:
    Name: demo1
    Dependencies: {}


    If I can determine the validity of this file, I might be able to narrow down the culprit of the problem.
     
  15. AndrewSkow

    AndrewSkow

    Unity Technologies

    Joined:
    Nov 17, 2020
    Posts:
    72
    Hi codecrafter2004,

    Using the Asset Bundle Browser shouldn't be an issue in this case - that tool has some limitations and doesn't scale well for really large builds but it does end up calling the same BuildPipeline.BuildAssetBundles() API as a build script would call.

    The file you reference mentioned "demo1", so Unity will also look inside demo1.manifest to take a look at the ClassTypes section in that file. E.g. the root file is what Unity uses to figure out what AssetBundles have been built.
     
  16. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    Ok, I figured it out. In short, when I generated my Asset Bundle, I would generate them in another Unity project, and then move the files over to a streamed assets folder for the game project. However, I would only end up moving one of the manifest files, resulting in errors. Once I moved over every file generated in the Asset Bundle's output, and built the project with the BuildPlayerOptions.assetBundleManifestPath option enabled, the project ran perfectly.
     
    AndrewSkow and unityruba like this.
  17. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    New question: since the .manifest file has to be specified at compile time, that effectively limits what asset bundle(s) can be loaded in at runtime, correct? Since under this method, if I were to load in a separate scene, that would create errors since I would be using the wrong manifest file. Is there a way around this, such that any scene can be loaded in without rebuilding the project?
     
  18. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    I'm stumped on how I can get around this. I was hoping for this project to dynamically load in scenes with external packages without rebuilding. Is there a way around this problem without using BuildPlayerOptions.assetBundleManifestPath, such as loading in a .manifest file during runtime or loading in only the external packages I want at buildtime?
     
  19. AndrewSkow

    AndrewSkow

    Unity Technologies

    Joined:
    Nov 17, 2020
    Posts:
    72
    The assetBundleManifestPath argument is useful to make sure types references by your AssetBundles that you have already built are not stripped.

    But if you want to load other AssetBundles, after you have already built your player build, then it becomes more up to you to control stripping considerations. You could either
    -make sure that your player build + base assetbundle build contains reference to all the things that you want to use in your AssetBundles
    -use a link.xml file to specify more manually things that you want to keep, even when they are not actually used in your most recent AssetBundle build.


    (Updated to remove suggestion to disable code stripping completely - i hadn't realized that that option is not available for il2cpp builds)
     
    Last edited: Jun 22, 2023
  20. codecrafter2004

    codecrafter2004

    Joined:
    Sep 17, 2021
    Posts:
    12
    Issue resolved - using this thread, I was able to create a link.xml file that forces the program to preserve the Cinemachine library at buildtime. Now, the program runs in WebGL with Cinemachine regardless of scene. Thanks for the help!