导出网络协议增加了缓存文件保证一致性

导出网络协议增加了缓存文件保证一致性
This commit is contained in:
ALEXTANGXIAO
2023-09-05 23:56:50 +08:00
parent 285483034e
commit caf5b2b54e
10 changed files with 240 additions and 80 deletions

3
.gitignore vendored
View File

@@ -129,4 +129,5 @@ DotNet/ThirdParty/obj/
Bin/
#Server_Config
DotNet/Config/GameConfig
DotNet/Config/GameConfig
DotNet/Config/ProtoBuf/OpCode.Cache

View File

@@ -1,12 +1,34 @@
#if TENGINE_NET
namespace TEngine.Core;
/// <summary>
/// 导出类型枚举,用于标识不同类型的导出操作。
/// </summary>
public enum ExportType
{
None = 0,
ProtoBuf = 1, // 导出ProtoBuf
AllExcelIncrement = 2, // 所有-增量导出Excel
AllExcel = 3, // 所有-全量导出Excel
Max, // 这个一定放最后
/// <summary>
/// 导出类型。
/// </summary>
None = 0,
/// <summary>
/// 导出ProtoBuf类型。
/// </summary>
ProtoBuf = 1,
/// <summary>
/// 导出网络协议并重新生成OpCode。
/// </summary>
ProtoBufAndOpCodeCache = 2,
/// <summary>
/// 所有数据的增量导出Excel类型。
/// </summary>
AllExcelIncrement = 3,
/// <summary>
/// 所有数据的全量导出Excel类型。
/// </summary>
AllExcel = 4,
/// <summary>
/// 导出类型枚举的最大值,一定要放在最后。
/// </summary>
Max,
}
#endif

View File

@@ -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;
/// <summary>
/// 数据导出器,用于执行导出操作。
/// </summary>
public sealed class Exporter
{
/// <summary>
/// 开始执行数据导出操作。
/// </summary>
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:导出网络协议并重新生成OpCodeProtoBuf");
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);
}
/// <summary>
/// 输出信息到控制台。
/// </summary>
/// <param name="msg">要输出的信息。</param>
public static void LogInfo(string msg)
{
Console.WriteLine(msg);
}
/// <summary>
/// 输出错误信息到控制台。
/// </summary>
/// <param name="msg">要输出的错误信息。</param>
public static void LogError(string msg)
{
ConsoleColor color = Console.ForegroundColor;
@@ -74,6 +92,10 @@ public sealed class Exporter
Console.ForegroundColor = color;
}
/// <summary>
/// 输出异常信息到控制台。
/// </summary>
/// <param name="e">要输出的异常。</param>
public static void LogError(Exception e)
{
ConsoleColor color = Console.ForegroundColor;

View File

@@ -0,0 +1,60 @@
#if TENGINE_NET
using TEngine.Helper;
namespace TEngine.Core;
/// <summary>
/// 网络协议操作码缓存。
/// </summary>
public class OpCodeCache
{
private readonly List<uint> _opCodes = new List<uint>();
private readonly SortedDictionary<string, uint> _opcodeCache;
private readonly SortedDictionary<string, uint> _saveOpCodeCache = new();
private readonly string _opcodeCachePath = $"{Define.ProtoBufDirectory}OpCode.Cache";
/// <summary>
/// 构造函数,用于初始化网络协议操作码缓存。
/// </summary>
public OpCodeCache(bool regenerate)
{
if (File.Exists(_opcodeCachePath) && !regenerate)
{
var readAllText = File.ReadAllText(_opcodeCachePath);
_opcodeCache = readAllText.Deserialize<SortedDictionary<string, uint>>();
_opCodes.AddRange(_opcodeCache.Values);
}
else
{
_opcodeCache = new SortedDictionary<string, uint>();
}
}
/// <summary>
/// 保存网络协议操作码。
/// </summary>
public void Save()
{
File.WriteAllText(_opcodeCachePath, _saveOpCodeCache.ToJson());
}
/// <summary>
/// 根据className获得OpCode、如果是新增的会产生一个新的OpCode。
/// </summary>
/// <param name="className">协议名。</param>
/// <param name="opcode">操作码。</param>
/// <returns></returns>
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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e0f0d02da06c4ca981417bfe43162809
timeCreated: 1693928511

View File

@@ -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;
/// <summary>
/// ProtoBuf操作码类型枚举
/// </summary>
public enum ProtoBufOpCodeType
{
/// <summary>
/// 无
/// </summary>
None = 0,
/// <summary>
/// 外部操作码类型
/// </summary>
Outer = 1,
/// <summary>
/// 内部操作码类型
/// </summary>
Inner = 2,
/// <summary>
/// 使用BSON的内部操作码类型
/// </summary>
InnerBson = 3,
}
/// <summary>
/// 操作码信息类
/// </summary>
public sealed class OpcodeInfo
{
/// <summary>
/// 操作码
/// </summary>
public uint Code;
/// <summary>
/// 名称
/// </summary>
public string Name;
}
/// <summary>
/// ProtoBuf导出器类
/// </summary>
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<OpcodeInfo> _opcodes = new();
public ProtoBufExporter()
/// <summary>
/// 构造函数,用于初始化导出器
/// </summary>
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<string, string>();
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
}
}
/// <summary>
/// 加载模板
/// </summary>
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;

View File

@@ -1,26 +1,29 @@
using System.Collections.Generic;
using System.IO;
namespace TEngine.Core
namespace TEngine
{
/// <summary>
/// 文件操作助手类,提供了各种文件操作方法。
/// </summary>
public static class FileHelper
{
/// <summary>
/// 获取文件全路径。
/// 获取相对路径的完整路径。
/// </summary>
/// <param name="relativePath"></param>
/// <returns></returns>
/// <param name="relativePath">相对路径。</param>
/// <returns>完整路径。</returns>
public static string GetFullPath(string relativePath)
{
return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath));
}
/// <summary>
/// 拷贝文件到目标路径如果目标目录不存在会自动创建目录
/// 将文件复制到目标路径如果目标目录不存在会自动创建目录
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="destinationFile"></param>
/// <param name="overwrite"></param>
/// <param name="sourceFile">源文件路径。</param>
/// <param name="destinationFile">目标文件路径。</param>
/// <param name="overwrite">是否覆盖已存在的目标文件。</param>
public static void Copy(string sourceFile, string destinationFile, bool overwrite)
{
var directoriesByFilePath = GetDirectoriesByFilePath(destinationFile);
@@ -39,10 +42,10 @@ namespace TEngine.Core
}
/// <summary>
/// 获取文件路径内的所有文件夹路径
/// 获取文件路径内的所有文件夹路径
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
/// <param name="filePath">文件路径。</param>
/// <returns>文件夹路径列表。</returns>
public static List<string> GetDirectoriesByFilePath(string filePath)
{
var dir = "";
@@ -59,11 +62,11 @@ namespace TEngine.Core
}
/// <summary>
/// 文件夹所有内容拷贝的目标位置
/// 文件夹内的所有内容复制到目标位置
/// </summary>
/// <param name="sourceDirectory"></param>
/// <param name="destinationDirectory"></param>
/// <param name="overwrite"></param>
/// <param name="sourceDirectory">源文件夹路径。</param>
/// <param name="destinationDirectory">目标文件夹路径。</param>
/// <param name="overwrite">是否覆盖已存在的文件。</param>
public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite)
{
// 创建目标文件夹
@@ -99,11 +102,23 @@ namespace TEngine.Core
CopyDirectory(directory, destinationPath, overwrite);
}
}
/// <summary>
/// 清除文件夹里的所有文件
/// 获取目录下的所有文件
/// </summary>
/// <param name="folderPath"></param>
/// <param name="folderPath">文件夹路径。</param>
/// <param name="searchPattern">需要查找的文件通配符</param>
/// <param name="searchOption">查找的类型</param>
/// <returns></returns>
public static string[] GetDirectoryFile(string folderPath, string searchPattern, SearchOption searchOption)
{
return Directory.GetFiles(folderPath, searchPattern, searchOption);
}
/// <summary>
/// 清空文件夹内的所有文件。
/// </summary>
/// <param name="folderPath">文件夹路径。</param>
public static void ClearDirectoryFile(string folderPath)
{
if (!Directory.Exists(folderPath))