Skip to content

Commit 83e3ecc

Browse files
authored
feat: add command to generate C# code (#22)
* add generate gogs csharp code command * add the flag for the csharp that only generate part of the code * add lib for unity protobuf * fix on listener name is not generated * fix csharp template generate error * fix lint error
1 parent 6483c86 commit 83e3ecc

File tree

22 files changed

+1715
-8
lines changed

22 files changed

+1715
-8
lines changed

bin/csharp/Google.Protobuf.dll

438 KB
Binary file not shown.

bin/csharp/System.Buffers.dll

27.2 KB
Binary file not shown.

bin/csharp/System.Memory.dll

141 KB
Binary file not shown.
23 KB
Binary file not shown.

proto/common.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package proto;
3+
package gogs;
44
option go_package = "/proto";
55

66

tools/gogs/cmd/csharp.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/metagogs/gogs/tools/gogs/csharp"
8+
"github.com/pterm/pterm"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func init() {
13+
RootCmd.AddCommand(csharpCmd)
14+
csharpCmd.Flags().StringVarP(&protoFile, "file", "f", "", "proto file")
15+
csharpCmd.Flags().BoolVarP(&gogsFiles, "gogs", "g", false, "should generate gogs framework code")
16+
}
17+
18+
var csharpCmd = &cobra.Command{
19+
Use: "csharp",
20+
Short: "generate csharp code",
21+
Long: ``,
22+
Run: func(cmd *cobra.Command, args []string) {
23+
if len(protoFile) == 0 {
24+
pterm.Error.Printfln("proto file is empty")
25+
os.Exit(1)
26+
}
27+
28+
fmt.Println(gogsFiles)
29+
gen, err := csharp.NewCSharpGen(protoFile, gogsFiles)
30+
if err != nil {
31+
fmt.Println(err)
32+
}
33+
_ = gen.Generate()
34+
},
35+
}

tools/gogs/cmd/flags.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package cmd
2+
3+
var (
4+
protoFile string
5+
gogsFiles bool
6+
)

tools/gogs/cmd/proto.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@ import (
1010
"github.com/spf13/cobra"
1111
)
1212

13-
var (
14-
protoFile string
15-
)
16-
1713
func init() {
1814
RootCmd.AddCommand(protoCmd)
19-
protoCmd.Flags().StringVarP(&protoFile, "file", "f", "", "proto文件")
15+
protoCmd.Flags().StringVarP(&protoFile, "file", "f", "", "proto file")
2016
}
2117

2218
var protoCmd = &cobra.Command{

tools/gogs/csharp/gen.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package csharp
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/emicklei/proto"
8+
"github.com/metagogs/gogs/packet"
9+
"github.com/metagogs/gogs/tools/gogs/csharp/gentemplate"
10+
"github.com/metagogs/gogs/tools/gogs/protoparse"
11+
"github.com/metagogs/gogs/utils/execx"
12+
"github.com/metagogs/gogs/utils/templatex"
13+
"github.com/pterm/pterm"
14+
)
15+
16+
type Components struct {
17+
Components []*Component
18+
}
19+
20+
type Component struct {
21+
Name string
22+
Index int
23+
BasePackage string
24+
Fields []*Field
25+
}
26+
27+
type Field struct {
28+
ComponentName string
29+
ComponentIndex int
30+
BasePackage string
31+
Package string
32+
Name string
33+
Index int
34+
ServerMessage bool
35+
Action10 string //action 10进制
36+
Action16 string //action 16进制
37+
}
38+
39+
type CSharpGen struct {
40+
proto protoparse.Proto
41+
protoFile string
42+
componets *Components
43+
messages map[string]protoparse.Message
44+
basePackage string
45+
Home string
46+
logicPath []string
47+
debugNoPb bool
48+
onlyCode bool //just generate code by proto exinclude gogs
49+
}
50+
51+
func NewCSharpGen(proto string, onlyCode bool) (*CSharpGen, error) {
52+
protoPrase, err := protoparse.NewProtoParser().Parse(proto)
53+
if err != nil {
54+
return nil, err
55+
}
56+
return &CSharpGen{
57+
protoFile: proto,
58+
proto: protoPrase,
59+
messages: make(map[string]protoparse.Message),
60+
onlyCode: onlyCode,
61+
}, nil
62+
}
63+
64+
func (g *CSharpGen) Generate() error {
65+
g.init()
66+
67+
if g.onlyCode {
68+
if err := g.gogs(); err != nil {
69+
return err
70+
}
71+
}
72+
73+
if err := g.register(); err != nil {
74+
return err
75+
}
76+
77+
return nil
78+
}
79+
80+
func (g *CSharpGen) init() {
81+
g.componets = new(Components)
82+
for _, m := range g.proto.Message {
83+
g.messages[m.Name] = m
84+
}
85+
//find components
86+
for _, m := range g.proto.Message {
87+
if m.Comment == nil {
88+
continue
89+
}
90+
if protoparse.CommentsContains(m.Comment.Lines, "@gogs:Components") {
91+
for _, e := range m.Elements {
92+
if v, ok := e.(*proto.NormalField); ok {
93+
com := g.parseComponent(v)
94+
g.componets.Components = append(g.componets.Components, com)
95+
}
96+
}
97+
}
98+
}
99+
100+
for _, c := range g.componets.Components {
101+
pterm.Success.Printf("Component: %s [%d]\n", c.Name, c.Index)
102+
for _, f := range c.Fields {
103+
pterm.Success.Printf(" Field: %s [%d][%v]\n", f.Name, f.Index, f.ServerMessage)
104+
}
105+
}
106+
}
107+
108+
func (g *CSharpGen) parseComponent(component *proto.NormalField) *Component {
109+
newCompoent := &Component{}
110+
newCompoent.Name = component.Name
111+
newCompoent.Index = component.Sequence
112+
newCompoent.BasePackage = g.basePackage
113+
114+
for _, e := range g.messages[component.Name].Elements {
115+
if v, ok := e.(*proto.NormalField); ok {
116+
data := &Field{}
117+
data.ComponentName = component.Name
118+
data.ComponentIndex = component.Sequence
119+
data.Name = v.Name
120+
data.Index = v.Sequence
121+
data.Package = g.proto.PbPackage
122+
data.BasePackage = g.basePackage
123+
//create action
124+
actionValue := packet.CreateAction(packet.ServicePacket, uint8(data.ComponentIndex), uint16(data.Index))
125+
data.Action10 = fmt.Sprint(actionValue)
126+
data.Action16 = fmt.Sprintf("0x%x", actionValue)
127+
if g.messages[v.Name].Comment != nil {
128+
if protoparse.CommentsContains(g.messages[v.Name].Comment.Lines, "@gogs:ServerMessage") {
129+
data.ServerMessage = true
130+
}
131+
}
132+
133+
newCompoent.Fields = append(newCompoent.Fields, data)
134+
}
135+
}
136+
137+
return newCompoent
138+
139+
}
140+
141+
func (g *CSharpGen) gogs() error {
142+
if err := templatex.With("gogs").Parse(gentemplate.CodecTpl).SaveTo(nil, g.Home+"Gogs/Codec.cs", true); err != nil {
143+
pterm.Error.Printfln("generate file error Gogs/Codec.cs:" + err.Error())
144+
return err
145+
}
146+
if err := templatex.With("gogs").Parse(gentemplate.CommonTpl).SaveTo(nil, g.Home+"Gogs/Common.cs", true); err != nil {
147+
pterm.Error.Printfln("generate file error Gogs/Common.cs:" + err.Error())
148+
return err
149+
}
150+
if err := templatex.With("gogs").Parse(gentemplate.EventsManagerTpl).SaveTo(nil, g.Home+"Gogs/EventsManager.cs", true); err != nil {
151+
pterm.Error.Printfln("generate file error Gogs/EventsManager.cs:" + err.Error())
152+
return err
153+
}
154+
if err := templatex.With("gogs").Parse(gentemplate.ICodecTpl).SaveTo(nil, g.Home+"Gogs/ICodec.cs", true); err != nil {
155+
pterm.Error.Printfln("generate file error Gogs/ICodec.cs:" + err.Error())
156+
return err
157+
}
158+
if err := templatex.With("gogs").Parse(gentemplate.MessagesTpl).SaveTo(nil, g.Home+"Gogs/Messages.cs", true); err != nil {
159+
pterm.Error.Printfln("generate file error Gogs/Messages.cs:" + err.Error())
160+
return err
161+
}
162+
if err := templatex.With("gogs").Parse(gentemplate.PacketTpl).SaveTo(nil, g.Home+"Gogs/Packet.cs", true); err != nil {
163+
pterm.Error.Printfln("generate file error Gogs/Packet.cs:" + err.Error())
164+
return err
165+
}
166+
167+
return nil
168+
}
169+
170+
func (g *CSharpGen) register() error {
171+
out := "Model"
172+
if len(g.Home) > 0 {
173+
out = g.Home + "Model"
174+
}
175+
if !g.debugNoPb {
176+
_ = os.MkdirAll(out, os.ModePerm)
177+
protocCmd := fmt.Sprintf("protoc --csharp_out=%s %s", out, g.protoFile)
178+
if _, err := execx.Exec(protocCmd); err != nil {
179+
fmt.Println(err.Error())
180+
pterm.Error.Println("run protoc error " + err.Error())
181+
return err
182+
}
183+
184+
}
185+
186+
data := map[string]interface{}{}
187+
data["Package"] = g.proto.PbPackage
188+
data["Components"] = g.componets.Components
189+
190+
if err := templatex.With("gogs").Parse(gentemplate.RegisterTpl).SaveTo(data, g.Home+"Model/Register.cs", true); err != nil {
191+
pterm.Error.Printfln("generate file error Model/Register.cs:" + err.Error())
192+
return err
193+
}
194+
195+
return nil
196+
}

tools/gogs/csharp/gen_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package csharp
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/metagogs/gogs/utils/filex"
8+
)
9+
10+
func TestNewGen(t *testing.T) {
11+
type args struct {
12+
proto string
13+
onlyCode bool
14+
}
15+
tests := []struct {
16+
name string
17+
args args
18+
wantErr bool
19+
}{
20+
{
21+
name: "new gen",
22+
args: args{
23+
proto: "testdata/data.proto",
24+
onlyCode: false,
25+
},
26+
wantErr: false,
27+
},
28+
}
29+
for _, tt := range tests {
30+
t.Run(tt.name, func(t *testing.T) {
31+
g, err := NewCSharpGen(tt.args.proto, tt.args.onlyCode)
32+
g.Home = "test/"
33+
if (err != nil) != tt.wantErr {
34+
t.Errorf("NewGen() error = %v, wantErr %v", err, tt.wantErr)
35+
return
36+
}
37+
_ = g.Generate()
38+
if (err != nil) != tt.wantErr {
39+
t.Errorf("NewGen() error = %v, wantErr %v", err, tt.wantErr)
40+
return
41+
}
42+
43+
var haveErr bool
44+
if ok := filex.IsFileEqual("testdata/Model/Register.cs", "test/Model/Register.cs"); !ok {
45+
t.Errorf("Init.Generate() error = %s is not equal to %s", "test/Model/Register.cs", "testdata/Model/Register.cs")
46+
haveErr = true
47+
}
48+
49+
if !haveErr {
50+
_ = os.RemoveAll("test")
51+
}
52+
})
53+
}
54+
}

0 commit comments

Comments
 (0)