Skip to content

Instantly share code, notes, and snippets.

@yene
Last active March 16, 2023 15:57
Show Gist options
  • Save yene/1277d563b3980271d4488c195873a1a2 to your computer and use it in GitHub Desktop.
Save yene/1277d563b3980271d4488c195873a1a2 to your computer and use it in GitHub Desktop.
Generate statistic of what Dota 2 game modes are played the most.
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
)
var (
apiKey = flag.String("key", "", "Provida an API key. http://steamcommunity.com/dev/apikey")
startSeq = flag.Int("start", 0, "Provida a start sequence. Omit to start with last match.")
)
var gameModes = []string{"Unknown", "All Pick", "Captain's Mode", "Random Draft", "Single Draft", "All Random", "Intro", "Diretide", "Reverse Captain's Mode", "The Greeviling", "Tutorial", "Mid Only", "Least Played", "Limited Hero Pool", "Compendium Matchmaking", "Custom", "Captains Draft", "Balanced Draft", "Ability Draft", "?? Event ??", "All Random Death Match", "1vs1 Solo Mid", "All Pick Ranked", "Captain's Mode Ranked", "Bot Game", "Random Draft Ranked"}
var counter = make([]int, len(gameModes))
var startDate = ""
var client *http.Client
func main() {
flag.Parse()
if *apiKey == "" {
log.Fatal("Please provide an API key with -key.")
}
tr := &http.Transport{}
//tr.DisableKeepAlives = true
client = &http.Client{Transport: tr}
// If start sequence is 0, grab the latest sequence ID
if *startSeq == 0 {
requestURL := "https://api.steampowered.com/IDOTA2Match_570/GetMatchHistory/V001/?key=" + *apiKey
res, err := client.Get(requestURL)
if err != nil {
fmt.Println("HTTP Get EOF")
}
data, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal("Error", err)
}
var dat JSONMatch
if err := json.Unmarshal(data, &dat); err != nil {
log.Fatal("JSON Error", err)
}
seq := dat.Result.Matches[0].Match_seq_num
// Subtract a good amount of sequences so we don't catch up with the latest match
// estimated new sequences per day
seq -= 1850000 * 10
fmt.Println("Starting with sequence", seq)
*startSeq = seq
}
seq := *startSeq
c := 0
endDate := ""
for {
c++
res := match(seq, 0)
for _, m := range res.Result.Matches {
if m.Lobby_type == LobbyPractice || m.Lobby_type == LobbyTournament || m.Lobby_type == LobbyTutorial || m.Lobby_type == LobbyTeamMatch || m.Lobby_type == LobbySoloQueue {
continue
}
mode := m.Game_mode
if m.Lobby_type == LobbyBots { // differentiate between All Pick and All Pick with bots
mode = 24
} else if m.Game_mode == ModeCaptainsMode && m.Lobby_type == LobbyRanked { // filter out Captains Mode played in ranked
mode = 23
} else if m.Game_mode == ModeRandomDraft && m.Lobby_type == LobbyRanked { // filter out Random Draft played in ranked
mode = 25
}
counter[mode] = counter[mode] + 1
//fmt.Println("id:", m.Match_id, "seq:", seq, "at:", time.Unix(int64(m.Start_Time), 0), gameModes[mode])
seq = m.Match_seq_num + 1
if startDate == "" {
startDate = time.Unix(int64(m.Start_Time), 0).Format("2006-01-02 15:04:05")
}
endDate = time.Unix(int64(m.Start_Time), 0).Format("2006-01-02 15:04:05")
}
if c%20 == 0 {
printData(seq, endDate)
}
}
printData(seq, endDate)
}
func printData(seq int, endDate string) {
fmt.Println("---------------------------------------")
fmt.Println("Stats from", startDate, "to", endDate)
for index, m := range gameModes {
if counter[index] == 0 {
continue
}
fmt.Println(counter[index], "\t", m)
}
}
func match(startSeq int, try int) JSONMatch {
time.Sleep(1 * time.Second) // Wait a second to not get ratelimited too much
requestURL := "https://api.steampowered.com/IDOTA2Match_570/GetMatchHistoryBySequenceNum/V001/?key=" + *apiKey
requestURL = requestURL + "&start_at_match_seq_num=" + strconv.Itoa(startSeq)
res, err := client.Get(requestURL)
if err != nil {
fmt.Println("HTTP Get EOF", startSeq)
return match(startSeq, try+1)
}
data, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
fmt.Println(requestURL)
log.Fatal("Reading", err)
}
if res.StatusCode == 500 {
if try >= 1 { // retry 1 times then wait because of API rate limiting
fmt.Println(try, "retry after pause", startSeq)
time.Sleep(35 * time.Second) // number was found out during trial and error
}
return match(startSeq, try+1)
}
var dat JSONMatch
if err := json.Unmarshal(data, &dat); err != nil {
log.Fatal("JSON Error", err)
}
return dat
}
type JSONMatch struct {
Result struct {
Num_results int
Matches []struct {
Match_id int
Match_seq_num int
Game_mode int
Lobby_type int
Start_Time int
}
}
}
const (
LobbyPublic = iota
LobbyPractice
LobbyTournament
LobbyTutorial
LobbyBots
LobbyTeamMatch
LobbySoloQueue
LobbyRanked
Lobby1vs1
)
const (
ModeUnknown = iota
ModeAllPick
ModeCaptainsMode
ModeRandomDraft
ModSingleDraft
ModeAllRandom
ModeIntro
ModeDiretide
ModeReverseCaptainsDraft
ModeGreeviling
ModeTutorial
ModeMidOnly
ModeLeastPlayed
ModeNewPlayerPool
ModeCompendiumMatchmaking
ModeCustom
ModeCaptainsDraft
ModeBalancedDraft
ModeAbilityDraft
ModeEvent
ModeAllRandomDeathMatch
Mode1vs1
ModeRankedAllPick
)
@wrstlrlp13
Copy link

wrstlrlp13 commented Aug 29, 2022

Any chance you could update this and run it, I'm super curious to see where AD falls these days and haven't figured out how to get these statistics. I attempted to run it, but .go is not my forte and it didn't work for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment