源战役客户端
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

320 行
14 KiB

  1. using UnityEditor;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using System;
  5. // using System.Collections;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. /// <summary>
  9. /// 给选中的特效添加脚本的
  10. /// </summary>
  11. namespace ParticleEffectProfilerNameSpace {
  12. [InitializeOnLoad]
  13. public class BatchTestParticleEffect
  14. {
  15. /// <summary>
  16. /// 需要有一个摄像机
  17. /// 每隔5s检查一个特效
  18. /// 检查结果保存在 \code\u3d\Assets\StreamingAssets\profiler_log\
  19. /// </summary>
  20. static string outPutTitleStr = "特效名,贴图内存(KB) 建议:<1024KB,贴图数量 建议:<5,粒子组件数 建议:<10,粒子数量 建议:<50,DrawCall 建议:<10,以下选项会导致特效无法自动剔除:";//检查结果分类名
  21. //////////////////分割线///////////////////分割线//////////////////分割线//////////////分割线////////////////////
  22. static string tempOutPutStr = "";//临时单条检查结果
  23. static bool isRestart = false;
  24. private const string RequestTestKey = "BatchTestParticleEffectRquestTest";// 打标记,指定是特效检查中
  25. private const string EffectStatusKey = "BatchTestParticleEffectStatusInt";// 检查进程状态
  26. private const string EffectWaitAddKey = "BatchTestParticleEffectWaitAddKey";// 打标记,指定是待增加新节点
  27. private const string EffectIndexKey = "BatchTestParticleEffectIndexInt";// 检查进程的进度index
  28. private const string EffectLastTimeKey = "BatchTestParticleEffectLastTimeFloat";// 检查进程的控制时间
  29. private const string ResultOutPutKey = "BatchTestParticleEffectResultOutPutKey";// 检查结果总数据
  30. private const string CheckAllNumKey = "BatchTestParticleCheckAllNumKey";// 检查总长度
  31. private const string CurFileIdKey = "BatchTestParticleCurFileIdKey";// 当前检查的文件名
  32. private const string CameraNameKey = "BatchTestParticleCameraNameKey";// 检查所用的摄像机名字
  33. [MenuItem("Assets/特效批量检查", false)]
  34. private static void BatchCheckStart()
  35. {
  36. //保存摄像机名
  37. bool find_camera = SaveCameraName();
  38. if (!find_camera){
  39. EditorUtility.DisplayDialog("Error", "当前根节点没有可用摄像机节点", "Ok");
  40. return;
  41. }
  42. // 检查文件目录是否存在
  43. string folder_path = Application.streamingAssetsPath + @"\profiler_log";
  44. if (!Directory.Exists(folder_path))
  45. Directory.CreateDirectory(folder_path);
  46. // 获得整个选中列表,用来备用
  47. UnityEngine.Object[] batch_check_list = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.TopLevel);
  48. //检查对象是否正确start
  49. foreach (UnityEngine.Object obj in batch_check_list)
  50. {
  51. string res_path = AssetDatabase.GetAssetPath(obj);
  52. GameObject layout_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(res_path, typeof(UnityEngine.Object)) as GameObject;
  53. if (layout_prefab == null) {
  54. EditorUtility.DisplayDialog("Error", "检查对象错误,请检查:" + res_path, "Ok");
  55. return;
  56. }
  57. }
  58. //检查对象是否正确end
  59. EditorPrefs.SetInt(CheckAllNumKey, batch_check_list.Length);
  60. if (batch_check_list.Length > 0) {
  61. EditorPrefs.SetString(CurFileIdKey, System.DateTime.Now.ToFileTime().ToString());//保存文件名id
  62. WriteDirCsvWait();//保存当前选中列表待使用
  63. //已经在播放状态,关闭
  64. if (EditorApplication.isPlaying)
  65. {
  66. EditorApplication.isPlaying = false;
  67. }
  68. // 初始化数据
  69. EditorPrefs.SetString(ResultOutPutKey, outPutTitleStr);//批处理状态-》开始
  70. EditorPrefs.SetBool(RequestTestKey, true);
  71. EditorPrefs.SetString(EffectStatusKey, "Going");//批处理状态-》开始
  72. EditorPrefs.SetFloat(EffectLastTimeKey, Time.time);
  73. int index = 1;//从第一个开始
  74. EditorPrefs.SetInt(EffectIndexKey, index);
  75. EditorPrefs.SetString(EffectWaitAddKey, "Non");//设置初始
  76. AddOneNode( index );
  77. BatchCheckOne(index);
  78. }
  79. else {
  80. EditorApplication.isPlaying = false;
  81. }
  82. }
  83. //设置摄像机名字
  84. private static bool SaveCameraName( ){
  85. foreach (GameObject rootObj in UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects())
  86. {
  87. Camera renders = rootObj.GetComponent<Camera>();
  88. if (renders != null) {
  89. EditorPrefs.SetString(CameraNameKey, rootObj.name);
  90. return true;
  91. }
  92. }
  93. return false;
  94. }
  95. /// 读取路径表CSV数据
  96. private static string GetCacheDirCsvWait( int index ){
  97. string filePath = Application.streamingAssetsPath + "/profiler_log/NameList" + EditorPrefs.GetString(CurFileIdKey) + ".csv";
  98. Dictionary<int, SaveWaitQueueCsvData> csvDataDic2 = SaveWaitQueueCsvData.LoadCsvData<SaveWaitQueueCsvData>(filePath);
  99. if ((csvDataDic2.Count) >= index){
  100. SaveWaitQueueCsvData csvDemo2 = csvDataDic2[index];
  101. return csvDemo2.Name;
  102. }
  103. else{
  104. return "";
  105. }
  106. }
  107. /// 写入路径表CSV数据
  108. private static void WriteDirCsvWait(){
  109. /* 把CSV文件按行存放,每一行的ID作为key值,内容作为value值 */
  110. UnityEngine.Object[] batch_check_list = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.TopLevel);
  111. string temp_str = "ID,Name";
  112. for (int i = 0; i < batch_check_list.Length; i++)
  113. {
  114. temp_str = temp_str + ";";
  115. temp_str = temp_str + (i+1) + "," + AssetDatabase.GetAssetPath(batch_check_list[i]);
  116. }
  117. string filePath = Application.streamingAssetsPath + "/profiler_log/NameList" + EditorPrefs.GetString(CurFileIdKey) + ".csv";
  118. string[] strs = temp_str.Split(';');
  119. CSVOptionTool.WriteCsv(strs, filePath);
  120. }
  121. /// 工作结束删除路径表CSV文件
  122. private static void RemoveFileDirCsvWait(){
  123. string filePath = Application.streamingAssetsPath + "/profiler_log/NameList" + EditorPrefs.GetString(CurFileIdKey) + ".csv";
  124. File.Delete(filePath);
  125. File.Delete(filePath + ".mata");
  126. }
  127. static BatchTestParticleEffect()
  128. {
  129. EditorApplication.update += Update;
  130. EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
  131. }
  132. public static void BatchCheckOne(int checkIndex )
  133. {
  134. string result_str = GetCacheDirCsvWait(checkIndex);
  135. if (result_str != "") {
  136. if (checkIndex != 1){
  137. //要在停止前保存,不然会丢数据
  138. WriteNewOutPutData();
  139. }
  140. // 停止运行
  141. if (EditorApplication.isPlaying)
  142. {
  143. EditorApplication.isPlaying = false;
  144. }
  145. if (checkIndex != 1){
  146. EditorPrefs.SetString(EffectWaitAddKey, "WaitAdd");
  147. }
  148. else{
  149. // 运行
  150. EditorPrefs.SetString(EffectWaitAddKey, "Non");
  151. ApplicationPlaying();
  152. }
  153. }
  154. else {
  155. OverCheckCall(false);
  156. }
  157. }
  158. // 加入一个特效节点
  159. public static void AddOneNode(int addIndex )
  160. {
  161. if (EditorApplication.isPlaying)
  162. {
  163. EditorApplication.isPlaying = false;
  164. }
  165. GameObject main_camera = GameObject.Find(EditorPrefs.GetString(CameraNameKey));
  166. // 清除节点下的子节点
  167. for (int i = main_camera.transform.childCount - 1; i >= 0; i--) {
  168. GameObject.DestroyImmediate(main_camera.transform.GetChild(i).gameObject);
  169. }
  170. // 创建测试节点
  171. string result_str = GetCacheDirCsvWait(addIndex);
  172. if (result_str != "") {
  173. GameObject layout_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(result_str, typeof(UnityEngine.Object)) as GameObject;
  174. if (layout_prefab == null) {
  175. OverCheckCall(true);
  176. EditorUtility.DisplayDialog("Error", "检查对象错误,请检查:" + result_str, "Ok");
  177. return;
  178. }
  179. GameObject particle_prefab = GameObject.Instantiate(layout_prefab) as GameObject;
  180. particle_prefab.transform.parent = main_camera.transform;
  181. particle_prefab.transform.localPosition = new Vector3(0, 0, 10);
  182. particle_prefab.transform.localScale = Vector3.one;
  183. Selection.activeGameObject = particle_prefab;
  184. // 加脚本
  185. var particleEffectScript = particle_prefab.GetComponentsInChildren<ParticleEffectScript>(true);
  186. if (particleEffectScript.Length == 0)
  187. {
  188. particle_prefab.AddComponent<ParticleEffectScript>();
  189. }
  190. // 取消标记
  191. EditorPrefs.SetString(EffectWaitAddKey, "AddOver");
  192. }
  193. else {
  194. OverCheckCall(false);
  195. }
  196. }
  197. //特效批量检查结束
  198. private static void OverCheckCall(bool mask_write)
  199. {
  200. if (!mask_write) {
  201. WriteNewOutPutData();
  202. }
  203. EditorApplication.isPlaying = false;
  204. EditorPrefs.SetString(EffectStatusKey, "WaitOver");//批处理状态-》等待关闭
  205. EditorUtility.ClearProgressBar();
  206. RemoveFileDirCsvWait();
  207. EditorUtility.DisplayDialog("提示", "特效批量检查结束,结果文件ID为:" + EditorPrefs.GetString(CurFileIdKey) , "Ok");
  208. OpenDirectory( Application.streamingAssetsPath + "/profiler_log" );
  209. }
  210. private static void Update()
  211. {
  212. int checkIndex = EditorPrefs.GetInt(EffectIndexKey);
  213. int all_len = EditorPrefs.GetInt(CheckAllNumKey);
  214. string wait_add_status = EditorPrefs.GetString(EffectWaitAddKey);//布尔值等待增节点
  215. if ( EditorPrefs.HasKey(RequestTestKey) && EditorApplication.isPlaying &&
  216. EditorApplication.isPlayingOrWillChangePlaymode)
  217. {
  218. bool isCancel = EditorUtility.DisplayCancelableProgressBar(string.Format("特效检查资源中({0}/{1})", checkIndex, all_len), "", (float)checkIndex / (float)all_len);
  219. if (isCancel) {
  220. OverCheckCall(true);
  221. return;
  222. }
  223. if (EditorPrefs.GetString(EffectStatusKey) == "Going"){//批处理状态-》开始
  224. // 计时器,每隔5s检查一个特效
  225. float lastTime = EditorPrefs.GetFloat(EffectLastTimeKey);
  226. float curTime = Time.time;
  227. if (curTime - lastTime >= 5)
  228. {
  229. EditorPrefs.SetFloat(EffectLastTimeKey, curTime);
  230. EditorPrefs.SetInt(EffectIndexKey, checkIndex+1);
  231. BatchCheckOne(checkIndex+1);
  232. }else if ((curTime - lastTime) < 0) {
  233. //矫正时间
  234. EditorPrefs.SetFloat(EffectLastTimeKey, curTime);
  235. }
  236. }
  237. }
  238. if ( EditorPrefs.HasKey(RequestTestKey) && !EditorApplication.isPlaying)
  239. {
  240. if (wait_add_status == "WaitAdd"){
  241. AddOneNode(checkIndex );
  242. }else if (wait_add_status == "AddOver") {
  243. ApplicationPlaying();
  244. }
  245. }
  246. }
  247. //运行状态切换的回调
  248. private static void PlaymodeStateChanged()
  249. {
  250. if (isRestart)
  251. {
  252. // 要重启游戏的情况
  253. EditorApplication.isPlaying = true;
  254. isRestart = false;
  255. }
  256. if (!EditorApplication.isPlaying && EditorPrefs.GetString(EffectStatusKey) == "WaitOver"){
  257. EditorPrefs.SetString(EffectStatusKey, "Non");//批处理状态-》结束
  258. EditorPrefs.DeleteKey(RequestTestKey);
  259. // 清除节点下的子节点
  260. GameObject main_camera = GameObject.Find(EditorPrefs.GetString(CameraNameKey));
  261. for (int i = main_camera.transform.childCount - 1; i >= 0; i--) {
  262. GameObject.DestroyImmediate(main_camera.transform.GetChild(i).gameObject);
  263. }
  264. }
  265. }
  266. //运行游戏
  267. public static void ApplicationPlaying()
  268. {
  269. if (EditorApplication.isPlaying)
  270. {
  271. //已经在播放状态,使其重新开始
  272. EditorApplication.isPlaying = false;
  273. isRestart = true;
  274. }
  275. else{
  276. EditorApplication.isPlaying = true;
  277. }
  278. }
  279. // 保存临时输出数据
  280. public static void SaveTempOutPutData(string outPut){
  281. tempOutPutStr = outPut;
  282. }
  283. //写入新数据
  284. public static void WriteNewOutPutData(){
  285. string outPutString = EditorPrefs.GetString(ResultOutPutKey);
  286. outPutString = outPutString + ";" + tempOutPutStr;
  287. EditorPrefs.SetString(ResultOutPutKey, outPutString);
  288. string filePath = Application.streamingAssetsPath + "/profiler_log/OutPut" + EditorPrefs.GetString(CurFileIdKey) + ".csv";
  289. string[] strs = outPutString.Split(';');
  290. CSVOptionTool.WriteCsv(strs, filePath);
  291. }
  292. //打开文件夹
  293. public static void OpenDirectory(string path){
  294. if (string.IsNullOrEmpty(path)) return;
  295. path=path.Replace("/", "\\");
  296. if (!Directory.Exists(path)){
  297. Debug.LogError("No Directory: " + path);
  298. return;
  299. }
  300. System.Diagnostics.Process.Start("explorer.exe", path);
  301. }
  302. }
  303. }