using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; using UnityEngine.UI; using Random = System.Random; public class UIExportTextBuilder { public static string nstr = "\n"; Random random = new Random(Guid.NewGuid().GetHashCode()); public string scripthead = @"/*------------------------------------------------------------------------------------- --- 创建人: --- 描 述: --- 创建时间: {0} -------------------------------------------------------------------------------------*/ using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; using CaoCao.Runtime; namespace Game.HotFix {{ /// /// xx 功能界面 /// public class {1} : {2} "; public string filePath = UIExportTool.ScriptDir + "/" + UIExportTool.ScriptName; private static readonly string TagUICtrlDefine = "//UIAutoBuild_CtrlDefine"; private static readonly string TagUICtrlBind = "//UIAutoBuild_CtrlBind"; private static readonly string TagUIEventReg = "//UIAutoBuild_EventReg"; private static readonly string TagUIEventUnReg = "//UIAutoBuild_EventUnReg"; //这是注册控件的方法 public StringBuilder uiElementSB = new StringBuilder(); public StringBuilder onAwake = new StringBuilder(); public StringBuilder onStart = new StringBuilder(); public StringBuilder onEnable = new StringBuilder(); public StringBuilder onDisable = new StringBuilder(); public StringBuilder onShow = new StringBuilder(); //public StringBuilder onDestroy = new StringBuilder(); //移除按钮点击事件 public StringBuilder btnClickRemove = new StringBuilder(); //按钮添加事件 public StringBuilder btnClickAdd = new StringBuilder(); public StringBuilder btnClickFun = new StringBuilder(); //toggle 移除事件 public StringBuilder tglRemove = new StringBuilder(); //toggle 添加事件 public StringBuilder tglAdd = new StringBuilder(); //toggle 方法 public StringBuilder tglfun = new StringBuilder(); //重名检查 public Dictionary nameCheck = new Dictionary(); //全部字符串 public StringBuilder AllStr = new StringBuilder(); public bool hasBtn = false; public bool hasToggle = false; private List objs; private string buildFileName = string.Empty; private bool isUI = true; public UIExportTextBuilder(List objs, string fileName) { this.objs = objs; buildFileName = fileName; scripthead = scripthead.Replace("\r\n", "\n"); if (fileName.Contains("Unit")) { isUI = false; scripthead = string.Format(scripthead, DateTime.Now.ToLongDateString(), fileName, "MonoBehaviour"); } else { isUI = true; scripthead = string.Format(scripthead, DateTime.Now.ToLongDateString(), fileName, "UIBase"); } scripthead += "{\n"; //scripthead += "\toverride public string UIFolder\n"; //scripthead += "\t{\n"; //string[] strAry = UIExportTool.ScriptDir.Split('/'); //string floder = strAry[strAry.Length - 1]; //scripthead += "\t\tget { return \"" + floder + "\"; }\n"; //scripthead += "\t}\n\n"; } /// /// 生成单个大写随机字母 /// private string createBigAbc() { //A-Z的 ASCII值为65-90 int num = random.Next(65, 91); string abc = Convert.ToChar(num).ToString(); return abc; } /// /// 生成单个小写随机字母 /// private string createSmallAbc() { //a-z的 ASCII值为97-122 int num = random.Next(97, 123); string abc = Convert.ToChar(num).ToString(); return abc; } //检查名字是否重名 public bool CheckNameIsRepeat() { bool isrepeat = false; string oldallPath = ""; for (var i = 0; i < objs.Count; i++) { GoInfo info = objs[i]; string goNewName = info.go.name; GoInfo exsistInfo; if (nameCheck.TryGetValue(goNewName, out exsistInfo)) { info.go.name = info.go.name + "_" + createSmallAbc(); goNewName = info.go.name; oldallPath = info.AllPath; info.AllPath = UIExportTool.GetAllPath(info.go.transform, info.go.transform.parent); Debug.LogErrorFormat("路径 {0} 与 路径 {1} 子物体重名 已经换成 {2} ", exsistInfo.AllPath, oldallPath, info.AllPath); isrepeat = true; } nameCheck[goNewName] = info; } return isrepeat; } public void BuildFileAllStr() { try { //TODO 选择一种方式是重名还是让其自己修改 // if (CheckNameIsRepeate()) // { // return ""; // } if (CheckNameIsRepeat()) { } BuildUIElement(uiElementSB); BuildFunction(onAwake, "Awake"); BuildFunction(onStart, "Start"); BuildFunction(onEnable, "OnEnable"); BuildFunction(onDisable, "OnDisable"); BuildFunction(onShow, "Show"); //BuildFunction(onDestroy, "OnDestroy"); onAwake.AppendLine("\t\t" + TagUICtrlBind); if(isUI) onAwake.Append("\t\tbase.Awake();\n"); onAwake.Append("\t\tTransform tf = transform;\n"); //检测是否有按钮 CheckHasBtn(objs); for (var i = 0; i < objs.Count; i++) { GoInfo info = objs[i]; if (info.go.name.Equals("btnClose")) continue; onAwake.Append(GetFindStr(info)); //button 注册 if (info.TypeName.Equals("Button")) { //驼峰命名方法 string goNewName = FirstLetterToUpper(info.go.name); string funName = string.Format("On{0}Click", goNewName); btnClickAdd.Append(string.Format("\t\t{0}.onClick.AddListener({1});\n", info.go.name, funName)); btnClickRemove.Append(string.Format("\t\t{0}.onClick.RemoveAllListeners();\n", info.go.name)); btnClickFun.Append(nstr); btnClickFun.Append(string.Format("\tprivate void {0}()\n", funName)); btnClickFun.Append("\t{\n"); AddFunctionEnd(btnClickFun); } if (info.TypeName.Equals("Toggle")) { //驼峰命名方法 string goNewName = FirstLetterToUpper(info.go.name); string funName = string.Format("On{0}Change", goNewName); tglAdd.Append( string.Format("\t\t{0}.onValueChanged.AddListener({1});\n", info.go.name, funName)); tglRemove.Append(string.Format("\t\t{0}.onValueChanged.RemoveAllListeners();\n", info.go.name)); tglfun.Append(nstr); tglfun.Append(string.Format("\tprivate void {0}(bool _isOn)\n", funName)); tglfun.Append("\t{\n"); AddFunctionEnd(tglfun); } } onAwake.AppendLine("\t\t" + TagUICtrlBind); AddFunctionEnd(onAwake); onEnable.AppendLine("\t\t" + TagUIEventReg); onEnable.Append(btnClickAdd); onEnable.Append(tglAdd); onEnable.AppendLine("\t\t" + TagUIEventReg); AddFunctionEnd(onEnable); onDisable.AppendLine("\t\t" + TagUIEventUnReg); onDisable.Append(btnClickRemove); onDisable.Append(tglRemove); onDisable.AppendLine("\t\t" + TagUIEventUnReg); AddFunctionEnd(onDisable); AddFunctionEnd(onStart); AddFunctionEnd(onShow); //AddFunctionEnd(onDestroy); AllStr.Append(scripthead); AllStr.Append(uiElementSB); AllStr.Append(onAwake); AllStr.Append(onEnable); AllStr.Append(onDisable); if (isUI) { AllStr.Append(onStart); AllStr.Append(onShow); } //AllStr.Append(onDestroy); if (hasBtn) // 有按钮才处理 { AllStr.Append(btnClickFun); } if (hasToggle) { AllStr.Append(tglfun); } AllStr.Append("\n}\n}\n"); } catch (Exception e) { Debug.LogError(e); } } public void BuildUIElement(StringBuilder _sb, bool hasN = true) { _sb.AppendLine("\t" + TagUICtrlDefine); for (var i = 0; i < objs.Count; i++) { GoInfo info = objs[i]; if (info.go.name.Equals("btnClose")) continue; _sb.Append(GetUIElementStr(info)); } _sb.AppendLine("\t" + TagUICtrlDefine); _sb.Append("\n"); } public void BuildFunction(StringBuilder funSb, string funName, bool hasN = true) { funSb.Append(nstr); string tem = nstr; if (!hasN) { tem = ""; } //if(funName == "Start") // funSb.Append("\t// 第一次打开时执行\n"); //if(funName == "Show") // funSb.Append("\t// 每次显示都执行") if (funName.Equals("Show")) { //if (buildFileName.Contains("Unit")) if(!isUI) { funSb.AppendLine("\t// Show()在 Unit和page脚本中都不起作用. 删除"); funSb.Append(string.Format("\tpublic void {0}(){1}", funName, tem)); funSb.AppendLine("\t{"); } else { funSb.AppendLine("\t// 每次显示都执行, 可定义参数"); funSb.Append(string.Format("\tpublic override void {0}(params object[] _params){1}", funName, tem)); funSb.AppendLine("\t{\n\t\tbase.Show(_params);\n"); } } else if(funName.Equals("Awake")) { if (isUI) { funSb.Append(string.Format("\tpublic override void {0}(){1}", funName, tem)); } else { funSb.Append(string.Format("\tpublic void {0}(){1}", funName, tem)); } funSb.Append("\t{\n"); } else { funSb.Append(string.Format("\tvoid {0}(){1}", funName, tem)); funSb.Append("\t{\n"); } } public void AddFunctionEnd(StringBuilder funSb, bool hasN = false) { if (hasN) funSb.Append(nstr); funSb.Append("\t}\n"); } private void CheckHasBtn(List objs) { hasBtn = false; hasToggle = false; for (var i = 0; i < objs.Count; i++) { GoInfo info = objs[i]; if (info.TypeName.Equals("Button")) { hasBtn = true; } if (info.TypeName.Equals("Toggle")) { hasToggle = true; if (hasBtn) { break; } } } } private string GetUIElementStr(GoInfo _info) { string str = "\tpublic "+ _info.TypeName + " " + _info.go.name + ";\n"; return str; } private string GetFindStr(GoInfo info) { string luaCom = ".gameObject;"; if (info.TypeName != "GameObject" && !info.TypeName.Equals("Transform")) { luaCom = string.Format(".GetComponent<{0}>();", info.TypeName); } else if (info.TypeName.Equals("Transform")) { luaCom = ";"; } //把类型注释上 //string notestr = string.Format("\t{0} ", info.TypeName); string findstr = string.Format("\t\t{0} = tf.Find(\"{1}\"){2}\n", info.go.name, info.AllPath, luaCom); return /*notestr +*/ findstr; } //首字母大写 public static string FirstLetterToUpper(string str) { if (str == null) return null; if (str.Length > 1) return char.ToUpper(str[0]) + str.Substring(1); return str.ToUpper(); } public void ReplaceFile() { byte[] buf = File.ReadAllBytes(filePath); if (buf.Length == 0) { Debug.LogError("文件里没有内容"); return; } // 老的脚本 string oldText = Encoding.UTF8.GetString(buf); oldText = oldText.Replace("\r\n", "\n"); // 新的脚本 BuildFileAllStr(); string newText = AllStr.ToString(); oldText = oldText.Replace("\r\n", "\n"); // 替换 控件定义 ReplaceFileCtrlText(ref oldText, newText, TagUICtrlDefine); // 替换 控件绑定 ReplaceFileCtrlText(ref oldText, newText, TagUICtrlBind); // 替换 注册事件 ReplaceFileCtrlText(ref oldText, newText, TagUIEventReg); // 替换 取消事件 ReplaceFileCtrlText(ref oldText, newText, TagUIEventUnReg); File.WriteAllBytes(filePath, Encoding.UTF8.GetBytes(oldText)); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } public string ReplaceFileCtrlText(ref string _oldText, string _newText, string _tag) { string oldStr = CutOutStr(_oldText, _tag, _tag); string newStr = CutOutStr(_newText, _tag, _tag); bool isEnmptyOld = string.IsNullOrEmpty(oldStr.Trim()); bool isEnmptyNew = string.IsNullOrEmpty(newStr.Trim()); // 两个都是空的 不需要替换 if (isEnmptyOld && isEnmptyNew) return _oldText; // 两个都不为空,直接替换 if (!isEnmptyOld && !isEnmptyNew) { _oldText = _oldText.Replace(oldStr, newStr); return _oldText; } // 其中有一个为空 oldStr = string.Format("{0}{1}{2}", _tag, oldStr, _tag); newStr = string.Format("{0}{1}{2}", _tag, newStr, _tag); _oldText = _oldText.Replace(oldStr, newStr); return _oldText; } //public void ReplaceFile() //{ // byte[] buf = File.ReadAllBytes(filePath); // if (buf.Length == 0) // { // Debug.LogError("文件里没有内容"); // return; // } // string oldstr = Encoding.UTF8.GetString(buf); // oldstr = oldstr.Replace("\r\n", "\n"); // BuildFileAllStr(); // AllStr.Clear(); // int firstFun = oldstr.IndexOf("void"); // if (firstFun != -1) // { // string head = oldstr.Substring(0, firstFun - 1); // AllStr.Append(head); // //截取后面的 // oldstr = oldstr.Substring(firstFun, oldstr.Length - firstFun); // } // else // { // AllStr.Append(scripthead); // } // Dictionary funNode = GetFunNote(oldstr); // string patt = @"void\s.+\(.*\)\n{(.*\n)*?}"; // // 把按钮事件拆分出来 // Dictionary clickDic = // MctoDicFunNameKey(Regex.Matches(btnClickFun.ToString(), patt, RegexOptions.Multiline)); // // toggle // Dictionary tglDic = // MctoDicFunNameKey(Regex.Matches(tglfun.ToString(), patt, RegexOptions.Multiline)); // Dictionary allMc = MctoDicFunNameKey(Regex.Matches(oldstr, patt, RegexOptions.Multiline)); // bool isChange = false; // //保证函数只检查一次,不拦截后面的 增对没有的函数 // string matkey = "void {0}()"; // string funStr; // string newKey; // //Awake // newKey = string.Format(matkey, "Awake"); // if (allMc.TryGetValue(newKey, out funStr)) // { // string oldFunstr = GetOldFunStr(funNode, newKey, funStr); // //awake不同使用新的 // if (!oldFunstr.Equals(awakesb.ToString())) // { // isChange = true; // AllStr.Append(awakesb); // } // else // { // AllStr.Append(oldFunstr); // } // } // //start // newKey = string.Format(matkey, "Start"); // if (allMc.TryGetValue(newKey, out funStr)) // { // string oldFunstr = GetOldFunStr(funNode, newKey, funStr); // AllStr.Append(oldFunstr); // } // string btnFunPatt = @"\t+btn.+onClick:.+\)\n"; // string tglFunPatt = @"\t+tgl.+onValueChanged:.+\)\n"; // newKey = string.Format(matkey, "OnEnable"); // if (allMc.TryGetValue(newKey, out funStr)) // { // string oldFunstr = GetOldFunStr(funNode, newKey, funStr); // //点击事件 // if (StringReplace(ref oldFunstr, btnClickAdd, btnFunPatt)) // isChange = true; // //toggle 事件 // if (StringReplace(ref oldFunstr, tglAdd, tglFunPatt)) // isChange = true; // AllStr.Append(oldFunstr); // } // newKey = string.Format(matkey, "OnDisable"); // if (allMc.TryGetValue(newKey, out funStr)) // { // string oldFunstr = GetOldFunStr(funNode, newKey, funStr); // //点击事件 // if (StringReplace(ref oldFunstr, btnClickRemove, btnFunPatt)) // isChange = true; // if (StringReplace(ref oldFunstr, tglRemove, tglFunPatt)) // isChange = true; // AllStr.Append(oldFunstr); // } // //newKey = string.Format(matkey, "OnDestroy"); // //if (allMc.TryGetValue(newKey, out funStr)) // //{ // // string oldFunstr = GetOldFunStr(funNode, newKey, funStr); // // AllStr.Append(oldFunstr); // //} // foreach (var funNameAndFun in allMc) // { // if (funNameAndFun.Key.Contains("Awake") // || funNameAndFun.Key.Contains("Start") // || funNameAndFun.Key.Contains("OnEnable") // || funNameAndFun.Key.Contains("OnDisable") // //|| funNameAndFun.Key.Contains("OnDestroy") // ) // { // continue; // } // string oldFunstr = GetOldFunStr(funNode, funNameAndFun.Key, funNameAndFun.Value); // //写回按钮老方法 // if (clickDic.ContainsKey(funNameAndFun.Key)) // { // AllStr.Append(oldFunstr); // continue; // } // //写回老方法 // if (tglDic.ContainsKey(funNameAndFun.Key)) // { // AllStr.Append(oldFunstr); // continue; // } // // 不是按钮方法的才加 // if (oldFunstr.Contains("Click") || oldFunstr.Contains("ValChange")) // { // continue; // } // //加最后面的方法 // AllStr.Append(oldFunstr); // } // //把以前没有的方法添加进去 // AddNewFun(clickDic, allMc, ref isChange); // AddNewFun(tglDic, allMc, ref isChange); // if (isChange) // { // File.WriteAllBytes(filePath, Encoding.UTF8.GetBytes(AllStr.ToString())); // AssetDatabase.SaveAssets(); // AssetDatabase.Refresh(); // } //} //private static string GetOldFunStr(Dictionary funNode, string newKey, string funStr) //{ // string node; // if (!funNode.TryGetValue(newKey, out node)) // { // node = nstr; //找到注释用注释,没找到使用以前的 // } // return node + funStr + nstr + nstr; //} //private void AddNewFun(Dictionary funDic, Dictionary allMc, ref bool isChange) //{ // foreach (KeyValuePair kv in funDic) // { // //把以前没有的按钮方法加上 // if (!allMc.ContainsKey(kv.Key)) // { // isChange = true; // AllStr.Append(nstr); // AllStr.Append(kv.Value); // AllStr.Append(nstr); // AllStr.Append(nstr); // } // } //} ////新不在旧里面加 ////旧不在新里面删 ///// ///// ///// ///// 以前方法的名称,后面可能还会用到所以这里传的引用进来 ///// ///// ///// 改变了返回true 没改变返回false //public bool StringReplace(ref string oldstr, StringBuilder funStr, string patt) //{ // Dictionary oldDic = MctoDic(Regex.Matches(oldstr, patt, RegexOptions.Multiline)); // //新没有旧有就减 // Dictionary newDic = MctoDic(Regex.Matches(funStr.ToString(), patt, RegexOptions.Multiline)); // if (oldDic.Count == 0 && newDic.Count == 0) // { // return false; // } // //string newString = ""; // List adds = new List(); // List removes = new List(); // foreach (var keyValuePair in newDic) // { // //旧不包含新 // if (!oldDic.ContainsKey(keyValuePair.Key)) // { // adds.Add(keyValuePair.Key); // } // } // foreach (var old in oldDic) // { // //新不含旧删 // if (!newDic.ContainsKey(old.Key)) // { // removes.Add(old.Key); // } // } // for (int i = 0; i < removes.Count; i++) // { // oldstr = oldstr.Replace(removes[i], ""); // } // if (adds.Count > 0) // { // int endIdex = oldstr.IndexOf("}"); // oldstr = oldstr.Substring(0, endIdex); // for (int i = 0; i < adds.Count; i++) // { // oldstr += adds[i]; // } // oldstr += "}\n\n"; // } // return adds.Count > 0 || removes.Count > 0; //} //private Dictionary MctoDic(MatchCollection mc) //{ // Dictionary dic = new Dictionary(); // for (int i = 0; i < mc.Count; i++) // { // string old = mc[i].ToString(); // dic[old] = old; // } // return dic; //} //private Dictionary MctoDicFunNameKey(MatchCollection mc) //{ // Dictionary dic = new Dictionary(); // for (int i = 0; i < mc.Count; i++) // { // string old = mc[i].ToString(); // Match funNameMc = Regex.Match(old, @"void\s.+\(.*\)", RegexOptions.Multiline); // dic[funNameMc.ToString()] = old; // } // return dic; //} ////是否是一个函数 //public static bool IsMathFunStr(string oldFunstr, string biuldFun) //{ // string patt = @"void\s.+\(.*\)\n"; // string matchfun = Regex.Match(oldFunstr, patt, RegexOptions.Multiline).ToString(); // return biuldFun.Equals(matchfun); //} ////获取函数注释 //private Dictionary GetFunNote(string str) //{ // MatchCollection mc = Regex.Matches(str, @"((---|--).*\n)+void\s.+\(.*\)", RegexOptions.Multiline); // Dictionary dic = new Dictionary(); // for (int i = 0; i < mc.Count; i++) // { // string old = mc[i].ToString(); // //函数名称 // Match funNameMc = Regex.Match(old, @"void\s.+\(.*\)", RegexOptions.Multiline); // //注释 // Match node = Regex.Match(old, @"((---|--).*\n)+", RegexOptions.Multiline); // dic[funNameMc.ToString()] = node.ToString(); // } // return dic; //} private string CutOutStr(string _res, string _startTag, string _endTag) { if (string.IsNullOrEmpty(_startTag)) { Debug.LogError("string.IsNullOrEmpty(_startTag)"); return string.Empty; } if (string.IsNullOrEmpty(_endTag)) { Debug.LogError("string.IsNullOrEmpty(_endTag)"); return string.Empty; } Regex rg = new Regex("(?<=(" + _startTag + "))[.\\s\\S]*?(?=(" + _endTag + "))"); ; return rg.Match(_res).Value; } }