Last active
March 16, 2023 15:57
-
-
Save yene/1277d563b3980271d4488c195873a1a2 to your computer and use it in GitHub Desktop.
Generate statistic of what Dota 2 game modes are played the most.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.