using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using System.Linq; using SceneManager = UnityEngine.SceneManagement.SceneManager; using EditorSceneManager = UnityEditor.SceneManagement.EditorSceneManager; public class ReplaceToolWindow : EditorWindow { private List currentSelection = new List(); // The selected GameObjects. public GameObject replacementObject; // GameObject to replace selection with. public static bool preserveChildren = true; public bool autoOffsetTransform = false; //autooffset public Vector3 originRotation = Vector3.zero; public Vector3 originScale = Vector3.zero; public Vector3 autoOffsetScale = Vector3.one; private bool isSelectionPersistent = false; private bool isReplacementPersistent = true; public bool MiscOptions = false; private Vector2 scrollView = Vector2.zero; [MenuItem("Assets/Replace object...")] static void Init() { // Get the Object Replacement Tool Window. ReplaceToolWindow window = (ReplaceToolWindow)EditorWindow.GetWindow(typeof(ReplaceToolWindow), false, "Replace Object..."); // Set boolean to true if you don't want to dock the window. window.minSize = new Vector2(300, 110); } private void OnGUI() { if (Selection.objects.Length > 0) { currentSelection = Selection.objects.OfType().ToList(); foreach (var go in Selection.gameObjects) { if (AssetDatabase.Contains(go)) { replacementObject = go; break; } } } else { currentSelection.Clear(); } // Check that a selection has been made. if (Selection.gameObjects.Length > 0) { isSelectionPersistent = EditorUtility.IsPersistent(Selection.activeGameObject); } else { isSelectionPersistent = false; } // A check to ensure that the replacement comes from the Project Window. if (replacementObject != null) { isReplacementPersistent = EditorUtility.IsPersistent(replacementObject); } else { isReplacementPersistent = true; } // Start Scroll View scrollView = EditorGUILayout.BeginScrollView(scrollView); replacementObject = EditorGUILayout.ObjectField(new GUIContent("Replacement Object", "The object that will replace the current selection."), replacementObject, typeof(GameObject), true) as GameObject; MiscOptions = EditorGUILayout.Foldout(MiscOptions, new GUIContent("Misc Options", "Extra options and functionalities")); if (MiscOptions) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(20); autoOffsetTransform = GUILayout.Toggle(autoOffsetTransform, new GUIContent("Auto Offset Transform", "Will apply the same transform offset that exist between the two prefabs (In doubt, keep disabled)")); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(20); preserveChildren = GUILayout.Toggle(preserveChildren, new GUIContent("Preserve Children", "Will preserve the children of the objects selected in the scene")); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(20); EditorGUILayout.HelpBox("These settings are also used for the context button \"Replace Scene Selection By This Prefab\" ", MessageType.Error, true); EditorGUILayout.EndHorizontal(); } // Disable the button if we don't have a selected object or replacement assigned. if (Selection.gameObjects.Length > 0 && !isSelectionPersistent && replacementObject != null && isReplacementPersistent) { GUI.enabled = true; } else { GUI.enabled = false; } EditorGUILayout.Separator(); if (GUILayout.Button("Replace Selection")) { ReplaceSelection(replacementObject); } GUI.enabled = true; // Display errors at the bottom of the window as they are needed. if (Selection.gameObjects.Length == 0) { EditorGUILayout.HelpBox("No Object Selected.", MessageType.Error, true); } else if (replacementObject == null) { EditorGUILayout.HelpBox("No Replacement Object was Assigned.", MessageType.Error, true); } else if (!isReplacementPersistent) { EditorGUILayout.HelpBox("Replacement Object must be added from the Project Window.", MessageType.Error, true); } else if (isSelectionPersistent) { EditorGUILayout.HelpBox("Selection must be made from the Scene or Hierarchy Window.", MessageType.Error, true); } EditorGUILayout.EndScrollView(); } private void OnInspectorUpdate() { Repaint(); } //Right CLick Shortcuts [MenuItem("Assets/Replace scene selection by this prefab", true)] private static bool ReplaceSelPrefabValidation() { // This returns true when the selected object is a Variable (the menu item will be disabled otherwise). int ProjectSelectedCount = 0; int SceneSelectedCount = 0; foreach (var go in Selection.gameObjects) { if (AssetDatabase.Contains(go)) { ProjectSelectedCount += 1; } else { SceneSelectedCount += 1; } if (ProjectSelectedCount > 1) return false; } if (ProjectSelectedCount == 0 || SceneSelectedCount == 0) return false; return true; } [MenuItem("Assets/Replace scene selection by this prefab", false)] private static void ReplaceSelPrefab(MenuCommand menuCommand) { GameObject ReplaceSource = null; //Sorting selected scene assets from selected project assets. foreach (var go in Selection.gameObjects) { if (AssetDatabase.Contains(go)) { ReplaceSource = go; break; } } ReplaceSelection(ReplaceSource); } private static void ReplaceSelection(GameObject ReplaceSource) { List ErrorGO = new List(); List NewGO = new List(); bool skipAll = false; foreach (var go in Selection.gameObjects) { if (go == null || skipAll) { ErrorGO.Add(go); continue; } if (AssetDatabase.Contains(go)) { continue; } if (PrefabUtility.GetPrefabAssetType(go) == PrefabAssetType.NotAPrefab || (PrefabUtility.GetPrefabAssetType(go) != PrefabAssetType.NotAPrefab && PrefabUtility.GetOutermostPrefabInstanceRoot(go) == go)) { var goRoot = go; NewGO.Add(Replace(ref goRoot, ref ReplaceSource)); continue; } else if (PrefabUtility.GetPrefabAssetType(go) != PrefabAssetType.NotAPrefab && PrefabUtility.GetOutermostPrefabInstanceRoot(go) != go) { int choice = EditorUtility.DisplayDialogComplex("Prefab child selected", "The selected gameobject [" + go.name + "] is not the prefab root", "Replace Prefab Root", "Skip All", "Skip this object"); switch (choice) { case 0: var goRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(go); Debug.Log("Replacing: [" + goRoot.name + "] by: [" + ReplaceSource.name + "]"); NewGO.Add(Replace(ref goRoot, ref ReplaceSource)); break; case 1: skipAll = true; ErrorGO.Add(go); break; case 2: ErrorGO.Add(go); continue; } } } if (ErrorGO.Any()) { bool haserror = false; foreach (var go in ErrorGO) { if (go != null) haserror = true; Debug.Log("ErrorGo: [" + go.name + "]"); } if (haserror && EditorUtility.DisplayDialog("Some objects have not been replaced", "Some objects have not been replaced, they are the only ones left selected.", "Ok")) { Selection.objects = ErrorGO.ToArray(); return; } } Selection.objects = NewGO.ToArray(); } public static GameObject Replace(ref GameObject ReplaceDest, ref GameObject ReplaceSource) { GameObject replacement = PrefabUtility.InstantiatePrefab(ReplaceSource) as GameObject; Transform[] children = ReplaceDest.GetComponentsInChildren(); replacement.transform.parent = ReplaceDest.transform.parent; //New object position. replacement.transform.localPosition = ReplaceDest.transform.localPosition; replacement.transform.eulerAngles = ReplaceDest.transform.eulerAngles; replacement.transform.localScale = ReplaceDest.transform.localScale; Undo.RegisterFullObjectHierarchyUndo(ReplaceDest, "Replace Keep hierarchy And Transform"); // If the selection has children in the hierarchy and we need to retain them. if (preserveChildren == true && ReplaceDest.transform.childCount > 0) { //Moving other children foreach (Transform child in children) { if (child == null) continue; if (child.parent == ReplaceDest.transform && PrefabUtility.GetOutermostPrefabInstanceRoot(child.gameObject) != ReplaceDest) { Vector3 storedPosition = child.localPosition; Vector3 storedRotation = child.localEulerAngles; Vector3 storedScale = child.localScale; child.parent = replacement.transform; child.localPosition = storedPosition; child.localEulerAngles = storedRotation; child.localScale = storedScale; } } } Object.DestroyImmediate(ReplaceDest); // Register the created object so that it will be destroyed if we undo the opperation. Undo.RegisterCreatedObjectUndo(replacement, "Replace Keep hierarchy And Transform - New Object"); return (replacement); } }