Editing Large Quantities of Prefabs in Code

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.

@Trasochi

Try disable asset importing while editing the prefabs.

AssetDatabase.StartAssetEditing();
foreach(prefab)
{
    var root = PrefabUtility.LoadPrefabContents(prefab);
    /* edit */
    PrefabUtility.SaveAsPrefabAsset(root, prefab);
    PrefabUtility.UnloadPrefabContents(root);
}
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.

1 Like

Thanks for the reply. We’ll try that.

@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

@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?

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?

@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.

2 Likes

Right, thanks for the explanation. That makes sense.

1 Like

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.

1 Like