/// <summary> /// 处理proto文件 /// </summary> /// <param name="protoPath">proto路径</param> /// <param name="decodeOutputPath">转换脚本导出路径,默认与proto同路径,后缀名为".lua"</param> /// <param name="adjustOutputPath">调整脚本导出路径,默认与proto同路径,后缀为"_adj.lua"</param> /// <param name="needCheckCSharpType">是否需要检查C#类型是否存在</param> /// <returns>是否有lua文件生成</returns> public bool DealProto(string protoPath, string decodeOutputPath = null, string adjustOutputPath = null, bool needCheckCSharpType = false) { if (string.IsNullOrEmpty(protoPath)) { return(false); } ClearCache(); //生成转换代码 if (string.IsNullOrEmpty(decodeOutputPath)) { decodeOutputPath = Path.ChangeExtension(protoPath, ".lua"); } decodeOutputFilePath = decodeOutputPath; proto = ProtocolControlCache_ProtoStructure.GetProtoStructure(protoPath); if (proto == null || (proto != null && string.IsNullOrEmpty(proto.Package))) { ClearCache(); return(false); } else { GenerateDecodeLuaCodes(needCheckCSharpType); if (!SaveLuaCodes(decodeOutputFilePath)) { ClearCache(); return(false); } ClearCache(); } //生成调整代码 if (string.IsNullOrEmpty(adjustOutputPath)) { adjustOutputPath = Path.ChangeExtension(protoPath, ".lua"); adjustOutputPath = adjustOutputPath.Substring(0, adjustOutputPath.Length - 4) + "_adj.lua"; } adjustOutputFilePath = adjustOutputPath; proto = ProtocolControlCache_ProtoStructure.GetProtoStructure(protoPath); if (proto == null || (proto != null && string.IsNullOrEmpty(proto.Package))) { ClearCache(); return(false); } else { GenerateAdjustLuaCodes(false); if (!SaveLuaCodes(adjustOutputFilePath)) { ClearCache(); return(false); } ClearCache(); return(true); } }
/// <summary> /// 清理缓存 /// </summary> private void ClearCache() { decodeOutputFilePath = null; adjustOutputFilePath = null; proto = null; cacheStringBuilder.Remove(0, cacheStringBuilder.Length); stringBuilderForRetract.Remove(0, stringBuilderForRetract.Length); stringBuilderForMessage.Remove(0, stringBuilderForMessage.Length); stringBuilderForVariable.Remove(0, stringBuilderForVariable.Length); retractCount = 0; isAnyMessageGenerated = false; }
/// <summary> /// 从协议的消息结构得到其使用的proto的数据结构,若返回null则表明该消息未使用proto /// </summary> /// <param name="msg"></param> /// <returns></returns> public static ProtocolControlCache_ProtoStructure GetProtoStructure(ProtocolControlCache_Message msg) { if (msg != null) { if (msg.hasProto) { string path = string.Format("{0}/{1}.proto", LocalServerProtoPath, msg.protoData.protoName); ProtocolControlCache_ProtoStructure protoStructure = ProtocolControlCache_ProtoStructure.GetProtoStructure(path); return(protoStructure); } } return(null); }
/// <summary> /// 获取proto结构 /// </summary> /// <param name="fullPath"></param> /// <returns></returns> public static ProtocolControlCache_ProtoStructure GetProtoStructure(string fullPath) { if (string.IsNullOrEmpty(fullPath)) { return(null); } if (ProtocolStructureCache.ContainsKey(fullPath)) { return(ProtocolStructureCache[fullPath]); } var temp = new ProtocolControlCache_ProtoStructure(fullPath); ProtocolStructureCache[fullPath] = temp; temp.Deal(); return(temp); }
/// <summary> /// 更新Lua提示文件 /// </summary> /// <param name="protoFolderPath">proto文件夹路径</param> /// <param name="luaRefrenceFileName">lua引用文件名</param> /// <param name="isCommitToSVN">是否生成后提交svn</param> public static void UpdateLuaHintFile(string protoFolderPath, string luaRefrenceFileName, bool isCommitToSVN) { if (!Directory.Exists(protoFolderPath)) { UnityEngine.Debug.LogErrorFormat("未找到 {0} 文件夹", protoFolderPath); return; } string luaRefrenceOutputPath = ProtoHintFolderPath; if (!Directory.Exists(luaRefrenceOutputPath)) { Directory.CreateDirectory(luaRefrenceOutputPath); } string[] files = Directory.GetFiles(protoFolderPath); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < files.Length; i++) { EditorUtility.DisplayProgressBar("解析proto结构", files[i], ((float)i) / files.Length); var protoStructure = ProtocolControlCache_ProtoStructure.GetProtoStructure(files[i]); EditorUtility.DisplayProgressBar("生成proto提示文件", files[i], ((float)i) / files.Length); for (int j = 0; j < protoStructure.Messages.Count; j++) { stringBuilder.Append(GenerateLuaClassHint(protoStructure, protoStructure.Messages[j])); stringBuilder.Append("\r\n\r\n"); } } EditorUtility.ClearProgressBar(); string outputFilePath = luaRefrenceOutputPath + "/" + luaRefrenceFileName; File.WriteAllText(outputFilePath, stringBuilder.ToString()); UnityEngine.Debug.LogFormat("{0} 生成完毕,idea中可以引用该文件或者其所在文件夹", outputFilePath); if (isCommitToSVN) { //SVNEditorUtility.SVNCommit(luaRefrenceOutputPath); } }
/// <summary> /// 生成lua类的提示 /// </summary> /// <param name="proto"></param> /// <param name="msg"></param> /// <returns></returns> public static string GenerateLuaClassHint(ProtocolControlCache_ProtoStructure proto, ProtocolControlCache_ProtoStructure.Message msg) { if (msg == null) { return(string.Empty); } stringBuilderForLuaClassHint.Remove(0, stringBuilderForLuaClassHint.Length); stringBuilderForLuaClassHint.Append("---@class "); stringBuilderForLuaClassHint.Append(proto.Package); stringBuilderForLuaClassHint.Append("."); stringBuilderForLuaClassHint.Append(msg.MessageName); stringBuilderForLuaClassHint.Append("\r\n"); stringBuilderForLuaClassHint.Append("---class properties"); stringBuilderForLuaClassHint.Append("\r\n"); for (int i = 0; i < msg.Variables.Length; i++) { var variable = msg.Variables[i]; string typeStr = null; switch (variable.VType) { case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Bool: typeStr = "boolean"; break; case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Double: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Float: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Int32: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.UInt32: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Int64: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.UInt64: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.SInt32: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.SInt64: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Sing64: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Fixed32: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Fixed64: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.SFixed32: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.SFixed64: typeStr = "number"; break; case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.String: case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Bytes: typeStr = "string"; break; case ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Others: ServerTool_ProtocolController_GenerateLuaFromProto.VariableTypeInOthers variableTypeInOthers = ServerTool_ProtocolController_GenerateLuaFromProto.GetVariableTypeInOthers(proto, msg, variable); if (variableTypeInOthers.isEnumType && variableTypeInOthers.enumType != null) { typeStr = "number"; } else { typeStr = variableTypeInOthers.typeString; } break; default: break; } switch (variable.Modifier) { case ProtocolControlCache_ProtoStructure.VariableInMessage.ModifierType.Required: stringBuilderForLuaClassHint.Append("---@field public "); stringBuilderForLuaClassHint.Append(variable.VariableName); stringBuilderForLuaClassHint.Append(" "); stringBuilderForLuaClassHint.Append(typeStr); if (!string.IsNullOrEmpty(variable.DefaultValue)) { stringBuilderForLuaClassHint.Append(" [default = "); stringBuilderForLuaClassHint.Append(variable.DefaultValue); stringBuilderForLuaClassHint.Append("]"); } if (!string.IsNullOrEmpty(variable.Comment)) { stringBuilderForLuaClassHint.Append(" "); stringBuilderForLuaClassHint.Append(variable.Comment.Replace("\n", " ").Replace("\r", "")); } stringBuilderForLuaClassHint.Append("\r\n"); break; case ProtocolControlCache_ProtoStructure.VariableInMessage.ModifierType.Optional: stringBuilderForLuaClassHint.Append("---@field public "); stringBuilderForLuaClassHint.Append(variable.VariableName); stringBuilderForLuaClassHint.Append(" "); stringBuilderForLuaClassHint.Append(typeStr); if (!string.IsNullOrEmpty(variable.DefaultValue)) { stringBuilderForLuaClassHint.Append(" [default = "); stringBuilderForLuaClassHint.Append(variable.DefaultValue); stringBuilderForLuaClassHint.Append("]"); } if (!string.IsNullOrEmpty(variable.Comment)) { stringBuilderForLuaClassHint.Append(" "); stringBuilderForLuaClassHint.Append(variable.Comment.Replace("\n", " ").Replace("\r", "")); } stringBuilderForLuaClassHint.Append("\r\n"); stringBuilderForLuaClassHint.Append("---@field public "); stringBuilderForLuaClassHint.Append(variable.VariableName); stringBuilderForLuaClassHint.Append("Specified boolean"); stringBuilderForLuaClassHint.Append("\r\n"); break; case ProtocolControlCache_ProtoStructure.VariableInMessage.ModifierType.Repeated: stringBuilderForLuaClassHint.Append("---@field public "); stringBuilderForLuaClassHint.Append(variable.VariableName); stringBuilderForLuaClassHint.Append(" table<number, "); stringBuilderForLuaClassHint.Append(typeStr); stringBuilderForLuaClassHint.Append(">"); if (!string.IsNullOrEmpty(variable.Comment)) { stringBuilderForLuaClassHint.Append(" "); stringBuilderForLuaClassHint.Append(variable.Comment.Replace("\n", " ").Replace("\r", "")); } stringBuilderForLuaClassHint.Append("\r\n"); break; case ProtocolControlCache_ProtoStructure.VariableInMessage.ModifierType.NULL: break; default: break; } } return(stringBuilderForLuaClassHint.ToString()); }
public void Deal() { try { protoContent = File.ReadAllText(protoFullPath); } catch (FileNotFoundException ex) { UnityEngine.Debug.LogError(string.Format("读取proto文件错误,文件路径无效 {0}\r\n{1}\r\n{2}", protoFullPath, ex.Message, ex.StackTrace)); return; } catch (DirectoryNotFoundException ex) { UnityEngine.Debug.LogError(string.Format("读取proto文件错误,目录无效 {0}\r\n{1}\r\n{2}", protoFullPath, ex.Message, ex.StackTrace)); return; } catch (IOException ex) { UnityEngine.Debug.LogError(string.Format("读取proto文件错误,文件IO被占用 {0}\r\n{1}\r\n{2}", protoFullPath, ex.Message, ex.StackTrace)); return; } catch (Exception ex) { UnityEngine.Debug.LogError(string.Format("读取proto文件错误 {0}\r\n{1}\r\n{2}", protoFullPath, ex.Message, ex.StackTrace)); return; } Match packageMatch = Regex.Match(protoContent, pattern_Package); if (packageMatch != null) { string strTemp = packageMatch.Value; package = strTemp.Replace("package ", string.Empty).Replace(';', ' ').Trim(); } MatchCollection importedProtoMatchCollection = Regex.Matches(protoContent, pattern_ImportProto); if (importedProtoMatchCollection != null) { foreach (Match item in importedProtoMatchCollection) { string newProtoName = item.Value.Replace("import", string.Empty).Replace('\"', ' ').Replace(';', ' ').Replace(".proto", string.Empty).Trim(); string dirPath = Path.GetDirectoryName(protoFullPath); ProtocolControlCache_ProtoStructure importedProtoTemp = GetProtoStructure(dirPath + '/' + newProtoName + ".proto"); ImportedProtos.Add(importedProtoTemp); } } MatchCollection messageMatchCollection = Regex.Matches(protoContent, Message.pattern); if (messageMatchCollection != null) { foreach (Match item in messageMatchCollection) { Message message = new Message(item.Value); message.Owner = this; if (message.Deal()) { Messages.Add(message); } } } MatchCollection enumMatchCollection = Regex.Matches(protoContent, EnumType.pattern); if (enumMatchCollection != null) { //将所有message中的枚举名放到一起 List <EnumType> enumnames = new List <EnumType>(); for (int i = 0; i < Messages.Count; i++) { for (int j = 0; j < Messages[i].Enums.Length; j++) { enumnames.Add(Messages[i].Enums[j]); } } //遍历proto中所有的枚举,若message中没有相同的枚举,则将其加入列表中 foreach (Match item in enumMatchCollection) { EnumType enumtemp = new EnumType(item.Value); if (enumtemp.Deal()) { bool isContain = false; for (int i = 0; i < enumnames.Count; i++) { if (enumnames[i].IsEqualTo(enumtemp)) { enumnames.RemoveAt(i); isContain = true; break; } } if (!isContain) { EnumsInProto.Add(enumtemp); } } } } protoContent = string.Empty; }
/// <summary> /// 获得变量类型为Others的变量的实际类型 /// </summary> /// <param name="proto">消息所属的proto</param> /// <param name="msg">变量所在消息</param> /// <param name="variable">需要获取类型的变量</param> /// <returns>其他类型变量的类型</returns> public static VariableTypeInOthers GetVariableTypeInOthers(ProtocolControlCache_ProtoStructure proto, ProtocolControlCache_ProtoStructure.Message msg, ProtocolControlCache_ProtoStructure.VariableInMessage variable) { VariableTypeInOthers variableTypeInOthers = new VariableTypeInOthers(); //Others一般只有枚举和消息两种类型,多层次遍历查询 //得到去掉包名或者消息名的变量类型名 string[] strs = variable.VariableTypeString.Split('.'); string pureVariableTypeString; if (strs != null && strs.Length > 1) { pureVariableTypeString = strs[strs.Length - 1]; } else { pureVariableTypeString = variable.VariableTypeString; } //先遍历本消息内定义的枚举 for (int i = 0; i < msg.Enums.Length; i++) { if (pureVariableTypeString == msg.Enums[i].EnumName) { variableTypeInOthers.isEnumType = true; variableTypeInOthers.isInOtherPackage = false; variableTypeInOthers.decodeHelpString = string.Format("CS.{0}.{1}.{2}.__CastFrom", proto.Package, msg.MessageName, msg.Enums[i].EnumName); variableTypeInOthers.typeString = string.Format("{0}.{1}.{2}", proto.Package, msg.MessageName, msg.Enums[i].EnumName); variableTypeInOthers.adjustHelpString = string.Empty; variableTypeInOthers.adjustNullAdjustString = string.Empty; variableTypeInOthers.enumType = msg.Enums[i]; variableTypeInOthers.messageType = null; return(variableTypeInOthers); } } //再遍历本proto中定义的枚举 for (int i = 0; i < proto.EnumsInProto.Count; i++) { if (pureVariableTypeString == proto.EnumsInProto[i].EnumName) { variableTypeInOthers.isEnumType = true; variableTypeInOthers.isInOtherPackage = false; variableTypeInOthers.decodeHelpString = string.Format("CS.{0}.{1}.__CastFrom", proto.Package, proto.EnumsInProto[i].EnumName); variableTypeInOthers.typeString = string.Format("{0}.{1}", proto.Package, proto.EnumsInProto[i].EnumName); variableTypeInOthers.adjustNullAdjustString = string.Empty; variableTypeInOthers.adjustHelpString = string.Empty; variableTypeInOthers.enumType = proto.EnumsInProto[i]; variableTypeInOthers.messageType = null; return(variableTypeInOthers); } } //而后遍历proto中定义的消息 for (int i = 0; i < proto.Messages.Count; i++) { if (pureVariableTypeString == proto.Messages[i].MessageName) { variableTypeInOthers.isEnumType = false; variableTypeInOthers.isInOtherPackage = false; variableTypeInOthers.decodeHelpString = string.Format("{0}.{1}", proto.Package, proto.Messages[i].MessageName); variableTypeInOthers.typeString = string.Format("{0}.{1}", proto.Package, proto.Messages[i].MessageName); variableTypeInOthers.adjustHelpString = string.Format("{0}_adj.Adjust{1}", proto.Package, proto.Messages[i].MessageName); variableTypeInOthers.adjustNullAdjustString = string.Format("{0}_adj.Adjust{1} ~= nil", proto.Package, proto.Messages[i].MessageName); variableTypeInOthers.enumType = null; variableTypeInOthers.messageType = proto.Messages[i]; return(variableTypeInOthers); } } //最后遍历其他proto for (int i = 0; i < proto.ImportedProtos.Count; i++) { //枚举 for (int j = 0; j < proto.ImportedProtos[i].EnumsInProto.Count; j++) { if (pureVariableTypeString == proto.ImportedProtos[i].EnumsInProto[j].EnumName) { variableTypeInOthers.isEnumType = true; variableTypeInOthers.isInOtherPackage = true; variableTypeInOthers.decodeHelpString = string.Format("CS.{0}.{1}.__CastFrom", proto.ImportedProtos[i].Package, proto.ImportedProtos[i].EnumsInProto[j].EnumName); variableTypeInOthers.typeString = string.Format("{0}.{1}", proto.ImportedProtos[i].Package, proto.ImportedProtos[i].EnumsInProto[j].EnumName); variableTypeInOthers.adjustHelpString = string.Empty; variableTypeInOthers.adjustNullAdjustString = string.Empty; variableTypeInOthers.enumType = proto.ImportedProtos[i].EnumsInProto[j]; variableTypeInOthers.messageType = null; return(variableTypeInOthers); } } //消息 for (int j = 0; j < proto.ImportedProtos[i].Messages.Count; j++) { if (pureVariableTypeString == proto.ImportedProtos[i].Messages[j].MessageName) { variableTypeInOthers.isEnumType = false; variableTypeInOthers.isInOtherPackage = true; variableTypeInOthers.decodeHelpString = string.Format("decodeTable.{0}.{1}", proto.ImportedProtos[i].ProtoFileName, proto.ImportedProtos[i].Messages[j].MessageName); variableTypeInOthers.typeString = string.Format("{0}.{1}", proto.ImportedProtos[i].Package, proto.ImportedProtos[i].Messages[j].MessageName); variableTypeInOthers.adjustHelpString = string.Format("adjustTable.{0}_adj.Adjust{1}", proto.ImportedProtos[i].ProtoFileName, proto.ImportedProtos[i].Messages[j].MessageName); variableTypeInOthers.adjustNullAdjustString = string.Format("adjustTable.{0}_adj ~= nil and adjustTable.{0}_adj.Adjust{1} ~= nil", proto.ImportedProtos[i].ProtoFileName, proto.ImportedProtos[i].Messages[j].MessageName); variableTypeInOthers.enumType = null; variableTypeInOthers.messageType = proto.ImportedProtos[i].Messages[j]; return(variableTypeInOthers); } } } //若还未找到,则返回原始的变量类型 variableTypeInOthers.isEnumType = false; variableTypeInOthers.isInOtherPackage = false; variableTypeInOthers.decodeHelpString = variable.VariableTypeString; variableTypeInOthers.typeString = variable.VariableTypeString; variableTypeInOthers.adjustHelpString = variable.VariableTypeString; variableTypeInOthers.adjustNullAdjustString = variable.VariableTypeString; variableTypeInOthers.enumType = null; variableTypeInOthers.messageType = null; if (variable.VType == ProtocolControlCache_ProtoStructure.VariableInMessage.VariableType.Others) { UnityEngine.Debug.LogErrorFormat("未在proto文件或其他proto文件中找到 {0}.{1} 的 {2} 字段类型", proto.Package, msg.MessageName, variable.VariableTypeString); } return(variableTypeInOthers); }
/// <summary> /// 初始化,后续代码在此添加 /// </summary> public void Initialize() { ProtocolControlCache_ProtoStructure.ClearProtoStructureCache(); }
private static void OnScriptCompileFinished() { ProtocolControlCache_ProtoStructure.ClearProtoStructureCache(); }