Search Unity

  1. Unity 2017.2 beta is now available for download.
    Dismiss Notice
  2. Unity 2017.1 is now released.
    Dismiss Notice
  3. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  4. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  5. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    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. }
     
    JimHL, Krucho, WDudderz and 8 others like this.
  2. Graham-B

    Graham-B

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

    cfloutier

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

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    503
    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.  
     
  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:
    81
    thanks! good script
     
  9. stylophone

    stylophone

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

    litebox

    Joined:
    Aug 29, 2011
    Posts:
    102
    Useful script, thanks!
     
  11. ad_adnan

    ad_adnan

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

    lindsaytalbot

    Joined:
    Sep 11, 2015
    Posts:
    10
    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. ad_adnan

    ad_adnan

    Joined:
    Mar 11, 2014
    Posts:
    110
    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,015
    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,015
    Krucho likes this.
  18. Krucho

    Krucho

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

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    243
    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,015
    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:
    243
    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