Advertisement
Guest User

Untitled

a guest
Mar 31st, 2015
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.84 KB | None | 0 0
  1. /**
  2. * Repairs missing pb_Object and pb_Entity references. It is based
  3. * on this article by Unity Gems: http://unitygems.com/lateral1/
  4. */
  5.  
  6. using UnityEngine;
  7. using UnityEditor;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10.  
  11. /**
  12. * Extends MonoBehaviour Inspector, automatically fixing missing script
  13. * references (typically caused by ProBuilder upgrade process).
  14. */
  15. [CustomEditor(typeof(MonoBehaviour))]
  16. public class pb_MissingScriptEditor : Editor
  17. {
  18. #region Members
  19.  
  20. static int index = 0; ///< general idea of where we are in terms of processing this scene.
  21. static float total; ///< general idea of how many missing script references are in this scene.
  22.  
  23. static bool doFix = false; ///< while true, the inspector will attempt to cycle to broken gameobjects until none are found.
  24. static List<GameObject> unfixable = new List<GameObject>(); ///< if a non-pb missing reference is encountered, need to let the iterator know not to bother,
  25.  
  26. static MonoScript _mono_pb; ///< MonoScript assets
  27. static MonoScript _mono_pe; ///< MonoScript assets
  28.  
  29. /**
  30. * Load the pb_Object and pb_Entity classes to MonoScript assets. Saves us from having to fall back on Reflection.
  31. */
  32. static void LoadMonoScript()
  33. {
  34. GameObject go = new GameObject();
  35.  
  36. pb_Object pb = go.AddComponent<pb_Object>();
  37. pb_Entity pe = go.AddComponent<pb_Entity>();
  38.  
  39. _mono_pb = MonoScript.FromMonoBehaviour( pb );
  40. _mono_pe = MonoScript.FromMonoBehaviour( pe );
  41.  
  42. DestroyImmediate(go);
  43. }
  44.  
  45. public MonoScript pb_monoscript
  46. {
  47. get
  48. {
  49. if(_mono_pb == null) LoadMonoScript();
  50. return _mono_pb;
  51. }
  52. }
  53.  
  54. public MonoScript pe_monoscript
  55. {
  56. get
  57. {
  58. if(_mono_pe == null) LoadMonoScript();
  59. return _mono_pe;
  60. }
  61. }
  62. #endregion
  63.  
  64. [MenuItem("Tools/" + pb_Constant.PRODUCT_NAME + "/Repair/Repair Missing Script References")]
  65. public static void MenuRepairMissingScriptReferences()
  66. {
  67. FixAllScriptReferencesInScene();
  68. }
  69.  
  70. static void FixAllScriptReferencesInScene()
  71. {
  72. EditorApplication.ExecuteMenuItem("Window/Inspector");
  73.  
  74. Object[] all = Resources.FindObjectsOfTypeAll(typeof(GameObject)).Where(x => ((GameObject)x).GetComponents<Component>().Any(n => n == null) ).ToArray();
  75. total = all.Length;
  76.  
  77. unfixable.Clear();
  78.  
  79. if(total > 1)
  80. {
  81. Undo.RecordObjects(all, "Fix missing script references");
  82.  
  83. index = 0;
  84. doFix = true;
  85.  
  86. Next();
  87. }
  88. else
  89. {
  90. EditorUtility.DisplayDialog("Success", "No missing ProBuilder script references found.", "Okay");
  91. }
  92. }
  93.  
  94. /**
  95. * Advance to the next gameobject with missing components. If none are found, display dialog and exit.
  96. */
  97. static void Next()
  98. {
  99. EditorUtility.DisplayProgressBar("Repair ProBuilder Script References", "Fixing " + (index+1) + " out of " + total + " objects in scene.", ((float)index/total) );
  100.  
  101. // Cycle through FindObjectsOfType on every Next() because using a static list didn't work for some reason.
  102. foreach(GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)))
  103. {
  104. if(go.GetComponents<Component>().Any(x => x == null) && !unfixable.Contains(go))
  105. {
  106. if( !go.GetComponent<MeshFilter>() || !go.GetComponent<MeshFilter>().sharedMesh) {
  107. unfixable.Add(go);
  108. Debug.LogError (go.name + " probably needs deleting." , go);
  109. continue;
  110. }
  111. else if (go.GetComponent<MeshFilter>().sharedMesh.vertices.Length == 0) {
  112. unfixable.Add(go);
  113. Debug.LogError (go.name + " probably needs deleting." , go);
  114. continue;
  115. }
  116.  
  117. if( (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance ||
  118. PrefabUtility.GetPrefabType(go) == PrefabType.Prefab ) )
  119. {
  120. GameObject pref = (GameObject)PrefabUtility.GetPrefabParent(go);
  121.  
  122.  
  123.  
  124. if(pref && (pref.GetComponent<pb_Object>() || pref.GetComponent<pb_Entity>()))
  125. {
  126. unfixable.Add(go);
  127. continue;
  128. }
  129.  
  130.  
  131. }
  132.  
  133. if(go.hideFlags != HideFlags.None)
  134. {
  135. unfixable.Add(go);
  136. continue;
  137. }
  138.  
  139. Selection.activeObject = go;
  140.  
  141. return;
  142. }
  143. }
  144.  
  145. pb_Object[] pbs = (pb_Object[])Resources.FindObjectsOfTypeAll(typeof(pb_Object));
  146.  
  147. for(int i = 0; i < pbs.Length; i++)
  148. {
  149. EditorUtility.DisplayProgressBar("Force Refresh ProBuilder Objects", "Refresh " + (i+1) + " out of " + total + " objects in scene.", ((float)i/pbs.Length) );
  150.  
  151. pbs[i].ToMesh();
  152. pbs[i].Refresh();
  153. pbs[i].GenerateUV2();
  154. }
  155.  
  156.  
  157. EditorUtility.ClearProgressBar();
  158.  
  159. EditorUtility.DisplayDialog("Success", "Successfully repaired " + total + " ProBuilder objects.", "Okay");
  160.  
  161. if(!EditorApplication.SaveCurrentSceneIfUserWantsTo())
  162. Debug.LogWarning("Repaired script references will be lost on exit if this scene is not saved!");
  163.  
  164. doFix = false;
  165. skipEvent = true;
  166. }
  167.  
  168. /**
  169. * SerializedProperty names found in pb_Entity.
  170. */
  171. List<string> PB_OBJECT_SCRIPT_PROPERTIES = new List<string>()
  172. {
  173. "_sharedIndices",
  174. "_vertices",
  175. "_uv",
  176. "_sharedIndicesUV",
  177. "_quads"
  178. };
  179.  
  180. /**
  181. * SerializedProperty names found in pb_Object.
  182. */
  183. List<string> PB_ENTITY_SCRIPT_PROPERTIES = new List<string>()
  184. {
  185. "pb",
  186. "userSetDimensions",
  187. "_entityType",
  188. "forceConvex"
  189. };
  190.  
  191. // Prevents ArgumentException after displaying 'Done' dialog. For some reason the Event loop skips layout phase after DisplayDialog.
  192. private static bool skipEvent = false;
  193.  
  194. public override void OnInspectorGUI()
  195. {
  196. if(skipEvent && Event.current.type == EventType.Repaint)
  197. {
  198. skipEvent = false;
  199. return;
  200. }
  201.  
  202. SerializedProperty scriptProperty = this.serializedObject.FindProperty("m_Script");
  203.  
  204. if(scriptProperty == null || scriptProperty.objectReferenceValue != null)
  205. {
  206. if(doFix)
  207. {
  208. if(Event.current.type == EventType.Repaint)
  209. {
  210. Next();
  211. }
  212. }
  213. else
  214. {
  215. base.OnInspectorGUI();
  216. }
  217.  
  218. return;
  219. }
  220.  
  221. int pbObjectMatches = 0, pbEntityMatches = 0;
  222.  
  223. // Shows a detailed tree view of all the properties in this serializedobject.
  224. // GUILayout.Label( SerializedObjectToString(this.serializedObject) );
  225.  
  226. SerializedProperty iterator = this.serializedObject.GetIterator();
  227.  
  228. iterator.Next(true);
  229.  
  230. while( iterator.Next(true) )
  231. {
  232. if( PB_OBJECT_SCRIPT_PROPERTIES.Contains(iterator.name) )
  233. pbObjectMatches++;
  234.  
  235. if( PB_ENTITY_SCRIPT_PROPERTIES.Contains(iterator.name) )
  236. pbEntityMatches++;
  237. }
  238.  
  239. // If we can fix it, show the help box, otherwise just default inspector it up.
  240. if(pbObjectMatches >= 3 || pbEntityMatches >= 3)
  241. {
  242. EditorGUILayout.HelpBox("Missing Script Reference\n\nProBuilder can automatically fix this missing reference. To fix all references in the scene, click \"Fix All in Scene\". To fix just this one, click \"Reconnect\".", MessageType.Warning);
  243. }
  244. else
  245. {
  246. if(doFix)
  247. {
  248. unfixable.Add( ((Component)target).gameObject );
  249. Next();
  250. GUIUtility.ExitGUI();
  251. return;
  252. }
  253. else
  254. {
  255. base.OnInspectorGUI();
  256. }
  257.  
  258. return;
  259. }
  260.  
  261. GUI.backgroundColor = Color.green;
  262.  
  263. if(!doFix)
  264. {
  265. if(GUILayout.Button("Fix All in Scene"))
  266. {
  267. FixAllScriptReferencesInScene();
  268. return;
  269. }
  270. }
  271.  
  272. GUI.backgroundColor = Color.cyan;
  273.  
  274. if((doFix && Event.current.type == EventType.Repaint) || GUILayout.Button("Reconnect"))
  275. {
  276. if(pbObjectMatches >= 3) // only increment for pb_Object otherwise the progress bar will fill 2x faster than it should
  277. {
  278. index++;
  279. }
  280. else
  281. {
  282. // Make sure that pb_Object is fixed first if we're automatically cycling objects.
  283. if(doFix && ((Component)target).gameObject.GetComponent<pb_Object>() == null)
  284. return;
  285. }
  286.  
  287. if(!doFix)
  288. {
  289. Undo.RegisterCompleteObjectUndo(target, "Fix missing reference.");
  290. }
  291.  
  292. // Debug.Log("Fix: " + (pbObjectMatches > 2 ? "pb_Object" : "pb_Entity") + " " + ((Component)target).gameObject.name);
  293.  
  294. scriptProperty.objectReferenceValue = pbObjectMatches >= 3 ? pb_monoscript : pe_monoscript;
  295. scriptProperty.serializedObject.ApplyModifiedProperties();
  296. scriptProperty = this.serializedObject.FindProperty("m_Script");
  297. scriptProperty.serializedObject.Update();
  298.  
  299. if(doFix)
  300. Next();
  301.  
  302. GUIUtility.ExitGUI();
  303. }
  304.  
  305. GUI.backgroundColor = Color.white;
  306. }
  307.  
  308. /**
  309. * Returns a formatted string with all properties in serialized object.
  310. */
  311. static string SerializedObjectToString(SerializedObject serializedObject)
  312. {
  313. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  314.  
  315. if(serializedObject == null)
  316. {
  317. sb.Append("NULL");
  318. return sb.ToString();
  319. }
  320.  
  321. SerializedProperty iterator = serializedObject.GetIterator();
  322.  
  323. iterator.Next(true);
  324.  
  325.  
  326. while( iterator.Next(true) )
  327. {
  328. string tabs = "";
  329. for(int i = 0; i < iterator.depth; i++) tabs += "\t";
  330.  
  331. sb.AppendLine(tabs + iterator.name + (iterator.propertyType == SerializedPropertyType.ObjectReference && iterator.type.Contains("Component") && iterator.objectReferenceValue == null ? " -> NULL" : "") );
  332.  
  333. tabs += " - ";
  334.  
  335. sb.AppendLine(tabs + "Type: (" + iterator.type + " / " + iterator.propertyType + " / " + " / " + iterator.name + ")");
  336. sb.AppendLine(tabs + iterator.propertyPath);
  337. sb.AppendLine(tabs + "Value: " + SerializedPropertyValue(iterator));
  338. }
  339.  
  340. return sb.ToString();
  341. }
  342.  
  343. /**
  344. * Return a string from the value of a SerializedProperty.
  345. */
  346. static string SerializedPropertyValue(SerializedProperty sp)
  347. {
  348. switch(sp.propertyType)
  349. {
  350. case SerializedPropertyType.Integer:
  351. return sp.intValue.ToString();
  352.  
  353. case SerializedPropertyType.Boolean:
  354. return sp.boolValue.ToString();
  355.  
  356. case SerializedPropertyType.Float:
  357. return sp.floatValue.ToString();
  358.  
  359. case SerializedPropertyType.String:
  360. return sp.stringValue.ToString();
  361.  
  362. case SerializedPropertyType.Color:
  363. return sp.colorValue.ToString();
  364.  
  365. case SerializedPropertyType.ObjectReference:
  366. return (sp.objectReferenceValue == null ? "null" : sp.objectReferenceValue.name);
  367.  
  368. case SerializedPropertyType.LayerMask:
  369. return sp.intValue.ToString();
  370.  
  371. case SerializedPropertyType.Enum:
  372. return sp.enumValueIndex.ToString();
  373.  
  374. case SerializedPropertyType.Vector2:
  375. return sp.vector2Value.ToString();
  376.  
  377. case SerializedPropertyType.Vector3:
  378. return sp.vector3Value.ToString();
  379.  
  380. // Not public api as of 4.3?
  381. // case SerializedPropertyType.Vector4:
  382. // return sp.vector4Value.ToString();
  383.  
  384. case SerializedPropertyType.Rect:
  385. return sp.rectValue.ToString();
  386.  
  387. case SerializedPropertyType.ArraySize:
  388. return sp.intValue.ToString();
  389.  
  390. case SerializedPropertyType.Character:
  391. return "Character";
  392.  
  393. case SerializedPropertyType.AnimationCurve:
  394. return sp.animationCurveValue.ToString();
  395.  
  396. case SerializedPropertyType.Bounds:
  397. return sp.boundsValue.ToString();
  398.  
  399. case SerializedPropertyType.Gradient:
  400. return "Gradient";
  401.  
  402. default:
  403. return "Unknown type";
  404. }
  405. }
  406.  
  407. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement