Skip to content

Commit 203ac99

Browse files
committed
Add Custom EventEmitters & fuzzy.TeamSwitchEvent
This is intended to fix #17
1 parent 50c660d commit 203ac99

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

demoinfocs_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ import (
1717
dem "github.com/markus-wa/demoinfocs-golang"
1818
common "github.com/markus-wa/demoinfocs-golang/common"
1919
events "github.com/markus-wa/demoinfocs-golang/events"
20+
fuzzy "github.com/markus-wa/demoinfocs-golang/fuzzy"
2021
msg "github.com/markus-wa/demoinfocs-golang/msg"
2122
)
2223

2324
const csDemosPath = "test/cs-demos"
2425
const demSetPath = csDemosPath + "/set"
2526
const defaultDemPath = csDemosPath + "/default.dem"
2627
const unexpectedEndOfDemoPath = csDemosPath + "/unexpected_end_of_demo.dem"
28+
const valveMatchmakingDemoPath = csDemosPath + "/valve_matchmaking.dem"
2729

2830
func init() {
2931
if _, err := os.Stat(defaultDemPath); err != nil {
@@ -166,6 +168,54 @@ func TestUnexpectedEndOfDemo(t *testing.T) {
166168
}
167169
}
168170

171+
func TestValveMatchmakingFuzzyEmitters(t *testing.T) {
172+
f, err := os.Open(valveMatchmakingDemoPath)
173+
if err != nil {
174+
t.Fatal(err)
175+
}
176+
defer f.Close()
177+
178+
cfg := dem.DefaultParserConfig
179+
cfg.AdditionalEventEmitters = []dem.EventEmitter{new(fuzzy.ValveMatchmakingTeamSwitchEmitter)}
180+
181+
p := dem.NewParserWithConfig(f, cfg)
182+
_, err = p.ParseHeader()
183+
if err != nil {
184+
t.Fatal(err)
185+
}
186+
187+
teamSwitchDone := false
188+
tScoreBeforeSwap, ctScoreBeforeSwap := -1, -1
189+
p.RegisterEventHandler(func(ev events.RoundEndedEvent) {
190+
switch ev.Winner {
191+
case common.TeamTerrorists:
192+
tScoreBeforeSwap = p.GameState().TState().Score() + 1
193+
194+
case common.TeamCounterTerrorists:
195+
ctScoreBeforeSwap = p.GameState().CTState().Score() + 1
196+
}
197+
})
198+
199+
p.RegisterEventHandler(func(fuzzy.TeamSwitchEvent) {
200+
teamSwitchDone = true
201+
if tScoreBeforeSwap != p.GameState().CTState().Score() {
202+
t.Error("T-Score before swap != CT-Score after swap")
203+
}
204+
if ctScoreBeforeSwap != p.GameState().TState().Score() {
205+
t.Error("CT-Score before swap != T-Score after swap")
206+
}
207+
})
208+
209+
err = p.ParseToEnd()
210+
if err != nil {
211+
t.Fatal(err)
212+
}
213+
214+
if !teamSwitchDone {
215+
t.Fatal("TeamSwitchEvent not received")
216+
}
217+
}
218+
169219
func TestCancelParseToEnd(t *testing.T) {
170220
f, err := os.Open(defaultDemPath)
171221
if err != nil {

fuzzy/team_switch.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package fuzzy
2+
3+
import (
4+
dem "github.com/markus-wa/demoinfocs-golang"
5+
common "github.com/markus-wa/demoinfocs-golang/common"
6+
events "github.com/markus-wa/demoinfocs-golang/events"
7+
dp "github.com/markus-wa/godispatch"
8+
)
9+
10+
// TeamSwitchEvent signals that the teams have switched.
11+
// See also: ValveMatchmakingTeamSwitchEmitter
12+
type TeamSwitchEvent struct{}
13+
14+
// ValveMatchmakingTeamSwitchEmitter emits a TeamSwitchEvent for Valve MM demos.
15+
// Sadly this WON'T work for Major games as it currently doesn't account for overtime.
16+
// This is a beta feature and may be changed or replaced without notice.
17+
// See also: github.com/markus-wa/demoinfocs-golang/ParserConfig.AdditionalEventEmitters
18+
type ValveMatchmakingTeamSwitchEmitter struct {
19+
parser *dem.Parser
20+
dispatch func(interface{})
21+
currentHandlerID dp.HandlerIdentifier
22+
tScoreBeforeSwitch int
23+
ctScoreBeforeSwitch int
24+
}
25+
26+
// Register registers the emitter on the parser. It should only be used by the parser.
27+
func (em *ValveMatchmakingTeamSwitchEmitter) Register(parser *dem.Parser, dispatch func(interface{})) {
28+
em.parser = parser
29+
em.dispatch = dispatch
30+
31+
em.currentHandlerID = parser.RegisterEventHandler(em.handleLastRoundHalf)
32+
}
33+
34+
// Get to the last round of the first half
35+
func (em *ValveMatchmakingTeamSwitchEmitter) handleLastRoundHalf(events.LastRoundHalfEvent) {
36+
em.parser.UnregisterEventHandler(em.currentHandlerID)
37+
em.currentHandlerID = em.parser.RegisterEventHandler(em.handleRoundEnded)
38+
}
39+
40+
// Get scores before switch
41+
func (em *ValveMatchmakingTeamSwitchEmitter) handleRoundEnded(ev events.RoundEndedEvent) {
42+
em.tScoreBeforeSwitch = em.parser.GameState().TState().Score()
43+
em.ctScoreBeforeSwitch = em.parser.GameState().CTState().Score()
44+
45+
// Score hasn't been updated yet because CS:GO demos are weird
46+
switch ev.Winner {
47+
case common.TeamTerrorists:
48+
em.tScoreBeforeSwitch++
49+
case common.TeamCounterTerrorists:
50+
em.ctScoreBeforeSwitch++
51+
}
52+
53+
em.parser.UnregisterEventHandler(em.currentHandlerID)
54+
em.currentHandlerID = em.parser.RegisterEventHandler(em.handleRoundStarted)
55+
}
56+
57+
// Find first round of second half
58+
func (em *ValveMatchmakingTeamSwitchEmitter) handleRoundStarted(events.RoundStartedEvent) {
59+
em.parser.UnregisterEventHandler(em.currentHandlerID)
60+
em.currentHandlerID = em.parser.RegisterEventHandler(em.handleTickDone)
61+
}
62+
63+
// Wait for score to update - this isn't (necessarily?) the case after RoundStartedEvent
64+
func (em *ValveMatchmakingTeamSwitchEmitter) handleTickDone(events.TickDoneEvent) {
65+
tScoreOk := em.parser.GameState().TState().Score() == em.ctScoreBeforeSwitch
66+
ctScoreOk := em.parser.GameState().CTState().Score() == em.tScoreBeforeSwitch
67+
if tScoreOk && ctScoreOk {
68+
em.dispatch(TeamSwitchEvent{})
69+
70+
em.parser.UnregisterEventHandler(em.currentHandlerID)
71+
}
72+
}

parser.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,18 @@ type ParserConfig struct {
166166
// Check out demopacket.go to see which net-messages are already being parsed by default.
167167
// This is a beta feature and may be changed or replaced without notice.
168168
AdditionalNetMessageCreators map[int]NetMessageCreator
169+
// AdditionalEventEmitters contains additional event emitters - either from the fuzzy package or custom ones.
170+
// This is mainly used to add logic specifically for one type of demo (e.g. Matchmaking, FaceIt etc.).
171+
// This is a beta feature and may be changed or replaced without notice.
172+
// See also: package fuzzy for existing emitters with fuzzy-logic that depends on the demo-type.
173+
AdditionalEventEmitters []EventEmitter
174+
}
175+
176+
// EventEmitter is the interface to define additional event-emitters.
177+
// The emitters may fire additional events by calling the eventDispatcher function received during registration of the emitter.
178+
// See also: package fuzzy for existing emitters with fuzzy-logic that depends on the demo-type.
179+
type EventEmitter interface {
180+
Register(parser *Parser, eventDispatcher func(event interface{}))
169181
}
170182

171183
// DefaultParserConfig is the default Parser configuration used by NewParser().
@@ -207,6 +219,10 @@ func NewParserWithConfig(demostream io.Reader, config ParserConfig) *Parser {
207219

208220
p.additionalNetMessageCreators = config.AdditionalNetMessageCreators
209221

222+
for _, emitter := range config.AdditionalEventEmitters {
223+
emitter.Register(&p, p.eventDispatcher.Dispatch)
224+
}
225+
210226
return &p
211227
}
212228

test/cs-demos

Submodule cs-demos updated from d851242 to 28d6183

0 commit comments

Comments
 (0)