Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  4. Build games and experiences that can load instantly and without install. Explore the Project Tiny Preview today!
    Dismiss Notice
  5. Nominations have been announced for this years Unity Awards. Celebrate the wonderful projects made by your peers this year and get voting! Vote here!
    Dismiss Notice
  6. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  7. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Little script : Apply and Revert several prefab at once.

Discussion in 'Extensions & OnGUI' started by baptisteLar, Feb 2, 2015.

  1. baptisteLar

    baptisteLar

    Joined:
    Jul 26, 2012
    Posts:
    31
    Hi,

    In a last project i had a lot of prefabs to modify every day, since it would have been too long to do it by hand, i made a little script that can apply and revert selected prefabs.

    I share it to you, it's not heavely tested but it suited my need.

    HIW : Select all your prefabs and use either shortcut or Tools menu item to apply and revert.

    (You can change shortcuts in the script if you want, currently it uses ctrl+shft+a to apply and ctrl+shft+r to revert)

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4.  
    5. public class ApplySelectedPrefabs : EditorWindow
    6. {
    7.     public delegate void ApplyOrRevert(GameObject _goCurrentGo, Object _ObjPrefabParent, ReplacePrefabOptions _eReplaceOptions);
    8.     [MenuItem ("Tools/Apply all selected prefabs %#a")]
    9.     static void ApplyPrefabs()
    10.     {
    11.         SearchPrefabConnections (ApplyToSelectedPrefabs);
    12.     }
    13.  
    14.     [MenuItem ("Tools/Revert all selected prefabs %#r")]
    15.     static void ResetPrefabs()
    16.     {
    17.         SearchPrefabConnections (RevertToSelectedPrefabs);
    18.     }
    19.  
    20.     //Look for connections
    21.     static void SearchPrefabConnections(ApplyOrRevert _applyOrRevert)
    22.     {
    23.         GameObject[] tSelection = Selection.gameObjects;
    24.        
    25.         if (tSelection.Length > 0)
    26.         {
    27.             GameObject goPrefabRoot;
    28.             GameObject goParent;
    29.             GameObject goCur;
    30.             bool bTopHierarchyFound;
    31.             int iCount=0;
    32.             PrefabType prefabType;
    33.             bool bCanApply;
    34.             //Iterate through all the selected gameobjects
    35.             foreach(GameObject go in tSelection)
    36.             {
    37.                 prefabType = PrefabUtility.GetPrefabType(go);
    38.                 //Is the selected gameobject a prefab?
    39.                 if(prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.DisconnectedPrefabInstance)
    40.                 {
    41.                     //Prefab Root;
    42.                     goPrefabRoot = ((GameObject)PrefabUtility.GetPrefabParent(go)).transform.root.gameObject;
    43.                     goCur = go;
    44.                     bTopHierarchyFound = false;
    45.                     bCanApply = true;
    46.                     //We go up in the hierarchy to apply the root of the go to the prefab
    47.                     while(goCur.transform.parent != null && !bTopHierarchyFound)
    48.                     {  
    49.                         //Are we still in the same prefab?
    50.                         if(goPrefabRoot == ((GameObject)PrefabUtility.GetPrefabParent(goCur.transform.parent.gameObject)).transform.root.gameObject)
    51.                         {
    52.                             goCur = goCur.transform.parent.gameObject;
    53.                         }
    54.                         else
    55.                         {
    56.                             //The gameobject parent is another prefab, we stop here
    57.                             bTopHierarchyFound = true;
    58.                             if(goPrefabRoot !=  ((GameObject)PrefabUtility.GetPrefabParent(goCur)))
    59.                             {
    60.                                 //Gameobject is part of another prefab
    61.                                 bCanApply = false;
    62.                             }
    63.                         }
    64.                     }
    65.  
    66.                     if(_applyOrRevert != null && bCanApply)
    67.                     {
    68.                         iCount++;
    69.                         _applyOrRevert(goCur, PrefabUtility.GetPrefabParent(goCur),ReplacePrefabOptions.ConnectToPrefab);
    70.                     }
    71.                 }
    72.             }
    73.             Debug.Log(iCount + " prefab" + (iCount>1 ? "s" : "") + " updated");
    74.         }
    75.     }
    76.  
    77.     //Apply      
    78.     static void ApplyToSelectedPrefabs(GameObject _goCurrentGo, Object _ObjPrefabParent, ReplacePrefabOptions _eReplaceOptions)
    79.     {
    80.         PrefabUtility.ReplacePrefab(_goCurrentGo, _ObjPrefabParent,_eReplaceOptions);
    81.     }
    82.  
    83.     //Revert
    84.     static void RevertToSelectedPrefabs(GameObject _goCurrentGo, Object _ObjPrefabParent, ReplacePrefabOptions _eReplaceOptions)
    85.     {
    86.         PrefabUtility.ReconnectToLastPrefab(_goCurrentGo);
    87.         PrefabUtility.RevertPrefabInstance(_goCurrentGo);
    88.     }
    89.  
    90.  
    91. }
     
    MD_Reptile, JimHL, Krucho and 9 others like this.
  2. Graham-B

    Graham-B

    Joined:
    Feb 27, 2013
    Posts:
    204
    Thanks! This is a real life saver.
     
  3. cfloutier

    cfloutier

    Joined:
    Jul 30, 2009
    Posts:
    30
    thanks a lot it's really great.
     
  4. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    505
    Thanks a lot :)))
     
  5. 10FingerArmy

    10FingerArmy

    Joined:
    Oct 10, 2013
    Posts:
    225
    Small bugfix to make it work with parents that are not prefabs themselves, e.g. light prefabs put into an empty "lights" gameobject for organizational issues

    Code (CSharp):
    1. //Are we still in the same prefab?
    2. if (PrefabUtility.GetPrefabParent(goCur.transform.parent.gameObject) != null && (goPrefabRoot == ((GameObject)PrefabUtility.GetPrefabParent(goCur.transform.parent.gameObject)).transform.root.gameObject)) {
    3.     goCur = goCur.transform.parent.gameObject;
    4. } else {
    5.  
     
    MD_Reptile likes this.
  6. Josh-Armour

    Josh-Armour

    Joined:
    Aug 8, 2014
    Posts:
    6
    Thank you baptisteLar for this script it is really helpful, but thank you 10FingerArmy for this little fix. I immediately ran into this problem! This code is eventually a must have when working with a lot of prefabs.
     
  7. fishtopherm

    fishtopherm

    Joined:
    May 29, 2013
    Posts:
    1
    This is amazing, thanks so much!
     
  8. Nolex

    Nolex

    Joined:
    Dec 10, 2010
    Posts:
    84
    thanks! good script
     
  9. stylophone

    stylophone

    Joined:
    Aug 16, 2012
    Posts:
    29
    been looking for this so long, thanks a lot!
     
  10. litebox

    litebox

    Joined:
    Aug 29, 2011
    Posts:
    115
    Useful script, thanks!
     
  11. zero_null

    zero_null

    Joined:
    Mar 11, 2014
    Posts:
    157
    useful !
     
  12. lindsaytalbot

    lindsaytalbot

    Joined:
    Sep 11, 2015
    Posts:
    23
    Still works in Unity 5.3.3! Very handy time saver
     
  13. asimov99

    asimov99

    Joined:
    Mar 13, 2015
    Posts:
    54
    Very good script ! and thanks for the fix !

    Useful when many objects are prefab instance break :))
     
  14. zero_null

    zero_null

    Joined:
    Mar 11, 2014
    Posts:
    157
    NullReferenceException: Object reference not set to an instance of an object
    ApplySelectedPrefabs.SearchPrefabConnections (.ApplyOrRevert _applyOrRevert) (at Assets/Scripts/Internal/Editor/ApplySelectedPrefabs.cs:48)
    ApplySelectedPrefabs.ApplyPrefabs () (at Assets/Scripts/Internal/Editor/ApplySelectedPrefabs.cs:9)
     
  15. PatrickBaroud

    PatrickBaroud

    Joined:
    Jun 15, 2014
    Posts:
    1
    Amazing time saver. I'm so surprised Unity don't have this implemented by default. Thanks so much!
     
  16. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    UT, heads up! Why don't we have this by default? "Instance Management Disabled" when selecting multiple prefabs...
     
  17. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    I was a having a little nullref in the line 50 so I changed this line:
    Code (csharp):
    1.  
    2. if (goPrefabRoot == ((GameObject)PrefabUtility.GetPrefabParent(goCur.transform.parent.gameObject)).transform.root.gameObject)
    3.  
    By these 2:
    Code (csharp):
    1.  
    2. var prefabParent = (GameObject)PrefabUtility.GetPrefabParent(goCur.transform.parent.gameObject);
    3. if (prefabParent && goPrefabRoot == prefabParent.transform.root.gameObject)
    4.  
    If someone gets a nullref, try this.
     
    Krucho likes this.
  18. Krucho

    Krucho

    Joined:
    Jul 23, 2014
    Posts:
    24
    this should be in default Unity
     
    Rodolfo-Rubens likes this.
  19. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    536
    Cleaned up the code and added a progressbar if more than 20 game objects are selected. The menu items are now at the same place as Unity's GameObject/Apply Changes To Prefab.

    Code (CSharp):
    1.  
    2. // --------------------------------------------------------------------------------------------------------------------
    3. // <copyright file="ApplySelectedPrefabs.cs" company="Supyrb">
    4. //   Copyright (c) 2017 Supyrb. All rights reserved.
    5. // </copyright>
    6. // <author>
    7. //   baptisteLar
    8. //   http://baptistelargaiolli.com/
    9. // </author>
    10. // <author>
    11. //   Johannes Deml
    12. //   send@johannesdeml.com
    13. // </author>
    14. // --------------------------------------------------------------------------------------------------------------------
    15.  
    16. namespace Supyrb.EditorTools
    17. {
    18.     using UnityEditor;
    19.     using UnityEngine;
    20.  
    21.     /// <summary>
    22.     /// Apply or revert multiple prefabs at the same time
    23.     /// From https://forum.unity3d.com/threads/little-script-apply-and-revert-several-prefab-at-once.295311/
    24.     /// </summary>
    25.     public class ApplySelectedPrefabs
    26.     {
    27.         private delegate void ChangePrefab(GameObject go);
    28.         private const int SelectionThresholdForProgressBar = 20;
    29.  
    30.         [MenuItem("GameObject/Apply Changes To Selected Prefabs", false, 100)]
    31.         private static void ApplyPrefabs()
    32.         {
    33.             SearchPrefabConnections(ApplyToSelectedPrefabs);
    34.         }
    35.  
    36.         [MenuItem("GameObject/Revert Changes Of Selected Prefabs", false, 100)]
    37.         private static void ResetPrefabs()
    38.         {
    39.             SearchPrefabConnections(RevertToSelectedPrefabs);
    40.         }
    41.  
    42.         [MenuItem("GameObject/Apply Changes To Selected Prefabs", true)]
    43.         [MenuItem("GameObject/Revert Changes Of Selected Prefabs", true)]
    44.         private static bool IsSceneObjectSelected()
    45.         {
    46.             return Selection.activeTransform != null;
    47.         }
    48.  
    49.         //Look for connections
    50.         private static void SearchPrefabConnections(ChangePrefab changePrefabAction)
    51.         {
    52.             GameObject[] selectedTransforms = Selection.gameObjects;
    53.             int numberOfTransforms = selectedTransforms.Length;
    54.             bool showProgressBar = numberOfTransforms >= SelectionThresholdForProgressBar;
    55.             int changedObjectsCount = 0;
    56.             //Iterate through all the selected gameobjects
    57.             try
    58.             {
    59.                 for (int i = 0; i < numberOfTransforms; i++)
    60.                 {
    61.                     if (showProgressBar)
    62.                     {
    63.                         EditorUtility.DisplayProgressBar("Update prefabs", "Updating prefabs (" + i + "/" + numberOfTransforms + ")",
    64.                             (float)i / (float)numberOfTransforms);
    65.                     }
    66.  
    67.                     var go = selectedTransforms[i];
    68.                     var prefabType = PrefabUtility.GetPrefabType(go);
    69.                     //Is the selected gameobject a prefab?
    70.                     if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.DisconnectedPrefabInstance)
    71.                     {
    72.                         var prefabRoot = PrefabUtility.FindRootGameObjectWithSameParentPrefab(go);
    73.                         if (prefabRoot == null)
    74.                         {
    75.                             continue;
    76.                         }
    77.  
    78.                         changePrefabAction(prefabRoot);
    79.                         changedObjectsCount++;
    80.                     }
    81.                 }
    82.             }
    83.             finally
    84.             {
    85.                 if (showProgressBar)
    86.                 {
    87.                     EditorUtility.ClearProgressBar();
    88.                 }
    89.                 Debug.LogFormat("{0} Prefab(s) updated", changedObjectsCount);
    90.             }
    91.         }
    92.  
    93.         //Apply    
    94.         private static void ApplyToSelectedPrefabs(GameObject go)
    95.         {
    96.             var prefabAsset = PrefabUtility.GetPrefabParent(go);
    97.             if (prefabAsset == null)
    98.             {
    99.                 return;
    100.             }
    101.             PrefabUtility.ReplacePrefab(go, prefabAsset, ReplacePrefabOptions.ConnectToPrefab);
    102.         }
    103.  
    104.         //Revert
    105.         private static void RevertToSelectedPrefabs(GameObject go)
    106.         {
    107.             PrefabUtility.ReconnectToLastPrefab(go);
    108.             PrefabUtility.RevertPrefabInstance(go);
    109.         }
    110.     }
    111. }
    112.  
     
    forestrf and Rodolfo-Rubens like this.
  20. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    True, when multiple prefabs are selected the Select/Revert/Apply vanishes from the inspector, makes no sense.
     
  21. r1

    r1

    Joined:
    May 24, 2013
    Posts:
    2
    Great script.

    @Johannski — with the added copyright, what can and can't be done with the script?
     
  22. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    536
    You can do everything you want with the script. I add the header by default to let other programmers in my team know who made the script. Also I love to search github with my name and see all the places my scripts and or modifications are used :D
     
  23. WBagley

    WBagley

    Joined:
    Oct 5, 2016
    Posts:
    2
    This little script has saved me and my team countless hours since we first stumbled across it. We loved it so much we decided to make a Unity integrated tool for all aspects of dealing with multiple prefabs. If you want to check it out, Multifab is on the asset store, supporting creating, applying and reverting changes to multiple prefabs, with a seamless inspector integration. It's a huge time saver so thanks for the inspiration!
     
  24. WickedCube

    WickedCube

    Joined:
    Jun 4, 2016
    Posts:
    2
    @Johannski , Script doesnt work with nested objects
     
  25. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    536
    Fair point. I didn't really need that functionality back then, but I guess it is not a mistake to have it in there. Here you go, updated version:
    Code (CSharp):
    1. // --------------------------------------------------------------------------------------------------------------------
    2. // <copyright file="ApplySelectedPrefabs.cs" company="Supyrb">
    3. //   Copyright (c) 2017 Supyrb. All rights reserved.
    4. // </copyright>
    5. // <author>
    6. //   baptisteLar
    7. //   http://baptistelargaiolli.com/
    8. // </author>
    9. // <author>
    10. //   Johannes Deml
    11. //   send@johannesdeml.com
    12. // </author>
    13. // --------------------------------------------------------------------------------------------------------------------
    14.  
    15. namespace Supyrb.EditorTools
    16. {
    17.     using UnityEditor;
    18.     using UnityEngine;
    19.  
    20.     /// <summary>
    21.     /// Apply or revert multiple prefabs at the same time
    22.     /// Source: https://forum.unity3d.com/threads/little-script-apply-and-revert-several-prefab-at-once.295311/
    23.     /// </summary>
    24.     public class ApplySelectedPrefabs
    25.     {
    26.         private delegate void ChangePrefab(GameObject go);
    27.         private const int SelectionThresholdForProgressBar = 20;
    28.         private static bool showProgressBar;
    29.         private static int changedObjectsCount;
    30.  
    31.         [MenuItem("GameObject/Apply Changes To Selected Prefabs %j", false, 100)]
    32.         private static void ApplyPrefabs()
    33.         {
    34.             SearchPrefabConnections(ApplyToSelectedPrefabs);
    35.         }
    36.  
    37.         [MenuItem("GameObject/Revert Changes Of Selected Prefabs", false, 100)]
    38.         private static void ResetPrefabs()
    39.         {
    40.             SearchPrefabConnections(RevertToSelectedPrefabs);
    41.         }
    42.  
    43.         [MenuItem("GameObject/Apply Changes To Selected Prefabs", true)]
    44.         [MenuItem("GameObject/Revert Changes Of Selected Prefabs", true)]
    45.         private static bool IsSceneObjectSelected()
    46.         {
    47.             return Selection.activeTransform != null;
    48.         }
    49.  
    50.         //Look for connections
    51.         private static void SearchPrefabConnections(ChangePrefab changePrefabAction)
    52.         {
    53.             GameObject[] selectedTransforms = Selection.gameObjects;
    54.             int numberOfTransforms = selectedTransforms.Length;
    55.             showProgressBar = numberOfTransforms >= SelectionThresholdForProgressBar;
    56.             changedObjectsCount = 0;
    57.             //Iterate through all the selected gameobjects
    58.             try
    59.             {
    60.                 for (int i = 0; i < numberOfTransforms; i++)
    61.                 {
    62.                     var go = selectedTransforms[i];
    63.                     if (showProgressBar)
    64.                     {
    65.                         EditorUtility.DisplayProgressBar("Update prefabs", "Updating prefab " + go.name + " (" + i + "/" + numberOfTransforms + ")",
    66.                             (float)i / (float)numberOfTransforms);
    67.                     }
    68.                     IterateThroughObjectTree(changePrefabAction, go);
    69.                 }
    70.             }
    71.             finally
    72.             {
    73.                 if (showProgressBar)
    74.                 {
    75.                     EditorUtility.ClearProgressBar();
    76.                 }
    77.                 Debug.LogFormat("{0} Prefab(s) updated", changedObjectsCount);
    78.             }
    79.         }
    80.  
    81.         private static void IterateThroughObjectTree(ChangePrefab changePrefabAction, GameObject go)
    82.         {
    83.             var prefabType = PrefabUtility.GetPrefabType(go);
    84.             //Is the selected gameobject a prefab?
    85.             if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.DisconnectedPrefabInstance)
    86.             {
    87.                 var prefabRoot = PrefabUtility.FindRootGameObjectWithSameParentPrefab(go);
    88.                 if (prefabRoot != null)
    89.                 {
    90.                     changePrefabAction(prefabRoot);
    91.                     changedObjectsCount++;
    92.                     return;
    93.                 }
    94.             }
    95.             // If not a prefab, go through all children
    96.             var transform = go.transform;
    97.             var children = transform.childCount;
    98.             for (int i = 0; i < children; i++)
    99.             {
    100.                 var childGo = transform.GetChild(i).gameObject;
    101.                 IterateThroughObjectTree(changePrefabAction, childGo);
    102.             }
    103.         }
    104.  
    105.         //Apply    
    106.         private static void ApplyToSelectedPrefabs(GameObject go)
    107.         {
    108.             var prefabAsset = PrefabUtility.GetPrefabParent(go);
    109.             if (prefabAsset == null)
    110.             {
    111.                 return;
    112.             }
    113.             PrefabUtility.ReplacePrefab(go, prefabAsset, ReplacePrefabOptions.ConnectToPrefab);
    114.         }
    115.  
    116.         //Revert
    117.         private static void RevertToSelectedPrefabs(GameObject go)
    118.         {
    119.             PrefabUtility.ReconnectToLastPrefab(go);
    120.             PrefabUtility.RevertPrefabInstance(go);
    121.         }
    122.     }
    123. }
    124.  
     
  26. ZerkyWerky

    ZerkyWerky

    Joined:
    Apr 2, 2009
    Posts:
    108
    This script is a gem! Thanks guys!
     
  27. resa12354

    resa12354

    Joined:
    Aug 7, 2015
    Posts:
    2
    Thanks so much for this script!
     
  28. NavrcL

    NavrcL

    Joined:
    Jul 30, 2014
    Posts:
    2
    Awesome! This is a huge time saver. Thanks a lot!
     
  29. ItsCaveMan

    ItsCaveMan

    Joined:
    Feb 14, 2015
    Posts:
    6
    what an fantastic piece! Thank you so much for this. Many cursor miles, miss-clicks and much time shall be saved!