using System.Reflection; namespace labelUtility { #if UNITY_EDITOR using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Xml; using UnityEditor; using UnityEngine; using UnityEngine.UI; [Serializable] public class RegistTarget { public string Name; public bool Force; public bool Ignore; //public bool CustomName; public bool CustomEvent = true; public Transform Transform; public ComponentType Type; } [Serializable] public class ComponentEventString { public ComponentType ComponentType; public List RegistStrings; public List MethodNames; } [Serializable] public class LabelSet //todo 更新 { public string Name; public UtilityType UtilityType; public string LabelScriptPath; public string LabelScriptName; public string LabePrefix = "public static string"; public TextAsset LabelScript; public string ComponentScriptPath; public string ComponentScriptName; public string DerivedString; public string RegistMethodString; public string ComponentPrefix = "private"; public string NameExcludeString; public string RegistString; public List RegistExtraLines; public TextAsset ComponentScript; public List Languages; //todo 需要更新为LanguageXml public List Prefabs; public bool FoldOut; public float TotalHeight; public List RegistTypes = new List(); public List RegistTargets = new List(); } [Serializable] public enum ComponentType //todo 更新 { None, Text, Slider, Image, Button, InputField, Transform, CanvasGroup, RectTransform, SpriteRenderer, VirtualScrollRectPlus, } public enum UtilityType { XmlLabel, PrefabLabel, Regist, } public class LabelUtility : MonoBehaviour { #region Config public List DllNames; public List EventStrings; public List LabelSets; public static string StartMark = "//StartMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string EndMark = "//EndMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string RegistStartMark = "//RegistStartMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string RegistEndMark = "//RegistEndMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string EventStartMark = "//EventStartMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string EventEndMark = "//EventEndMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string RegistEventStartMark = "//RegistEventStartMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string RegistEventEndMark = "//RegistEventEndMark-Used by LabelUtility-Do not remove"; //todo 更新 public static string Prefix = "public static string "; #endregion public static void CreateLabelScript(LabelSet labelSet, bool showWarning = true, bool auto = false) { if (showWarning) { if (!EditorUtility.DisplayDialog("注意", "新建LabelScript?", "确定", "取消")) { return; } } if (!auto) { auto = EditorUtility.DisplayDialog("提示", "是否自动提取标签", "确定", "取消"); } string scriptContent = ""; foreach (var dllName in InstanceManager.SearchInstance().DllNames) { scriptContent += $"using {dllName};\r\n"; } scriptContent += "\r\n"; scriptContent += $"public class {labelSet.LabelScriptName}"; scriptContent += "\r\n"; scriptContent += $"{{\r\n\t#region Config\r\n\r\n\t{StartMark}\r\n\t{EndMark}\r\n\r\n\t#endregion\r\n}}"; labelSet.LabelScript = CreateScript(labelSet.LabelScriptName, labelSet.LabelScriptPath, scriptContent); if (auto) { if (labelSet.UtilityType == UtilityType.XmlLabel) { CreateLabelFromLanguageXml(labelSet, false); } else if (labelSet.UtilityType == UtilityType.Regist || labelSet.UtilityType == UtilityType.PrefabLabel) { CreateLabelFromPrefab(labelSet, false); } } } public static void CreateComponentScript(LabelSet labelSet, bool showWarning = true, bool regist = false) { if (showWarning) { if (!EditorUtility.DisplayDialog("注意", "新建ComponentScript?", "确定", "取消")) { return; } } if (!regist) { regist = EditorUtility.DisplayDialog("提示", "是否自动注册", "确定", "取消"); } string scriptContent = ""; foreach (var dllName in InstanceManager.SearchInstance().DllNames) { scriptContent += $"using {dllName};\r\n"; } scriptContent += "\r\n"; scriptContent += $"public class {labelSet.ComponentScriptName}"; if (string.IsNullOrEmpty(labelSet.DerivedString)) { scriptContent += "\r\n"; } else { scriptContent += $" : {labelSet.DerivedString}\r\n"; } scriptContent += $"{{\r\n\t#region Config\r\n\r\n\t{StartMark}\r\n\t{EndMark}\r\n\r\n\t#endregion\r\n"; scriptContent += "\r\n"; if (!string.IsNullOrEmpty(labelSet.RegistMethodString)) { scriptContent += $"\t{labelSet.RegistMethodString}\r\n\t{{\r\n"; scriptContent += $"\t\t{RegistStartMark}\r\n"; scriptContent += $"\t\t{RegistEndMark}\r\n"; scriptContent += $"\t\t{RegistEventStartMark}\r\n"; scriptContent += $"\t\t{RegistEventEndMark}\r\n"; scriptContent += $"\t}}\r\n"; } scriptContent += "\r\n"; scriptContent += $"\t{EventStartMark}\r\n"; scriptContent += $"\t{EventEndMark}\r\n"; scriptContent += $"}}"; labelSet.ComponentScript = CreateScript(labelSet.ComponentScriptName, labelSet.ComponentScriptPath, scriptContent); if (regist) { CreateComponentsFromPrefab(labelSet, false); } } private static TextAsset CreateScript(string scriptName, string scriptPath, string content) { string directory = scriptPath.TrimEnd('/', '\\') + "/"; if (directory.Length < 6 || directory.Substring(0, 6).ToLower() != "assets") { throw new Exception("ScripPath必须位置Assets目录内"); } if (!Directory.Exists(directory)) { throw new Exception("文件夹不存在"); } if (string.IsNullOrEmpty(scriptName) || scriptName.Any(Path.GetInvalidFileNameChars().Contains)) { throw new Exception("ScripName包含无效字符"); } string fullPath = $"{scriptPath}/{scriptName}.cs"; if (File.Exists(fullPath)) { throw new Exception($"已经存在一个 {fullPath}"); } File.WriteAllText(fullPath, content); AssetDatabase.Refresh(); return AssetDatabase.LoadAssetAtPath(fullPath); } public static void CreateLabelFromPrefab(LabelSet labelSet, bool showWarning = true, bool regist = false) //todo 更新 { if (labelSet.LabelScript == null) { Debug.LogError("LabelScript is null"); return; } if (showWarning) { if (!EditorUtility.DisplayDialog("注意", "重新生成Prefab Label?", "确定", "取消")) { return; } } if (!regist) { regist = EditorUtility.DisplayDialog("提示", "是否自动注册", "确定", "取消"); } List labels = new List(); List transforms = GetAllTransformFromPrefab(labelSet.Prefabs); foreach (var transform in transforms) { labels.Add($"{labelSet.LabePrefix} {transform.name} = \"{transform.name}\";"); } InsertLineToScript(StartMark, EndMark, labelSet.LabelScript, labels); if (regist) { CreateComponentsFromPrefab(labelSet, false); } } public static void CreateLabelFromLanguageXml(LabelSet labelSet, bool showWarning = true) //todo 更新 { if (labelSet.LabelScript == null) { Debug.LogError("LabelScript is null"); return; } if (showWarning) { if (!EditorUtility.DisplayDialog("注意", "重新生成LanguageXml Label?", "确定", "取消")) { return; } } List labels = new List(); foreach (var language in labelSet.Languages) { XmlDocument document = new XmlDocument(); document.LoadXml(language.text); XmlNodeList childNodes = document.SelectSingleNode("lan").ChildNodes; for (int i = 0; i < childNodes.Count; i++) { labels.AddRange(GetAllLabelFromXmlNode(childNodes[i], labelSet)); } } InsertLineToScript(StartMark, EndMark, labelSet.LabelScript, labels); } private static List GetAllLabelFromXmlNode(XmlNode node, LabelSet labelSet) //todo 增加 { List labels = new List(); for (int i = 0; i < node.ChildNodes.Count; i++) { XmlNode childNode = node.ChildNodes[i]; string label; if (i == 0) { label = $"\t{labelSet.LabePrefix} {node.Name} = \"{node.Name}\";"; labels.Add(label); } label = $"\t{labelSet.LabePrefix} {node.Name}{LanguageLabel.LanguagePageSeperator}{childNode.Name} = \"{node.Name}{LanguageLabel.LanguagePageSeperator}{childNode.Name}\";"; labels.Add(label); } return labels; } public static Type GetType(ComponentType componentType) { Assembly assembly = Assembly.Load("UnityEngine.UI"); Type type = assembly.GetType($"UnityEngine.UI.{componentType}"); if (type == null) { assembly = Assembly.Load("UnityEngine"); type = assembly.GetType($"UnityEngine.{componentType}"); } if (type == null) { assembly = Assembly.Load("Assembly-CSharp"); type = assembly.GetType($"{componentType}"); } return type; } public static void CreateComponentsFromPrefab(LabelSet labelSet, bool showWarning = true) //todo 更新 { if (labelSet.ComponentScript == null) { Debug.LogError("ComponentScript is null"); return; } if (showWarning) { if (!EditorUtility.DisplayDialog("注意", "重新生成PrefabComponent?", "确定", "取消")) { return; } } List defineStrings = new List(); List registStrings = new List(); List eventNames = new List(); List registEventStrings = new List(); registStrings.AddRange(labelSet.RegistExtraLines); foreach (var registTarget in labelSet.RegistTargets) { if (registTarget.Ignore) continue; defineStrings.Add($"{labelSet.ComponentPrefix} {registTarget.Type} {registTarget.Transform.name};"); string registString = labelSet.RegistString.Replace("#NAME", registTarget.Transform.name).Replace("#TYPE", registTarget.Type.ToString()).Replace("#NEWNAME", registTarget.Name); if (labelSet.LabelScript != null) { registString = registString.Replace("#LABEL", labelSet.LabelScript.name); } registStrings.Add(registString); foreach (var eventString in InstanceManager.SearchInstance().EventStrings) { if (eventString.ComponentType == registTarget.Type) { if (!registTarget.CustomEvent) { continue; } for (int i = 0; i < eventString.MethodNames.Count; i++) { eventNames.Add($"{eventString.MethodNames[i].Replace("#NEWNAME", registTarget.Name).Replace("#NAME", registTarget.Transform.name)}"); } for (int i = 0; i < eventString.RegistStrings.Count; i++) { registEventStrings.Add($"{eventString.RegistStrings[i].Replace("#NEWNAME", registTarget.Name).Replace("#NAME", registTarget.Transform.name)};"); } } } } //foreach (var eventString in eventStrings) //{ // Debug.Log(eventString); //} int? startIndex = null; int? endIndex = null; List oldEventMethods = GetScriptContentBetweenMarks(EventStartMark, EventEndMark, labelSet.ComponentScript, ref startIndex, ref endIndex); List newEventMethods = new List(); int? tabAmount = GetMarkSpaceAmount(labelSet.ComponentScript, EventStartMark); for (int i = 0; i < eventNames.Count; i++) { List methodStrings = TryGetMethodStrings(eventNames[i], oldEventMethods); if (methodStrings.Valid()) { for (int j = 0; j < methodStrings.Count; j++) { if (tabAmount == null) { newEventMethods.Add(methodStrings[j]); } else { //Debug.Log((int)methodStrings[j][0]); //Debug.Log((int)methodStrings[j][1]); //Debug.LogWarning(methodStrings[j]); //Debug.Log(methodStrings[j].Length); string str = methodStrings[j].Length > 0 ? methodStrings[j].Substring(tabAmount.Value) : methodStrings[j]; newEventMethods.Add(str); } } if (i < eventNames.Count - 1) { newEventMethods.Add(""); } } else { newEventMethods.Add($"{labelSet.ComponentPrefix} {eventNames[i]}"); newEventMethods.Add("{\r\n"); newEventMethods.Add(i < eventNames.Count - 1 ? "}\r\n" : "}"); } } InsertLineToScript(StartMark, EndMark, labelSet.ComponentScript, defineStrings); InsertLineToScript(RegistStartMark, RegistEndMark, labelSet.ComponentScript, registStrings); InsertLineToScript(RegistEventStartMark, RegistEventEndMark, labelSet.ComponentScript, registEventStrings); InsertLineToScript(EventStartMark, EventEndMark, labelSet.ComponentScript, newEventMethods); //foreach (var registEventString in registEventStrings) //{ // Debug.Log(registEventString); //} //List typeNames = new List(); //foreach (var purview in labelSet.RegistTypes) //{ // typeNames.Add(purview.ToString()); //} //List transforms = GetAllTransformFromPrefab(labelSet.Prefabs); //Dictionary> namesDictionary = new Dictionary>(); //foreach (var name in typeNames) //{ // namesDictionary.Add(name, new List()); //} //foreach (var kv in namesDictionary) //{ // Assembly assembly = Assembly.Load("UnityEngine.UI"); // Type type = assembly.GetType($"UnityEngine.UI.{kv.Key}"); // if (type == null) // { // assembly = Assembly.Load("UnityEngine"); // type = assembly.GetType($"UnityEngine.{kv.Key}"); // } // if (type == null) // { // assembly = Assembly.Load("Assembly-CSharp"); // type = assembly.GetType($"{kv.Key}"); // } // foreach (var transform in transforms) // { // if (transform.GetComponent(type) == null) continue; // namesDictionary[kv.Key].Add(transform.name); // } //} //List names = new List(); //List components = new List(); //List registStrings = new List(); //registStrings.AddRange(labelSet.RegistExtraLines); //foreach (var kv in namesDictionary) //{ // foreach (var name in kv.Value) // { // names.Add(name); // string newName = string.IsNullOrEmpty(labelSet.NameExcludeString) ? name : name.Replace(labelSet.NameExcludeString, ""); // components.Add($"{labelSet.ComponentPrefix} {kv.Key} {newName};"); // string registString = labelSet.RegistString.Replace("#NAME", name).Replace("#TYPE", kv.Key).Replace("#NEWNAME", newName); // if (labelSet.LabelScript != null) // { // registString = registString.Replace("#LABEL", labelSet.LabelScript.name); // } // registStrings.Add(registString); // } //} //InsertLineToScript(StartMark, EndMark, labelSet.ComponentScript, components); //InsertLineToScript(RegistStartMark, RegistEndMark, labelSet.ComponentScript, registStrings); } private static List TryGetMethodStrings(string methodName, List strings) { List results = new List(); for (int i = 0; i < strings.Count; i++) { if (!strings[i].Contains(methodName)) continue; for (int j = i; j < strings.Count; j++) { results.Add(strings[j]); if (strings[j].Trim() == "}") { return results; } } } return results; } private static void InsertLineToScript(int startIndex, TextAsset textAsset, List insertLines) { List strings = GetScriptContents(textAsset); int prefixIndex = strings[startIndex].IndexOf("//"); string prefix = strings[startIndex].Substring(0, prefixIndex); for (int i = 0; i < insertLines.Count; i++) { strings.Insert(startIndex, prefix + insertLines[i]); startIndex++; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < strings.Count; i++) { stringBuilder.AppendLine(strings[i]); } string content = stringBuilder.ToString(); content = content.Substring(0, content.Length - 2); File.WriteAllText(AssetDatabase.GetAssetPath(textAsset), content); AssetDatabase.Refresh(); } private static void InsertLineToScript(string startMark, string endMark, TextAsset textAsset, List insertLines) { int? startMarkLineIndex = null; int? endMarkLineIndex = null; List strings = GetScriptContentAfterClearMarks(startMark, endMark, textAsset, ref startMarkLineIndex, ref endMarkLineIndex); int prefixIndex = strings[startMarkLineIndex.Value].IndexOf("//"); string prefix = strings[startMarkLineIndex.Value].Substring(0, prefixIndex); for (int i = 0; i < insertLines.Count; i++) { strings.Insert(startMarkLineIndex.Value + 1, prefix + insertLines[i]); startMarkLineIndex++; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < strings.Count; i++) { stringBuilder.AppendLine(strings[i]); } string content = stringBuilder.ToString(); content = content.Substring(0, content.Length - 2); File.WriteAllText(AssetDatabase.GetAssetPath(textAsset), content); AssetDatabase.Refresh(); } private static int? GetMarkIndex(TextAsset textAsset, string mark) { List strings = textAsset.text.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList(); for (int i = 0; i < strings.Count; i++) { if (strings[i].Contains(mark)) { return i; } } return null; } private static int? GetMarkSpaceAmount(TextAsset textAsset, string mark) { List strings = textAsset.text.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList(); for (int i = 0; i < strings.Count; i++) { if (strings[i].Contains(mark)) { if (Regex.Match(strings[i], "^\\s+").Success) { //Debug.Log(Regex.Match(strings[i], "^\\s+").Length); return Regex.Match(strings[i], "^\\s+").Length; } else { return null; } } } return null; } private static List GetScriptContentBetweenMarks(string startMark, string endMark, TextAsset textAsset, ref int? startMarkLineIndex, ref int? endMarkLineIndex) { //Debug.Log(textAsset.text); List strings = textAsset.text.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList(); for (int i = 0; i < strings.Count; i++) { if (strings[i].Contains(startMark)) { //Debug.Log(strings[i][0]); //Debug.LogWarning(strings[i][1]); //Debug.Log(strings[i][2]); //Debug.LogWarning(strings[i][3]); //Debug.Log(strings[i][4]); //Debug.LogWarning(strings[i][5]); startMarkLineIndex = i; } else if (strings[i].Contains(endMark)) { endMarkLineIndex = i; } } List results = new List(); for (int i = startMarkLineIndex.Value + 1; i < endMarkLineIndex.Value; i++) { //if (strings[i].Length > 0) //{ // Debug.Log(strings[i][0]); //} //if (strings[i].Length > 1) //{ // Debug.LogWarning(strings[i][1]); //} results.Add(strings[i]); } return results; } private static List GetScriptContents(TextAsset textAsset) { List strings = textAsset.text.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList(); return strings; } private static List GetScriptContentAfterClearMarks(string startMark, string endMark, TextAsset textAsset, ref int? startMarkLineIndex, ref int? endMarkLineIndex) { List strings = textAsset.text.Split(new[] {"\r\n"}, StringSplitOptions.None).ToList(); //List currentDefinedNames = new List(); for (int i = 0; i < strings.Count; i++) { if (strings[i].Contains(startMark)) { startMarkLineIndex = i; } else if (strings[i].Contains(endMark)) { endMarkLineIndex = i; } //if (startMarkLineIndex != null) //{ // if (endMarkLineIndex != null) // { // if (i > startMarkLineIndex.Value && i < endMarkLineIndex.Value) // { // currentDefinedNames.Add(GetDefinedName(strings[i])); // } // } // else // { // if (i > startMarkLineIndex.Value) // { // currentDefinedNames.Add(GetDefinedName(strings[i])); // } // } //} } int definedCount = endMarkLineIndex.Value - startMarkLineIndex.Value - 1; for (int i = 0; i < definedCount; i++) { strings.RemoveAt(startMarkLineIndex.Value + 1); } return strings; } private static List GetAllTransformFromPrefab(List prefabs) { List transforms = new List(); for (int i = 0; i < prefabs.Count; i++) { transforms.AddRange(prefabs[i].GetComponentsInChildren(true)); } return transforms; } } #endif }