您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

435 行
18 KiB

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<GameObject> currentSelection = new List<GameObject>(); // 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<GameObject>().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<GameObject> ErrorGO = new List<GameObject>();
List<GameObject> NewGO = new List<GameObject>();
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<Transform>();
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<GameObject> ResultList = new List<GameObject>();
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<GameObject> ResultList = new List<GameObject>();
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<GameObject> SelectRecursive(GameObject CurrentGO, bool selectDisabled = false, bool selectBroken = false)
{
List<GameObject> ResultList = new List<GameObject>();
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<GameObject> ResultListChild = new List<GameObject>();
//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<GameObject> OutputGO = new List<GameObject>();
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<GameObject> OutputGO = new List<GameObject>();
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);
}
}