LabelUtility.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. using System.Reflection;
  2. namespace labelUtility
  3. {
  4. #if UNITY_EDITOR
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Text.RegularExpressions;
  12. using System.Xml;
  13. using UnityEditor;
  14. using UnityEngine;
  15. using UnityEngine.UI;
  16. [Serializable]
  17. public class RegistTarget
  18. {
  19. public string Name;
  20. public bool Force;
  21. public bool Ignore;
  22. public Transform Transform;
  23. public ComponentType Type;
  24. }
  25. [Serializable]
  26. public class ComponentEventString
  27. {
  28. public ComponentType ComponentType;
  29. public List<string> Strings;
  30. }
  31. [Serializable]
  32. public class LabelSet //todo 更新
  33. {
  34. public string Name;
  35. public UtilityType UtilityType;
  36. public string LabelScriptPath;
  37. public string LabelScriptName;
  38. public string LabePrefix = "public static string";
  39. public TextAsset LabelScript;
  40. public string ComponentScriptPath;
  41. public string ComponentScriptName;
  42. public string DerivedString;
  43. public string RegistMethodString;
  44. public string ComponentPrefix = "private";
  45. public string NameExcludeString;
  46. public string RegistString;
  47. public List<string> RegistExtraLines;
  48. public TextAsset ComponentScript;
  49. public List<TextAsset> Languages; //todo 需要更新为LanguageXml
  50. public List<GameObject> Prefabs;
  51. public bool FoldOut;
  52. public float TotalHeight;
  53. public List<ComponentType> RegistTypes = new List<ComponentType>();
  54. public List<RegistTarget> RegistTargets = new List<RegistTarget>();
  55. }
  56. [Serializable]
  57. public enum ComponentType //todo 更新
  58. {
  59. None,
  60. Text,
  61. Slider,
  62. Image,
  63. Button,
  64. InputField,
  65. Transform,
  66. RectTransform,
  67. SpriteRenderer,
  68. VirtualScrollRectPlus,
  69. }
  70. public enum UtilityType
  71. {
  72. XmlLabel,
  73. PrefabLabel,
  74. Regist,
  75. }
  76. public class LabelUtility : MonoBehaviour
  77. {
  78. #region Config
  79. public List<string> DllNames;
  80. public List<ComponentEventString> EventStrings;
  81. public List<LabelSet> LabelSets;
  82. public static string StartMark = "//StartMark-Used by LabelUtility-Do not remove"; //todo 更新
  83. public static string EndMark = "//EndMark-Used by LabelUtility-Do not remove"; //todo 更新
  84. public static string RegistStartMark = "//RegistStartMark-Used by LabelUtility-Do not remove"; //todo 更新
  85. public static string RegistEndMark = "//RegistEndMark-Used by LabelUtility-Do not remove"; //todo 更新
  86. public static string EventStartMark = "//EventStartMark-Used by LabelUtility-Do not remove"; //todo 更新
  87. public static string EventEndMark = "//EventEndMark-Used by LabelUtility-Do not remove"; //todo 更新
  88. public static string Prefix = "public static string ";
  89. #endregion
  90. public static void CreateLabelScript(LabelSet labelSet, bool showWarning = true, bool auto = false)
  91. {
  92. if (showWarning)
  93. {
  94. if (!EditorUtility.DisplayDialog("注意", "新建LabelScript?", "确定", "取消"))
  95. {
  96. return;
  97. }
  98. }
  99. if (!auto)
  100. {
  101. auto = EditorUtility.DisplayDialog("提示", "是否自动提取标签", "确定", "取消");
  102. }
  103. string scriptContent = "";
  104. foreach (var dllName in InstanceManager.SearchInstance<LabelUtility>().DllNames)
  105. {
  106. scriptContent += $"using {dllName};\r\n";
  107. }
  108. scriptContent += "\r\n";
  109. scriptContent += $"public class {labelSet.LabelScriptName}";
  110. scriptContent += "\r\n";
  111. scriptContent += $"{{\r\n\t#region Config\r\n\r\n\t{StartMark}\r\n\t{EndMark}\r\n\r\n\t#endregion\r\n}}";
  112. labelSet.LabelScript = CreateScript(labelSet.LabelScriptName, labelSet.LabelScriptPath, scriptContent);
  113. if (auto)
  114. {
  115. if (labelSet.UtilityType == UtilityType.XmlLabel)
  116. {
  117. CreateLabelFromLanguageXml(labelSet, false);
  118. }
  119. else if (labelSet.UtilityType == UtilityType.Regist || labelSet.UtilityType == UtilityType.PrefabLabel)
  120. {
  121. CreateLabelFromPrefab(labelSet, false);
  122. }
  123. }
  124. }
  125. public static void CreateComponentScript(LabelSet labelSet, bool showWarning = true, bool regist = false)
  126. {
  127. if (showWarning)
  128. {
  129. if (!EditorUtility.DisplayDialog("注意", "新建ComponentScript?", "确定", "取消"))
  130. {
  131. return;
  132. }
  133. }
  134. if (!regist)
  135. {
  136. regist = EditorUtility.DisplayDialog("提示", "是否自动注册", "确定", "取消");
  137. }
  138. string scriptContent = "";
  139. foreach (var dllName in InstanceManager.SearchInstance<LabelUtility>().DllNames)
  140. {
  141. scriptContent += $"using {dllName};\r\n";
  142. }
  143. scriptContent += "\r\n";
  144. scriptContent += $"public class {labelSet.ComponentScriptName}";
  145. if (string.IsNullOrEmpty(labelSet.DerivedString))
  146. {
  147. scriptContent += "\r\n";
  148. }
  149. else
  150. {
  151. scriptContent += $" : {labelSet.DerivedString}\r\n";
  152. }
  153. scriptContent += $"{{\r\n\t#region Config\r\n\r\n\t{StartMark}\r\n\t{EndMark}\r\n\r\n\t#endregion\r\n";
  154. scriptContent += "\r\n";
  155. if (!string.IsNullOrEmpty(labelSet.RegistMethodString))
  156. {
  157. scriptContent += $"\t{labelSet.RegistMethodString}\r\n\t{{\r\n";
  158. scriptContent += $"\t\t{RegistStartMark}\r\n";
  159. scriptContent += $"\t\t{RegistEndMark}\r\n";
  160. scriptContent += $"\t}}\r\n";
  161. }
  162. scriptContent += "\r\n";
  163. scriptContent += $"\t{EventStartMark}\r\n";
  164. scriptContent += $"\t{EventEndMark}\r\n";
  165. scriptContent += $"}}";
  166. labelSet.ComponentScript = CreateScript(labelSet.ComponentScriptName, labelSet.ComponentScriptPath, scriptContent);
  167. if (regist)
  168. {
  169. CreateComponentsFromPrefab(labelSet, false);
  170. }
  171. }
  172. private static TextAsset CreateScript(string scriptName, string scriptPath, string content)
  173. {
  174. string directory = scriptPath.TrimEnd('/', '\\') + "/";
  175. if (directory.Length < 6 || directory.Substring(0, 6).ToLower() != "assets")
  176. {
  177. throw new Exception("ScripPath必须位置Assets目录内");
  178. }
  179. if (!Directory.Exists(directory))
  180. {
  181. throw new Exception("文件夹不存在");
  182. }
  183. if (string.IsNullOrEmpty(scriptName) || scriptName.Any(Path.GetInvalidFileNameChars().Contains))
  184. {
  185. throw new Exception("ScripName包含无效字符");
  186. }
  187. string fullPath = $"{scriptPath}/{scriptName}.cs";
  188. if (File.Exists(fullPath))
  189. {
  190. throw new Exception($"已经存在一个 {fullPath}");
  191. }
  192. File.WriteAllText(fullPath, content);
  193. AssetDatabase.Refresh();
  194. return AssetDatabase.LoadAssetAtPath<TextAsset>(fullPath);
  195. }
  196. public static void CreateLabelFromPrefab(LabelSet labelSet, bool showWarning = true) //todo 更新
  197. {
  198. if (labelSet.LabelScript == null)
  199. {
  200. Debug.LogError("LabelScript is null");
  201. return;
  202. }
  203. if (showWarning)
  204. {
  205. if (!EditorUtility.DisplayDialog("注意", "重新生成Prefab Label?", "确定", "取消"))
  206. {
  207. return;
  208. }
  209. }
  210. List<string> labels = new List<string>();
  211. List<Transform> transforms = GetAllTransformFromPrefab(labelSet.Prefabs);
  212. foreach (var transform in transforms)
  213. {
  214. labels.Add($"{labelSet.LabePrefix} {transform.name} = \"{transform.name}\";");
  215. }
  216. InsertLineToScript(StartMark, EndMark, labelSet.LabelScript, labels);
  217. }
  218. public static void CreateLabelFromLanguageXml(LabelSet labelSet, bool showWarning = true) //todo 更新
  219. {
  220. if (labelSet.LabelScript == null)
  221. {
  222. Debug.LogError("LabelScript is null");
  223. return;
  224. }
  225. if (showWarning)
  226. {
  227. if (!EditorUtility.DisplayDialog("注意", "重新生成LanguageXml Label?", "确定", "取消"))
  228. {
  229. return;
  230. }
  231. }
  232. List<string> labels = new List<string>();
  233. foreach (var language in labelSet.Languages)
  234. {
  235. XmlDocument document = new XmlDocument();
  236. document.LoadXml(language.text);
  237. XmlNodeList childNodes = document.SelectSingleNode("lan").ChildNodes;
  238. for (int i = 0; i < childNodes.Count; i++)
  239. {
  240. labels.AddRange(GetAllLabelFromXmlNode(childNodes[i], labelSet));
  241. }
  242. }
  243. InsertLineToScript(StartMark, EndMark, labelSet.LabelScript, labels);
  244. }
  245. private static List<string> GetAllLabelFromXmlNode(XmlNode node, LabelSet labelSet) //todo 增加
  246. {
  247. List<string> labels = new List<string>();
  248. for (int i = 0; i < node.ChildNodes.Count; i++)
  249. {
  250. XmlNode childNode = node.ChildNodes[i];
  251. string label;
  252. if (i == 0)
  253. {
  254. label = $"\t{labelSet.LabePrefix} {node.Name} = \"{node.Name}\";";
  255. labels.Add(label);
  256. }
  257. label = $"\t{labelSet.LabePrefix} {node.Name}{LanguageLabel.LanguagePageSeperator}{childNode.Name} = \"{node.Name}{LanguageLabel.LanguagePageSeperator}{childNode.Name}\";";
  258. labels.Add(label);
  259. }
  260. return labels;
  261. }
  262. public static Type GetType(ComponentType componentType)
  263. {
  264. Assembly assembly = Assembly.Load("UnityEngine.UI");
  265. Type type = assembly.GetType($"UnityEngine.UI.{componentType}");
  266. if (type == null)
  267. {
  268. assembly = Assembly.Load("UnityEngine");
  269. type = assembly.GetType($"UnityEngine.{componentType}");
  270. }
  271. if (type == null)
  272. {
  273. assembly = Assembly.Load("Assembly-CSharp");
  274. type = assembly.GetType($"{componentType}");
  275. }
  276. return type;
  277. }
  278. public static void CreateComponentsFromPrefab(LabelSet labelSet, bool showWarning = true) //todo 更新
  279. {
  280. if (labelSet.ComponentScript == null)
  281. {
  282. Debug.LogError("ComponentScript is null");
  283. return;
  284. }
  285. if (showWarning)
  286. {
  287. if (!EditorUtility.DisplayDialog("注意", "重新生成PrefabComponent?", "确定", "取消"))
  288. {
  289. return;
  290. }
  291. }
  292. List<string> defineStrings = new List<string>();
  293. List<string> registStrings = new List<string>();
  294. List<string> eventStrings = new List<string>();
  295. registStrings.AddRange(labelSet.RegistExtraLines);
  296. foreach (var registTarget in labelSet.RegistTargets)
  297. {
  298. if (registTarget.Ignore) continue;
  299. defineStrings.Add($"{labelSet.ComponentPrefix} {registTarget.Type} {registTarget.Transform.name};");
  300. string registString = labelSet.RegistString.Replace("#NAME", registTarget.Transform.name).Replace("#TYPE", registTarget.Type.ToString()).Replace("#NEWNAME", registTarget.Name);
  301. if (labelSet.LabelScript != null)
  302. {
  303. registString = registString.Replace("#LABEL", labelSet.LabelScript.name);
  304. }
  305. registStrings.Add(registString);
  306. foreach (var eventString in InstanceManager.SearchInstance<LabelUtility>().EventStrings)
  307. {
  308. if (eventString.ComponentType == registTarget.Type)
  309. {
  310. for (int i = 0; i < eventString.Strings.Count; i++)
  311. {
  312. eventStrings.Add($"{labelSet.ComponentPrefix} {eventString.Strings[i].Replace("#NEWNAME", registTarget.Name)}");
  313. eventStrings.Add("{");
  314. eventStrings.Add("}");
  315. }
  316. }
  317. }
  318. }
  319. InsertLineToScript(StartMark, EndMark, labelSet.ComponentScript, defineStrings);
  320. InsertLineToScript(RegistStartMark, RegistEndMark, labelSet.ComponentScript, registStrings);
  321. //List <string> typeNames = new List<string>();
  322. //foreach (var purview in labelSet.RegistTypes)
  323. //{
  324. // typeNames.Add(purview.ToString());
  325. //}
  326. //List <Transform> transforms = GetAllTransformFromPrefab(labelSet.Prefabs);
  327. //Dictionary<string, List<string>> namesDictionary = new Dictionary<string, List<string>>();
  328. //foreach (var name in typeNames)
  329. //{
  330. // namesDictionary.Add(name, new List<string>());
  331. //}
  332. //foreach (var kv in namesDictionary)
  333. //{
  334. // Assembly assembly = Assembly.Load("UnityEngine.UI");
  335. // Type type = assembly.GetType($"UnityEngine.UI.{kv.Key}");
  336. // if (type == null)
  337. // {
  338. // assembly = Assembly.Load("UnityEngine");
  339. // type = assembly.GetType($"UnityEngine.{kv.Key}");
  340. // }
  341. // if (type == null)
  342. // {
  343. // assembly = Assembly.Load("Assembly-CSharp");
  344. // type = assembly.GetType($"{kv.Key}");
  345. // }
  346. // foreach (var transform in transforms)
  347. // {
  348. // if (transform.GetComponent(type) == null) continue;
  349. // namesDictionary[kv.Key].Add(transform.name);
  350. // }
  351. //}
  352. //List<string> names = new List<string>();
  353. //List<string> components = new List<string>();
  354. //List<string> registStrings = new List<string>();
  355. //registStrings.AddRange(labelSet.RegistExtraLines);
  356. //foreach (var kv in namesDictionary)
  357. //{
  358. // foreach (var name in kv.Value)
  359. // {
  360. // names.Add(name);
  361. // string newName = string.IsNullOrEmpty(labelSet.NameExcludeString) ? name : name.Replace(labelSet.NameExcludeString, "");
  362. // components.Add($"{labelSet.ComponentPrefix} {kv.Key} {newName};");
  363. // string registString = labelSet.RegistString.Replace("#NAME", name).Replace("#TYPE", kv.Key).Replace("#NEWNAME", newName);
  364. // if (labelSet.LabelScript != null)
  365. // {
  366. // registString = registString.Replace("#LABEL", labelSet.LabelScript.name);
  367. // }
  368. // registStrings.Add(registString);
  369. // }
  370. //}
  371. //InsertLineToScript(StartMark, EndMark, labelSet.ComponentScript, components);
  372. //InsertLineToScript(RegistStartMark, RegistEndMark, labelSet.ComponentScript, registStrings);
  373. }
  374. private static void InsertLineToScript(string startMark, string endMark, TextAsset textAsset, List<string> insertLines)
  375. {
  376. int? startMarkLineIndex = null;
  377. int? endMarkLineIndex = null;
  378. List<string> strings = GetScriptContentAfterClearMarks(startMark, endMark, textAsset, ref startMarkLineIndex, ref endMarkLineIndex);
  379. int prefixIndex = strings[startMarkLineIndex.Value].IndexOf("//");
  380. string prefix = strings[startMarkLineIndex.Value].Substring(0, prefixIndex);
  381. for (int i = 0; i < insertLines.Count; i++)
  382. {
  383. strings.Insert(startMarkLineIndex.Value + 1, prefix + insertLines[i]);
  384. startMarkLineIndex++;
  385. }
  386. StringBuilder stringBuilder = new StringBuilder();
  387. for (int i = 0; i < strings.Count; i++)
  388. {
  389. stringBuilder.AppendLine(strings[i]);
  390. }
  391. string content = stringBuilder.ToString();
  392. content = content.Substring(0, content.Length - 2);
  393. File.WriteAllText(AssetDatabase.GetAssetPath(textAsset), content);
  394. AssetDatabase.Refresh();
  395. }
  396. private static List<string> GetScriptContentAfterClearMarks(string startMark, string endMark, TextAsset textAsset, ref int? startMarkLineIndex, ref int? endMarkLineIndex)
  397. {
  398. List<string> strings = textAsset.text.Split(new[] {"\r\n"}, StringSplitOptions.None).ToList();
  399. //List<string> currentDefinedNames = new List<string>();
  400. for (int i = 0; i < strings.Count; i++)
  401. {
  402. if (strings[i].Contains(startMark))
  403. {
  404. startMarkLineIndex = i;
  405. }
  406. else if (strings[i].Contains(endMark))
  407. {
  408. endMarkLineIndex = i;
  409. }
  410. //if (startMarkLineIndex != null)
  411. //{
  412. // if (endMarkLineIndex != null)
  413. // {
  414. // if (i > startMarkLineIndex.Value && i < endMarkLineIndex.Value)
  415. // {
  416. // currentDefinedNames.Add(GetDefinedName(strings[i]));
  417. // }
  418. // }
  419. // else
  420. // {
  421. // if (i > startMarkLineIndex.Value)
  422. // {
  423. // currentDefinedNames.Add(GetDefinedName(strings[i]));
  424. // }
  425. // }
  426. //}
  427. }
  428. int definedCount = endMarkLineIndex.Value - startMarkLineIndex.Value - 1;
  429. for (int i = 0; i < definedCount; i++)
  430. {
  431. strings.RemoveAt(startMarkLineIndex.Value + 1);
  432. }
  433. return strings;
  434. }
  435. private static List<Transform> GetAllTransformFromPrefab(List<GameObject> prefabs)
  436. {
  437. List<Transform> transforms = new List<Transform>();
  438. for (int i = 0; i < prefabs.Count; i++)
  439. {
  440. transforms.AddRange(prefabs[i].GetComponentsInChildren<Transform>(true));
  441. }
  442. return transforms;
  443. }
  444. }
  445. #endif
  446. }