Reverting several GameObjects to Prefab settings at once

Hey all,

I’ve ran into an issue this evening. I have a Prefab that contains a simple cube mesh and a material, and I’ve placed hundreds of instances of this through several different scenes.

I was attempting to change the prefab material when I realized that all the instances have overridden the material property due to something I must have changed on the first instance I ever created, thus not allowing me to reflect the changes to the Prefab across all of its instances.

I know that you can revert an instance to its Prefab but even when selecting all the instances (each scene they are all contained inside an empty GameObject) the revert only affects the last one I selected.

Is there no way to execute variable changes across multiple selected GameObjects? If not I assume I need to write an Editor script, something I have not delved into yet but if it comes to that I’m sure the experience will be worth something.

Hope I’m not overlooking something ridiculous here, it’s 5:30am so I’m prepared for it. I’ve searched thoroughly and the only thing I found to go on is this thread on the main forums. It’s dated 2009 though so I was hoping things have changed since then.

Thanks in advance!

Non-programmer here… Had a coworker update your script to work in Unity 5(.2.3)

using UnityEngine;
using UnityEditor;
using System.Collections;

public class RevertPrefabInstance : MonoBehaviour {

	[MenuItem ("Tools/Revert to Prefab %r")]
	static void Revert() {
		var selection = Selection.gameObjects;
		
		if (selection.Length > 0) {
			for (var i = 0; i < selection.Length; i++) {
				PrefabUtility.RevertPrefabInstance(selection*);*
  •  	}*
    
  •  } else {*
    
  •  	Debug.Log("Cannot revert to prefab - nothing selected");*
    
  •  }*
    
  • }*
    }

Well after more unsuccessful searching I read up on the Editor scripting reference and managed to write a script that resets all selected GameObjects to their prefab settings.

@MenuItem ("Tools/Revert to Prefab %r")
static function Revert() {
    var selection = Selection.gameObjects;

    if (selection.length > 0) {
        for (var i : int = 0; i < selection.length; i++) {
		    EditorUtility.ResetGameObjectToPrefabState(selection*);*
  •       }*
    
  •   } else {*
    
  •       Debug.Log("Cannot revert to prefab - nothing selected");*
    
  •   }*
    

}
As I said I’m new to scripting the editor and it may not be the best way to do this but it works for me and that’s all I need right now.

Here’s a much more robust version:

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

/// <summary>
/// http://answers.unity3d.com/questions/144453/reverting-several-gameobjects-to-prefab-settings-a.html
/// </summary>
public class RevertPrefabInstance : UnityEditor.Editor
{
    [MenuItem( "Tools/Revert Selected Prefabs %&#r" )]
    static void Revert()
    {
        GameObject[] selection = Selection.gameObjects;

        if ( selection.Length > 0 )
        {
            int revertedCount = 0;
            Dictionary<UnityEngine.Object,bool> prefabsAlreadyReverted = new Dictionary<UnityEngine.Object, bool>();

            //we tell the user that we're about to do an expensive operation, because otherwise they may think the editor is hanging
            //additionally if the hotkey doesn't work (aka clash with another hotkey) they won't even know it failed to run!
            EditorUtility.DisplayDialog( "Please wait", "Checking " + selection.Length + " objects and their children to revert prefab status -- this may take a while!", "OK" );
            for ( int i = 0; i < selection.Length; i++ )
                RecursiveRevertPrefabInstances( selection*, ref revertedCount, ref prefabsAlreadyReverted );*

//tell them we finished, because otherwise they have no easy way to notice if it takes a bit!
EditorUtility.DisplayDialog( “All done!”, “Performed " + revertedCount + " reversions.”, “OK” );
}
else {
EditorUtility.DisplayDialog( “Error”, “Cannot revert to prefab - nothing selected.”, “OK” );
}
}

///


/// This allows for both nested prefabs as well as simply going into object trees without having to expand the whole tree first.
///

static void RecursiveRevertPrefabInstances( GameObject obj, ref int revertedCount, ref Dictionary<UnityEngine.Object, bool> prefabsAlreadyReverted )
{
if ( obj == null )
return;
if ( IsAPrefabNotYetReverted( obj, ref prefabsAlreadyReverted ) )
{
revertedCount++;
PrefabUtility.RevertPrefabInstance( obj );
}
Transform trans = obj.transform;
for ( int i = 0; i < trans.childCount; i++ )
RecursiveRevertPrefabInstances( trans.GetChild( i ).gameObject, ref revertedCount, ref prefabsAlreadyReverted );
}

///


/// This keeps us from reverting the same prefab over and over, which otherwise happens when we’re doing checks for nested prefabs.
///

static bool IsAPrefabNotYetReverted( GameObject obj, ref Dictionary<UnityEngine.Object, bool> prefabsAlreadyReverted )
{
bool wasValidAtEitherLevel = false;
UnityEngine.Object prefab = PrefabUtility.GetPrefabParent( obj );
if ( prefab != null && !prefabsAlreadyReverted.ContainsKey( prefab ) )
{
wasValidAtEitherLevel = true;
prefabsAlreadyReverted[prefab] = true;
}
prefab = PrefabUtility.GetPrefabObject( obj );
if ( prefab != null && !prefabsAlreadyReverted.ContainsKey( prefab ) )
{
wasValidAtEitherLevel = true;
prefabsAlreadyReverted[prefab] = true;
}
return wasValidAtEitherLevel;
}
}