From caf5b2b54e73eaf95415926866282ba3817926ab Mon Sep 17 00:00:00 2001 From: ALEXTANGXIAO <574809918@qq.com> Date: Tue, 5 Sep 2023 23:56:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E7=BD=91=E7=BB=9C=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E5=A2=9E=E5=8A=A0=E4=BA=86=E7=BC=93=E5=AD=98=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=BF=9D=E8=AF=81=E4=B8=80=E8=87=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 导出网络协议增加了缓存文件保证一致性 --- .gitignore | 3 +- .../Core/Exporter/Excel/Base/ExportType.cs | 32 ++++- .../DotNet/Core/Exporter/Exporter.cs | 36 ++++- .../Core/Exporter/ProtoBuf/OpCodeCache.cs | 60 ++++++++ .../Exporter/ProtoBuf/OpCodeCache.cs.meta | 3 + .../Exporter/ProtoBuf/ProtoBufExporter.cs | 135 +++++++++++------- .../DotNet/Core/Helper/FileHelper.cs | 51 ++++--- .../ProtoBuf/{ => Inner}/InnerMessage.proto | 0 .../{ => InnerBosn}/InnerBsonMessage.proto | 0 .../ProtoBuf/{ => Outer}/OuterMessage.proto | 0 10 files changed, 240 insertions(+), 80 deletions(-) create mode 100644 Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs create mode 100644 Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs.meta rename DotNet/Config/ProtoBuf/{ => Inner}/InnerMessage.proto (100%) rename DotNet/Config/ProtoBuf/{ => InnerBosn}/InnerBsonMessage.proto (100%) rename DotNet/Config/ProtoBuf/{ => Outer}/OuterMessage.proto (100%) diff --git a/.gitignore b/.gitignore index 9c630850..df089d85 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,5 @@ DotNet/ThirdParty/obj/ Bin/ #Server_Config -DotNet/Config/GameConfig \ No newline at end of file +DotNet/Config/GameConfig +DotNet/Config/ProtoBuf/OpCode.Cache diff --git a/Assets/GameScripts/DotNet/Core/Exporter/Excel/Base/ExportType.cs b/Assets/GameScripts/DotNet/Core/Exporter/Excel/Base/ExportType.cs index 6a9c6f83..6f435890 100644 --- a/Assets/GameScripts/DotNet/Core/Exporter/Excel/Base/ExportType.cs +++ b/Assets/GameScripts/DotNet/Core/Exporter/Excel/Base/ExportType.cs @@ -1,12 +1,34 @@ #if TENGINE_NET namespace TEngine.Core; +/// +/// 导出类型枚举,用于标识不同类型的导出操作。 +/// public enum ExportType { - None = 0, - ProtoBuf = 1, // 导出ProtoBuf - AllExcelIncrement = 2, // 所有-增量导出Excel - AllExcel = 3, // 所有-全量导出Excel - Max, // 这个一定放最后 + /// + /// 无导出类型。 + /// + None = 0, + /// + /// 导出ProtoBuf类型。 + /// + ProtoBuf = 1, + /// + /// 导出网络协议并重新生成OpCode。 + /// + ProtoBufAndOpCodeCache = 2, + /// + /// 所有数据的增量导出Excel类型。 + /// + AllExcelIncrement = 3, + /// + /// 所有数据的全量导出Excel类型。 + /// + AllExcel = 4, + /// + /// 导出类型枚举的最大值,一定要放在最后。 + /// + Max, } #endif diff --git a/Assets/GameScripts/DotNet/Core/Exporter/Exporter.cs b/Assets/GameScripts/DotNet/Core/Exporter/Exporter.cs index 80ed1a53..e9bfd275 100644 --- a/Assets/GameScripts/DotNet/Core/Exporter/Exporter.cs +++ b/Assets/GameScripts/DotNet/Core/Exporter/Exporter.cs @@ -3,16 +3,21 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.Loader; using System.Text; -using TEngine.Core; +using TEngine.Helper; using Microsoft.Extensions.Configuration; #pragma warning disable CS8601 -#pragma warning disable CS8618 namespace TEngine.Core; +/// +/// 数据导出器,用于执行导出操作。 +/// public sealed class Exporter { + /// + /// 开始执行数据导出操作。 + /// public void Start() { Console.OutputEncoding = Encoding.UTF8; @@ -25,8 +30,9 @@ public sealed class Exporter LogInfo("请输入你想要做的操作:"); LogInfo("1:导出网络协议(ProtoBuf)"); - LogInfo("2:增量导出服务器启动Excel(包含常量枚举)"); - LogInfo("3:全量导出服务器启动Excel(包含常量枚举)"); + LogInfo("2:导出网络协议并重新生成OpCode(ProtoBuf)"); + LogInfo("3:增量导出Excel(包含常量枚举)"); + LogInfo("4:全量导出Excel(包含常量枚举)"); var keyChar = Console.ReadKey().KeyChar; @@ -39,13 +45,17 @@ public sealed class Exporter LogInfo(""); exportType = (ExportType) key; - // LoadConfig(); - + switch (exportType) { case ExportType.ProtoBuf: { - _ = new ProtoBufExporter(); + _ = new ProtoBufExporter(false); + break; + } + case ExportType.ProtoBufAndOpCodeCache: + { + _ = new ProtoBufExporter(true); break; } case ExportType.AllExcel: @@ -61,11 +71,19 @@ public sealed class Exporter Environment.Exit(0); } + /// + /// 输出信息到控制台。 + /// + /// 要输出的信息。 public static void LogInfo(string msg) { Console.WriteLine(msg); } + /// + /// 输出错误信息到控制台。 + /// + /// 要输出的错误信息。 public static void LogError(string msg) { ConsoleColor color = Console.ForegroundColor; @@ -74,6 +92,10 @@ public sealed class Exporter Console.ForegroundColor = color; } + /// + /// 输出异常信息到控制台。 + /// + /// 要输出的异常。 public static void LogError(Exception e) { ConsoleColor color = Console.ForegroundColor; diff --git a/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs b/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs new file mode 100644 index 00000000..0183c7b7 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs @@ -0,0 +1,60 @@ +#if TENGINE_NET +using TEngine.Helper; + +namespace TEngine.Core; + +/// +/// 网络协议操作码缓存。 +/// +public class OpCodeCache +{ + private readonly List _opCodes = new List(); + private readonly SortedDictionary _opcodeCache; + private readonly SortedDictionary _saveOpCodeCache = new(); + private readonly string _opcodeCachePath = $"{Define.ProtoBufDirectory}OpCode.Cache"; + + /// + /// 构造函数,用于初始化网络协议操作码缓存。 + /// + public OpCodeCache(bool regenerate) + { + if (File.Exists(_opcodeCachePath) && !regenerate) + { + var readAllText = File.ReadAllText(_opcodeCachePath); + _opcodeCache = readAllText.Deserialize>(); + _opCodes.AddRange(_opcodeCache.Values); + } + else + { + _opcodeCache = new SortedDictionary(); + } + } + + /// + /// 保存网络协议操作码。 + /// + public void Save() + { + File.WriteAllText(_opcodeCachePath, _saveOpCodeCache.ToJson()); + } + + /// + /// 根据className获得OpCode、如果是新增的会产生一个新的OpCode。 + /// + /// 协议名。 + /// 操作码。 + /// + public uint GetOpcodeCache(string className, ref uint opcode) + { + if (!_opcodeCache.TryGetValue(className, out var opCode)) + { + while (_opCodes.Contains(++opcode)) { } + opCode = opcode; + _opCodes.Add(opCode); + } + + _saveOpCodeCache.Add(className, opCode); + return opCode; + } +} +#endif \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs.meta b/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs.meta new file mode 100644 index 00000000..f7e5402c --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/OpCodeCache.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e0f0d02da06c4ca981417bfe43162809 +timeCreated: 1693928511 \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/ProtoBufExporter.cs b/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/ProtoBufExporter.cs index ce2b2d59..1b5f5f24 100644 --- a/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/ProtoBufExporter.cs +++ b/Assets/GameScripts/DotNet/Core/Exporter/ProtoBuf/ProtoBufExporter.cs @@ -1,28 +1,52 @@ #if TENGINE_NET using System.Text; using TEngine.Core.Network; - -#pragma warning disable CS8604 -#pragma warning disable CS8602 -#pragma warning disable CS8600 -#pragma warning disable CS8618 +using TEngine.Helper; namespace TEngine.Core; +/// +/// ProtoBuf操作码类型枚举 +/// public enum ProtoBufOpCodeType { + /// + /// 无 + /// None = 0, + /// + /// 外部操作码类型 + /// Outer = 1, + /// + /// 内部操作码类型 + /// Inner = 2, + /// + /// 使用BSON的内部操作码类型 + /// InnerBson = 3, } +/// +/// 操作码信息类 +/// public sealed class OpcodeInfo { + /// + /// 操作码 + /// public uint Code; + /// + /// 名称 + /// public string Name; } + +/// +/// ProtoBuf导出器类 +/// public sealed class ProtoBufExporter { private uint _aMessage; @@ -33,18 +57,21 @@ public sealed class ProtoBufExporter private uint _aRouteResponse; private string _serverTemplate; private string _clientTemplate; - + private readonly OpCodeCache _opCodeCache; private readonly List _opcodes = new(); - public ProtoBufExporter() + /// + /// 构造函数,用于初始化导出器 + /// + public ProtoBufExporter(bool regenerateOpCodeCache) { Console.OutputEncoding = Encoding.UTF8; - + if (!Directory.Exists(Define.ProtoBufServerDirectory)) { Directory.CreateDirectory(Define.ProtoBufServerDirectory); } - + if (!Directory.Exists(Define.ProtoBufClientDirectory)) { Directory.CreateDirectory(Define.ProtoBufClientDirectory); @@ -54,17 +81,19 @@ public sealed class ProtoBufExporter { Directory.CreateDirectory($"{Define.ProtoBufDirectory}Outer"); } - + if (!Directory.Exists($"{Define.ProtoBufDirectory}Inner")) { Directory.CreateDirectory($"{Define.ProtoBufDirectory}Inner"); } - if (!Directory.Exists($"{Define.ProtoBufDirectory}Bson")) + if (!Directory.Exists($"{Define.ProtoBufDirectory}InnerBosn")) { - Directory.CreateDirectory($"{Define.ProtoBufDirectory}Bson"); + Directory.CreateDirectory($"{Define.ProtoBufDirectory}InnerBosn"); } + _opCodeCache = new OpCodeCache(regenerateOpCodeCache); + var tasks = new Task[2]; tasks[0] = Task.Run(RouteType); tasks[1] = Task.Run(async () => @@ -75,6 +104,7 @@ public sealed class ProtoBufExporter await Start(ProtoBufOpCodeType.InnerBson); }); Task.WaitAll(tasks); + _opCodeCache.Save(); } private async Task Start(ProtoBufOpCodeType opCodeType) @@ -85,7 +115,7 @@ public sealed class ProtoBufExporter _opcodes.Clear(); var file = new StringBuilder(); var saveDirectory = new Dictionary(); - + switch (opCodeType) { case ProtoBufOpCodeType.Outer: @@ -99,8 +129,9 @@ public sealed class ProtoBufExporter opCodeName = "OuterOpcode"; saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate); saveDirectory.Add(Define.ProtoBufClientDirectory, _clientTemplate); - files.Add($"{Define.ProtoBufDirectory}OuterMessage.proto"); - files.AddRange(Directory.GetFiles($"{Define.ProtoBufDirectory}Outer").ToList()); + var protoBufFiles = FileHelper.GetDirectoryFile( + $"{Define.ProtoBufDirectory}Outer", "*.proto", SearchOption.AllDirectories); + files.AddRange(protoBufFiles); break; } case ProtoBufOpCodeType.Inner: @@ -114,8 +145,8 @@ public sealed class ProtoBufExporter _aRouteResponse = Opcode.InnerRouteResponse + 1000; opCodeName = "InnerOpcode"; saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate); - files.Add($"{Define.ProtoBufDirectory}InnerMessage.proto"); - files.AddRange(Directory.GetFiles($"{Define.ProtoBufDirectory}Inner").ToList()); + var protoBufFiles = FileHelper.GetDirectoryFile($"{Define.ProtoBufDirectory}Inner", "*.proto", SearchOption.AllDirectories); + files.AddRange(protoBufFiles); break; } case ProtoBufOpCodeType.InnerBson: @@ -129,8 +160,8 @@ public sealed class ProtoBufExporter _aRouteResponse = Opcode.InnerBsonRouteResponse + 1000; opCodeName = "InnerBsonOpcode"; saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate); - files.Add($"{Define.ProtoBufDirectory}InnerBsonMessage.proto"); - files.AddRange(Directory.GetFiles($"{Define.ProtoBufDirectory}Bson").ToList()); + var protoBufFiles = FileHelper.GetDirectoryFile($"{Define.ProtoBufDirectory}InnerBosn", "*.proto", SearchOption.AllDirectories); + files.AddRange(protoBufFiles); break; } } @@ -143,6 +174,7 @@ public sealed class ProtoBufExporter var isMsgHead = false; string responseTypeStr = null; string customRouteType = null; + var protoFileText = await File.ReadAllTextAsync(filePath); foreach (var line in protoFileText.Split('\n')) @@ -176,17 +208,20 @@ public sealed class ProtoBufExporter switch (parameterArray.Length) { case 2: + { + if (parameter == "ICustomRouteMessage") + { + customRouteType = parameterArray[1].Trim(); + break; + } + responseTypeStr = parameterArray[1].Trim(); break; + } case 3: { - customRouteType = parameterArray[1].Trim(); - - if (parameterArray.Length == 3) - { - responseTypeStr = parameterArray[2].Trim(); - } - + responseTypeStr = parameterArray[1].Trim(); + customRouteType = parameterArray[2].Trim(); break; } } @@ -197,8 +232,8 @@ public sealed class ProtoBufExporter } file.Append(string.IsNullOrWhiteSpace(parameter) - ? $"\tpublic partial class {className} : AProto" - : $"\tpublic partial class {className} : AProto, {parameter}"); + ? $"\tpublic partial class {className} : AProto" + : $"\tpublic partial class {className} : AProto, {parameter}"); opcodeInfo.Name = className; continue; } @@ -216,7 +251,7 @@ public sealed class ProtoBufExporter if (string.IsNullOrWhiteSpace(parameter) || parameter == "IMessage") { - opcodeInfo.Code += ++_aMessage; + opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aMessage); file.AppendLine($"\t\tpublic uint OpCode() {{ return {opCodeName}.{className}; }}"); } else @@ -260,13 +295,13 @@ public sealed class ProtoBufExporter case "IRequest": case "IBsonRequest": { - opcodeInfo.Code += ++_aRequest; + opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRequest); break; } case "IResponse": case "IBsonResponse": { - opcodeInfo.Code += ++_aResponse; + opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aResponse); file.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]"); file.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); break; @@ -275,15 +310,15 @@ public sealed class ProtoBufExporter { if (parameter.EndsWith("RouteMessage") || parameter == "IRouteMessage") { - opcodeInfo.Code += ++_aRouteMessage; + opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRouteMessage); } else if (parameter.EndsWith("RouteRequest") || parameter == "IRouteRequest") { - opcodeInfo.Code += ++_aRouteRequest; + opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRouteRequest); } else if (parameter.EndsWith("RouteResponse") || parameter == "IRouteResponse") { - opcodeInfo.Code += ++_aRouteResponse; + opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRouteResponse); file.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]"); file.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); } @@ -343,14 +378,14 @@ public sealed class ProtoBufExporter file.AppendLine("{"); file.AppendLine($"\tpublic static partial class {opCodeName}"); file.AppendLine("\t{"); - + foreach (var opcode in _opcodes) { file.AppendLine($"\t\t public const int {opcode.Name} = {opcode.Code};"); } - + _opcodes.Clear(); - + file.AppendLine("\t}"); file.AppendLine("}"); @@ -359,7 +394,6 @@ public sealed class ProtoBufExporter var csFile = Path.Combine(directory, $"{opCodeName}.cs"); await File.WriteAllTextAsync(csFile, file.ToString()); } - #endregion } @@ -380,11 +414,11 @@ public sealed class ProtoBufExporter { continue; } - - var splits = currentLine.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries); + + var splits = currentLine.Split(new[] {"//"}, StringSplitOptions.RemoveEmptyEntries); var routeTypeStr = splits[0].Split("=", StringSplitOptions.RemoveEmptyEntries); routeTypeFileSb.Append($"\t\t{routeTypeStr[0].Trim()} = {routeTypeStr[1].Trim()},"); - + if (splits.Length > 1) { routeTypeFileSb.Append($" // {splits[1].Trim()}\n"); @@ -400,7 +434,7 @@ public sealed class ProtoBufExporter await File.WriteAllTextAsync($"{Define.ProtoBufServerDirectory}RouteType.cs", file); await File.WriteAllTextAsync($"{Define.ProtoBufClientDirectory}RouteType.cs", file); } - + private void Repeated(StringBuilder file, string newline) { try @@ -421,7 +455,7 @@ public sealed class ProtoBufExporter Exporter.LogError($"{newline}\n {e}"); } } - + private void Members(StringBuilder file, string currentLine) { try @@ -434,7 +468,7 @@ public sealed class ProtoBufExporter var memberIndex = int.Parse(property[3]); var typeCs = ConvertType(type); string defaultValue = GetDefault(typeCs); - + file.AppendLine($"\t\t[ProtoMember({memberIndex})]"); file.AppendLine($"\t\tpublic {typeCs} {name} {{ get; set; }}"); } @@ -443,7 +477,7 @@ public sealed class ProtoBufExporter Exporter.LogError($"{currentLine}\n {e}"); } } - + private string ConvertType(string type) { return type switch @@ -458,11 +492,11 @@ public sealed class ProtoBufExporter _ => type }; } - + private string GetDefault(string type) { type = type.Trim(); - + switch (type) { case "byte": @@ -479,6 +513,9 @@ public sealed class ProtoBufExporter } } + /// + /// 加载模板 + /// private void LoadTemplate() { string[] lines = File.ReadAllLines(Define.ProtoBufTemplatePath, Encoding.UTF8); @@ -496,12 +533,12 @@ public sealed class ProtoBufExporter flag = 1; continue; } - else if (trim.StartsWith("#else")) + else if(trim.StartsWith("#else")) { flag = 2; continue; } - else if (trim.StartsWith($"#endif")) + else if(trim.StartsWith($"#endif")) { flag = 0; continue; diff --git a/Assets/GameScripts/DotNet/Core/Helper/FileHelper.cs b/Assets/GameScripts/DotNet/Core/Helper/FileHelper.cs index 88c91469..fc34225b 100644 --- a/Assets/GameScripts/DotNet/Core/Helper/FileHelper.cs +++ b/Assets/GameScripts/DotNet/Core/Helper/FileHelper.cs @@ -1,26 +1,29 @@ using System.Collections.Generic; using System.IO; -namespace TEngine.Core +namespace TEngine { + /// + /// 文件操作助手类,提供了各种文件操作方法。 + /// public static class FileHelper { /// - /// 获取文件全路径。 + /// 获取相对路径的完整路径。 /// - /// - /// + /// 相对路径。 + /// 完整路径。 public static string GetFullPath(string relativePath) { return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath)); } /// - /// 拷贝文件到目标路径、如果目标目录不存在会自动创建目录 + /// 将文件复制到目标路径,如果目标目录不存在会自动创建目录。 /// - /// - /// - /// + /// 源文件路径。 + /// 目标文件路径。 + /// 是否覆盖已存在的目标文件。 public static void Copy(string sourceFile, string destinationFile, bool overwrite) { var directoriesByFilePath = GetDirectoriesByFilePath(destinationFile); @@ -39,10 +42,10 @@ namespace TEngine.Core } /// - /// 获取文件路径内的所有文件夹路径 + /// 获取文件路径内的所有文件夹路径。 /// - /// - /// + /// 文件路径。 + /// 文件夹路径列表。 public static List GetDirectoriesByFilePath(string filePath) { var dir = ""; @@ -59,11 +62,11 @@ namespace TEngine.Core } /// - /// 把文件夹里所有内容拷贝的目标位置 + /// 将文件夹内的所有内容复制到目标位置。 /// - /// - /// - /// + /// 源文件夹路径。 + /// 目标文件夹路径。 + /// 是否覆盖已存在的文件。 public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite) { // 创建目标文件夹 @@ -99,11 +102,23 @@ namespace TEngine.Core CopyDirectory(directory, destinationPath, overwrite); } } - + /// - /// 清除文件夹里的所有文件 + /// 获取目录下的所有文件 /// - /// + /// 文件夹路径。 + /// 需要查找的文件通配符 + /// 查找的类型 + /// + public static string[] GetDirectoryFile(string folderPath, string searchPattern, SearchOption searchOption) + { + return Directory.GetFiles(folderPath, searchPattern, searchOption); + } + + /// + /// 清空文件夹内的所有文件。 + /// + /// 文件夹路径。 public static void ClearDirectoryFile(string folderPath) { if (!Directory.Exists(folderPath)) diff --git a/DotNet/Config/ProtoBuf/InnerMessage.proto b/DotNet/Config/ProtoBuf/Inner/InnerMessage.proto similarity index 100% rename from DotNet/Config/ProtoBuf/InnerMessage.proto rename to DotNet/Config/ProtoBuf/Inner/InnerMessage.proto diff --git a/DotNet/Config/ProtoBuf/InnerBsonMessage.proto b/DotNet/Config/ProtoBuf/InnerBosn/InnerBsonMessage.proto similarity index 100% rename from DotNet/Config/ProtoBuf/InnerBsonMessage.proto rename to DotNet/Config/ProtoBuf/InnerBosn/InnerBsonMessage.proto diff --git a/DotNet/Config/ProtoBuf/OuterMessage.proto b/DotNet/Config/ProtoBuf/Outer/OuterMessage.proto similarity index 100% rename from DotNet/Config/ProtoBuf/OuterMessage.proto rename to DotNet/Config/ProtoBuf/Outer/OuterMessage.proto