From 66ba09e8a0fa74e820954ec931b5eecd1f5b32d8 Mon Sep 17 00:00:00 2001 From: walon Date: Tue, 30 Nov 2021 01:52:47 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E7=89=B9=E6=80=A7=E3=80=91=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=94=9F=E6=88=90=20proto=E5=AE=9A=E4=B9=89=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=92=8Cproto=E4=BA=8C=E8=BF=9B=E5=88=B6=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Luban.Common/Source/Utils/TypeUtil.cs | 5 + .../Source/DataExporters/ProtobufExportor.cs | 300 ++++++++++++++++++ .../Source/DataVisitors/IDataActionVisitor.cs | 36 +-- src/Luban.Job.Cfg/Source/Defs/DefBean.cs | 22 ++ src/Luban.Job.Cfg/Source/Defs/DefTable.cs | 4 + .../Source/Generate/DataScatterRender.cs | 1 + .../Source/Generate/LuaCodeRenderBase.cs | 2 - .../Source/Generate/Protobuf2SchemaRender.cs | 20 ++ .../Source/Generate/Protobuf3SchemaRender.cs | 15 + .../Generate/ProtobufSchemaRenderBase.cs | 27 ++ .../Source/Generate/TemplateCodeRenderBase.cs | 16 + .../Source/Utils/DataExporterUtil.cs | 6 + src/Luban.Job.Common/Luban.Job.Common.csproj | 1 + .../Source/Defs/DefFieldBase.cs | 8 +- .../Source/Defs/DefTypeBase.cs | 2 + .../Source/Defs/TTypeTemplateCommonExtends.cs | 40 +++ src/Luban.Job.Common/Source/ELanguage.cs | 1 + .../TypeVisitors/IsProtobufPackedType.cs | 71 +++++ .../TypeVisitors/ProtobufTypeNameVisitor.cs | 130 ++++++++ .../TypeVisitors/ProtobufWireTypeVisitor.cs | 131 ++++++++ src/Luban.Job.Common/Source/Types/TArray.cs | 2 +- src/Luban.Job.Common/Source/Types/TList.cs | 2 +- src/Luban.Job.Common/Source/Types/TSet.cs | 2 +- src/Luban.Job.Common/Source/Types/TType.cs | 2 + src/Luban.Job.Common/Source/Utils/DefUtil.cs | 1 + .../Source/Utils/RenderFileUtil.cs | 3 + src/Luban.Server/Luban.Server.csproj | 15 + src/Luban.Server/Templates/common/pb/enum.tpl | 15 + src/Luban.Server/Templates/config/pb2/all.tpl | 33 ++ .../Templates/config/pb2/bean.tpl | 20 ++ .../Templates/config/pb2/table.tpl | 9 + .../Templates/config/pb2/tables.tpl | 13 + 32 files changed, 930 insertions(+), 25 deletions(-) create mode 100644 src/Luban.Job.Cfg/Source/DataExporters/ProtobufExportor.cs create mode 100644 src/Luban.Job.Cfg/Source/Generate/Protobuf2SchemaRender.cs create mode 100644 src/Luban.Job.Cfg/Source/Generate/Protobuf3SchemaRender.cs create mode 100644 src/Luban.Job.Cfg/Source/Generate/ProtobufSchemaRenderBase.cs create mode 100644 src/Luban.Job.Common/Source/TypeVisitors/IsProtobufPackedType.cs create mode 100644 src/Luban.Job.Common/Source/TypeVisitors/ProtobufTypeNameVisitor.cs create mode 100644 src/Luban.Job.Common/Source/TypeVisitors/ProtobufWireTypeVisitor.cs create mode 100644 src/Luban.Server/Templates/common/pb/enum.tpl create mode 100644 src/Luban.Server/Templates/config/pb2/all.tpl create mode 100644 src/Luban.Server/Templates/config/pb2/bean.tpl create mode 100644 src/Luban.Server/Templates/config/pb2/table.tpl create mode 100644 src/Luban.Server/Templates/config/pb2/tables.tpl diff --git a/src/Luban.Common/Source/Utils/TypeUtil.cs b/src/Luban.Common/Source/Utils/TypeUtil.cs index e3a1ab8..28f9bc9 100644 --- a/src/Luban.Common/Source/Utils/TypeUtil.cs +++ b/src/Luban.Common/Source/Utils/TypeUtil.cs @@ -126,6 +126,11 @@ namespace Luban.Common.Utils return MakeGoNamespace(module) + name; } + public static string MakePbFullName(string module, string name) + { + return MakeGoNamespace(module) + name; + } + public static string MakeNamespace(string module, string subModule) { if (module.Length == 0) diff --git a/src/Luban.Job.Cfg/Source/DataExporters/ProtobufExportor.cs b/src/Luban.Job.Cfg/Source/DataExporters/ProtobufExportor.cs new file mode 100644 index 0000000..6e8ee9c --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataExporters/ProtobufExportor.cs @@ -0,0 +1,300 @@ +using Google.Protobuf; +using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; +using Luban.Job.Cfg.DataVisitors; +using Luban.Job.Cfg.Defs; +using Luban.Job.Common.Generate; +using Luban.Job.Common.Types; +using Luban.Job.Common.TypeVisitors; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.DataExporters +{ + class ProtobufExportor : IDataActionVisitor + { + public static ProtobufExportor Ins { get; } = new(); + + public void WriteList(DefTable table, List datas, MemoryStream x) + { + var cos = new CodedOutputStream(x); + foreach (var d in datas) + { + cos.WriteTag(1, WireFormat.WireType.LengthDelimited); + d.Data.Apply(this, cos); + } + cos.Flush(); + } + + public void Accept(DBool type, CodedOutputStream x) + { + x.WriteBool(type.Value); + } + + public void Accept(DByte type, CodedOutputStream x) + { + x.WriteInt32(type.Value); + } + + public void Accept(DShort type, CodedOutputStream x) + { + x.WriteInt32(type.Value); + } + + public void Accept(DFshort type, CodedOutputStream x) + { + x.WriteInt32(type.Value); + } + + public void Accept(DInt type, CodedOutputStream x) + { + x.WriteInt32(type.Value); + } + + public void Accept(DFint type, CodedOutputStream x) + { + x.WriteSFixed32(type.Value); + } + + public void Accept(DLong type, CodedOutputStream x) + { + x.WriteInt64(type.Value); + } + + public void Accept(DFlong type, CodedOutputStream x) + { + x.WriteSFixed64(type.Value); + } + + public void Accept(DFloat type, CodedOutputStream x) + { + x.WriteFloat(type.Value); + } + + public void Accept(DDouble type, CodedOutputStream x) + { + x.WriteDouble(type.Value); + } + + public void Accept(DEnum type, CodedOutputStream x) + { + x.WriteInt32(type.Value); + } + + public void Accept(DDateTime type, CodedOutputStream x) + { + x.WriteInt32(type.GetUnixTime(DefAssembly.LocalAssebmly.TimeZone)); + } + + public void Accept(DString type, CodedOutputStream x) + { + x.WriteString(type.Value); + } + + public void Accept(DBytes type, CodedOutputStream x) + { + x.WriteBytes(ByteString.CopyFrom(type.Value)); + } + + public void Accept(DText type, CodedOutputStream x) + { + // 此处与 binary格式不同. binary格式还包含了key + // 意味pb格式是无法支持动态本土化的。 + var ass = DefAssembly.LocalAssebmly; + x.WriteString(type.GetText(ass.ExportTextTable, ass.NotConvertTextSet)); + } + + private MemoryStream AllocMemoryStream() + { + return new MemoryStream(); + } + + private void FreeMemoryStream(MemoryStream cos) + { + cos.Seek(0, SeekOrigin.Begin); + } + + public void Accept(DVector2 type, CodedOutputStream x) + { + var ms = AllocMemoryStream(); + var temp = new CodedOutputStream(ms); + temp.WriteTag(1, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.X); + temp.WriteTag(2, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.Y); + temp.Flush(); + ms.Seek(0, SeekOrigin.Begin); + x.WriteBytes(ByteString.FromStream(ms)); + FreeMemoryStream(ms); + } + + public void Accept(DVector3 type, CodedOutputStream x) + { + var ms = AllocMemoryStream(); + var temp = new CodedOutputStream(ms); + temp.WriteTag(1, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.X); + temp.WriteTag(2, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.Y); + temp.WriteTag(3, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.Z); + temp.Flush(); + ms.Seek(0, SeekOrigin.Begin); + x.WriteBytes(ByteString.FromStream(ms)); + FreeMemoryStream(ms); + } + + public void Accept(DVector4 type, CodedOutputStream x) + { + var ms = AllocMemoryStream(); + var temp = new CodedOutputStream(ms); + temp.WriteTag(1, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.X); + temp.WriteTag(2, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.Y); + temp.WriteTag(3, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.Z); + temp.WriteTag(4, WireFormat.WireType.Fixed32); + temp.WriteFloat(type.Value.W); + temp.Flush(); + ms.Seek(0, SeekOrigin.Begin); + x.WriteBytes(ByteString.FromStream(ms)); + FreeMemoryStream(ms); + } + + public void Accept(DBean type, CodedOutputStream x) + { + var bean = type.Type; + if (bean.IsAbstractType) + { + x.WriteTag(type.ImplType.AutoId, WireFormat.WireType.LengthDelimited); + } + + var ms = AllocMemoryStream(); + var temp = new CodedOutputStream(ms); + + var defFields = type.ImplType.HierarchyFields; + int index = 0; + foreach (var field in type.Fields) + { + var defField = (DefField)defFields[index++]; + if (!defField.NeedExport) + { + continue; + } + var fieldType = defField.CType; + if (field == null) + { + continue; + } + switch (field) + { + case DArray arr: + { + WriteList(fieldType.ElementType, defField.AutoId, arr.Datas, temp); + break; + } + case DList list: + { + WriteList(fieldType.ElementType, defField.AutoId, list.Datas, temp); + break; + } + case DSet set: + { + WriteList(fieldType.ElementType, defField.AutoId, set.Datas, temp); + break; + } + case DMap map: + { + WriteMap(map, defField.AutoId, temp); + break; + } + default: + { + temp.WriteTag(defField.AutoId, defField.CType.Apply(ProtobufWireTypeVisitor.Ins)); + field.Apply(this, temp); + break; + } + } + } + temp.Flush(); + ms.Seek(0, SeekOrigin.Begin); + var bs = ByteString.FromStream(ms); + x.WriteBytes(bs); + FreeMemoryStream(ms); + } + + private void WriteList(TType elementType, int fieldId, List datas, CodedOutputStream x) + { + if (elementType.Apply(IsProtobufPackedType.Ins)) + { + x.WriteTag(fieldId, WireFormat.WireType.LengthDelimited); + var ms = AllocMemoryStream(); + var temp = new CodedOutputStream(ms); + foreach (var data in datas) + { + data.Apply(this, temp); + } + temp.Flush(); + ms.Seek(0, SeekOrigin.Begin); + x.WriteBytes(ByteString.FromStream(ms)); + FreeMemoryStream(ms); + } + else + { + var eleWireType = elementType.Apply(ProtobufWireTypeVisitor.Ins); + foreach (var data in datas) + { + x.WriteTag(fieldId, eleWireType); + data.Apply(this, x); + } + } + } + + public void Accept(DArray type, CodedOutputStream x) + { + throw new NotImplementedException(); + } + + public void Accept(DList type, CodedOutputStream x) + { + throw new NotImplementedException(); + } + + public void Accept(DSet type, CodedOutputStream x) + { + throw new NotImplementedException(); + } + + private void WriteMap(DMap type, int fieldId, CodedOutputStream x) + { + var keyType = type.Type.KeyType; + var valueType = type.Type.ValueType; + var ms = AllocMemoryStream(); + foreach (var e in type.Datas) + { + x.WriteTag(fieldId, WireFormat.WireType.LengthDelimited); + ms.Seek(0, SeekOrigin.Begin); + var temp = new CodedOutputStream(ms); + temp.WriteTag(1, keyType.Apply(ProtobufWireTypeVisitor.Ins)); + e.Key.Apply(this, temp); + temp.WriteTag(2, valueType.Apply(ProtobufWireTypeVisitor.Ins)); + e.Value.Apply(this, temp); + temp.Flush(); + ms.Seek(0, SeekOrigin.Begin); + x.WriteBytes(ByteString.FromStream(ms)); + + } + FreeMemoryStream(ms); + } + + public void Accept(DMap type, CodedOutputStream x) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataVisitors/IDataActionVisitor.cs b/src/Luban.Job.Cfg/Source/DataVisitors/IDataActionVisitor.cs index ba49db3..397ec3d 100644 --- a/src/Luban.Job.Cfg/Source/DataVisitors/IDataActionVisitor.cs +++ b/src/Luban.Job.Cfg/Source/DataVisitors/IDataActionVisitor.cs @@ -28,9 +28,17 @@ namespace Luban.Job.Cfg.DataVisitors void Accept(DString type, T x); + void Accept(DText type, T x); + void Accept(DBytes type, T x); - void Accept(DText type, T x); + void Accept(DVector2 type, T x); + + void Accept(DVector3 type, T x); + + void Accept(DVector4 type, T x); + + void Accept(DDateTime type, T x); void Accept(DBean type, T x); @@ -41,14 +49,6 @@ namespace Luban.Job.Cfg.DataVisitors void Accept(DSet type, T x); void Accept(DMap type, T x); - - void Accept(DVector2 type, T x); - - void Accept(DVector3 type, T x); - - void Accept(DVector4 type, T x); - - void Accept(DDateTime type, T x); } public interface IDataActionVisitor @@ -75,11 +75,19 @@ namespace Luban.Job.Cfg.DataVisitors void Accept(DEnum type, T1 x, T2 y); + void Accept(DDateTime type, T1 x, T2 y); + void Accept(DString type, T1 x, T2 y); + void Accept(DText type, T1 x, T2 y); + void Accept(DBytes type, T1 x, T2 y); - void Accept(DText type, T1 x, T2 y); + void Accept(DVector2 type, T1 x, T2 y); + + void Accept(DVector3 type, T1 x, T2 y); + + void Accept(DVector4 type, T1 x, T2 y); void Accept(DBean type, T1 x, T2 y); @@ -90,13 +98,5 @@ namespace Luban.Job.Cfg.DataVisitors void Accept(DSet type, T1 x, T2 y); void Accept(DMap type, T1 x, T2 y); - - void Accept(DVector2 type, T1 x, T2 y); - - void Accept(DVector3 type, T1 x, T2 y); - - void Accept(DVector4 type, T1 x, T2 y); - - void Accept(DDateTime type, T1 x, T2 y); } } diff --git a/src/Luban.Job.Cfg/Source/Defs/DefBean.cs b/src/Luban.Job.Cfg/Source/Defs/DefBean.cs index b768148..44d571b 100644 --- a/src/Luban.Job.Cfg/Source/Defs/DefBean.cs +++ b/src/Luban.Job.Cfg/Source/Defs/DefBean.cs @@ -26,6 +26,8 @@ namespace Luban.Job.Cfg.Defs public List ExportFields { get; private set; } + public int AutoId { get; set; } + public bool IsDefineEquals(DefBean b) { return DeepCompareTypeDefine.Ins.Compare(this, b, new Dictionary(), new HashSet()); @@ -196,6 +198,18 @@ namespace Luban.Job.Cfg.Defs } } DefField.CompileFields(this, HierarchyFields, false); + + var allocAutoIds = this.HierarchyFields.Select(f => f.Id).ToHashSet(); + + int nextAutoId = 1; + foreach (var f in this.HierarchyFields) + { + while (!allocAutoIds.Add(nextAutoId)) + { + ++nextAutoId; + } + f.AutoId = nextAutoId; + } } public override void PostCompile() @@ -204,6 +218,14 @@ namespace Luban.Job.Cfg.Defs { field.PostCompile(); } + if (this.IsAbstractType && this.ParentDefType == null) + { + int nextAutoId = 0; + foreach (DefBean c in this.HierarchyNotAbstractChildren) + { + c.AutoId = ++nextAutoId; + } + } } } } diff --git a/src/Luban.Job.Cfg/Source/Defs/DefTable.cs b/src/Luban.Job.Cfg/Source/Defs/DefTable.cs index cbca6ff..96d2c8d 100644 --- a/src/Luban.Job.Cfg/Source/Defs/DefTable.cs +++ b/src/Luban.Job.Cfg/Source/Defs/DefTable.cs @@ -49,6 +49,8 @@ namespace Luban.Job.Cfg.Defs public TBean ValueTType { get; private set; } + public TType Type { get; private set; } + public DefField IndexField { get; private set; } public int IndexFieldIdIndex { get; private set; } @@ -86,6 +88,7 @@ namespace Luban.Job.Cfg.Defs case ETableMode.ONE: { KeyTType = null; + Type = ValueTType; break; } case ETableMode.MAP: @@ -113,6 +116,7 @@ namespace Luban.Job.Cfg.Defs IndexFieldIdIndex = 0; } KeyTType = IndexField.CType; + Type = TMap.Create(false, null, KeyTType, ValueTType, false); break; } default: throw new Exception($"unknown mode:'{Mode}'"); diff --git a/src/Luban.Job.Cfg/Source/Generate/DataScatterRender.cs b/src/Luban.Job.Cfg/Source/Generate/DataScatterRender.cs index 0aa9220..c17ef56 100644 --- a/src/Luban.Job.Cfg/Source/Generate/DataScatterRender.cs +++ b/src/Luban.Job.Cfg/Source/Generate/DataScatterRender.cs @@ -13,6 +13,7 @@ namespace Luban.Job.Cfg.Generate [Render("data_lua")] [Render("data_xml")] [Render("data_yaml")] + [Render("data_protobuf")] class DataScatterRender : DataRenderBase { public override void Render(GenContext ctx) diff --git a/src/Luban.Job.Cfg/Source/Generate/LuaCodeRenderBase.cs b/src/Luban.Job.Cfg/Source/Generate/LuaCodeRenderBase.cs index e9b5be0..2cfdeb5 100644 --- a/src/Luban.Job.Cfg/Source/Generate/LuaCodeRenderBase.cs +++ b/src/Luban.Job.Cfg/Source/Generate/LuaCodeRenderBase.cs @@ -19,7 +19,5 @@ namespace Luban.Job.Cfg.Generate var md5 = CacheFileUtil.GenMd5AndAddCache(file, string.Join('\n', content)); ctx.GenCodeFilesInOutputCodeDir.Add(new FileInfo() { FilePath = file, MD5 = md5 }); } - - public abstract string RenderAll(List types); } } diff --git a/src/Luban.Job.Cfg/Source/Generate/Protobuf2SchemaRender.cs b/src/Luban.Job.Cfg/Source/Generate/Protobuf2SchemaRender.cs new file mode 100644 index 0000000..20e1dbe --- /dev/null +++ b/src/Luban.Job.Cfg/Source/Generate/Protobuf2SchemaRender.cs @@ -0,0 +1,20 @@ +using Luban.Common.Protos; +using Luban.Job.Cfg.Defs; +using Luban.Job.Common.Defs; +using Luban.Job.Common.Generate; +using Luban.Job.Common.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.Generate +{ + [Render("code_protobuf")] + [Render("code_protobuf2")] + class Protobuf2SchemaRender : ProtobufSchemaRenderBase + { + protected override string RenderTemplateDir => "pb2"; + } +} diff --git a/src/Luban.Job.Cfg/Source/Generate/Protobuf3SchemaRender.cs b/src/Luban.Job.Cfg/Source/Generate/Protobuf3SchemaRender.cs new file mode 100644 index 0000000..bc55c96 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/Generate/Protobuf3SchemaRender.cs @@ -0,0 +1,15 @@ +using Luban.Job.Common.Generate; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.Generate +{ + [Render("code_protobuf3")] + class Protobuf3SchemaRender : ProtobufSchemaRenderBase + { + protected override string RenderTemplateDir => "pb3"; + } +} diff --git a/src/Luban.Job.Cfg/Source/Generate/ProtobufSchemaRenderBase.cs b/src/Luban.Job.Cfg/Source/Generate/ProtobufSchemaRenderBase.cs new file mode 100644 index 0000000..fb2e024 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/Generate/ProtobufSchemaRenderBase.cs @@ -0,0 +1,27 @@ +using Luban.Common.Protos; +using Luban.Job.Cfg.Defs; +using Luban.Job.Common.Defs; +using Luban.Job.Common.Generate; +using Luban.Job.Common.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.Generate +{ + abstract class ProtobufSchemaRenderBase : TemplateCodeRenderBase + { + protected override string CommonRenderTemplateDir => "pb"; + + public override void Render(GenContext ctx) + { + DefAssembly.LocalAssebmly.CurrentLanguage = Common.ELanguage.LUA; + var file = RenderFileUtil.GetFileOrDefault(ctx.GenArgs.OutputCodeMonolithicFile, "config.proto"); + var content = this.RenderAll(ctx.ExportTypes); + var md5 = CacheFileUtil.GenMd5AndAddCache(file, string.Join('\n', content)); + ctx.GenCodeFilesInOutputCodeDir.Add(new FileInfo() { FilePath = file, MD5 = md5 }); + } + } +} diff --git a/src/Luban.Job.Cfg/Source/Generate/TemplateCodeRenderBase.cs b/src/Luban.Job.Cfg/Source/Generate/TemplateCodeRenderBase.cs index 48c0cc9..46c8c04 100644 --- a/src/Luban.Job.Cfg/Source/Generate/TemplateCodeRenderBase.cs +++ b/src/Luban.Job.Cfg/Source/Generate/TemplateCodeRenderBase.cs @@ -52,5 +52,21 @@ namespace Luban.Job.Cfg.Generate }); return result; } + + public virtual string RenderAll(List types) + { + var enums = types.Where(t => t is DefEnum).ToList(); + var beans = types.Where(t => t is DefBean).ToList(); + var tables = types.Where(t => t is DefTable).ToList(); + + var template = StringTemplateUtil.GetTemplate($"config/{RenderTemplateDir}/all"); + var result = template.RenderCode(new { + Namespace = DefAssembly.LocalAssebmly.TopModule, + Enums = enums.Select(e => Render((DefEnum)e)).ToList(), + Beans = beans.Select(b => Render((DefBean)b)).ToList(), + Tables = tables.Select(t => Render((DefTable)t)).ToList(), + }); + return result; + } } } diff --git a/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs index 0335050..dcc875b 100644 --- a/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs +++ b/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs @@ -86,6 +86,12 @@ namespace Luban.Job.Cfg.Utils } return string.Join('\n', content); } + case "data_protobuf": + { + var ms = new MemoryStream(); + ProtobufExportor.Ins.WriteList(table, records, ms); + return DataUtil.StreamToBytes(ms); + } //case "data_erlang": //{ // var content = new StringBuilder(); diff --git a/src/Luban.Job.Common/Luban.Job.Common.csproj b/src/Luban.Job.Common/Luban.Job.Common.csproj index 12bddaa..814338f 100644 --- a/src/Luban.Job.Common/Luban.Job.Common.csproj +++ b/src/Luban.Job.Common/Luban.Job.Common.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs b/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs index 7253c64..110cb8e 100644 --- a/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs +++ b/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs @@ -13,9 +13,11 @@ namespace Luban.Job.Common.Defs public DefTypeBase HostType { get; set; } - public int Id { get; set; } + public int Id { get; protected set; } - public string Name { get; set; } + public string Name { get; protected set; } + + public int AutoId { get; set; } public string ConventionName { @@ -44,6 +46,7 @@ namespace Luban.Job.Common.Defs case ELanguage.TYPESCRIPT: cn = TypeUtil.ToCamelCase(Name); break; case ELanguage.PYTHON: cn = TypeUtil.ToUnderScores(Name); break; case ELanguage.RUST: cn = TypeUtil.ToUnderScores(Name); break; + case ELanguage.PROTOBUF: cn = Name; break; default: throw new Exception($"unknown language:{curLan}"); } break; @@ -91,6 +94,7 @@ namespace Luban.Job.Common.Defs { HostType = host; Id = f.Id + idOffset; + AutoId = Id; Name = f.Name; Type = f.Type; Comment = f.Comment; diff --git a/src/Luban.Job.Common/Source/Defs/DefTypeBase.cs b/src/Luban.Job.Common/Source/Defs/DefTypeBase.cs index fe12e47..c88f43a 100644 --- a/src/Luban.Job.Common/Source/Defs/DefTypeBase.cs +++ b/src/Luban.Job.Common/Source/Defs/DefTypeBase.cs @@ -47,6 +47,8 @@ namespace Luban.Job.Common.Defs public string RustFullName => TypeUtil.MakeRustFullName(Namespace, Name); + public string PbFullName => TypeUtil.MakePbFullName(Namespace, Name); + public string Comment { get; protected set; } public string EscapeComment => DefUtil.EscapeCommentByCurrentLanguage(Comment); diff --git a/src/Luban.Job.Common/Source/Defs/TTypeTemplateCommonExtends.cs b/src/Luban.Job.Common/Source/Defs/TTypeTemplateCommonExtends.cs index fff48dd..6b353e8 100644 --- a/src/Luban.Job.Common/Source/Defs/TTypeTemplateCommonExtends.cs +++ b/src/Luban.Job.Common/Source/Defs/TTypeTemplateCommonExtends.cs @@ -205,6 +205,46 @@ namespace Luban.Job.Common.Defs return type.Apply(GoDeserializeBinVisitor.Ins, name, bufName, err); } + public static string ProtobufDefineType(TType type) + { + return type.Apply(ProtobufTypeNameVisitor.Ins); + } + + public static string ProtobufPreDecorator(TType type) + { + if (type.IsNullable) + { + return "optional"; + } + else if (type.IsCollection) + { + if (type is TMap) + { + return ""; + } + else + { + return "repeated"; + } + } + else + { + return "required"; + } + } + + public static string ProtobufSuffixOptions(TType type) + { + if (type.IsCollection && !(type is TMap)) + { + return $"[packed = {(type.ElementType.Apply(IsProtobufPackedType.Ins) ? "true" : "false")}]"; + } + else + { + return ""; + } + } + public static bool HasTag(dynamic obj, string attrName) { return obj.HasTag(attrName); diff --git a/src/Luban.Job.Common/Source/ELanguage.cs b/src/Luban.Job.Common/Source/ELanguage.cs index e36115a..3600150 100644 --- a/src/Luban.Job.Common/Source/ELanguage.cs +++ b/src/Luban.Job.Common/Source/ELanguage.cs @@ -13,5 +13,6 @@ namespace Luban.Job.Common PYTHON, ERLANG, RUST, + PROTOBUF, } } diff --git a/src/Luban.Job.Common/Source/TypeVisitors/IsProtobufPackedType.cs b/src/Luban.Job.Common/Source/TypeVisitors/IsProtobufPackedType.cs new file mode 100644 index 0000000..462659d --- /dev/null +++ b/src/Luban.Job.Common/Source/TypeVisitors/IsProtobufPackedType.cs @@ -0,0 +1,71 @@ +using Luban.Job.Common.Types; +using Luban.Job.Common.TypeVisitors; + +namespace Luban.Job.Common.TypeVisitors +{ + public class IsProtobufPackedType : AllTrueVisitor + { + public static IsProtobufPackedType Ins { get; } = new(); + + + public override bool Accept(TString type) + { + return false; + } + + public override bool Accept(TText type) + { + return false; + } + + public override bool Accept(TBytes type) + { + return false; + } + + public override bool Accept(TVector2 type) + { + return false; + } + + public override bool Accept(TVector3 type) + { + return false; + } + + public override bool Accept(TVector4 type) + { + return false; + } + + public override bool Accept(TEnum type) + { + return false; + } + + public override bool Accept(TBean type) + { + return false; + } + + public override bool Accept(TArray type) + { + return false; + } + + public override bool Accept(TList type) + { + return false; + } + + public override bool Accept(TSet type) + { + return false; + } + + public override bool Accept(TMap type) + { + return false; + } + } +} diff --git a/src/Luban.Job.Common/Source/TypeVisitors/ProtobufTypeNameVisitor.cs b/src/Luban.Job.Common/Source/TypeVisitors/ProtobufTypeNameVisitor.cs new file mode 100644 index 0000000..e862423 --- /dev/null +++ b/src/Luban.Job.Common/Source/TypeVisitors/ProtobufTypeNameVisitor.cs @@ -0,0 +1,130 @@ +using Luban.Job.Common.Types; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Common.TypeVisitors +{ + public class ProtobufTypeNameVisitor : ITypeFuncVisitor + { + public static ProtobufTypeNameVisitor Ins { get; } = new(); + + public string Accept(TBool type) + { + return "bool"; + } + + public string Accept(TByte type) + { + return "int32"; + } + + public string Accept(TShort type) + { + return "int32"; + } + + public string Accept(TFshort type) + { + return "int32"; + } + + public string Accept(TInt type) + { + return "int32"; + } + + public string Accept(TFint type) + { + return "sfixed32"; + } + + public string Accept(TLong type) + { + return "int64"; + } + + public string Accept(TFlong type) + { + return "sfixed64"; + } + + public string Accept(TFloat type) + { + return "float"; + } + + public string Accept(TDouble type) + { + return "double"; + } + + public string Accept(TEnum type) + { + return type.DefineEnum.PbFullName; + } + + public string Accept(TString type) + { + return "string"; + } + + public string Accept(TText type) + { + return "string"; + } + + public string Accept(TBytes type) + { + return "bytes"; + } + + public string Accept(TVector2 type) + { + return "Vector2"; + } + + public string Accept(TVector3 type) + { + return "Vector3"; + } + + public string Accept(TVector4 type) + { + return "Vector4"; + } + + public string Accept(TDateTime type) + { + return "int32"; + } + + public string Accept(TBean type) + { + return type.Bean.GoFullName; + } + + public string Accept(TArray type) + { + return $"{type.ElementType.Apply(this)}"; + } + + public string Accept(TList type) + { + return $"{type.ElementType.Apply(this)}"; + } + + public string Accept(TSet type) + { + return $"{type.ElementType.Apply(this)}"; + } + + public string Accept(TMap type) + { + string key = type.KeyType is TEnum ? "int32" : (type.KeyType.Apply(this)); + return $"map<{key}, {type.ValueType.Apply(this)}>"; + } + } +} diff --git a/src/Luban.Job.Common/Source/TypeVisitors/ProtobufWireTypeVisitor.cs b/src/Luban.Job.Common/Source/TypeVisitors/ProtobufWireTypeVisitor.cs new file mode 100644 index 0000000..5b8c511 --- /dev/null +++ b/src/Luban.Job.Common/Source/TypeVisitors/ProtobufWireTypeVisitor.cs @@ -0,0 +1,131 @@ +using Google.Protobuf; +using Luban.Job.Common.Types; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Common.TypeVisitors +{ + public class ProtobufWireTypeVisitor : ITypeFuncVisitor + { + public static ProtobufWireTypeVisitor Ins { get; } = new(); + + public WireFormat.WireType Accept(TBool type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TByte type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TShort type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TFshort type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TInt type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TFint type) + { + return WireFormat.WireType.Fixed32; + } + + public WireFormat.WireType Accept(TLong type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TFlong type) + { + return WireFormat.WireType.Fixed64; + } + + public WireFormat.WireType Accept(TFloat type) + { + return WireFormat.WireType.Fixed32; + } + + public WireFormat.WireType Accept(TDouble type) + { + return WireFormat.WireType.Fixed64; + } + + public WireFormat.WireType Accept(TEnum type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TString type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TText type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TBytes type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TVector2 type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TVector3 type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TVector4 type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TDateTime type) + { + return WireFormat.WireType.Varint; + } + + public WireFormat.WireType Accept(TBean type) + { + return WireFormat.WireType.LengthDelimited; + } + + public WireFormat.WireType Accept(TArray type) + { + //return WireFormat.WireType.LengthDelimited; + throw new System.NotSupportedException(); + } + + public WireFormat.WireType Accept(TList type) + { + throw new System.NotSupportedException(); + } + + public WireFormat.WireType Accept(TSet type) + { + throw new System.NotSupportedException(); + } + + public WireFormat.WireType Accept(TMap type) + { + return WireFormat.WireType.LengthDelimited; + } + } +} diff --git a/src/Luban.Job.Common/Source/Types/TArray.cs b/src/Luban.Job.Common/Source/Types/TArray.cs index a4a16b4..32041d7 100644 --- a/src/Luban.Job.Common/Source/Types/TArray.cs +++ b/src/Luban.Job.Common/Source/Types/TArray.cs @@ -12,7 +12,7 @@ namespace Luban.Job.Common.Types return new TArray(isNullable, tags, elementType); } - public TType ElementType { get; } + public override TType ElementType { get; } private TArray(bool isNullable, Dictionary tags, TType elementType) : base(isNullable, tags) { diff --git a/src/Luban.Job.Common/Source/Types/TList.cs b/src/Luban.Job.Common/Source/Types/TList.cs index d672998..403b577 100644 --- a/src/Luban.Job.Common/Source/Types/TList.cs +++ b/src/Luban.Job.Common/Source/Types/TList.cs @@ -12,7 +12,7 @@ namespace Luban.Job.Common.Types return new TList(isNullable, tags, elementType, isArrayList); } - public TType ElementType { get; } + public override TType ElementType { get; } public bool IsArrayList { get; } diff --git a/src/Luban.Job.Common/Source/Types/TSet.cs b/src/Luban.Job.Common/Source/Types/TSet.cs index 22979f1..3f537ce 100644 --- a/src/Luban.Job.Common/Source/Types/TSet.cs +++ b/src/Luban.Job.Common/Source/Types/TSet.cs @@ -12,7 +12,7 @@ namespace Luban.Job.Common.Types return new TSet(isNullable, tags, elementType, isOrdered); } - public TType ElementType { get; } + public override TType ElementType { get; } public bool IsOrderSet { get; } diff --git a/src/Luban.Job.Common/Source/Types/TType.cs b/src/Luban.Job.Common/Source/Types/TType.cs index b31174b..64e6dd9 100644 --- a/src/Luban.Job.Common/Source/Types/TType.cs +++ b/src/Luban.Job.Common/Source/Types/TType.cs @@ -42,6 +42,8 @@ namespace Luban.Job.Common.Types public virtual bool IsBean => false; + public virtual TType ElementType => null; + public abstract void Apply(ITypeActionVisitor visitor, T x); public abstract void Apply(ITypeActionVisitor visitor, T1 x, T2 y); public abstract TR Apply(ITypeFuncVisitor visitor); diff --git a/src/Luban.Job.Common/Source/Utils/DefUtil.cs b/src/Luban.Job.Common/Source/Utils/DefUtil.cs index 62cbfd4..c8a2603 100644 --- a/src/Luban.Job.Common/Source/Utils/DefUtil.cs +++ b/src/Luban.Job.Common/Source/Utils/DefUtil.cs @@ -173,6 +173,7 @@ namespace Luban.Job.Common.Utils case ELanguage.TYPESCRIPT: case ELanguage.PYTHON: case ELanguage.RUST: + case ELanguage.PROTOBUF: #if !LUBAN_LITE return System.Web.HttpUtility.HtmlEncode(comment).Replace("\n", "
"); #else diff --git a/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs b/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs index 9107143..407a49b 100644 --- a/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs +++ b/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs @@ -18,6 +18,7 @@ namespace Luban.Job.Common.Utils case ELanguage.JS: return fullName + ".js"; case ELanguage.TYPESCRIPT: return fullName.Replace('.', '/') + ".ts"; case ELanguage.RUST: return fullName.Replace('.', '_') + ".rs"; + case ELanguage.PROTOBUF: return fullName.Replace('.', '_') + ".pb"; default: throw new NotSupportedException(); } @@ -71,6 +72,7 @@ namespace Luban.Job.Common.Utils { "javascript", ELanguage.JS }, { "erlang", ELanguage.ERLANG }, { "rust", ELanguage.RUST }, + { "pb", ELanguage.PROTOBUF }, }; public static ELanguage GetLanguage(string genType) @@ -96,6 +98,7 @@ namespace Luban.Job.Common.Utils { "erlang", "erl" }, { "erl", "erl" }, { "xlsx", "xlsx" }, + { "protobuf", "pb" }, }; public static string GetOutputFileSuffix(string genType) diff --git a/src/Luban.Server/Luban.Server.csproj b/src/Luban.Server/Luban.Server.csproj index ec2b479..2d4a1b8 100644 --- a/src/Luban.Server/Luban.Server.csproj +++ b/src/Luban.Server/Luban.Server.csproj @@ -61,6 +61,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -163,6 +166,18 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Luban.Server/Templates/common/pb/enum.tpl b/src/Luban.Server/Templates/common/pb/enum.tpl new file mode 100644 index 0000000..39467e9 --- /dev/null +++ b/src/Luban.Server/Templates/common/pb/enum.tpl @@ -0,0 +1,15 @@ +{{~ + name = x.name + namespace_with_top_module = x.namespace_with_top_module + comment = x.comment + items = x.items +~}} + +enum {{x.pb_full_name}} { + {{~for item in items ~}} + {{x.pb_full_name}}_{{item.name}} = {{item.int_value}}; + {{~end~}} + {{~if items.empty?~}} + {{x.pb_full_name}}_EMPTY_PLACEHOLDER = 0; + {{~end~}} +} \ No newline at end of file diff --git a/src/Luban.Server/Templates/config/pb2/all.tpl b/src/Luban.Server/Templates/config/pb2/all.tpl new file mode 100644 index 0000000..27aa13c --- /dev/null +++ b/src/Luban.Server/Templates/config/pb2/all.tpl @@ -0,0 +1,33 @@ +syntax = "proto2"; +// luban internal types begin +message Vector2 { + required float x = 1; + required float y = 2; +} + +message Vector3 { + required float x = 1; + required float y = 2; + required float z = 3; +} + +message Vector4 { + required float x = 1; + required float y = 2; + required float z = 3; + required float w = 4; +} +// luban internal types end + +{{~for enum in x.enums ~}} +{{enum}} +{{~end~}} + +{{~for bean in x.beans~}} +{{bean}} +{{~end~}} + +{{~for table in x.tables~}} +{{table}} +{{~end~}} + diff --git a/src/Luban.Server/Templates/config/pb2/bean.tpl b/src/Luban.Server/Templates/config/pb2/bean.tpl new file mode 100644 index 0000000..b961331 --- /dev/null +++ b/src/Luban.Server/Templates/config/pb2/bean.tpl @@ -0,0 +1,20 @@ +{{~ + name = x.name + parent_def_type = x.parent_def_type + export_fields = x.export_fields + hierarchy_export_fields = x.hierarchy_export_fields +~}} + +message {{x.pb_full_name}} { +{{~if x.is_abstract_type ~}} + oneof value { + {{~for c in x.hierarchy_not_abstract_children~}} + {{c.pb_full_name}} {{c.name}} = {{c.auto_id}}; + {{~end~}} + } +{{~else~}} + {{~for f in hierarchy_export_fields ~}} + {{protobuf_pre_decorator f.ctype}} {{protobuf_define_type f.ctype}} {{f.name}} = {{f.auto_id}} {{protobuf_suffix_options f.ctype}}; + {{~end~}} +{{~end~}} +} \ No newline at end of file diff --git a/src/Luban.Server/Templates/config/pb2/table.tpl b/src/Luban.Server/Templates/config/pb2/table.tpl new file mode 100644 index 0000000..36d1699 --- /dev/null +++ b/src/Luban.Server/Templates/config/pb2/table.tpl @@ -0,0 +1,9 @@ +{{~ + name = x.name + key_type = x.key_ttype + value_type = x.value_ttype +~}} + +message {{x.pb_full_name}} { + repeated {{protobuf_define_type value_type}} data_list = 1 [packed = false]; +} \ No newline at end of file diff --git a/src/Luban.Server/Templates/config/pb2/tables.tpl b/src/Luban.Server/Templates/config/pb2/tables.tpl new file mode 100644 index 0000000..8fd56d8 --- /dev/null +++ b/src/Luban.Server/Templates/config/pb2/tables.tpl @@ -0,0 +1,13 @@ +{{~ + name = x.name + namespace = x.namespace + tables = x.tables +~}} + +message {{name}} { +{{~index = 0~}} +{{~for table in tables~}} + {{~index = index + 1~}} + {{table.pb_full_name}} {{name}} = {{index}}; +{{~end~}} +}