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; if (PrefabUtility.FindPrefabRoot(go) != go) return false; } 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(); foreach (var go in Selection.gameObjects) { if (go != null && !AssetDatabase.Contains(go) && (PrefabUtility.FindPrefabRoot(go) == go || (PrefabUtility.FindPrefabRoot(go) != go && EditorUtility.DisplayDialog("Prefab child selected", "The selected gameobject [" + go.name + "] is not the prefab root", "Replace the prefab root", "Skip this object")))) { var goRoot = PrefabUtility.FindPrefabRoot(go); Debug.Log("Replacing: [" + goRoot.name + "] by: [" + ReplaceSource.name + "]"); NewGO.Add(Replace(ref goRoot, ref ReplaceSource)); } else if (go != ReplaceSource) ErrorGO.Add(go); } 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(); } private 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 do so now. if (preserveChildren == true && ReplaceDest.transform.childCount > 0) { foreach (Transform child in children) { if (child.parent == ReplaceDest.transform && PrefabUtility.FindPrefabRoot(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); } } static class ToolBox { [MenuItem("Tools/ToolBox/Selection and filtering/Select disabled children gameobjects", false, 900)] static void SelectDisabled() { List ResultList = new List(); foreach (var go in Selection.gameObjects) { var ResultListCurrent = SelectRecursive(go, true, false); ResultList = ResultList.Concat(ResultListCurrent).ToList(); } if (ResultList.Count > 0) Selection.objects = ResultList.ToArray(); } [MenuItem("Tools/ToolBox/Selection and filtering/Select broken prefabs", false, 900)] static void SelectBrokenPrefab() { List ResultList = new List(); foreach (var go in Selection.gameObjects) { var ResultListCurrent = SelectRecursive(go, false, true); ResultList = ResultList.Concat(ResultListCurrent).ToList(); } if (ResultList.Count > 0) Selection.objects = ResultList.ToArray(); } static List SelectRecursive(GameObject CurrentGO, bool selectDisabled = false, bool selectBroken = false) { List ResultList = new List(); foreach (Transform child in CurrentGO.transform) { var isPrefab = (PrefabUtility.GetCorrespondingObjectFromSource(child.gameObject) != null); var isBroken = (PrefabUtility.GetPrefabObject(child.gameObject) == null); var isPrefabRoot = (child.gameObject == PrefabUtility.FindRootGameObjectWithSameParentPrefab(child.gameObject)); var isDisabled = (!child.gameObject.activeSelf); List ResultListChild = new List(); //Debug.Log("Parsing: ["+child.name+"] - isActive:"+child.gameObject.activeSelf+" - isPrefab:"+isPrefab+" - isPrefabRoot: "+isPrefabRoot+" - isBroken: "+isBroken); if (isDisabled && selectDisabled) { ResultList.Add(child.gameObject); continue; } if (isBroken && selectBroken && isPrefab) { ResultList.Add(child.gameObject); if (!isPrefabRoot) { ResultListChild = SelectRecursive(child.gameObject, selectDisabled, selectBroken); ResultList = ResultList.Concat(ResultListChild).ToList(); } continue; } ResultListChild = SelectRecursive(child.gameObject, selectDisabled, selectBroken); ResultList = ResultList.Concat(ResultListChild).ToList(); } return ResultList; } [MenuItem("Tools/ToolBox/Create prefab from selected LOD", false, 922)] static void CreateprefabfromLOD() { List OutputGO = new List(); foreach (var go in Selection.gameObjects) { var goParent = go.transform.parent.gameObject; GameObject SourceGO = PrefabUtility.GetCorrespondingObjectFromSource(go) as GameObject; GameObject SourceGORoot = SourceGO.transform.parent.gameObject; Debug.Log("GO:" + go.name + " - GetPrefabParent:" + SourceGORoot.name); go.transform.parent = go.transform.parent.parent; GameObject replacement = PrefabUtility.InstantiatePrefab(SourceGORoot) as GameObject; replacement.transform.parent = go.transform.parent; replacement.transform.localPosition = goParent.transform.localPosition; replacement.transform.eulerAngles = goParent.transform.eulerAngles; replacement.transform.localScale = goParent.transform.localScale; go.transform.parent = replacement.transform; OutputGO.Add(UseCurrentLodTransform(go)); UnityEngine.Object.DestroyImmediate(go); } Selection.objects = OutputGO.ToArray(); } [MenuItem("Tools/ToolBox/Use current LOD transform", false, 923)] static void UseCurrentLodTransformSelection() { List OutputGO = new List(); foreach (GameObject currentSelection in Selection.gameObjects) { OutputGO.Add(UseCurrentLodTransform(currentSelection)); } Selection.objects = OutputGO.ToArray(); } static GameObject UseCurrentLodTransform(GameObject go) { Undo.RecordObject(go.transform.parent, "UseCurrentLODTransformParent"); Undo.RecordObject(go.transform, "UseCurrentLODTransform"); var LocalLODTransform = new GameObject("LocalLODTransform"); LocalLODTransform.transform.parent = go.transform.parent; LocalLODTransform.transform.localPosition = go.transform.localPosition; LocalLODTransform.transform.localEulerAngles = go.transform.localRotation.eulerAngles; LocalLODTransform.transform.localScale = go.transform.localScale; var DefaultLODTransform = new GameObject("DefaultLODTransform"); DefaultLODTransform.transform.parent = go.transform.parent; DefaultLODTransform.transform.localPosition = (PrefabUtility.GetCorrespondingObjectFromSource(go.transform) as Transform).localPosition; DefaultLODTransform.transform.localEulerAngles = (PrefabUtility.GetCorrespondingObjectFromSource(go.transform) as Transform).localRotation.eulerAngles; DefaultLODTransform.transform.localScale = (PrefabUtility.GetCorrespondingObjectFromSource(go.transform) as Transform).localScale; //Move Both Transform to Prefab's parent LocalLODTransform.transform.parent = go.transform.parent.parent; DefaultLODTransform.transform.parent = LocalLODTransform.transform; go.transform.parent.parent = DefaultLODTransform.transform; DefaultLODTransform.transform.parent = LocalLODTransform.transform; //Reset LocalTransform DefaultLODTransform.transform.localPosition = Vector3.zero; DefaultLODTransform.transform.localEulerAngles = Vector3.zero; DefaultLODTransform.transform.localScale = Vector3.one; //Reset selection transform go.transform.localPosition = (PrefabUtility.GetCorrespondingObjectFromSource(go.transform) as Transform).localPosition; go.transform.localEulerAngles = (PrefabUtility.GetCorrespondingObjectFromSource(go.transform) as Transform).localRotation.eulerAngles; go.transform.localScale = (PrefabUtility.GetCorrespondingObjectFromSource(go.transform) as Transform).localScale; //Set Correct Prefab Parent if (LocalLODTransform.transform.parent != null) go.transform.parent.parent = LocalLODTransform.transform.parent; else go.transform.parent.parent = null; //Storing Transform var PrefabPosition = go.transform.parent.localPosition; var PrefabRotation = go.transform.parent.localRotation.eulerAngles; var PrefabScale = go.transform.parent.localScale; //Reset prefab children transform foreach (Transform child in go.transform.parent) { child.localPosition = (PrefabUtility.GetCorrespondingObjectFromSource(child) as Transform).localPosition; child.localEulerAngles = (PrefabUtility.GetCorrespondingObjectFromSource(child) as Transform).localRotation.eulerAngles; child.localScale = (PrefabUtility.GetCorrespondingObjectFromSource(child) as Transform).localScale; } //Delete temp GO if (DefaultLODTransform != null) { UnityEngine.Object.DestroyImmediate(DefaultLODTransform); DefaultLODTransform = null; } if (LocalLODTransform != null) { UnityEngine.Object.DestroyImmediate(LocalLODTransform); LocalLODTransform = null; } return (go.transform.parent.gameObject); } }