ScriptableObjectCreator.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using UnityEditor;
  2. using UnityEngine;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.IO; // 引入 System.IO
  7. namespace MTool
  8. {
  9. public class ScriptableObjectCreator : EditorWindow
  10. {
  11. private List<Type> _soTypes = new List<Type>();
  12. private Vector2 _scrollPosition;
  13. private string _searchPath;
  14. [MenuItem("Tools/ScriptableObject Creator")]
  15. public static void ShowWindow()
  16. {
  17. GetWindow<ScriptableObjectCreator>("SO CREATOR");
  18. }
  19. private void OnEnable()
  20. {
  21. _searchPath = EditorPrefs.GetString("ScriptableObjectCreator_SearchPath", "Assets/Scripts");
  22. // FindAllScriptableObjectTypes();
  23. }
  24. void OnDisable()
  25. {
  26. // 保存当前的搜索路径到 EditorPrefs
  27. EditorPrefs.SetString("ScriptableObjectCreator_SearchPath", _searchPath);
  28. }
  29. private void OnGUI()
  30. {
  31. GUILayout.Label("Create ScriptableObject Instances", EditorStyles.boldLabel);
  32. // 路径选择区域
  33. EditorGUILayout.BeginHorizontal();
  34. GUILayout.Label("Path:", GUILayout.Width(40)); // 设置标签的宽度为40像素
  35. _searchPath = EditorGUILayout.TextField(_searchPath);
  36. if (GUILayout.Button("Browse", GUILayout.Width(60)))
  37. {
  38. string selectedPath = EditorUtility.OpenFolderPanel("Select Script Folder", _searchPath, "");
  39. if (!string.IsNullOrEmpty(selectedPath))
  40. {
  41. // 将绝对路径转换为相对于项目的路径
  42. if (selectedPath.StartsWith(Application.dataPath))
  43. {
  44. _searchPath = "Assets" + selectedPath.Substring(Application.dataPath.Length);
  45. }
  46. else
  47. {
  48. Debug.LogError("Selected path is not within the project's Assets folder.");
  49. // 可以选择在这里给 _searchPath 设置一个默认值,或者禁用“确定”按钮
  50. }
  51. }
  52. }
  53. if (GUILayout.Button("OK", GUILayout.Width(60)))
  54. {
  55. FindAllScriptableObjectTypes(); // 点击“确定”按钮时,重新查找 SO 类型
  56. }
  57. // 结束一个水平布局组
  58. EditorGUILayout.EndHorizontal();
  59. EditorGUILayout.Space();
  60. _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
  61. // 遍历 _soTypes 集合中的每一个 Type 对象
  62. foreach (Type soType in _soTypes)
  63. {
  64. // 使用 GUILayout.Button 创建一个按钮,按钮的文本为 "Create " 加上当前 Type 的名称
  65. if (GUILayout.Button(soType.Name))
  66. {
  67. // 如果按钮被点击,则调用 CreateScriptableObjectAsset 方法,并传入当前的 Type 对象
  68. CreateScriptableObjectAsset(soType);
  69. }
  70. }
  71. EditorGUILayout.EndScrollView();
  72. }
  73. private void FindAllScriptableObjectTypes()
  74. {
  75. _soTypes.Clear();
  76. // 1. 获取 Scripts 文件夹及其子文件夹中的所有 .cs 文件
  77. string[] scriptFiles = Directory.GetFiles(_searchPath, "*.cs", SearchOption.AllDirectories);
  78. // 2. 遍历所有脚本文件
  79. foreach (string scriptFile in scriptFiles)
  80. {
  81. // 3. 从文件路径获取脚本的类名 (不含 .cs 扩展名)
  82. string className = Path.GetFileNameWithoutExtension(scriptFile);
  83. // 4. 尝试从当前程序集中加载该类
  84. Type type = Type.GetType(className); // Type.GetType 可能会因为命名空间问题失败,见下文改进
  85. if (type == null)
  86. {
  87. //如果直接Type.GetType失败了, 就遍历所有程序集
  88. type = AppDomain.CurrentDomain.GetAssemblies()
  89. .SelectMany(assembly => assembly.GetTypes())
  90. .FirstOrDefault(t => t.Name == className);
  91. }
  92. // 5. 检查是否是 ScriptableObject 的子类且非抽象类
  93. if (type != null && type.IsSubclassOf(typeof(ScriptableObject)) && !type.IsAbstract)
  94. {
  95. _soTypes.Add(type);
  96. }
  97. }
  98. }
  99. private void CreateScriptableObjectAsset(Type soType)
  100. {
  101. // 创建 ScriptableObject 实例
  102. ScriptableObject instance = CreateInstance(soType);
  103. // 获取保存路径
  104. string path = EditorUtility.SaveFilePanelInProject(
  105. "Save ScriptableObject",
  106. soType.Name,
  107. "asset",
  108. "Please enter a file name to save the ScriptableObject to");
  109. if (string.IsNullOrEmpty(path))
  110. {
  111. return; // 如果用户取消了保存,则不执行任何操作
  112. }
  113. // 创建资源文件
  114. AssetDatabase.CreateAsset(instance, path);
  115. AssetDatabase.SaveAssets();
  116. AssetDatabase.Refresh();
  117. // 选中新创建的资源
  118. EditorUtility.FocusProjectWindow();
  119. Selection.activeObject = instance;
  120. }
  121. }
  122. }