You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
7.2 KiB

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. using System;
  6. /// <summary>
  7. /// Editor Class used to search and replace objects with prefabs;
  8. /// </summary>
  9. public class MassReplacer : EditorWindow {
  10. #region Editor Settings
  11. //base settings
  12. private string FilterText;
  13. private ListItem[] FilteredList;
  14. private GameObject CopiedPrefab;
  15. //advanced settings
  16. private bool doCopyScale = true;
  17. private bool doCopyRot = true;
  18. private bool isCaseSensitive = false;
  19. #endregion Editor Settings
  20. #region Private Variables
  21. private Vector2 scrollPosition;
  22. private string prevFilterText;
  23. private bool showAdvancedSettings;
  24. #endregion Private Variables
  25. #region GUI Functions
  26. [MenuItem("Tools/Mass Replace %e")]
  27. static void createWindow()
  28. {
  29. MassReplacer window = (MassReplacer)GetWindow(typeof(MassReplacer), true, "Replace", true);
  30. window.ReFilterList(window.FilterText);
  31. window.Repaint();
  32. }
  33. void OnGUI()
  34. {
  35. Event e = Event.current;
  36. //Base Settings
  37. EditorGUILayout.LabelField("Base Settings", EditorStyles.boldLabel);
  38. FilterText = EditorGUILayout.TextField((FilterText == null || FilterText == "") ? "Search..." : FilterText); //If textFiled is empty display "Searching..." else display search filter
  39. CopiedPrefab = (GameObject)EditorGUILayout.ObjectField(CopiedPrefab, typeof(GameObject), true);
  40. //Advanced Settings
  41. GUIStyle BoldFold = new GUIStyle(EditorStyles.foldout); BoldFold.font = EditorStyles.boldFont; //create foldoutstyle with bold text
  42. showAdvancedSettings = EditorGUILayout.Foldout(showAdvancedSettings, "Advanced Settings", BoldFold);
  43. if (showAdvancedSettings) {
  44. doCopyScale = EditorGUILayout.Toggle("Copy Scale", doCopyScale);
  45. doCopyRot = EditorGUILayout.Toggle("Copy Rotation", doCopyRot);
  46. isCaseSensitive = EditorGUILayout.Toggle("Case Sensitive Search", isCaseSensitive);
  47. }
  48. float advancedSettingHeight = 3 * ((showAdvancedSettings) ? 18 : 0);
  49. //Start of List
  50. GUILayout.Box("", GUILayout.Height(1), GUILayout.ExpandWidth(true));
  51. Rect scrollRect = GUILayoutUtility.GetLastRect();
  52. scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Width(position.width), GUILayout.Height(position.height - (108 + advancedSettingHeight) ));
  53. scrollRect.height = position.height - (108 + advancedSettingHeight);
  54. //Each Item
  55. foreach (ListItem listItem in FilteredList) {
  56. GUILayout.BeginHorizontal();
  57. listItem.isRepplaceable = GUILayout.Toggle(listItem.isRepplaceable, "", GUILayout.MaxWidth(10));
  58. GUILayout.Label(listItem.gameObject.name);
  59. Rect tempRect = GUILayoutUtility.GetLastRect();
  60. tempRect.position -= Vector2.down * (82 + advancedSettingHeight) + scrollPosition;
  61. if (tempRect.Overlaps(scrollRect))
  62. listItem.rect = tempRect;
  63. GUILayout.EndHorizontal();
  64. }
  65. GUILayout.EndScrollView(); //end list
  66. //Buttons at bottom of window
  67. GUILayout.BeginHorizontal();
  68. GUI.enabled = (CopiedPrefab != null);
  69. if (GUILayout.Button("Replace")) {
  70. replaceFiltedList();
  71. }
  72. GUI.enabled = true;
  73. if (GUILayout.Button("Cancel")) {
  74. }
  75. GUILayout.EndHorizontal(); // end buttons
  76. //Interaction
  77. //Check if filter is updated;
  78. if (prevFilterText != FilterText) {
  79. ReFilterList(FilterText);
  80. }
  81. //If clicked window check where clicked happened
  82. if (e.button == 0 && e.type == EventType.MouseDown)
  83. OnWindowClick(e.mousePosition);
  84. }
  85. /// <summary>
  86. /// Logic of when the window has been clicked
  87. /// </summary>
  88. /// <param name="mousePos">position of mouse when clicked</param>
  89. /// <returns></returns>
  90. private void OnWindowClick(Vector2 mousePos)
  91. {
  92. //Loops through each asset to see if one has been clicked on
  93. foreach (ListItem listItem in FilteredList) {
  94. if (listItem.rect.Contains(mousePos)) {
  95. Debug.Log("clicked: " + listItem.gameObject.name);
  96. Selection.activeGameObject = listItem.gameObject;
  97. break;
  98. }//end if
  99. }//end foreach
  100. }
  101. #endregion GUI Functions
  102. #region Search Functions
  103. #region Helper Functions
  104. private void ReFilterList(string filter)
  105. {
  106. if (filter == null)
  107. filter = "";
  108. StringComparison caseComparer = (isCaseSensitive) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
  109. FilteredList = getFilteredList(filter, caseComparer);
  110. prevFilterText = filter;
  111. Repaint();
  112. }
  113. #endregion Helper Fucntions
  114. #region Static Functions
  115. /// <summary>
  116. /// Returns an array of listItems of gameobjects in scene which contains a string
  117. /// </summary>
  118. /// <param name="filter">look for gameobjects containing this string</param>
  119. /// <returns></returns>
  120. private static ListItem[] getFilteredList(string filter, StringComparison caseComparer = StringComparison.OrdinalIgnoreCase)
  121. {
  122. List<ListItem> retVal = new List<ListItem>();
  123. object[] obj = FindObjectsOfType(typeof(GameObject));
  124. foreach (object o in obj) {
  125. GameObject g = (GameObject)o;
  126. if (g.name.Contains(filter, caseComparer)) {
  127. ListItem newItem = new ListItem(g);
  128. retVal.Add(newItem);
  129. }
  130. }
  131. return retVal.ToArray();
  132. }
  133. #endregion Static Functions
  134. #endregion Search Functions
  135. #region Replace Fucntions
  136. private void replaceFiltedList()
  137. {
  138. foreach (ListItem listItem in FilteredList) {
  139. if (!listItem.isRepplaceable || listItem.gameObject.Equals(CopiedPrefab))
  140. continue;
  141. GameObject replaceObject = (GameObject)PrefabUtility.InstantiatePrefab(CopiedPrefab);
  142. replaceObject.transform.parent = listItem.gameObject.transform.parent;
  143. replaceObject.transform.position = listItem.gameObject.transform.position;
  144. replaceObject.name = listItem.gameObject.name;
  145. if (doCopyRot)
  146. replaceObject.transform.rotation = listItem.gameObject.transform.rotation;
  147. if (doCopyScale)
  148. replaceObject.transform.localScale = listItem.gameObject.transform.localScale;
  149. Undo.RegisterCreatedObjectUndo(replaceObject, "Replaced Objects (" + FilterText + ")");
  150. Undo.DestroyObjectImmediate(listItem.gameObject);
  151. }
  152. ReFilterList(FilterText);
  153. }
  154. #endregion Replace Fucntions
  155. class ListItem {
  156. public GameObject gameObject;
  157. public bool isRepplaceable;
  158. public Rect rect;
  159. public ListItem(GameObject gameObject)
  160. {
  161. this.gameObject = gameObject;
  162. isRepplaceable = true;
  163. rect = new Rect();
  164. }
  165. }
  166. }
  167. static class MassReplaceOverides {
  168. public static bool Contains(this string source, string toCheck, StringComparison comp)
  169. {
  170. return source != null && toCheck != null && source.IndexOf(toCheck, comp) >= 0;
  171. }
  172. }