using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; using UnityEngine; namespace ET.PackageManager.Editor { /// /// 简单的模板引擎, 主要用在编辑器上 /// public class TemplateEngine { private static readonly Dictionary g_templateCacheMap = new Dictionary(); /// /// 模板文件的基础路径 /// eg: Assets/Ediotr/Config/Decoder/Template/ /// 注意: 前面不要“/”,后面要“/” /// public static string TemplateBasePath; private const string m_StartSignFormat = "#region {0}开始"; private const string m_EndSignFormat = "#endregion {0}结束"; /// /// 处理模板 /// /// /// /// /// /// public static string Do(string templatePath, Dictionary valueDic, Dictionary valueDic2, bool readTemplateCache = true) { if (!string.IsNullOrEmpty(TemplateBasePath)) { if (TemplateBasePath.Contains("Assets/") && templatePath.Contains("Assets/")) { templatePath = templatePath.Replace("Assets/", ""); } templatePath = TemplateBasePath + templatePath; } string templateStr = null; if (readTemplateCache) { g_templateCacheMap.TryGetValue(templatePath, out templateStr); } if (templateStr == null) { string path = EditorHelper.GetProjPath(templatePath); try { templateStr = File.ReadAllText(path); } catch (Exception e) { Debug.LogError("读取文件失败: " + e); return null; } g_templateCacheMap[templatePath] = templateStr; } if (valueDic != null) { foreach (KeyValuePair pair in valueDic) { templateStr = templateStr.Replace("${" + pair.Key + "}", pair.Value); } } if (valueDic2 != null) { foreach (KeyValuePair pair in valueDic2) { templateStr = templateStr.Replace("${" + pair.Key + "}", pair.Value); } } return templateStr; } /// /// 处理列表类型模板 /// /// /// /// /// /// 后处理函数 /// public static string DoList(string itemTemplateStr, TItemType[] list, string[] fieldOrPropNames, Func afterProcessItem = null) { Type itemType = typeof(TItemType); int len = list.Length; StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { TItemType item = list[i]; string template = itemTemplateStr; foreach (string name in fieldOrPropNames) { string tName = "${" + name + "}"; FieldInfo fi = itemType.GetField(name); if (fi != null) { template = template.Replace(tName, fi.GetValue(item).ToString()); continue; } PropertyInfo pi = itemType.GetProperty(name); if (pi == null) { Debug.LogWarning($"no {name} fields or attributes in the {itemType}"); continue; } template = template.Replace(tName, pi.GetValue(item, null).ToString()); } if (afterProcessItem != null) { template = afterProcessItem(template, item); } sb.Append(template); } return sb.ToString(); } /// /// 检查目标文件是否存在 /// /// /// public static bool FileExists(string path) { try { path = EditorHelper.GetProjPath(path); return File.Exists(path); } catch (Exception e) { Debug.LogError("检查目标文件是否存在失败: path =" + path + ", err=" + e); return false; } } public static bool CreateCodeFile(string path, string templateName, Dictionary valueDic) { templateName = templateName.Contains(".txt") ? templateName : templateName + ".txt"; string clsStr = Do(templateName, valueDic, null, false); if (clsStr == null) { Debug.LogError("模板转化失败, templateName:" + templateName); return false; } try { path = EditorHelper.GetProjPath(path); string dir = Path.GetDirectoryName(path); if (dir == null) { Debug.LogError("dir == null"); return false; } if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } File.WriteAllText(path, clsStr, Encoding.UTF8); Debug.Log(path + "创建成功"); return true; } catch (Exception e) { Debug.LogError("创建代码文件失败: path =" + path + ", err=" + e); return false; } } /// /// 使用Unity #region 为标识的替换规则 /// 在#region >> #endregion 这块区域内查找规则替换 /// /// 标记中的其他的是否保留 /// private static bool RegionReplace(string path, KeyValuePair pair, bool otherRetain = true) { //获取文件 if (path != null) { StringBuilder stringBuilder = new StringBuilder(); StreamReader streamReader = new StreamReader(path); string line = streamReader.ReadLine(); bool isWrite = false; //标记中途是否检查到已经写入过这个字段 防止重复 string startStr = string.Format(m_StartSignFormat, pair.Key); string endStr = string.Format(m_EndSignFormat, pair.Key); while (line != null) { if (line.IndexOf(startStr) > -1) { isWrite = true; stringBuilder.Append(line + "\n"); } else if (line.IndexOf(endStr) > -1) { if (isWrite) { stringBuilder.Append($"{pair.Value}\n"); isWrite = false; } stringBuilder.Append(line + "\n"); } else { if (isWrite) { if (line.IndexOf(pair.Value) > -1) { isWrite = false; } if (otherRetain) { stringBuilder.Append(line + "\n"); } } else { stringBuilder.Append(line + "\n"); } } line = streamReader.ReadLine(); } streamReader.Close(); StreamWriter streamWriter = new StreamWriter(path); streamWriter.Write(stringBuilder.ToString()); streamWriter.Close(); } else { Debug.LogError($"没有读取到{path}文件,请检查是否生成"); return false; } return true; } /// /// 重写文件 /// 根据标识的范围重写 /// /// 精准路径 Assets/ ... XX.CS(扩展名) /// 精准替换的范围与值 /// 范围内的是否保留 默认保留 否则会覆盖 /// public static bool OverrideCodeFile(string path, Dictionary valueDic, bool otherRetain = true) { path = EditorHelper.GetProjPath(path); foreach (var pair in valueDic) { if (!RegionReplace(path, pair, otherRetain)) { return false; } } return true; } /// /// 指定区域内进行检查写入 /// 需要区域内不存在才写入 /// private static bool RegionCheckReplace2(string path, string signKey, string checkContent, string valueContent, bool otherRetain = true) { //获取文件 if (path != null) { StringBuilder stringBuilder = new StringBuilder(); StreamReader streamReader = new StreamReader(path); string line = streamReader.ReadLine(); bool checkExist = false; //检查是否已经存在 如果已经存在则不重写 否则需要重写 bool isWrite = false; //标记中途是否检查到已经写入过这个字段 防止重复 string startStr = string.Format(m_StartSignFormat, signKey); string endStr = string.Format(m_EndSignFormat, signKey); while (line != null) { if (line.IndexOf(startStr) > -1) { isWrite = true; stringBuilder.Append(line + "\n"); } else if (line.IndexOf(endStr) > -1) { if (isWrite) { if (!checkExist) { stringBuilder.Append($"{valueContent}\n"); } isWrite = false; } stringBuilder.Append(line + "\n"); } else { if (isWrite) { if (line.IndexOf(checkContent) > -1) { checkExist = true; } if (otherRetain) { stringBuilder.Append(line + "\n"); } } else { stringBuilder.Append(line + "\n"); } } line = streamReader.ReadLine(); } streamReader.Close(); StreamWriter streamWriter = new StreamWriter(path); streamWriter.Write(stringBuilder.ToString()); streamWriter.Close(); } else { Debug.LogError($"没有读取到{path}文件,请检查是否生成"); return false; } return true; } /// /// 指定区域内进行检查写入 /// 需要区域内不存在才写入 /// public static bool OverrideCheckCodeFile(string path, Dictionary>> replaceDic, bool cover = false) { var clsStr = RegionCheckReplace(path, replaceDic, cover); if (clsStr == null) { Debug.LogError("模板转化失败, path:" + path); return false; } try { path = EditorHelper.GetProjPath(path); string dir = Path.GetDirectoryName(path); if (dir == null) { Debug.LogError("dir == null"); return false; } if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } File.WriteAllText(path, clsStr, Encoding.UTF8); Debug.Log(path + "重写成功"); return true; } catch (Exception e) { Debug.LogError("重写文件失败: path =" + path + ", err=" + e); return false; } } /// /// 指定区域内进行检查写入 /// 需要区域内不存在才写入 /// private static string RegionCheckReplace(string path, Dictionary>> replaceDic, bool cover = false) { var templateStr = File.ReadAllText(path); foreach (var item in replaceDic) { var key = item.Key; var valueList = item.Value; var startStr = string.Format(m_StartSignFormat, key); var endStr = string.Format(m_EndSignFormat, key); var startIndex = templateStr.IndexOf(startStr, StringComparison.Ordinal); var endIndex = templateStr.IndexOf(endStr, StringComparison.Ordinal); if (startIndex <= -1 || endIndex <= startIndex) { Debug.LogError($"{path} 此文件没有检查到关键字 {key} 请手动添加 关键字不允许移除"); continue; } var tempStr = templateStr.Substring(startIndex, endIndex - startIndex).Replace(" ", ""); foreach (var data in valueList) { foreach (var ovDic in data) { var check = ovDic.Key.Replace(" ", ""); var content = ovDic.Value; if (tempStr.IndexOf(check, StringComparison.Ordinal) <= -1) { if (cover) { //直接覆盖 templateStr = templateStr.Substring(0, startIndex + startStr.Length) + content + templateStr.Substring(endIndex); } else { //添加到最后 templateStr = templateStr.Insert(endIndex, content); } } } } } return templateStr; } } }