Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Asset Bundle cannot find scripts from Assembly Definition files.

Discussion in 'Asset Bundles' started by AlienMe, May 17, 2018.

  1. AlienMe

    AlienMe

    Joined:
    Sep 16, 2014
    Posts:
    93
    Hope to get some help on this issue.

    When loading a scene from asset bundle, which contains scripts added to an Assembly Definition, Unity errors out with

    "The referenced script on this Behaviour (Game Object 'Cube-Blue') is missing!"

    If I remove the asmdef file.. the referenced script is found correctly. Tested this on Unity 2018.1.0f2 and on Unity 2017.4.1f1.

    I will submit a bug report shortly with a repro project, but if anybody has seen / or found a solution for this, it'd be appreciated.
     
  2. AlienMe

    AlienMe

    Joined:
    Sep 16, 2014
    Posts:
    93
  3. Ryanc_unity

    Ryanc_unity

    Unity Technologies

    Joined:
    Jul 22, 2015
    Posts:
    332
    To load scripts correctly in C#, we store assembly, namespace, and class information in the asset bundle:
    Code (CSharp):
    1.     m_ClassName "<ClassStrippedForPrivacy>" (string)
    2.     m_Namespace "<NamespaceStrippedForPrivacy>" (string)
    3.     m_AssemblyName "Assembly-CSharp.dll" (string)
    This means that any time you rename a class, move the class to a new namespace, move the code to a new assembly, or rename the assembly it is in, you will need to rebuild your asset bundles.
     
  4. AlienMe

    AlienMe

    Joined:
    Sep 16, 2014
    Posts:
    93
    Hi @Ryanc_unity, I re-build the asset bundles after I make any changes.

    However, I just tested this with Unity 2018.1.3, and now it seems to be working (initially it was failing with Unity 2018.1.0, and 2017.4)

    So, this is now working.

    Thanks!
     
  5. brendan-vance

    brendan-vance

    Joined:
    Jan 16, 2014
    Posts:
    36
    Hey y'all,

    We encountered problems like this today! For us it was not upgrading unity that fixed it (this seems to have no effect), but performing a clean build of our asset bundles (deleting the 'library' folder et cetera and having unity regenerate everything).

    Some probing into our bundles revealed that m_AssemblyName was getting stuck on the old value even after we rebuilt them! I would therefore speculate that it's necessary to reimport the bundled prefabs (or just nuke the library) after changing your MonoBehaviours' assemblies around.
     
  6. Ryanc_unity

    Ryanc_unity

    Unity Technologies

    Joined:
    Jul 22, 2015
    Posts:
    332
    That may actually be due to the incremental build process of the build pipeline is not detecting the rename. You could try using "BuildAssetBundleOptions.ForceRebuildAssetBundle" to force it to rebuild and see if that works instead.
     
    brendan-vance likes this.
  7. kienbb

    kienbb

    Joined:
    Sep 10, 2014
    Posts:
    13
    I have same problem, My scenes in project is loaded from assetbunle and scripts can't find.
    I rebuild with "BuildAssetBundleOptions.ForceRebuildAssetBundle" option but not working
     
  8. AlienMe

    AlienMe

    Joined:
    Sep 16, 2014
    Posts:
    93
    In my case the issue got resolved by upgrading Unity to 2018.1.3. I'm currently running 2018.1.5, and it is still working fine.

    When I was troubleshooting this, I built the bundle with no compression, and dumped the content of the bundles, and the issue was the assembly for the scripts was not referring to the asmdef assembly.
    I used this tool here (I think):
    https://7daystodie.com/forums/showthread.php?22675-Unity-Assets-Bundle-Extractor

    In any case, check what version of Unity you are using.
     
    kienbb likes this.
  9. kienbb

    kienbb

    Joined:
    Sep 10, 2014
    Posts:
    13
    Oh. Thank you @AlienMe , I added option no compression when build asset bundle and now working perfect
     
  10. AlienMe

    AlienMe

    Joined:
    Sep 16, 2014
    Posts:
    93
    Well, you don't want to leave compression off for release, your bundles will be huge.

    Try removing the bundles before rebuilding them (with cmpression enabled).
     
  11. monry_kidsstar

    monry_kidsstar

    Joined:
    Jun 7, 2013
    Posts:
    10
    Hi, @Ryanc_unity .

    Are you planning to fix it so that can detect changes in AssemblyName when build AssetBundle?
    Or, if you have a way to get an AssemblyName from AssetBundle with Editor script, please let me know as I can create the validator on my own.
     
    nick-morhun likes this.
  12. DaveBurlingame

    DaveBurlingame

    Joined:
    May 4, 2021
    Posts:
    3
    I would like to add a namespace for some scripts. Is there any way to update/fix/relink an asset bundle through code without rebuilding the bundles? Also, just curious, but why not use the guid of the script? why use the name?
     
    nick-morhun, sandolkakos and mvilano like this.
  13. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
    @Ryanc_unity
    That is exactly my question. Why not use only the GUID for that, when its main purpose is to allow us renaming and moving stuff around our project without losing the references?

    Also, with more and more people making use of AssembyDefinitions and Unity Package Manager to create reusable modules whenever we can, I feel that this kind of renaming would start being a very "hidden" problematic issue.
     
    Last edited: Dec 9, 2021
  14. Harrishun

    Harrishun

    Joined:
    Apr 13, 2016
    Posts:
    59
    I found this thread searching for some clarity as to how Assembly Definitions are referenced. We were experiencing an issue where after unpacking Asset Bundles, our scripts on prefabs were appearing as missing, despite those same scripts definitely being present in the project. We presumed we were having some issues with our ADs, as this was our first use of them. I was initially confused as to why Unity would choose string references too, but now I'm actually pretty glad they did.

    Our pipeline features a separate Unity project that handles building Asset Bundles. However, this project hadn't been set up with Assembly Definitions just yet, so the scripts were considered part of "Assembly-Csharp.dll". If Unity chose to reference ADs by GUID, I believe that would mean that we couldn't use the system, as assets have different GUIDs across different projects, even if they're essentially duplicates.

    I don't know enough to say that it's definitely Unity's reason for going that route though.
     
    sandolkakos likes this.
  15. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
    Thanks for sharing your experience, it really helps me/us to understand the different ways of using Unity.
    I have two notes about your workflow:

    1. Yes, if you just recreate the AssemblyDefinition on a separate project, it will for sure take a GUID different from the one in your main project. I would say you should not re-create it, but really have a copy of it with its meta file, the same way you probably have done with the scripts. (of course, it is better if you have a way of sharing everything between both projects (via Unity Package Manager for instance), so that you just import them, instead of manually copying from one to another).

    2. I don't understand why your assets would work since in the separate project the scripts are part of "Assembly-Csharp.dll" and in the other project, the scripts are part of an AssemblyDefinition. According to that post, it should be a problem:

     
  16. Harrishun

    Harrishun

    Joined:
    Apr 13, 2016
    Posts:
    59
    I actually did do this (manually copied our AssemblyDefinitions and their respective meta files), but I noticed that the referenced definitions were broken, which I believe means that the copied ADs were essentially different because they were in a different project.

    Apologies if I was not clear initially, here's a breakdown of what (I think) happened:
    1. Asset Bundling project did not contain AssemblyDefinitions (i.e. all scripts were a part of "Assembly-CSharp.dll"), project that unpacks Asset Bundles did have AssemblyDefinitions
    2. When unpacking Asset Bundles, scripts were appearing as missing
    3. ADs were copied into Asset Bundling project
    4. AD references were broken, indicating that despite being copied from the other project into the Asset Bundling project, the ADs were effectively different, with different GUIDs
    5. References were fixed
    6. A test was done where the Asset Bundle was rebundled and re-unpacked by the other project
    7. (I assume that when rebundled, "m_assemblyName" was set to the name of the respective AssemblyDefinitions, since it is just a string)
    8. When unpacked, scripts were found and linked successfully in the unpacking project
     
    sandolkakos likes this.
  17. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    514
    I found this thread due to a similar issue where any scenes I have which live in asset bundles were unable to find references to scripts which live in an assembly definition... but... any of the suggestions listed here were not helping my case. I have however narrowed down the source of the issue which you all might find interesting because it could explain why some of you are having issues. I'm in the process of submitting a reproduction project. Here's the bug report write up:

    1. What happened?
    We get a heap of logs that scripts are missing when our scripts are added to assembly defintions and referenced in a scene which lives inside of an asset bundle:
    The referenced script on this Behaviour (Game Object 'SomeObject') is missing!

    What I've found is that if scripts are located in a package with an assembly definition, any scene that is bundled inside of an asset bundle can not find a reference to any scripts in that package, if:
    - IL2CPP is the active scripting backend, which we must use for platforms like Switch
    - the app is built manually using the BuildPipeline.BuildPlayer method which we must use for our very extensive compiler pipeline

    It's as though under these circumstances that the script address (class, namespace and assembly name) is not being stored in asset bundles.

    2. How to reproduce:
    - create a project that has two scenes, a scene called LaunchScene which has one job, to load a second scene BundledScene, which is a scene that we'll store in an asset bundle, code example to load the second scene:
    Code (CSharp):
    1.  
    2.    void Start()
    3.       LoadScene( "BundledScene", LoadSceneMode.Single );
    4.     }
    5.  
    6.     private void LoadScene ( string scene, LoadSceneMode mode ) {
    7.         var path = $"{Application.streamingAssetsPath}/{scene.ToLowerInvariant()}";
    8.         AssetBundle.LoadFromFile( path );
    9.         SceneManager.LoadScene( scene, mode );
    10.     }
    11.  
    - add a monobehaviour test script to a local embedded package with an assembly defintion, and then add this script as a component to an empty game object in the scene called BundledScene
    - set BundledScene to have an asset bundle name: bundledscene, the example compiler code below has a line to build this out to an asset bundle stored in the StreamingAssets folder,
    - note: only add the LaunchScene to BuildSettings, don't add the BundledScene to the list because it'll be loaded from an asset bundle instead
    - set the standalone platform as the active platform, it doesn't matter if it's windows or mac, make sure IL2CPP is the active scripting backend (Mono doesn't have this issue)
    - then compile out the app using the BuildPipeline method, example code:
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEditor;
    6. using System.IO;
    7. public class BuildTools {
    8.     [MenuItem( "Tools/Build App" )]
    9.     static void BuildApp () {
    10.         // force build asset bundles, which for this test should only build one bundle for the scene called 'BundledScene'
    11.         var assetBundleOptions = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.ForceRebuildAssetBundle;
    12.         BuildPipeline.BuildAssetBundles( Application.streamingAssetsPath, assetBundleOptions, EditorUserBuildSettings.activeBuildTarget );
    13.         // compile out app using BuildPipeline
    14.         var directlyIncludedScenes = new List<string>();
    15.         foreach ( var s in EditorBuildSettings.scenes ) {
    16.             directlyIncludedScenes.Add( s.path );
    17.         }
    18.         var buildOptions = BuildOptions.ShowBuiltPlayer;
    19.         if ( EditorUserBuildSettings.development ) {
    20.             buildOptions |= BuildOptions.Development;
    21.         }
    22.         BuildPipeline.BuildPlayer( directlyIncludedScenes.ToArray(), $"{Application.dataPath}/../Builds/Test", EditorUserBuildSettings.activeBuildTarget, buildOptions );
    23.     }
    24. }
    25.  
    - When you run the app check the player.log to find logs saying the referenced script is missing!

    If you change to Mono this issue goes away, the script references are not missing. If you build using the manual Build button in Build Settings the problem also doesn't occur. But none of these workarounds are an option for us in our production pipeline. The script references should not be missing.

    note: I've used several revisions of 2021.2.x, currently on the latest at time of writing 2021.2.13 and the issue remains.
     
    Last edited: Feb 28, 2022
  18. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    514
    I'm not sure if ChunkBasedCompression for asset bundles was also needed or not to replicate the issue, but is what we need to use for most of our platforms so I just left that there when setting up the reproduction project. The bug report issue number is: 1407312
     
    sandolkakos likes this.
  19. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    514
    So how obscure is that, scripts are missing if the build is: IL2CPP, the scripts live in a package (with assembly defintion) that are used by a scene which lives in an asset bundle when the app is built using the manual BuildPipeline method.

    Note that if a reference to at least 'one' script from the assembly definition is referenced or used in a scene which is 'not' added to an asset bundle, then all of a sudden the references to 'all' scripts start working. This workaround allows the build pipeline to start working properly and adds the script references to asset bundles. But if the only reference to scripts is within asset bundles then they're not compiled properly and can't be found. ONLY when using IL2CPP, and ONLY when building with the BuildPipeline method.... o_O
     
    sandolkakos likes this.
  20. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    514
    Hi @Ryanc_unity just wondering if anyone is looking at this bug report, I've submitted a super simple project that reproduces this script missing error consistently, it's been three weeks since submitted, it'd be great to know if this is being looked at, thanks.
     
    sandolkakos likes this.
  21. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    514
    FYI - Unity have received my bug report and have reproduced the issue that causes scripts to go missing at their end. A summary again of what causes them to go missing:

    The issue occurs if:
    - mono behaviour scripts are added to a scene, where that scene is bundled into an asset bundle
    - where there scripts also live inside of a package
    - and there is no other usage of any script from the package in a non-asset bundled scene

    last reproduced in v2021.2.13, but would expect this issue to still exist in newer versions at time of writing
     
    sandolkakos likes this.
  22. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
  23. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    514
    So my bug report was escalated to a senior dev and they've gotten back to me with some info about why in my case the scripts were being stripped. Nothing was referencing the scripts when the player or app is built because the script references are somewhat hidden within asset bundles, the build pipeline is not aware of them and they were being stripped.

    To fix the issue, there is a different way to call the BuildPlayer.BuildPipeline method which I wasn't aware of where you can send in a BuildPlayerOptions struct, and note that this is different to BuildOptions. The BuildPlayerOptions has a property where you can set a path to the assetBundleManifestPath, a file which is built when you build out asset bundles which describes all of the scripts referenced within the asset bundles:
    https://docs.unity3d.com/2021.3/Doc...ildPlayerOptions-assetBundleManifestPath.html

    So at least in my case the behaviour where scripts go missing is somewhat by design. Here's an example of the change I've made when I compile my app which solves my issue, note that the asset bundle manifest file is only named StreamingAssets.manifest because this manifest file takes on the name of the folder the asset bundles are built to, you'd need to change that to whatever path you have built your asset bundles to.

    Code (CSharp):
    1.  
    2. // previous build player code
    3. var buildOptions = BuildOptions.ShowBuiltPlayer;
    4. if ( EditorUserBuildSettings.development ) {
    5.     buildOptions |= BuildOptions.Development;
    6. }
    7. BuildPipeline.BuildPlayer( directlyIncludedScenes.ToArray(), $"{Application.dataPath}/../Builds/Test", EditorUserBuildSettings.activeBuildTarget, buildOptions );
    8.  
    Code (CSharp):
    1.  
    2. // updated build player code to use BuildPlayerOptions so we can send in the assetBundleManifestPath
    3. var buildOptions = BuildOptions.ShowBuiltPlayer;
    4. if ( EditorUserBuildSettings.development ) {
    5.     buildOptions |= BuildOptions.Development;
    6. }
    7. var buildPlayerOptions = new BuildPlayerOptions {
    8.     scenes = directlyIncludedScenes.ToArray(),
    9.     locationPathName = $"{Application.dataPath}/../Builds/Test",
    10.     target = EditorUserBuildSettings.activeBuildTarget,
    11.     options = buildOptions,
    12.     assetBundleManifestPath = $"{Application.streamingAssetsPath}/StreamingAssets.manifest",
    13. };
    14. BuildPipeline.BuildPlayer( buildPlayerOptions );
    15.