MB_ReplacePrefabsInSceneEditorWindow.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. using DigitalOpus.MB.Core;
  6. namespace DigitalOpus.MB.MBEditor
  7. {
  8. public class MB_ReplacePrefabsInSceneEditorWindow : EditorWindow
  9. {
  10. private MB_ReplacePrefabsSettings model;
  11. private SerializedObject soModel;
  12. private SerializedProperty prefabPairs;
  13. private SerializedProperty reverseSrcAndTarg;
  14. private SerializedProperty enforceSrcAndTargHaveSameStructure;
  15. Vector2 scrollViewPos;
  16. private string errorMessages;
  17. private string infoMessages;
  18. private GUIContent GUI_replacePefabsInScene = new GUIContent("Replace Prefabs In Scene", "This will find all instances of the source prefabs in the scene and replace them with instances of the target prefabs." +
  19. "Will attempt to copy component settings from the source to the target (ignoring references to project assets, those are left alone)." +
  20. "Prefabs should have identical hierarchy and components for the copy component settings to work.");
  21. private GUIContent GUI_switchSrcAndTarget = new GUIContent("Switch Source and Target Prefabs", "If this is checked then search the scene for target prefabs and replace them with source prefabs.");
  22. private GUIContent GUI_enforceSrcAndTargetHaveSameStructure = new GUIContent("Enforce Source And Target Have Same Structure", "If this is checked then prefab instances will only be replaced if they have the same hierarchy and components. \n\n" +
  23. "If it is not checked then prefabs can be very different and ONLY THE TRANSFORM, LAYERS, TAGS & STATIC FLAGS ARE COPIED.\n\n" +
  24. "WARNING THIS IS A DESTRUCTIVE OPERARTION! BACK UP YOUR SCENE FIRST.");
  25. [MenuItem("Window/Mesh Baker/Replace Prefabs In Scene")]
  26. public static void ShowWindow()
  27. {
  28. GetWindow<MB_ReplacePrefabsInSceneEditorWindow>(true, "Replace Prefabs In Scene", true).Show();
  29. }
  30. public static void ShowWindow(MB3_BatchPrefabBaker.MB3_PrefabBakerRow[] prefabPairs)
  31. {
  32. MB_ReplacePrefabsInSceneEditorWindow window = GetWindow<MB_ReplacePrefabsInSceneEditorWindow>(true, "Replace Prefabs In Scene", true);
  33. window.Show();
  34. MB_ReplacePrefabsSettings.PrefabPair[] pps = new MB_ReplacePrefabsSettings.PrefabPair[prefabPairs.Length];
  35. for (int i = 0; i < pps.Length; i++)
  36. {
  37. pps[i] = new MB_ReplacePrefabsSettings.PrefabPair()
  38. {
  39. enabled = true,
  40. srcPrefab = prefabPairs[i].sourcePrefab,
  41. targPrefab = prefabPairs[i].resultPrefab,
  42. };
  43. }
  44. window.model.prefabsToSwitch = pps;
  45. window.soModel.Update();
  46. }
  47. private void InitModel()
  48. {
  49. soModel = new SerializedObject(model);
  50. prefabPairs = soModel.FindProperty("prefabsToSwitch");
  51. reverseSrcAndTarg = soModel.FindProperty("reverseSrcAndTarg");
  52. enforceSrcAndTargHaveSameStructure = soModel.FindProperty("enforceSrcAndTargHaveSameStructure");
  53. infoMessages = "";
  54. errorMessages = "";
  55. }
  56. private void OnEnable()
  57. {
  58. minSize = new Vector2(800f, 290f);
  59. if (model == null)
  60. {
  61. model = ScriptableObject.CreateInstance<MB_ReplacePrefabsSettings>();
  62. // Set the Hide flags so that this windows data not destroyed when entering playmode or a new scene.
  63. model.hideFlags = HideFlags.DontSave;
  64. }
  65. InitModel();
  66. }
  67. private void OnGUI()
  68. {
  69. EditorGUILayout.BeginHorizontal();
  70. MB_ReplacePrefabsSettings newModel = (MB_ReplacePrefabsSettings)EditorGUILayout.ObjectField("Settings", model, typeof(MB_ReplacePrefabsSettings), false);
  71. if (newModel != model)
  72. {
  73. if (newModel != null)
  74. {
  75. model = newModel;
  76. }
  77. else
  78. {
  79. if (model == null) model = ScriptableObject.CreateInstance<MB_ReplacePrefabsSettings>();
  80. // Set the Hide flags so that this windows data not destroyed when entering playmode or a new scene.
  81. model.hideFlags = HideFlags.DontSave;
  82. }
  83. InitModel();
  84. }
  85. if (model != null)
  86. {
  87. if (GUILayout.Button("Save Settings", GUILayout.Width(200)))
  88. {
  89. string path = EditorUtility.SaveFilePanel("Save Settings", Application.dataPath, "ReplacePrefabSettings", "asset");
  90. if (path != null)
  91. {
  92. model.hideFlags = HideFlags.None;
  93. string relativepath = "Assets" + path.Substring(Application.dataPath.Length);
  94. Debug.Log("Saved: " + relativepath);
  95. AssetDatabase.CreateAsset(model, relativepath);
  96. }
  97. }
  98. }
  99. EditorGUILayout.EndHorizontal();
  100. EditorGUILayout.Space();
  101. EditorGUILayout.Space();
  102. soModel.Update();
  103. if (GUILayout.Button(GUI_replacePefabsInScene))
  104. {
  105. if (EditorUtility.DisplayDialog("Replace Prefabs In Scene",
  106. "Are you sure you want to replace all source prefab instances with the target prefab instances in this scene? \n\n" +
  107. "It is highly recommended that you back up your scene before doing this.", "OK", "Cancel"))
  108. {
  109. ReplacePrefabsInScene();
  110. }
  111. }
  112. float labelWidth = EditorGUIUtility.labelWidth;
  113. EditorGUIUtility.labelWidth = 300f;
  114. EditorGUILayout.PropertyField(reverseSrcAndTarg, GUI_switchSrcAndTarget);
  115. EditorGUILayout.PropertyField(enforceSrcAndTargHaveSameStructure, GUI_enforceSrcAndTargetHaveSameStructure);
  116. EditorGUIUtility.labelWidth = labelWidth;
  117. if (infoMessages != "" || errorMessages != "")
  118. {
  119. EditorGUILayout.HelpBox(errorMessages + "\n" + infoMessages, errorMessages == "" ? MessageType.Info : MessageType.Error);
  120. }
  121. scrollViewPos = EditorGUILayout.BeginScrollView(scrollViewPos);
  122. EditorGUILayout.PropertyField(prefabPairs, true);
  123. EditorGUILayout.EndScrollView();
  124. soModel.ApplyModifiedProperties();
  125. }
  126. private void ReplacePrefabsInScene()
  127. {
  128. MB_ReplacePrefabsInScene rp = new MB_ReplacePrefabsInScene();
  129. rp.replaceEnforceStructure = model.enforceSrcAndTargHaveSameStructure;
  130. int numReplaced = 0;
  131. int numErrors = 0;
  132. errorMessages = "";
  133. infoMessages = "";
  134. EditorUtility.DisplayProgressBar("Replace Prefabs In Scene", "Replace Prefabs In Scene", 0);
  135. for (int i = 0; i < model.prefabsToSwitch.Length; i++)
  136. {
  137. MB_ReplacePrefabsSettings.PrefabPair pp = model.prefabsToSwitch[i];
  138. pp.objsWithErrors.Clear();
  139. if (pp.enabled)
  140. {
  141. GameObject src, targ;
  142. if (model.reverseSrcAndTarg)
  143. {
  144. src = pp.targPrefab;
  145. targ = pp.srcPrefab;
  146. }
  147. else
  148. {
  149. src = pp.srcPrefab;
  150. targ = pp.targPrefab;
  151. }
  152. numReplaced += rp.ReplacePrefabInstancesInScene(src, targ, pp.objsWithErrors);
  153. numErrors += pp.objsWithErrors.Count;
  154. }
  155. EditorUtility.DisplayProgressBar("Replace Prefabs In Scene", "Replace In Scene: " + pp.srcPrefab, (float)i / (float)model.prefabsToSwitch.Length);
  156. }
  157. EditorUtility.ClearProgressBar();
  158. Debug.Log("Total prefab instances replaced: " + numReplaced);
  159. infoMessages = "Total prefab instances replaced: " + numReplaced;
  160. if (numErrors > 0)
  161. {
  162. errorMessages = "There were errors replacing some of the prefabs in the scene. See console for details.";
  163. }
  164. soModel.Update();
  165. }
  166. }
  167. }