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

Applying list of overrides and obtaining ObjectOverride owner

Discussion in 'Prefabs' started by n-gist, May 11, 2020.

  1. n-gist

    n-gist

    Joined:
    Mar 7, 2016
    Posts:
    41
    Hi there!

    I write a thing which needs to filter overrides, and save only those that are under a specific GO (prefab instance) in the scene hierarchy (named 'root' in the following code)
    Code (CSharp):
    1. if (PrefabUtility.HasPrefabInstanceAnyOverrides(root.gameObject, false)) {
    2.     var list1 = PrefabUtility.GetAddedGameObjects(root.gameObject);
    3.     var list2 = PrefabUtility.GetAddedComponents(root.gameObject);
    4.     var list3 = PrefabUtility.GetRemovedComponents(root.gameObject);
    5.     var list4 = PrefabUtility.GetObjectOverrides(root.gameObject, false);
    6.    
    7.     List<PrefabOverride> overridesList = new List<PrefabOverride>();
    8.    
    9.     list1.ForEach(item => {
    10.         if (item.instanceGameObject.transform.IsChildOf(root))
    11.             overridesList.Add(item);});
    12.     list2.ForEach(item => {
    13.         if (item.instanceComponent.transform.IsChildOf(root))
    14.             overridesList.Add(item);});
    15.     list3.ForEach(item => {
    16.         if (item.containingInstanceGameObject.transform.IsChildOf(root))
    17.             overridesList.Add(item);});
    18.     list4.ForEach(item => {
    19.         System.Type type = item.instanceObject.GetType();
    20.         if (type == typeof(Transform) && ((Transform)item.instanceObject).IsChildOf(root))
    21.             overridesList.Add(item);
    22.     });
    23.  
    24.     overridesList.ForEach(item => item.Apply(rootPrefabPath));
    25. }
    The list can be large, and then it causes a series of saves in a row, which can be time consuming.

    1. Can we have something like
    Code (CSharp):
    1. PrefabUtility.ApplyOverrides(string prefabAssetPath, PrefabOverride[] overrides);
    that will save them in one pass?

    2. Can ObjectOverride have a reference to corresponding GameObject? It seems to me wrong to do as I did for list4. Or maybe we can have a
    Code (CSharp):
    1. List<PrefabOverride> PrefabUtility.GetOverrides(GameObject prefabInstance);
    returning combined list?
     
  2. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,877
  3. n-gist

    n-gist

    Joined:
    Mar 7, 2016
    Posts:
    41
  4. n-gist

    n-gist

    Joined:
    Mar 7, 2016
    Posts:
    41
    Ran into an issue when applying overrides from EditorWindow.OnSelectionChange message function, having another script just called AssetDatabase.Refresh(), resulting in somewhat of broken state:

    applyIssue.png

    with error:

    Assertion failed on expression: 'gForceReimports->empty()'
    UnityEditor.AssetDatabase:Refresh()
    twicebetter.TB_ChangesChecker:Update() (at Assets/Code/twicebetter/Editor/TB_ChangesChecker.cs:30)
    UnityEditor.EditorApplication:Internal_CallUpdateFunctions()

    pointing to line with AssetDatabase.Refresh() call.

    Solved this way for now (in EditorWindow):
    Code (CSharp):
    1. void Save() {
    2.     if (EditorApplication.isUpdating) {
    3.         deferredSave = true;
    4.         return;
    5.     }
    6.     deferredSave = false;
    7.  
    8.     // Applying overrides here
    9. }
    10. void Update() {
    11.     if (deferredSave) Save();
    12. }
     
  5. n-gist

    n-gist

    Joined:
    Mar 7, 2016
    Posts:
    41
    Another issue is when applying different types of overrides. For example, if old object is moved, resulting in ObjectOverride for its Transform, and another one GameObject is added, resulting in AddedGameObject for it, applying these overrides in one pass turns references to the added one to become null. So had to split applying into four passes

    Code (CSharp):
    1. List<PrefabOverride>[] overrides = new List<PrefabOverride>[]{
    2.     addedGameObjectsOverrides,
    3.     addedComponentsOverrides,
    4.     removedComponentsOverrides,
    5.     objectOverrides
    6. };
    7. for (int i = 0; i < overrides.Length; i++) {
    8.     if (overrides[i].Count > 0) {
    9.         AssetDatabase.StartAssetEditing();
    10.         for (int j = 0; j < overrides[i].Count; j++) overrides[i][j].Apply(rootPrefabPath);
    11.         AssetDatabase.StopAssetEditing();
    12.     }
    13. }
     
    Last edited: May 17, 2020