Skip to content

Commit 6dc276e

Browse files
committed
user-messages: refactored similar to game-events
1 parent 489d6fb commit 6dc276e

File tree

5 files changed

+287
-78
lines changed

5 files changed

+287
-78
lines changed

demoinfocs_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ func TestUnexpectedEndOfDemo(t *testing.T) {
186186
}
187187

188188
func TestCancelParseToEnd(t *testing.T) {
189+
if testing.Short() {
190+
t.Skip("skipping test")
191+
}
192+
189193
f, err := os.Open(defaultDemPath)
190194
if err != nil {
191195
t.Fatal(err)

game_events.go

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -608,81 +608,3 @@ func getCommunityID(guid string) int64 {
608608
// WTF are we doing here?
609609
return valveMagicNumber + authID*2 + authSrv
610610
}
611-
612-
func (p *Parser) handleUserMessage(um *msg.CSVCMsg_UserMessage) {
613-
switch msg.ECstrike15UserMessages(um.MsgType) {
614-
case msg.ECstrike15UserMessages_CS_UM_SayText:
615-
st := new(msg.CCSUsrMsg_SayText)
616-
err := st.Unmarshal(um.MsgData)
617-
if err != nil {
618-
p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("Failed to decode SayText message: %s", err.Error())})
619-
}
620-
621-
p.eventDispatcher.Dispatch(events.SayText{
622-
EntIdx: int(st.EntIdx),
623-
IsChat: st.Chat,
624-
IsChatAll: st.Textallchat,
625-
Text: st.Text,
626-
})
627-
628-
case msg.ECstrike15UserMessages_CS_UM_SayText2:
629-
st := new(msg.CCSUsrMsg_SayText2)
630-
err := st.Unmarshal(um.MsgData)
631-
if err != nil {
632-
p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("Failed to decode SayText2 message: %s", err.Error())})
633-
}
634-
635-
p.eventDispatcher.Dispatch(events.SayText2{
636-
EntIdx: int(st.EntIdx),
637-
IsChat: st.Chat,
638-
IsChatAll: st.Textallchat,
639-
MsgName: st.MsgName,
640-
Params: st.Params,
641-
})
642-
643-
switch st.MsgName {
644-
case "Cstrike_Chat_All":
645-
fallthrough
646-
case "Cstrike_Chat_AllDead":
647-
var sender *common.Player
648-
for _, pl := range p.gameState.playersByUserID {
649-
// This could be a problem if the player changed his name
650-
// as the name is only set initially and never updated
651-
if pl.Name == st.Params[0] {
652-
sender = pl
653-
}
654-
}
655-
656-
p.eventDispatcher.Dispatch(events.ChatMessage{
657-
Sender: sender,
658-
Text: st.Params[1],
659-
IsChatAll: st.Textallchat,
660-
})
661-
662-
case "#CSGO_Coach_Join_T": // Ignore these
663-
case "#CSGO_Coach_Join_CT":
664-
665-
default:
666-
p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("Skipped sending ChatMessageEvent for SayText2 with unknown MsgName %q", st.MsgName)})
667-
}
668-
case msg.ECstrike15UserMessages_CS_UM_ServerRankUpdate:
669-
st := new(msg.CCSUsrMsg_ServerRankUpdate)
670-
err := st.Unmarshal(um.MsgData)
671-
if err != nil {
672-
p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("Failed to decode ServerRankUpdate message: %s", err.Error())})
673-
}
674-
675-
for _, v := range st.RankUpdate {
676-
p.eventDispatcher.Dispatch(events.RankUpdate{
677-
SteamID: int64(v.AccountId),
678-
RankOld: int(v.RankOld),
679-
RankNew: int(v.RankNew),
680-
WinCount: int(v.NumWins),
681-
RankChange: v.RankChange,
682-
})
683-
}
684-
default:
685-
// TODO: handle more user messages (if they are interesting)
686-
// Maybe msg.ECstrike15UserMessages_CS_UM_RadioText
687-
}
688-
}

parser.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type Parser struct {
4848
msgQueue chan interface{} // Queue of net-messages
4949
msgDispatcher dp.Dispatcher // Net-message dispatcher
5050
gameEventHandler gameEventHandler
51+
userMessageHandler userMessageHandler
5152
eventDispatcher dp.Dispatcher
5253
currentFrame int // Demo-frame, not ingame-tick
5354
header *common.DemoHeader // Pointer so we can check for nil
@@ -235,6 +236,7 @@ func NewParserWithConfig(demostream io.Reader, config ParserConfig) *Parser {
235236
p.gameState = newGameState()
236237
p.grenadeModelIndices = make(map[int]common.EquipmentElement)
237238
p.gameEventHandler = newGameEventHandler(&p)
239+
p.userMessageHandler = newUserMessageHandler(&p)
238240

239241
// Attach proto msg handlers
240242
p.msgDispatcher.RegisterHandler(p.handlePacketEntities)

user_messages.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package demoinfocs
2+
3+
import (
4+
"fmt"
5+
6+
events "github.com/markus-wa/demoinfocs-golang/events"
7+
msg "github.com/markus-wa/demoinfocs-golang/msg"
8+
)
9+
10+
func (p *Parser) handleUserMessage(um *msg.CSVCMsg_UserMessage) {
11+
p.userMessageHandler.handler(msg.ECstrike15UserMessages(um.MsgType))(um)
12+
}
13+
14+
type userMessageHandler struct {
15+
parser *Parser
16+
msgTypeToHandler map[msg.ECstrike15UserMessages]userMessageHandlerFunc
17+
}
18+
19+
func (umh userMessageHandler) handler(msgType msg.ECstrike15UserMessages) userMessageHandlerFunc {
20+
if handler, eventKnown := umh.msgTypeToHandler[msgType]; eventKnown {
21+
return handler
22+
}
23+
return func(*msg.CSVCMsg_UserMessage) { /* NOP */ }
24+
}
25+
26+
func (umh userMessageHandler) dispatch(event interface{}) {
27+
umh.parser.eventDispatcher.Dispatch(event)
28+
}
29+
30+
func (umh userMessageHandler) gameState() *GameState {
31+
return umh.parser.gameState
32+
}
33+
34+
type userMessageHandlerFunc func(*msg.CSVCMsg_UserMessage)
35+
36+
func newUserMessageHandler(parser *Parser) userMessageHandler {
37+
umh := userMessageHandler{parser: parser}
38+
39+
umh.msgTypeToHandler = map[msg.ECstrike15UserMessages]userMessageHandlerFunc{
40+
msg.ECstrike15UserMessages_CS_UM_SayText: umh.sayText,
41+
msg.ECstrike15UserMessages_CS_UM_SayText2: umh.sayText2,
42+
msg.ECstrike15UserMessages_CS_UM_ServerRankUpdate: umh.rankUpdate,
43+
// TODO: handle more user messages (if they are interesting)
44+
// Maybe msg.ECstrike15UserMessages_CS_UM_RadioText
45+
}
46+
47+
return umh
48+
}
49+
50+
func (umh userMessageHandler) sayText(um *msg.CSVCMsg_UserMessage) {
51+
st := new(msg.CCSUsrMsg_SayText)
52+
err := st.Unmarshal(um.MsgData)
53+
if err != nil {
54+
umh.dispatch(events.ParserWarn{Message: fmt.Sprintf("Failed to decode SayText message: %s", err.Error())})
55+
}
56+
57+
umh.dispatch(events.SayText{
58+
EntIdx: int(st.EntIdx),
59+
IsChat: st.Chat,
60+
IsChatAll: st.Textallchat,
61+
Text: st.Text,
62+
})
63+
}
64+
65+
func (umh userMessageHandler) sayText2(um *msg.CSVCMsg_UserMessage) {
66+
st := new(msg.CCSUsrMsg_SayText2)
67+
err := st.Unmarshal(um.MsgData)
68+
if err != nil {
69+
umh.dispatch(events.ParserWarn{Message: fmt.Sprintf("Failed to decode SayText2 message: %s", err.Error())})
70+
}
71+
72+
umh.dispatch(events.SayText2{
73+
EntIdx: int(st.EntIdx),
74+
IsChat: st.Chat,
75+
IsChatAll: st.Textallchat,
76+
MsgName: st.MsgName,
77+
Params: st.Params,
78+
})
79+
80+
switch st.MsgName {
81+
case "Cstrike_Chat_All":
82+
fallthrough
83+
case "Cstrike_Chat_AllDead":
84+
sender := umh.gameState().playersByEntityID[int(st.EntIdx)]
85+
86+
umh.dispatch(events.ChatMessage{
87+
Sender: sender,
88+
Text: st.Params[1],
89+
IsChatAll: st.Textallchat,
90+
})
91+
92+
case "#CSGO_Coach_Join_T": // Ignore these
93+
case "#CSGO_Coach_Join_CT":
94+
95+
default:
96+
umh.dispatch(events.ParserWarn{Message: fmt.Sprintf("Skipped sending ChatMessageEvent for SayText2 with unknown MsgName %q", st.MsgName)})
97+
}
98+
}
99+
100+
func (umh userMessageHandler) rankUpdate(um *msg.CSVCMsg_UserMessage) {
101+
st := new(msg.CCSUsrMsg_ServerRankUpdate)
102+
err := st.Unmarshal(um.MsgData)
103+
if err != nil {
104+
umh.dispatch(events.ParserWarn{Message: fmt.Sprintf("Failed to decode ServerRankUpdate message: %s", err.Error())})
105+
}
106+
107+
for _, v := range st.RankUpdate {
108+
umh.dispatch(events.RankUpdate{
109+
SteamID: int64(v.AccountId),
110+
RankOld: int(v.RankOld),
111+
RankNew: int(v.RankNew),
112+
WinCount: int(v.NumWins),
113+
RankChange: v.RankChange,
114+
})
115+
}
116+
}

user_messages_test.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package demoinfocs
2+
3+
import (
4+
"testing"
5+
6+
proto "github.com/gogo/protobuf/proto"
7+
assert "github.com/stretchr/testify/assert"
8+
9+
common "github.com/markus-wa/demoinfocs-golang/common"
10+
events "github.com/markus-wa/demoinfocs-golang/events"
11+
msg "github.com/markus-wa/demoinfocs-golang/msg"
12+
)
13+
14+
func Test_UserMessages_ServerRankUpdate(t *testing.T) {
15+
rankUpdate := &msg.CCSUsrMsg_ServerRankUpdate{
16+
RankUpdate: []*msg.CCSUsrMsg_ServerRankUpdate_RankUpdate{{
17+
AccountId: 123,
18+
RankOld: 1,
19+
RankNew: 2,
20+
NumWins: 5,
21+
RankChange: 1,
22+
}, {
23+
AccountId: 456,
24+
RankOld: 2,
25+
RankNew: 3,
26+
NumWins: 6,
27+
RankChange: 2,
28+
}},
29+
}
30+
userMessageData, err := proto.Marshal(rankUpdate)
31+
assert.Nil(t, err)
32+
um := &msg.CSVCMsg_UserMessage{
33+
MsgType: int32(msg.ECstrike15UserMessages_CS_UM_ServerRankUpdate),
34+
MsgData: userMessageData,
35+
}
36+
37+
p := NewParser(new(DevNullReader))
38+
var evs []events.RankUpdate
39+
p.RegisterEventHandler(func(update events.RankUpdate) {
40+
evs = append(evs, update)
41+
})
42+
43+
p.handleUserMessage(um)
44+
45+
expected := []events.RankUpdate{{
46+
SteamID: 123,
47+
RankOld: 1,
48+
RankNew: 2,
49+
WinCount: 5,
50+
RankChange: 1,
51+
}, {
52+
SteamID: 456,
53+
RankOld: 2,
54+
RankNew: 3,
55+
WinCount: 6,
56+
RankChange: 2,
57+
}}
58+
assert.Equal(t, expected, evs)
59+
}
60+
61+
func Test_UserMessages_SayText(t *testing.T) {
62+
sayText := &msg.CCSUsrMsg_SayText{
63+
EntIdx: 1,
64+
Text: "glhf",
65+
Chat: true,
66+
Textallchat: true,
67+
}
68+
userMessageData, err := proto.Marshal(sayText)
69+
assert.Nil(t, err)
70+
um := &msg.CSVCMsg_UserMessage{
71+
MsgType: int32(msg.ECstrike15UserMessages_CS_UM_SayText),
72+
MsgData: userMessageData,
73+
}
74+
75+
p := NewParser(new(DevNullReader))
76+
var actual events.SayText
77+
p.RegisterEventHandler(func(chat events.SayText) {
78+
actual = chat
79+
})
80+
81+
p.handleUserMessage(um)
82+
83+
expected := events.SayText{
84+
EntIdx: 1,
85+
IsChat: true,
86+
Text: "glhf",
87+
IsChatAll: true,
88+
}
89+
assert.Equal(t, expected, actual)
90+
}
91+
92+
func Test_UserMessages_SayText2_Generic(t *testing.T) {
93+
sayText2 := &msg.CCSUsrMsg_SayText2{
94+
EntIdx: 1,
95+
MsgName: "#CSGO_Coach_Join_T",
96+
Chat: true,
97+
Textallchat: true,
98+
Params: []string{"hi there", "hello"},
99+
}
100+
userMessageData, err := proto.Marshal(sayText2)
101+
assert.Nil(t, err)
102+
um := &msg.CSVCMsg_UserMessage{
103+
MsgType: int32(msg.ECstrike15UserMessages_CS_UM_SayText2),
104+
MsgData: userMessageData,
105+
}
106+
107+
p := NewParser(new(DevNullReader))
108+
109+
chatter := &common.Player{
110+
Name: "The Suspect",
111+
}
112+
p.gameState.playersByEntityID[1] = chatter
113+
114+
var actual events.SayText2
115+
p.RegisterEventHandler(func(event events.SayText2) {
116+
actual = event
117+
})
118+
119+
p.handleUserMessage(um)
120+
121+
expected := events.SayText2{
122+
EntIdx: 1,
123+
MsgName: "#CSGO_Coach_Join_T",
124+
Params: sayText2.Params,
125+
IsChat: true,
126+
IsChatAll: true,
127+
}
128+
assert.Equal(t, expected, actual)
129+
}
130+
131+
func Test_UserMessages_SayText2_ChatMessage(t *testing.T) {
132+
sayText2 := &msg.CCSUsrMsg_SayText2{
133+
EntIdx: 1,
134+
MsgName: "Cstrike_Chat_All",
135+
Textallchat: true,
136+
Params: []string{"The Suspect", "glhf"},
137+
}
138+
userMessageData, err := proto.Marshal(sayText2)
139+
assert.Nil(t, err)
140+
um := &msg.CSVCMsg_UserMessage{
141+
MsgType: int32(msg.ECstrike15UserMessages_CS_UM_SayText2),
142+
MsgData: userMessageData,
143+
}
144+
145+
p := NewParser(new(DevNullReader))
146+
147+
chatter := &common.Player{
148+
Name: "The Suspect",
149+
}
150+
p.gameState.playersByEntityID[1] = chatter
151+
152+
var actual events.ChatMessage
153+
p.RegisterEventHandler(func(chat events.ChatMessage) {
154+
actual = chat
155+
})
156+
157+
p.handleUserMessage(um)
158+
159+
expected := events.ChatMessage{
160+
Sender: chatter,
161+
Text: "glhf",
162+
IsChatAll: true,
163+
}
164+
assert.Equal(t, expected, actual)
165+
}

0 commit comments

Comments
 (0)