提交 d0a53bbd 编写于 作者: T tanghai

把proto生成独立成一个工具,cd Proto, 运行dotnet Proto2CS.dll即可生成proto代码。仍然可以在unity tools中生成,调用的是同一个工具

上级 cc7e9134
......@@ -47,3 +47,4 @@ _ReSharper.CSharp/
.DS_Store
Server/.DS_Store
/Server/.vscode/
.vs/
......@@ -35,6 +35,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.ThirdParty", "Unity\U
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KcpLib", "Server\ThirdParty\KcpLib\KcpLib.csproj", "{CD9683D9-0B4B-42D1-A1E0-1689BEEFD725}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{4BC66C3C-D55F-4FAA-A2F5-29E8EB1797AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proto2CS", "Tools\Proto2CS\Proto2CS.csproj", "{CC55624F-D5CB-4705-A879-9FCAEC1FED71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -189,6 +193,18 @@ Global
{CD9683D9-0B4B-42D1-A1E0-1689BEEFD725}.Release|x64.Build.0 = Release|Any CPU
{CD9683D9-0B4B-42D1-A1E0-1689BEEFD725}.Release|x86.ActiveCfg = Release|Any CPU
{CD9683D9-0B4B-42D1-A1E0-1689BEEFD725}.Release|x86.Build.0 = Release|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Debug|x64.ActiveCfg = Debug|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Debug|x64.Build.0 = Debug|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Debug|x86.ActiveCfg = Debug|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Debug|x86.Build.0 = Debug|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Release|Any CPU.Build.0 = Release|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Release|x64.ActiveCfg = Release|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Release|x64.Build.0 = Release|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Release|x86.ActiveCfg = Release|Any CPU
{CC55624F-D5CB-4705-A879-9FCAEC1FED71}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -208,6 +224,7 @@ Global
{C17F48D3-964E-E97C-3D2E-966F7A6C6D93} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
{CFBC0A95-3456-3439-6B2E-60FDE0FE5EE1} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
{CD9683D9-0B4B-42D1-A1E0-1689BEEFD725} = {78640FA0-9F11-412D-A639-61F03D02407A}
{CC55624F-D5CB-4705-A879-9FCAEC1FED71} = {4BC66C3C-D55F-4FAA-A2F5-29E8EB1797AE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EABC01E3-3EB5-47EF-B46E-AAD8BB3585F1}
......
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v2.1",
"signature": "da39a3ee5e6b4b0d3255bfef95601890afd80709"
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v2.1": {
"Proto2CS/1.0.0": {
"runtime": {
"Proto2CS.dll": {}
}
}
}
},
"libraries": {
"Proto2CS/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}
\ No newline at end of file
文件已添加
文件已添加
{
"runtimeOptions": {
"additionalProbingPaths": [
"C:\\Users\\USER-PC\\.dotnet\\store\\|arch|\\|tfm|",
"C:\\Users\\USER-PC\\.nuget\\packages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
]
}
}
\ No newline at end of file
{
"runtimeOptions": {
"tfm": "netcoreapp2.1",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "2.1.0"
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using ETModel;
using NLog;
using PF;
using ABPath = ETModel.ABPath;
using Path = System.IO.Path;
namespace App
{
......
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
namespace ETTools
{
internal class OpcodeInfo
{
public string Name;
public int Opcode;
}
public static class Program
{
public static void Main()
{
Run("protoc.exe", "--csharp_out=\"../Unity/Assets/Model/Module/Message/\" --proto_path=\"./\" OuterMessage.proto");
Run("protoc.exe", "--csharp_out=\"../Unity/Assets/Hotfix/Module/Message/\" --proto_path=\"./\" HotfixMessage.proto");
// InnerMessage.proto生成cs代码
InnerProto2CS.Proto2CS();
msgOpcode.Clear();
Proto2CS("ETModel", "OuterMessage.proto", clientMessagePath, "OuterOpcode", 100);
msgOpcode.Clear();
Proto2CS("ETHotfix", "HotfixMessage.proto", hotfixMessagePath, "HotfixOpcode", 10000);
Console.WriteLine("proto2cs succeed!");
}
private const string protoPath = ".";
private const string clientMessagePath = "../Unity/Assets/Model/Module/Message/";
private const string hotfixMessagePath = "../Unity/Assets/Hotfix/Module/Message/";
private static readonly char[] splitChars = { ' ', '\t' };
private static readonly List<OpcodeInfo> msgOpcode = new List<OpcodeInfo>();
public static void Run(string exe, string arguments)
{
Console.WriteLine($"execute: {exe} {arguments}");
ProcessStartInfo info = new ProcessStartInfo
{
FileName = exe,
Arguments = arguments,
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = ".",
RedirectStandardOutput = true,
RedirectStandardError = true,
};
Process process = Process.Start(info);
process.WaitForExit();
if (process.ExitCode != 0)
{
throw new Exception(process.StandardOutput.ReadToEnd() + process.StandardError.ReadToEnd());
}
}
public static void Proto2CS(string ns, string protoName, string outputPath, string opcodeClassName, int startOpcode, bool isClient = true)
{
msgOpcode.Clear();
string proto = Path.Combine(protoPath, protoName);
string s = File.ReadAllText(proto);
StringBuilder sb = new StringBuilder();
sb.Append("using ETModel;\n");
sb.Append($"namespace {ns}\n");
sb.Append("{\n");
bool isMsgStart = false;
foreach (string line in s.Split('\n'))
{
string newline = line.Trim();
if (newline == "")
{
continue;
}
if (newline.StartsWith("//"))
{
sb.Append($"{newline}\n");
}
if (newline.StartsWith("message"))
{
string parentClass = "";
isMsgStart = true;
string msgName = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries)[1];
string[] ss = newline.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries);
if (ss.Length == 2)
{
parentClass = ss[1].Trim();
}
else
{
parentClass = "";
}
msgOpcode.Add(new OpcodeInfo() { Name = msgName, Opcode = ++startOpcode });
sb.Append($"\t[Message({opcodeClassName}.{msgName})]\n");
sb.Append($"\tpublic partial class {msgName} ");
if (parentClass != "")
{
sb.Append($": {parentClass} ");
}
sb.Append("{}\n\n");
}
if (isMsgStart && newline == "}")
{
isMsgStart = false;
}
}
sb.Append("}\n");
GenerateOpcode(ns, opcodeClassName, outputPath, sb);
}
private static void GenerateOpcode(string ns, string outputFileName, string outputPath, StringBuilder sb)
{
sb.AppendLine($"namespace {ns}");
sb.AppendLine("{");
sb.AppendLine($"\tpublic static partial class {outputFileName}");
sb.AppendLine("\t{");
foreach (OpcodeInfo info in msgOpcode)
{
sb.AppendLine($"\t\t public const ushort {info.Name} = {info.Opcode};");
}
sb.AppendLine("\t}");
sb.AppendLine("}");
string csPath = Path.Combine(outputPath, outputFileName + ".cs");
File.WriteAllText(csPath, sb.ToString());
}
}
public static class InnerProto2CS
{
private const string protoPath = ".";
private const string serverMessagePath = "../Server/Model/Module/Message/";
private static readonly char[] splitChars = { ' ', '\t' };
private static readonly List<OpcodeInfo> msgOpcode = new List<OpcodeInfo>();
public static void Proto2CS()
{
msgOpcode.Clear();
Proto2CS("ETModel", "InnerMessage.proto", serverMessagePath, "InnerOpcode", 1000);
GenerateOpcode("ETModel", "InnerOpcode", serverMessagePath);
}
public static void Proto2CS(string ns, string protoName, string outputPath, string opcodeClassName, int startOpcode)
{
msgOpcode.Clear();
string proto = Path.Combine(protoPath, protoName);
string csPath = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(proto) + ".cs");
string s = File.ReadAllText(proto);
StringBuilder sb = new StringBuilder();
sb.Append("using ETModel;\n");
sb.Append("using System.Collections.Generic;\n");
sb.Append($"namespace {ns}\n");
sb.Append("{\n");
bool isMsgStart = false;
string parentClass = "";
foreach (string line in s.Split('\n'))
{
string newline = line.Trim();
if (newline == "")
{
continue;
}
if (newline.StartsWith("//"))
{
sb.Append($"{newline}\n");
}
if (newline.StartsWith("message"))
{
parentClass = "";
isMsgStart = true;
string msgName = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries)[1];
string[] ss = newline.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries);
if (ss.Length == 2)
{
parentClass = ss[1].Trim();
}
msgOpcode.Add(new OpcodeInfo() { Name = msgName, Opcode = ++startOpcode });
sb.Append($"\t[Message({opcodeClassName}.{msgName})]\n");
sb.Append($"\tpublic partial class {msgName}");
if (parentClass == "IActorMessage" || parentClass == "IActorRequest" || parentClass == "IActorResponse" ||
parentClass == "IFrameMessage")
{
sb.Append($": {parentClass}\n");
}
else if (parentClass != "")
{
sb.Append($": {parentClass}\n");
}
else
{
sb.Append("\n");
}
continue;
}
if (isMsgStart)
{
if (newline == "{")
{
sb.Append("\t{\n");
continue;
}
if (newline == "}")
{
isMsgStart = false;
sb.Append("\t}\n\n");
continue;
}
if (newline.Trim().StartsWith("//"))
{
sb.AppendLine(newline);
continue;
}
if (newline.Trim() != "" && newline != "}")
{
if (newline.StartsWith("repeated"))
{
Repeated(sb, ns, newline);
}
else
{
Members(sb, newline, true);
}
}
}
}
sb.Append("}\n");
File.WriteAllText(csPath, sb.ToString());
}
private static void GenerateOpcode(string ns, string outputFileName, string outputPath)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"namespace {ns}");
sb.AppendLine("{");
sb.AppendLine($"\tpublic static partial class {outputFileName}");
sb.AppendLine("\t{");
foreach (OpcodeInfo info in msgOpcode)
{
sb.AppendLine($"\t\t public const ushort {info.Name} = {info.Opcode};");
}
sb.AppendLine("\t}");
sb.AppendLine("}");
string csPath = Path.Combine(outputPath, outputFileName + ".cs");
File.WriteAllText(csPath, sb.ToString());
}
private static void Repeated(StringBuilder sb, string ns, string newline)
{
try
{
int index = newline.IndexOf(";");
newline = newline.Remove(index);
string[] ss = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
string type = ss[1];
type = ConvertType(type);
string name = ss[2];
sb.Append($"\t\tpublic List<{type}> {name} = new List<{type}>();\n\n");
}
catch (Exception e)
{
Console.WriteLine($"{newline}\n {e}");
}
}
private static string ConvertType(string type)
{
string typeCs = "";
switch (type)
{
case "int16":
typeCs = "short";
break;
case "int32":
typeCs = "int";
break;
case "bytes":
typeCs = "byte[]";
break;
case "uint32":
typeCs = "uint";
break;
case "long":
typeCs = "long";
break;
case "int64":
typeCs = "long";
break;
case "uint64":
typeCs = "ulong";
break;
case "uint16":
typeCs = "ushort";
break;
default:
typeCs = type;
break;
}
return typeCs;
}
private static void Members(StringBuilder sb, string newline, bool isRequired)
{
try
{
int index = newline.IndexOf(";");
newline = newline.Remove(index);
string[] ss = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
string type = ss[0];
string name = ss[1];
string typeCs = ConvertType(type);
sb.Append($"\t\tpublic {typeCs} {name} {{ get; set; }}\n\n");
}
catch (Exception e)
{
Console.WriteLine($"{newline}\n {e}");
}
}
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>../../Proto/</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>../../Proto/</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Remove=".vs\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove=".vs\**" />
</ItemGroup>
<ItemGroup>
<None Remove=".vs\**" />
</ItemGroup>
</Project>

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2046
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Proto2CS", "Proto2CS\Proto2CS.csproj", "{6903B08C-40ED-4324-9F33-E65E9341EC95}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6903B08C-40ED-4324-9F33-E65E9341EC95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6903B08C-40ED-4324-9F33-E65E9341EC95}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6903B08C-40ED-4324-9F33-E65E9341EC95}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6903B08C-40ED-4324-9F33-E65E9341EC95}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {26215A9A-992A-4D3E-9EE3-DE8128C832E2}
EndGlobalSection
EndGlobal
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using ETModel;
using UnityEditor;
......@@ -16,135 +13,39 @@ namespace ETEditor
public class Proto2CSEditor : EditorWindow
{
private const string protoPath = "../Proto/";
private const string clientMessagePath = "Assets/Model/Module/Message/";
private const string hotfixMessagePath = "Assets/Hotfix/Module/Message/";
private static readonly char[] splitChars = { ' ', '\t' };
private static readonly List<OpcodeInfo> msgOpcode = new List<OpcodeInfo>();
[MenuItem("Tools/Proto2CS")]
public static void AllProto2CS()
{
// InnerMessage.proto生成cs代码
InnerProto2CS.Proto2CS();
msgOpcode.Clear();
Proto2CS("ETModel", "OuterMessage.proto", clientMessagePath, "OuterOpcode", 100);
msgOpcode.Clear();
Proto2CS("ETHotfix", "HotfixMessage.proto", hotfixMessagePath, "HotfixOpcode", 10000);
#if !UNITY_EDITOR_OSX
CommandRun($"protoc.bat", "");
#else
"bash ./protoc.sh".Bash(System.Environment.CurrentDirectory);
#endif
CommandRun();
AssetDatabase.Refresh();
}
public static void CommandRun(string exe, string arguments)
public static void CommandRun()
{
try
{
ProcessStartInfo info = new ProcessStartInfo
{
CreateNoWindow = true,
FileName = exe,
Arguments = arguments,
UseShellExecute = true,
FileName = "dotnet",
Arguments = "Proto2CS.dll",
UseShellExecute = false,
WorkingDirectory = "../Proto/",
RedirectStandardOutput = true,
RedirectStandardError = true,
};
Process p = Process.Start(info);
p.WaitForExit();
}
catch (Exception e)
{
Log.Error(e);
}
}
public static void Proto2CS(string ns, string protoName, string outputPath, string opcodeClassName, int startOpcode, bool isClient = true)
{
msgOpcode.Clear();
string proto = Path.Combine(protoPath, protoName);
//CommandRun($"protoc.exe", $"--csharp_out=\"./{outputPath}\" --proto_path=\"{protoPath}\" {protoName}");
string s = File.ReadAllText(proto);
StringBuilder sb = new StringBuilder();
sb.Append("using ETModel;\n");
sb.Append($"namespace {ns}\n");
sb.Append("{\n");
bool isMsgStart = false;
foreach (string line in s.Split('\n'))
{
string newline = line.Trim();
if (newline == "")
Process process = Process.Start(info);
process.WaitForExit();
if (process.ExitCode != 0)
{
continue;
}
if (newline.StartsWith("//"))
{
sb.Append($"{newline}\n");
}
if (newline.StartsWith("message"))
{
string parentClass = "";
isMsgStart = true;
string msgName = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries)[1];
string[] ss = newline.Split(new []{"//"}, StringSplitOptions.RemoveEmptyEntries);
if (ss.Length == 2)
{
parentClass = ss[1].Trim();
}
else
{
parentClass = "";
}
msgOpcode.Add(new OpcodeInfo() { Name = msgName, Opcode = ++startOpcode});
sb.Append($"\t[Message({opcodeClassName}.{msgName})]\n");
sb.Append($"\tpublic partial class {msgName} ");
if (parentClass != "")
{
sb.Append($": {parentClass} ");
}
sb.Append("{}\n\n");
}
if (isMsgStart && newline == "}")
{
isMsgStart = false;
throw new Exception(process.StandardOutput.ReadToEnd() + process.StandardError.ReadToEnd());
}
Log.Info(process.StandardOutput.ReadToEnd());
}
sb.Append("}\n");
GenerateOpcode(ns, opcodeClassName, outputPath, sb);
}
private static void GenerateOpcode(string ns, string outputFileName, string outputPath, StringBuilder sb)
{
sb.AppendLine($"namespace {ns}");
sb.AppendLine("{");
sb.AppendLine($"\tpublic static partial class {outputFileName}");
sb.AppendLine("\t{");
foreach (OpcodeInfo info in msgOpcode)
catch (Exception e)
{
sb.AppendLine($"\t\t public const ushort {info.Name} = {info.Opcode};");
Log.Error(e);
}
sb.AppendLine("\t}");
sb.AppendLine("}");
string csPath = Path.Combine(outputPath, outputFileName + ".cs");
File.WriteAllText(csPath, sb.ToString());
}
}
}
@echo off
protoc.exe --csharp_out="./Assets/Model/Module/Message/" --proto_path="../Proto/" OuterMessage.proto
protoc.exe --csharp_out="./Assets/Hotfix/Module/Message/" --proto_path="../Proto/" HotfixMessage.proto
echo finish...
pause
\ No newline at end of file
#!/bin/bash
protoc --csharp_out="./Assets/Model/Module/Message/" --proto_path="../Proto/" OuterMessage.proto
protoc --csharp_out="./Assets/Hotfix/Module/Message/" --proto_path="../Proto/" HotfixMessage.proto
echo finish
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册