Skip to content

Commit fb732ff

Browse files
committed
Better example (heatmaps, yay!)
1 parent 3d2aa5d commit fb732ff

File tree

9 files changed

+129
-73
lines changed

9 files changed

+129
-73
lines changed

Gopkg.lock

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 31 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,99 +21,68 @@ There are also [some other rooms](https://gitter.im/csgodemos) available around
2121

2222
## Example
2323

24-
This is a simple example on how to use the library. After each round (on every `RoundEndedEvent`) it prints out which team won.
24+
This is a simple example on how to use the library. It collects all positions where weapons were fired and creates a heatmap using [go-heatmap](https://github.com/dustin/go-heatmap).
2525

26-
Check out the godoc of the `events` package for some more information about the available events and their purpose.
26+
Check out the `examples` folder for more examples and the godoc of the `events` package for some information about the other available events and their purpose.
2727

2828
```go
29+
package main
30+
2931
import (
30-
"fmt"
32+
"image"
33+
"image/png"
3134
"log"
3235
"os"
3336

37+
heatmap "github.com/dustin/go-heatmap"
38+
schemes "github.com/dustin/go-heatmap/schemes"
39+
3440
dem "github.com/markus-wa/demoinfocs-golang"
35-
common "github.com/markus-wa/demoinfocs-golang/common"
3641
events "github.com/markus-wa/demoinfocs-golang/events"
3742
)
3843

44+
// Run like this: go run heatmap.go > out.png
3945
func main() {
40-
f, err := os.Open("path/to/demo.dem")
41-
defer f.Close()
46+
f, err := os.Open("/path/to/demo.dem")
4247
if err != nil {
4348
log.Fatal(err)
4449
}
50+
defer f.Close()
4551

4652
p := dem.NewParser(f)
4753

48-
// Parse header
49-
h, err := p.ParseHeader()
54+
// Parse header (contains map-name etc.)
55+
_, err = p.ParseHeader()
5056
if err != nil {
51-
t.Fatal(err)
57+
log.Fatal(err)
5258
}
53-
fmt.Println("Map:", h.MapName)
54-
55-
// Register handler on round end to figure out who won
56-
p.RegisterEventHandler(func(e events.RoundEndedEvent) {
57-
gs := p.GameState()
58-
switch e.Winner {
59-
case common.TeamTerrorists:
60-
// Winner's score + 1 because it hasn't actually been updated yet
61-
fmt.Printf("Round finished: winnerSide=T ; score=%d:%d\n", gs.TState().Score()+1, gs.CTState().Score())
62-
case common.TeamCounterTerrorists:
63-
fmt.Printf("Round finished: winnerSide=CT ; score=%d:%d\n", gs.CTState().Score()+1, gs.TState().Score())
64-
default:
65-
// Probably match medic or something similar
66-
fmt.Println("Round finished: No winner (tie)")
67-
}
59+
60+
// Register handler for WeaponFiredEvent, triggered every time a shot is fired
61+
points := []heatmap.DataPoint{}
62+
p.RegisterEventHandler(func(e events.WeaponFiredEvent) {
63+
// Add shooter's position as datapoint
64+
points = append(points, heatmap.P(e.Shooter.Position.X, e.Shooter.Position.Y))
6865
})
6966

7067
// Parse to end
7168
err = p.ParseToEnd()
7269
if err != nil {
7370
log.Fatal(err)
7471
}
72+
73+
// Generate heatmap and write to standard output
74+
img := heatmap.Heatmap(image.Rect(0, 0, 1024, 1024), points, 15, 128, schemes.AlphaFire)
75+
png.Encode(os.Stdout, img)
7576
}
7677
```
7778

78-
<details>
79-
<summary>Sample output</summary>
79+
### Result
8080

81-
```
82-
Map: de_cache
83-
Round finished: winnerSide=CT ; score=1:0
84-
Round finished: winnerSide=CT ; score=2:0
85-
Round finished: winnerSide=CT ; score=3:0
86-
Round finished: winnerSide=CT ; score=4:0
87-
Round finished: winnerSide=CT ; score=5:0
88-
Round finished: winnerSide=T ; score=1:5
89-
Round finished: winnerSide=CT ; score=6:1
90-
Round finished: winnerSide=T ; score=2:6
91-
Round finished: winnerSide=CT ; score=7:2
92-
Round finished: winnerSide=T ; score=3:7
93-
Round finished: winnerSide=CT ; score=8:3
94-
Round finished: winnerSide=CT ; score=9:3
95-
Round finished: winnerSide=CT ; score=10:3
96-
Round finished: winnerSide=CT ; score=11:3
97-
Round finished: winnerSide=T ; score=4:11
98-
Round finished: winnerSide=CT ; score=5:11
99-
Round finished: winnerSide=T ; score=12:5
100-
Round finished: winnerSide=CT ; score=6:12
101-
Round finished: winnerSide=CT ; score=7:12
102-
Round finished: winnerSide=CT ; score=8:12
103-
Round finished: winnerSide=CT ; score=9:12
104-
Round finished: winnerSide=T ; score=13:9
105-
Round finished: winnerSide=CT ; score=10:13
106-
Round finished: No winner (tie)
107-
Round finished: No winner (tie)
108-
Round finished: No winner (tie)
109-
Round finished: winnerSide=T ; score=14:10
110-
Round finished: winnerSide=CT ; score=11:14
111-
Round finished: winnerSide=T ; score=15:11
112-
Round finished: winnerSide=CT ; score=12:15
113-
Round finished: winnerSide=CT ; score=13:15
114-
Round finished: winnerSide=T ; score=16:13
115-
```
116-
</details>
81+
Running the above code (`go run heatmap.go > heatmap.png`) will create a PNG with dots on all the locations where shots were fired (the heatmap 'overlay').
82+
83+
This doesn't look too interesting on it's own but that can be helped by quickly mapping it to the map overview in an image editing tool (2 min tops, no skills required).
84+
85+
![Resulting heatmap before and after mapping to map overview](https://raw.githubusercontent.com/markus-wa/demoinfocs-golang/dev/examples/heatmap/heatmap.jpg)
11786

11887
## Features
11988

events/events.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ type MatchStartedEvent struct{}
2323
// RoundAnnounceMatchStartedEvent signals that the announcement "Match Started" has been displayed.
2424
type RoundAnnounceMatchStartedEvent struct{}
2525

26-
// RoundEndedEvent signals that the last round is over
26+
// RoundEndedEvent signals that a round just finished.
27+
// Attention: TeamState.Score() won't be up to date yet after this.
28+
// Add +1 to the winner's score as a workaround.
2729
type RoundEndedEvent struct {
2830
Message string
2931
Reason common.RoundEndReason

examples/heatmap/heatmap.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package main
2+
3+
import (
4+
"image"
5+
"image/png"
6+
"log"
7+
"os"
8+
9+
heatmap "github.com/dustin/go-heatmap"
10+
schemes "github.com/dustin/go-heatmap/schemes"
11+
12+
dem "github.com/markus-wa/demoinfocs-golang"
13+
events "github.com/markus-wa/demoinfocs-golang/events"
14+
)
15+
16+
const defaultDemPath = "../../test/cs-demos/default.dem"
17+
18+
// Run like this: go run heatmap.go > out.png
19+
func main() {
20+
f, err := os.Open(defaultDemPath)
21+
if err != nil {
22+
log.Fatal(err)
23+
}
24+
defer f.Close()
25+
26+
p := dem.NewParser(f)
27+
28+
// Parse header (contains map-name etc.)
29+
_, err = p.ParseHeader()
30+
if err != nil {
31+
log.Fatal(err)
32+
}
33+
34+
// Register handler for WeaponFiredEvent, triggered every time a shot is fired
35+
points := []heatmap.DataPoint{}
36+
p.RegisterEventHandler(func(e events.WeaponFiredEvent) {
37+
// Add shooter's position as datapoint
38+
points = append(points, heatmap.P(e.Shooter.Position.X, e.Shooter.Position.Y))
39+
})
40+
41+
// Parse to end
42+
err = p.ParseToEnd()
43+
if err != nil {
44+
log.Fatal(err)
45+
}
46+
47+
// Generate heatmap and write to standard output
48+
img := heatmap.Heatmap(image.Rect(0, 0, 1024, 1024), points, 15, 128, schemes.AlphaFire)
49+
png.Encode(os.Stdout, img)
50+
}

examples/heatmap/heatmap.jpg

166 KB
Loading

examples/heatmap/heatmap_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
// Just make sure the example runs
9+
func TestScores(t *testing.T) {
10+
old := os.Stdout
11+
_, w, _ := os.Pipe()
12+
os.Stdout = w
13+
14+
main()
15+
16+
os.Stdout = old
17+
}

example_test.go renamed to examples/scores/scores.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1-
package demoinfocs_test
1+
package main
22

33
import (
44
"fmt"
5+
"log"
56
"os"
6-
"testing"
77

88
dem "github.com/markus-wa/demoinfocs-golang"
99
common "github.com/markus-wa/demoinfocs-golang/common"
1010
events "github.com/markus-wa/demoinfocs-golang/events"
1111
)
1212

13-
// Make sure the example from the README.md compiles and runs.
14-
func TestExample(t *testing.T) {
13+
const defaultDemPath = "../../test/cs-demos/default.dem"
14+
15+
func main() {
1516
f, err := os.Open(defaultDemPath)
17+
defer f.Close()
1618
if err != nil {
17-
t.Fatal(err)
19+
log.Fatal(err)
1820
}
19-
defer f.Close()
2021

2122
p := dem.NewParser(f)
2223

2324
// Parse header
2425
h, err := p.ParseHeader()
2526
if err != nil {
26-
t.Fatal(err)
27+
log.Fatal(err)
2728
}
2829
fmt.Println("Map:", h.MapName)
2930

@@ -45,6 +46,6 @@ func TestExample(t *testing.T) {
4546
// Parse to end
4647
err = p.ParseToEnd()
4748
if err != nil {
48-
t.Fatal(err)
49+
log.Fatal(err)
4950
}
5051
}

examples/scores/scores_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package main
2+
3+
import "testing"
4+
5+
// Just make sure the example runs
6+
func TestScores(t *testing.T) {
7+
main()
8+
}

0 commit comments

Comments
 (0)