/
parse.go
116 lines (90 loc) · 2.88 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package main
import (
"fmt"
"time"
"github.com/dotabuff/manta"
"github.com/dotabuff/manta/dota"
"github.com/davecgh/go-spew/spew"
)
type PlayerStats struct {
SteamId uint64 `json:"steam_id"`
HeroName string `json:"raw_hero_name"`
Slot uint `json:"-"`
Kills int32 `json:"kills"`
Deaths int32 `json:"deaths"`
Assists int32 `json:"assist"`
Gold int32 `json:"total_gold"`
Xp int32 `json:"total_experience"`
}
type MatchStats struct {
Players map[uint64]*PlayerStats
Duration float64
Winner string
MatchId uint32
}
var pp = spew.Dump
func ignoreError(v int32, e bool) int32 {
return v
}
func Parse(parseQueue <-chan *FilePending, finishedQueue chan<- *FileFinished) {
for {
file := <-parseQueue
DebugPrint("parsing: %s at %s\n", file.Name, file.Path)
match := &MatchStats{}
match.Players = make(map[uint64]*PlayerStats)
parser, _ := manta.NewParserFromFile(file.Path)
parsed := false
var totalTime time.Duration
var gameEndTime, gameStartTime float32
parser.OnPacketEntity(func(e *manta.PacketEntity, pet manta.EntityEventType) error {
// once we get the data once, it won't change, so we can skip it after one load
if parsed {
return nil
}
if e.ClassName == "CDOTAGamerulesProxy" {
gameEndTime, _ = e.FetchFloat32("CDOTAGamerules.m_flGameEndTime")
gameStartTime, _ = e.FetchFloat32("CDOTAGamerules.m_flGameStartTime")
totalTime = time.Duration(gameEndTime-gameStartTime) * time.Second
}
// the ancient has fallen, gather final stats
if gameEndTime > 0 {
if e.ClassName == "CDOTA_PlayerResource" {
for i := 0; i < 10; i++ {
suffix := fmt.Sprintf("%04d", i)
id, _ := e.FetchUint64("m_iPlayerSteamIDs." + suffix)
match.Players[id] = &PlayerStats{
SteamId: id,
Slot: uint(i),
Kills: ignoreError(e.FetchInt32("m_iKills." + suffix)),
Deaths: ignoreError(e.FetchInt32("m_iDeaths." + suffix)),
Assists: ignoreError(e.FetchInt32("m_iAssists." + suffix)),
Gold: ignoreError(e.FetchInt32("m_iTotalEarnedGold." + suffix)),
Xp: ignoreError(e.FetchInt32("m_iTotalEarnedXP." + suffix)),
}
}
match.Duration = totalTime.Minutes()
parsed = true
}
}
return nil
})
parser.Callbacks.OnCDemoFileInfo(func(fileinfo *dota.CDemoFileInfo) error {
gameInfo := fileinfo.GetGameInfo().GetDota()
match.MatchId = gameInfo.GetMatchId()
// game winner team IDs are hard-coded because reasons
if gameInfo.GetGameWinner() == 2 {
match.Winner = "radiant"
} else {
match.Winner = "dire"
}
for _, pls := range gameInfo.GetPlayerInfo() {
match.Players[pls.GetSteamid()].HeroName = pls.GetHeroName()
}
return nil
})
_ = parser.Start()
//spew.Dump(match)
DebugPrint("done parsing: %s\n", file.Name)
finishedQueue <- &FileFinished{Path: file.Path, Name: file.Name, Stats: match}
}
}