Skip to content

Commit f6aea67

Browse files
committed
feat: generate events automatically
1 parent 0669240 commit f6aea67

13 files changed

+2338
-79
lines changed

apigen/api_generate.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,21 @@ func GenerateAPI(ctx context.Context, clientOutput, eventsOutput io.Writer) erro
2828
msgIds := getSortedMsgIDs()
2929
var requestFuncs []*generatedRequestFunc
3030

31+
eventsImports := make(map[string]struct{})
32+
eventsImports["github.com/paralin/go-dota2/protocol/dota_gcmessages_msgid"] = struct{}{}
33+
eventsImports["github.com/golang/protobuf/proto"] = struct{}{}
34+
3135
clientImports := make(map[string]struct{})
3236
clientImports["context"] = struct{}{}
3337
clientImports["github.com/paralin/go-dota2/protocol/dota_shared_enums"] = struct{}{}
3438
clientImports["github.com/faceit/go-steam/steamid"] = struct{}{}
3539
clientImports["github.com/paralin/go-dota2/protocol/dota_gcmessages_msgid"] = struct{}{}
36-
37-
eventsImports := make(map[string]struct{})
38-
eventsImports["context"] = struct{}{}
40+
clientImports["github.com/paralin/go-dota2/events"] = struct{}{}
3941

4042
// responseMsgs are messages that are known to be responses.
4143
responseMsgs := make(map[gcm.EDOTAGCMsg]struct{})
4244
eventHandlers := make(map[gcm.EDOTAGCMsg]*generatedEventHandler)
45+
var eventHandlersOrdered []*generatedEventHandler
4346

4447
for _, msgID := range msgIds {
4548
sender := GetMessageSender(msgID)
@@ -71,19 +74,19 @@ func GenerateAPI(ctx context.Context, clientOutput, eventsOutput io.Writer) erro
7174
}
7275

7376
eventHandlers[msgID] = eventHandler
77+
eventHandlersOrdered = append(eventHandlersOrdered, eventHandler)
7478
}
7579
}
7680

77-
sort.Slice(requestFuncs, func(i int, j int) bool {
78-
return requestFuncs[i].methodName < requestFuncs[j].methodName
79-
})
80-
8181
for pakPath := range clientImports {
8282
fmt.Fprintf(clientOutput, "\t\"%s\"\n", pakPath)
8383
}
84-
8584
fmt.Fprintf(clientOutput, ")\n")
8685

86+
sort.Slice(requestFuncs, func(i int, j int) bool {
87+
return requestFuncs[i].methodName < requestFuncs[j].methodName
88+
})
89+
8790
steamIDFieldOverrides := make(map[string]string)
8891
for _, f := range requestFuncs {
8992
fmt.Fprintf(clientOutput, "\n// %s\n", f.generateComment())
@@ -243,6 +246,55 @@ func GenerateAPI(ctx context.Context, clientOutput, eventsOutput io.Writer) erro
243246
fmt.Fprintf(clientOutput, "}\n")
244247
}
245248

249+
sort.Slice(eventHandlersOrdered, func(i int, j int) bool {
250+
return eventHandlersOrdered[i].eventName < eventHandlersOrdered[j].eventName
251+
})
252+
253+
fmt.Fprintf(clientOutput, "\n// registerGeneratedHandlers registers the auto-generated event handlers.\n")
254+
fmt.Fprintf(clientOutput, "func (d *Dota2) registerGeneratedHandlers() {\n")
255+
256+
fmt.Fprintf(eventsOutput, "package events\n\nimport (\n")
257+
for pakPath := range eventsImports {
258+
fmt.Fprintf(eventsOutput, "\t\"%s\"\n", pakPath)
259+
}
260+
fmt.Fprintf(eventsOutput, ")\n")
261+
262+
fmt.Fprintf(eventsOutput, "\n\n// Event is a DOTA event.\ntype Event interface {\n")
263+
fmt.Fprintf(eventsOutput, "\t// GetDotaEventMsgID returns the DOTA event message ID.\n")
264+
fmt.Fprintf(eventsOutput, "\tGetDotaEventMsgID() dota_gcmessages_msgid.EDOTAGCMsg\n")
265+
fmt.Fprintf(eventsOutput, "\t// GetEventBody event body.\n")
266+
fmt.Fprintf(eventsOutput, "\tGetEventBody() proto.Message\n")
267+
fmt.Fprintf(eventsOutput, "}\n")
268+
269+
for _, eventHandler := range eventHandlersOrdered {
270+
fmt.Fprintf(eventsOutput, "\n")
271+
fmt.Fprintf(eventsOutput, eventHandler.generateComment())
272+
fmt.Fprintf(eventsOutput, "type %s struct {\n", eventHandler.eventName)
273+
fmt.Fprintf(eventsOutput, "\t")
274+
if err := printFieldType(eventsOutput, eventHandler.eventType.Obj.Type()); err != nil {
275+
return err
276+
}
277+
fmt.Fprintf(eventsOutput, "\n}\n")
278+
279+
fmt.Fprintf(eventsOutput, "\n// GetDotaEventMsgID returns the dota message ID of the event.\n")
280+
fmt.Fprintf(eventsOutput, "func (e *%s) GetDotaEventMsgID() dota_gcmessages_msgid.EDOTAGCMsg {\n", eventHandler.eventName)
281+
fmt.Fprintf(eventsOutput, "\treturn dota_gcmessages_msgid.EDOTAGCMsg_%s\n", eventHandler.msgID.String())
282+
fmt.Fprintf(eventsOutput, "}\n")
283+
284+
fmt.Fprintf(eventsOutput, "\n// GetEventBody returns the event body.\n")
285+
fmt.Fprintf(eventsOutput, "func (e *%s) GetEventBody() proto.Message {\n", eventHandler.eventName)
286+
fmt.Fprintf(eventsOutput, "\treturn &e.%s\n", eventHandler.eventType.TypeName)
287+
fmt.Fprintf(eventsOutput, "}\n")
288+
289+
fmt.Fprintf(
290+
clientOutput,
291+
"\td.handlers[uint32(dota_gcmessages_msgid.EDOTAGCMsg_%s)] = d.getEventEmitter(func() events.Event {\n",
292+
eventHandler.msgID.String(),
293+
)
294+
fmt.Fprintf(clientOutput, "\t\treturn &events.%s{}\n\t})\n", eventHandler.eventName)
295+
}
296+
297+
fmt.Fprintf(clientOutput, "}\n")
246298
return nil
247299
}
248300

apigen/api_generate_event.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package main
22

33
import (
4+
"fmt"
5+
46
gcm "github.com/paralin/go-dota2/protocol/dota_gcmessages_msgid"
57
)
68

@@ -28,3 +30,7 @@ func buildGeneratedEventHandler(
2830
eventType: eventProtoType,
2931
}, nil
3032
}
33+
34+
func (g *generatedEventHandler) generateComment() string {
35+
return fmt.Sprintf("// %s event.\n// MessageID: %s\n", g.eventName, g.msgID.String())
36+
}

apigen/api_generate_func.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,15 @@ func (f *generatedRequestFunc) generateComment() string {
115115
)
116116
}
117117

118-
return fmt.Sprintf("%s %s", f.methodName, purpose)
118+
acA := "// Request ID: " + f.reqMsgID.String()
119+
if f.respMsgID != 0 {
120+
acA += "\n// Response ID: " + f.respMsgID.String()
121+
}
122+
123+
acB := "// Request type: " + f.reqType.Name()
124+
if f.respMsgID != 0 {
125+
acB += "\n// Response type: " + f.respType.Name()
126+
}
127+
128+
return fmt.Sprintf("%s %s\n%s\n%s", f.methodName, purpose, acA, acB)
119129
}

apigen/cmd_generate.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,27 @@ func init() {
4343

4444
clientFileDat, err := gofmt.Source(clientFileBuf.Bytes())
4545
if err != nil {
46-
return err
46+
clientFileDat = clientFileBuf.Bytes()
4747
}
4848

4949
if err := ioutil.WriteFile(clientOutFile, clientFileDat, 0655); err != nil {
5050
return err
5151
}
5252

53-
/*
54-
eventsFileDat, err := gofmt.Source(eventsFileBuf.Bytes())
55-
if err != nil {
56-
return err
57-
}
53+
if err != nil {
54+
return err
55+
}
5856

59-
if err := ioutil.WriteFile(eventsOutFile, eventsFileDat, 0655); err != nil {
60-
return err
61-
}
62-
*/
57+
eventsFileDat, err := gofmt.Source(eventsFileBuf.Bytes())
58+
if err != nil {
59+
eventsFileDat = eventsFileBuf.Bytes()
60+
}
61+
62+
if err := ioutil.WriteFile(eventsOutFile, eventsFileDat, 0655); err != nil {
63+
return err
64+
}
6365

64-
return nil
66+
return err
6567
},
6668
})
6769
}

apigen/msg_event.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

apigen/msg_event_name.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ import (
88

99
// GetMessageEventName returns the event name for the message.
1010
func GetMessageEventName(msg dota_gcmessages_msgid.EDOTAGCMsg) string {
11+
if over, ok := msgEventNameOverrides[msg]; ok {
12+
return over
13+
}
14+
1115
msgName := msg.String()
1216
msgName = strings.TrimPrefix(msgName, "k_EMsg")
1317
msgName = strings.TrimPrefix(msgName, "GC")
1418
msgName = strings.TrimPrefix(msgName, "ToClient")
19+
msgName = strings.Replace(msgName, "_", "", -1)
1520
return msgName
1621
}

apigen/msg_overrides.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ var msgSenderOverrides = map[dm.EDOTAGCMsg]MsgSender{
2525
dm.EDOTAGCMsg_k_EMsgGCSuggestTeamMatchmaking: MsgSenderNone,
2626
dm.EDOTAGCMsg_k_EMsgGCUpdateClippy: MsgSenderNone,
2727

28+
dm.EDOTAGCMsg_k_EMsgClientsRejoinChatChannels: MsgSenderClient,
29+
2830
dm.EDOTAGCMsg_k_EMsgGCConsumeFantasyTicket: MsgSenderNone,
2931
dm.EDOTAGCMsg_k_EMsgGCConsumeFantasyTicketFailure: MsgSenderNone,
3032

@@ -162,6 +164,13 @@ var msgSenderOverrides = map[dm.EDOTAGCMsg]MsgSender{
162164

163165
dm.EDOTAGCMsg_k_EMsgGCToClientLobbyMVPNotifyRecipient: MsgSenderGC,
164166
dm.EDOTAGCMsg_k_EMsgGCToClientLobbyMVPAwarded: MsgSenderGC,
167+
168+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_InviterToGC: MsgSenderClient,
169+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCImmediateResponseToInviter: MsgSenderGC,
170+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCRequestToInvitee: MsgSenderGC,
171+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_InviteeResponseToGC: MsgSenderClient,
172+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCResponseToInvitee: MsgSenderClient,
173+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCResponseToInviter: MsgSenderGC,
165174
}
166175

167176
// msgMethodNameOverrides overrides the generated client method names.
@@ -184,6 +193,9 @@ var msgMethodNameOverrides = map[dm.EDOTAGCMsg]string{
184193
dm.EDOTAGCMsg_k_EMsgGCPracticeLobbyKick: "KickLobbyMember",
185194
dm.EDOTAGCMsg_k_EMsgGCPracticeLobbyKickFromTeam: "KickLobbyMemberFromTeam",
186195
dm.EDOTAGCMsg_k_EMsgGCBotGameCreate: "CreateBotGame",
196+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_InviterToGC: "InvitePlayerToTeam",
197+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_InviteeResponseToGC: "RespondToTeamInvite",
198+
dm.EDOTAGCMsg_k_EMsgClientsRejoinChatChannels: "RejoinAllChatChannels",
187199
}
188200

189201
// msgResponseOverrides maps request message IDs to response message IDs.
@@ -193,6 +205,9 @@ var msgResponseOverrides = map[dm.EDOTAGCMsg]dm.EDOTAGCMsg{
193205
// dm.EDOTAGCMsg_k_EMsgClientToGCCreatePlayerCardPack: dm.EDOTAGCMsg_k_EMsgClientToGCCreatePlayerCardPackResponse,
194206
dm.EDOTAGCMsg_k_EMsgGCNotificationsMarkReadRequest: 0,
195207
dm.EDOTAGCMsg_k_EMsgClientToGCMyTeamInfoRequest: dm.EDOTAGCMsg_k_EMsgGCToClientTeamInfo,
208+
209+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_InviterToGC: dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCImmediateResponseToInviter,
210+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_InviteeResponseToGC: dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCResponseToInvitee,
196211
}
197212

198213
// msgProtoTypeOverrides overrides the GC message to proto mapping.
@@ -268,3 +283,8 @@ var msgProtoTypeOverrides = map[dm.EDOTAGCMsg]proto.Message{
268283
var msgArgAsParameterOverrides = map[dm.EDOTAGCMsg]bool{
269284
dm.EDOTAGCMsg_k_EMsgGCPracticeLobbySetDetails: true,
270285
}
286+
287+
var msgEventNameOverrides = map[dm.EDOTAGCMsg]string{
288+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCRequestToInvitee: "TeamInviteReceived",
289+
dm.EDOTAGCMsg_k_EMsgGCTeamInvite_GCResponseToInviter: "TeamInviteResponseReceived",
290+
}

apigen/msg_verb.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,52 +8,53 @@ var verbs = make(map[string]struct{})
88

99
func init() {
1010
verbList := []string{
11-
"Find",
12-
"Publish",
13-
"Retrieve",
14-
"Cancel",
11+
"Abandon",
12+
"Apply",
1513
"Autograph",
16-
"Destroy",
1714
"Award",
15+
"Cancel",
1816
"Close",
19-
"Send",
20-
"Kick",
2117
"Create",
18+
"Demote",
19+
"Destroy",
2220
"Edit",
21+
"Find",
2322
"Flip",
2423
"Get",
25-
"Redeem",
26-
"Record",
27-
"Recycle",
28-
"Refresh",
29-
"Track",
30-
"Upgrade",
31-
"Vote",
32-
"Reroll",
33-
"Promote",
34-
"Demote",
3524
"Give",
3625
"Grant",
3726
"Join",
38-
"List",
27+
"Kick",
3928
"Launch",
40-
"Purchase",
41-
"Abandon",
4229
"Leave",
30+
"List",
4331
"Open",
32+
"Promote",
33+
"Publish",
34+
"Purchase",
4435
"Query",
36+
"Record",
37+
"Recycle",
38+
"Redeem",
39+
"Refresh",
4540
"Release",
4641
"Report",
4742
"Request",
43+
"Reroll",
4844
"Reserve",
45+
"Retrieve",
4946
"Select",
47+
"Send",
5048
"Set",
5149
"Spectate",
5250
"Start",
5351
"Submit",
5452
"Swap",
5553
"Toggle",
54+
"Track",
5655
"Transfer",
56+
"Upgrade",
57+
"Vote",
5758
}
5859
for _, v := range verbList {
5960
verbs[strings.ToLower(v)] = struct{}{}

client.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ func (d *Dota2) buildHandlerMap() {
9393
// System events
9494
uint32(gcsm.EGCBaseClientMsg_k_EMsgGCPingRequest): d.handlePingRequest,
9595
}
96+
97+
d.registerGeneratedHandlers()
9698
}
9799

98100
// write sends a message to the game coordinator.
@@ -165,3 +167,16 @@ func (d *Dota2) handlePingRequest(packet *gamecoordinator.GCPacket) error {
165167
d.write(uint32(gcsm.EGCBaseClientMsg_k_EMsgGCPingResponse), &gcsdkm.CMsgGCClientPing{})
166168
return nil
167169
}
170+
171+
// getEventEmitter returns a handler that emits an event, used by the generated code.
172+
func (d *Dota2) getEventEmitter(ctor func() devents.Event) func(packet *gamecoordinator.GCPacket) error {
173+
return func(packet *gamecoordinator.GCPacket) error {
174+
obj := ctor()
175+
if err := d.unmarshalBody(packet, obj.GetEventBody()); err != nil {
176+
return err
177+
}
178+
179+
d.emit(obj)
180+
return nil
181+
}
182+
}

0 commit comments

Comments
 (0)