Safe Apply and Play
2014

(Very big and frustrating) Problem: When you instantiate a Unity prefab in the scene, changes you make to it are not applied to the original prefab. This is generally a Good Thing™. Part of the reason is that, if you have Animation mode turned on, a lot of other changes are made to the instance that would break the prefab - such as disabling its Animator component, and temporary changes to the state of any animated properties - but make it possible to see your work in the editor.


This treacherous little bugger

But it's all too easy to get into the habit of clicking the Apply button whenever you make a change. It's like saving your work often, a good habit, right? However if you do it while in Animation mode, Unity will punish you by messing up the default values of your prefab.

Solution: Safe Apply and Play. This does with one button press what Unity artists wish it would do when you press Apply.


This non-treacherous little bugger

In short, this is a convenience/cleanup tool to help enfranchise artists out of their second-class citizenship in Unity. Nota bene: Unity 5 addresses the main problem by graying out the Apply button when Animation Mode is on, and removing it when in Play mode. This isn't bad, but my tool will still save you the extra step of switching modes.

Code sample: To use, save as SafeApplyAndPlay.cs in your project's Editor folder.


using UnityEngine;
using UnityEditor;
using System.Collections;

//by Joseph Jacir

//Accepts an instance of a prefab
//When the button is pressed, stops animation mode, simulates "apply" button, saves the project, then plays the game.
//The purpose is to prevent accidentally applying the animated state on the current frame to the unanimated defaults of the prefab.
//Also prevents data loss and delayed updates (especially for version control) by periodically saving the project.

class SafeApplyAndPlay : EditorWindow {
	private GameObject subject;

	[MenuItem ("Window/Safe Apply and Play")]
	public static void  ShowWindow () {
		EditorWindow.GetWindow(typeof(SafeApplyAndPlay));
	}
	
	void OnGUI () {
		subject = (GameObject) EditorGUILayout.ObjectField("GameObject", (Object) subject, typeof(GameObject), true);
		if (subject) {
			if (PrefabUtility.GetPrefabType(subject) == PrefabType.PrefabInstance || PrefabUtility.GetPrefabType(subject) == PrefabType.DisconnectedPrefabInstance) {
				if(GUILayout.Button("Safe Apply & Play", GUILayout.MaxWidth(200))) {
					EditorApplication.isPlaying = false;
					if (AnimationMode.InAnimationMode()) {
						AnimationMode.StopAnimationMode();
					}
					EditorApplication.SaveAssets();
					PrefabUtility.ReplacePrefab(subject, PrefabUtility.GetPrefabParent(subject), ReplacePrefabOptions.ConnectToPrefab);
					EditorApplication.isPlaying = true;
				}
			} else {
				EditorGUILayout.LabelField("Must be a prefab instance. Is " + PrefabUtility.GetPrefabType(subject).ToString());
			}
		}
	}
	
	void OnInspectorWindowUpdate() {
		Repaint();
	}
}