Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Editing Large Quantities of Prefabs in Code

Discussion in 'Prefabs' started by Trasochi, Jan 31, 2019.

  1. Trasochi

    Trasochi

    Joined:
    May 26, 2017
    Posts:
    2
    My team is currently in the process of trying to switch from 2018.2 to 2018.3. One of our sticking points is the need to edit large quantities of prefabs in code.

    We have about 400 ability prefabs, and a comparable number for actors. We often need to make systematic changes to all these prefabs at once, such as swapping one component for another and copying over the variables from the old one to the new one. This requires changing and saving all the prefabs in sequence with editor scripts. In 2018.2 this process generally took a few minutes, in 2018.3 it takes about an hour. The increase in time taken is specifically in the process of saving the prefabs after making changes.

    We have tried with auto save on and off and we have tried using the new methods PrefabUtility.LoadPrefabContents, PrefabUtility.SaveAsPrefabAsset and PrefabUtility.UnloadPrefabContents, but nothing so far has cut down the saving time.

    With how frequently we need to make these sorts of changes this massively slows down our workflow and makes upgrading to 2018.3 on our master branch unworkable for us, so we'd really appreciate it if anyone has ideas on how to speed up the process in 2018.3, or any indication as to whether the situation is going to be improved in a version of Unity 2019.
     
  2. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    567
    @Trasochi

    Try disable asset importing while editing the prefabs.
    Code (CSharp):
    1. AssetDatabase.StartAssetEditing();
    2. foreach(prefab)
    3. {
    4.     var root = PrefabUtility.LoadPrefabContents(prefab);
    5.     /* edit */
    6.     PrefabUtility.SaveAsPrefabAsset(root, prefab);
    7.     PrefabUtility.UnloadPrefabContents(root);
    8. }
    9. AssetDatabase.StopAssetEditing();
    Doing this will batch import the prefabs when you call
    AssetDatabase.StopAssetEditing()
    instead of importing each prefab and their dependencies every time you save a prefab.
     
  3. Trasochi

    Trasochi

    Joined:
    May 26, 2017
    Posts:
    2
    Thanks for the reply. We'll try that.
     
  4. Bonfi_96

    Bonfi_96

    Joined:
    Oct 2, 2013
    Posts:
    34
    @SteenLund Using PrefabUtility.SavePrefabAsset is the same as SaveAsPrefabAsset in case the object used is already a prefab?
    I'm asking this because the doc page about SavePrefabAsset is a bit convoluted
     
  5. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    567
    @Bonfi_96

    Some what of topic but ok.
    SavePrefabAsset
    is used to write any changes made to the imported objects back to the Assets folder.
    Most assets in Unity are imported, meaning we read what is in the Assets folder and write the processed data into the Library folder.

    When using
    AssetDatabase.LoadMainAssetAtPath
    you get the objects from the Library folder.
    If you then modify these objects the modifications are not reflected into the Assets folder, meaning your imported data is out of synch with the source data. In order to fix this you call
    SavePrefabAsset
    .

    Obviously this is a very dangerous workflow and I would never recommend editing the objects from the Library folder. Always use
    LoadPrefabContents
    and
    SaveAsPrefabAsset
    as this works on the source assets.

    Makes sense?
     
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    5,100
    What?

    We constantly load assets from the AssetDatabase, edit them, and save them. That's never been a problem with anything else. Is this prefabs being special, or are you actually telling us not to use the asset database to edit assets?
     
  7. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    567
    @Baste

    It depends on the asset. If you load a Material or scriptableObject using AssetDatabase.LoadMainAsset it works fine because those assets are not imported assets, they don't have processed data in the Library.

    But eg. Textures and Models this is not possible you can't edit the objects you get from LoadMainAsset and have the changes saved back to the Asset folder.

    Prefabs used to only live in the Assets folder, we changed that, but in order so have some backwards compatibility we still allows scripts to edit prefabs like this. As long at you make sure to call AssetDatabase.SaveAssets or SavePrefabAsset directly you are fine.
     
    Last edited: Jan 31, 2019
    Bonfi_96 and Baste like this.
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    5,100
    Right, thanks for the explanation. That makes sense.
     
  9. vigoAtWork

    vigoAtWork

    Joined:
    Apr 25, 2016
    Posts:
    11
    It is, however, a good deal faster, especially when only examining prefab contents - most likely because LoadPrefabContents()/UnloadPrefabContents() always creates/destroys a new preview scene, and because it doesn't benefit from AssetDatabase caching as much.
    Also, LoadAssetAtPath() - Change stuff - ImportAsset() is the generic asset manipulation workflow, and clearly indicates that Start/StopAssetEditing() will (greatly) help.

    I'd reason that branching off the usual workflow is both more time consuming (learning the above prefab workflow), and more dangerous (keeping the exceptional behaviour in mind) than sticking with "more of the same".

    As an aside: LoadPrefabContentsIntoPreviewScene(), presumably the workaround for scene creation/destruction overhead, currently a) doesn't return a GameObject (even though the documentation says so), b) doesn't have a sensible unload counterpart (UnloadPrefabContents() destroys the preview scene), and c) isn't any faster.
     
unityunity