Search Unity

How to persist custom import data from AssetImporter.userData into the actual build?

Discussion in 'Scripting' started by Xarbrough, Jun 17, 2019.

  1. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    I'm writing some custom data into the userData field of the AssetImporter of some special project assets (e.g. metadata about scene files). This works nicely with the callbacks from the AssetModificationProcessor class. For example like this:

    Code (CSharp):
    1. using UnityEditor;
    2.  
    3. public class SceneImporter : UnityEditor.AssetModificationProcessor
    4. {
    5.     private static string[] OnWillSaveAssets(string[] paths)
    6.     {
    7.         for (int i = 0; i < paths.Length; i++)
    8.         {
    9.             string path = paths[i];
    10.             if (IsUnitySceneFile(path))
    11.             {
    12.                 SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(path);
    13.                 var importer = AssetImporter.GetAtPath(path);
    14.                 importer.userData = CreateSceneMetadata(sceneAsset);
    15.             }
    16.         }
    17.         return paths;
    18.     }
    19.  
    20.     private static bool IsUnitySceneFile(string path)
    21.     {
    22.         return path.EndsWith(".unity");
    23.     }
    24.  
    25.     private static string CreateSceneMetadata(SceneAsset sceneAsset)
    26.     {
    27.         return sceneAsset.name;
    28.     }
    29. }
    But, what is a good way to persist this data into the actual build game and make it available at runtime?

    I'm thinking about using the AssetImporter again to read the userData field during the build, extract the data and store it somewhere else, like a Prefab or ScriptableObject. However, I really don't need these objects at edit time in the project, so I'd rather only stick them into the player.

    I can probably create a prefab during the build process, wait for the build to complete and then delete the prefab again, but this feels a little hacky. Is there any recommended approach for this kind of situation?

    It may also be that I want to use the custom userData during play mode in the editor in the future. In this case I was thinking about whether it would make sense to save the data into a completely custom data file in the Library folder on the local machine as kind of a cache for the data and copy this file to the player when building.

    Does anyone have any experience and tips for these things?
     
    Noisecrime likes this.
  2. Dr-Nick

    Dr-Nick

    Joined:
    Sep 9, 2013
    Posts:
    25
    You'd have to create some other solution here as the metafile data associated with each asset in a unity project would not be included in the final build.

    An example would be storing the relevant metafile information in a json file and looking it up on demand at runtime. But without an idea of your use case, finding a need to do this appears to be questionable.
     
  3. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    Thanks for bringing this up again! Yes, custom metadata needs to be stored with a serialized or streamed asset to be used at runtime. There are many ways to hack this together, but I was hoping for experience which approach works well.

    Turns out, at least from my point of view, no solution is really elegant in Unity today. Different official Unity packages use different approaches, e.g. write json files to StreamingAssets, then delete after the build, or write a ScriptableObject to Resources or add it to the always loaded objects lists. However, all of these feel like they could be abstracted away by a cleaner engine API. Also, there’s always a case where something fails during the build and then the project is left in a dirty state.

    I recently generated a ScriptableObject before play mode and build in the assets folder, but put it on the version control ignore list. This seem pretty robust but feels just a little hacky with the ignore file.