From 268793f0e5938e1e7bab3bee78d768fccf59c995 Mon Sep 17 00:00:00 2001 From: Giovanni Harting <539@idlegandalf.com> Date: Sat, 30 Oct 2021 08:22:05 +0200 Subject: [PATCH] some refactoring --- csgo/demo_loader.go | 335 ++++++++++++++++----------------- csgo/demo_parser.go | 443 ++++++++++++++++++++++---------------------- 2 files changed, 388 insertions(+), 390 deletions(-) diff --git a/csgo/demo_loader.go b/csgo/demo_loader.go index 9f78d88..12bf08c 100644 --- a/csgo/demo_loader.go +++ b/csgo/demo_loader.go @@ -16,6 +16,7 @@ import ( "google.golang.org/protobuf/proto" "io/ioutil" "os" + "sync" "time" ) @@ -48,6 +49,7 @@ type DemoMatchLoader struct { dp *DemoParser parseDemo chan *Demo parseMap map[string]bool + parseMapL *sync.Mutex cache *cache.Cache connecting bool } @@ -156,6 +158,7 @@ func (d *DemoMatchLoader) Setup(config *DemoMatchLoaderConfig) error { d.db = config.Db d.dp = &DemoParser{} d.parseMap = map[string]bool{} + d.parseMapL = new(sync.Mutex) d.cache = config.Cache err := d.dp.Setup(config.Db, config.Worker) if err != nil { @@ -298,172 +301,172 @@ func (d *DemoMatchLoader) requestDemoInfo(matchId uint64, conclusionId uint64, t } func (d *DemoMatchLoader) gcWorker(apiKey string, rl ratelimit.Limiter) { - for { - select { - case demo := <-d.parseDemo: - if _, ok := d.parseMap[demo.ShareCode]; ok { - log.Infof("[DL] Skipping %s: parsing in progress", demo.ShareCode) - continue - } else { - d.parseMap[demo.ShareCode] = true - } - - if !d.GCReady { - log.Infof("[DL] Postponing match %d (%s): GC not ready", demo.MatchId, demo.ShareCode) - time.Sleep(5 * time.Second) - delete(d.parseMap, demo.ShareCode) - d.parseDemo <- demo - continue - } - - matchId, _, _, err := DecodeSharecode(demo.ShareCode) - if err != nil || matchId == 0 { - log.Warningf("[DL] Can't parse match with sharecode %s: %v", demo.ShareCode, err) - delete(d.parseMap, demo.ShareCode) - continue - } - - iMatch, err := d.db.Match.Get(context.Background(), matchId) - if err != nil { - switch e := err.(type) { - case *ent.NotFoundError: - break - default: - log.Errorf("[DL] Failure trying to lookup match %d in db: %v", matchId, e) - delete(d.parseMap, demo.ShareCode) - continue - } - } else { - if iMatch.DemoParsed == false && iMatch.Date.After(time.Now().UTC().AddDate(0, 0, -30)) { - log.Infof("[DL] Match %d is loaded, but not parsed. Try parsing.", demo.MatchId) - demo.MatchId = matchId - demo.Url = iMatch.ReplayURL - err := d.dp.ParseDemo(demo) - if err != nil { - log.Warningf("[DL] Parsing demo from match %d failed: %v", demo.MatchId, err) - } - delete(d.parseMap, demo.ShareCode) - continue - } - - log.Debugf("[DL] Skipped match %d: already parsed", matchId) - delete(d.parseMap, demo.ShareCode) - continue - } - - matchDetails, err := d.getMatchDetails(demo.ShareCode) - if err != nil { - log.Warningf("[DL] Failure to get match-details for %d from GC: %v", demo.MatchId, err) - delete(d.parseMap, demo.ShareCode) - continue - } - - matchZero := matchDetails.GetMatches()[0] - lastRound := matchZero.GetRoundstatsall()[len(matchZero.Roundstatsall)-1] - var players []*ent.Player - - for _, accountId := range lastRound.GetReservation().GetAccountIds() { - tPlayer, err := utils.GetPlayer(d.db, AccountId2SteamId(accountId), apiKey, rl) - if err != nil { - log.Warningf("[DL] Unable to get player for steamid %d: %v", AccountId2SteamId(accountId), err) - continue - } - players = append(players, tPlayer) - } - - demo.Url = lastRound.GetMap() - demo.MatchId = matchZero.GetMatchid() - - tMatch, err := d.db.Match.Create(). - SetID(matchZero.GetMatchid()). - AddPlayers(players...). - SetDate(time.Unix(int64(matchZero.GetMatchtime()), 0).UTC()). - SetMaxRounds(int(lastRound.GetMaxRounds())). - SetDuration(int(lastRound.GetMatchDuration())). - SetShareCode(demo.ShareCode). - SetReplayURL(lastRound.GetMap()). - SetScoreTeamA(int(lastRound.GetTeamScores()[0])). - SetScoreTeamB(int(lastRound.GetTeamScores()[1])). - SetMatchResult(int(lastRound.GetMatchResult())). - Save(context.Background()) - if err != nil { - log.Warningf("[DL] Unable to create match %d: %v", matchZero.GetMatchid(), err) - delete(d.parseMap, demo.ShareCode) - continue - } - - for i, mPlayer := range players { - var ( - teamId int - mk2 uint - mk3 uint - mk4 uint - mk5 uint - ) - - if i > 4 { - teamId = 2 - } else { - teamId = 1 - } - - var oldKills int32 - for _, round := range matchZero.GetRoundstatsall() { - kills, _, _, _, _, _ := playerStatsFromRound(round, mPlayer) - - killDiff := kills - oldKills - - switch killDiff { - case 2: - mk2++ - case 3: - mk3++ - case 4: - mk4++ - case 5: - mk5++ - } - oldKills = kills - } - - kills, deaths, assists, hs, score, mvp := playerStatsFromRound(lastRound, mPlayer) - err := d.db.Stats.Create(). - SetMatches(tMatch). - SetPlayers(mPlayer). - SetTeamID(teamId). - SetKills(int(kills)). - SetDeaths(int(deaths)). - SetAssists(int(assists)). - SetMvp(uint(mvp)). - SetScore(int(score)). - SetHeadshot(int(hs)). - SetMk2(mk2). - SetMk3(mk3). - SetMk4(mk4). - SetMk5(mk5). - Exec(context.Background()) - if err != nil { - log.Warningf("[DL] Unable to create stats for player %d in match %d: %v", mPlayer.ID, tMatch.ID, err) - } - } - - // clear cache for player - for _, p := range players { - err = d.cache.Delete(context.Background(), fmt.Sprintf(utils.SideMetaCacheKey, p.ID)) - if err != nil { - log.Warningf("[DL] Unable to delete cache key %s: %v", fmt.Sprintf(utils.SideMetaCacheKey, p.ID), err) - } - err = d.cache.Delete(context.Background(), fmt.Sprintf(utils.MatchMetaCacheKey, p.ID)) - if err != nil { - log.Warningf("[DL] Unable to delete cache key %s: %v", fmt.Sprintf(utils.MatchMetaCacheKey, p.ID), err) - } - } - - err = d.dp.ParseDemo(demo) - if err != nil { - log.Warningf("[DL] Can't queue demo %d for parsing: %v", demo.MatchId, err) - } - delete(d.parseMap, demo.ShareCode) + for demo := range d.parseDemo { + d.parseMapL.Lock() + if _, ok := d.parseMap[demo.ShareCode]; ok { + log.Infof("[DL] Skipping %s: parsing in progress", demo.ShareCode) + d.parseMapL.Unlock() + continue + } else { + d.parseMap[demo.ShareCode] = true } + d.parseMapL.Unlock() + + if !d.GCReady { + log.Infof("[DL] Postponing match %d (%s): GC not ready", demo.MatchId, demo.ShareCode) + time.Sleep(5 * time.Second) + delete(d.parseMap, demo.ShareCode) + d.parseDemo <- demo + continue + } + + matchId, _, _, err := DecodeSharecode(demo.ShareCode) + if err != nil || matchId == 0 { + log.Warningf("[DL] Can't parse match with sharecode %s: %v", demo.ShareCode, err) + delete(d.parseMap, demo.ShareCode) + continue + } + + iMatch, err := d.db.Match.Get(context.Background(), matchId) + if err != nil { + switch e := err.(type) { + case *ent.NotFoundError: + break + default: + log.Errorf("[DL] Failure trying to lookup match %d in db: %v", matchId, e) + delete(d.parseMap, demo.ShareCode) + continue + } + } else { + if iMatch.DemoParsed == false && iMatch.Date.After(time.Now().UTC().AddDate(0, 0, -30)) { + log.Infof("[DL] Match %d is loaded, but not parsed. Try parsing.", demo.MatchId) + demo.MatchId = matchId + demo.Url = iMatch.ReplayURL + err := d.dp.ParseDemo(demo) + if err != nil { + log.Warningf("[DL] Parsing demo from match %d failed: %v", demo.MatchId, err) + } + delete(d.parseMap, demo.ShareCode) + continue + } + + log.Debugf("[DL] Skipped match %d: already parsed", matchId) + delete(d.parseMap, demo.ShareCode) + continue + } + + matchDetails, err := d.getMatchDetails(demo.ShareCode) + if err != nil { + log.Warningf("[DL] Failure to get match-details for %d from GC: %v", demo.MatchId, err) + delete(d.parseMap, demo.ShareCode) + continue + } + + matchZero := matchDetails.GetMatches()[0] + lastRound := matchZero.GetRoundstatsall()[len(matchZero.Roundstatsall)-1] + var players []*ent.Player + + for _, accountId := range lastRound.GetReservation().GetAccountIds() { + tPlayer, err := utils.GetPlayer(d.db, AccountId2SteamId(accountId), apiKey, rl) + if err != nil { + log.Warningf("[DL] Unable to get player for steamid %d: %v", AccountId2SteamId(accountId), err) + continue + } + players = append(players, tPlayer) + } + + demo.Url = lastRound.GetMap() + demo.MatchId = matchZero.GetMatchid() + + tMatch, err := d.db.Match.Create(). + SetID(matchZero.GetMatchid()). + AddPlayers(players...). + SetDate(time.Unix(int64(matchZero.GetMatchtime()), 0).UTC()). + SetMaxRounds(int(lastRound.GetMaxRounds())). + SetDuration(int(lastRound.GetMatchDuration())). + SetShareCode(demo.ShareCode). + SetReplayURL(lastRound.GetMap()). + SetScoreTeamA(int(lastRound.GetTeamScores()[0])). + SetScoreTeamB(int(lastRound.GetTeamScores()[1])). + SetMatchResult(int(lastRound.GetMatchResult())). + Save(context.Background()) + if err != nil { + log.Warningf("[DL] Unable to create match %d: %v", matchZero.GetMatchid(), err) + delete(d.parseMap, demo.ShareCode) + continue + } + + for i, mPlayer := range players { + var ( + teamId int + mk2 uint + mk3 uint + mk4 uint + mk5 uint + ) + + if i > 4 { + teamId = 2 + } else { + teamId = 1 + } + + var oldKills int32 + for _, round := range matchZero.GetRoundstatsall() { + kills, _, _, _, _, _ := playerStatsFromRound(round, mPlayer) + + killDiff := kills - oldKills + + switch killDiff { + case 2: + mk2++ + case 3: + mk3++ + case 4: + mk4++ + case 5: + mk5++ + } + oldKills = kills + } + + kills, deaths, assists, hs, score, mvp := playerStatsFromRound(lastRound, mPlayer) + err := d.db.Stats.Create(). + SetMatches(tMatch). + SetPlayers(mPlayer). + SetTeamID(teamId). + SetKills(int(kills)). + SetDeaths(int(deaths)). + SetAssists(int(assists)). + SetMvp(uint(mvp)). + SetScore(int(score)). + SetHeadshot(int(hs)). + SetMk2(mk2). + SetMk3(mk3). + SetMk4(mk4). + SetMk5(mk5). + Exec(context.Background()) + if err != nil { + log.Warningf("[DL] Unable to create stats for player %d in match %d: %v", mPlayer.ID, tMatch.ID, err) + } + } + + // clear cache for player + for _, p := range players { + err = d.cache.Delete(context.Background(), fmt.Sprintf(utils.SideMetaCacheKey, p.ID)) + if err != nil { + log.Warningf("[DL] Unable to delete cache key %s: %v", fmt.Sprintf(utils.SideMetaCacheKey, p.ID), err) + } + err = d.cache.Delete(context.Background(), fmt.Sprintf(utils.MatchMetaCacheKey, p.ID)) + if err != nil { + log.Warningf("[DL] Unable to delete cache key %s: %v", fmt.Sprintf(utils.MatchMetaCacheKey, p.ID), err) + } + } + + err = d.dp.ParseDemo(demo) + if err != nil { + log.Warningf("[DL] Can't queue demo %d for parsing: %v", demo.MatchId, err) + } + delete(d.parseMap, demo.ShareCode) } } diff --git a/csgo/demo_parser.go b/csgo/demo_parser.go index 6de02e8..f67a6dc 100644 --- a/csgo/demo_parser.go +++ b/csgo/demo_parser.go @@ -51,7 +51,7 @@ func (p *DemoParser) ParseDemo(demo *Demo) error { } } -func (p *DemoParser) downloadReplay(demo *Demo) (io.Reader, error) { +func (p *DemoParser) downloadDecompressReplay(demo *Demo) (io.Reader, error) { log.Debugf("[DP] Downloading replay for %d", demo.MatchId) r, err := http.Get(demo.Url) @@ -63,7 +63,6 @@ func (p *DemoParser) downloadReplay(demo *Demo) (io.Reader, error) { return nil, DemoNotFoundError{fmt.Errorf("demo not found")} } return bzip2.NewReader(r.Body), nil - } func (p *DemoParser) getDBPlayer(demo *Demo, demoPlayer *common.Player) (*ent.Stats, error) { @@ -95,253 +94,249 @@ func (p *DemoParser) getMatchPlayerBySteamID(stats []*ent.Stats, steamId uint64) } func (p *DemoParser) parseWorker() { - for { - select { - case demo := <-p.demoQueue: - if demo.MatchId == 0 { - log.Warningf("[DP] can't parse match %s: no matchid found", demo.ShareCode) - continue - } + for demo := range p.demoQueue { + if demo.MatchId == 0 { + log.Warningf("[DP] can't parse match %s: no matchid found", demo.ShareCode) + continue + } - tMatch, err := p.db.Match.Get(context.Background(), demo.MatchId) - if err != nil { - log.Errorf("[DP] Unable to get match %d: %v", demo.MatchId, err) - continue - } + tMatch, err := p.db.Match.Get(context.Background(), demo.MatchId) + if err != nil { + log.Errorf("[DP] Unable to get match %d: %v", demo.MatchId, err) + continue + } - if tMatch.DemoParsed { - log.Infof("[DP] skipped already parsed %d", demo.MatchId) - continue - } + if tMatch.DemoParsed { + log.Infof("[DP] skipped already parsed %d", demo.MatchId) + continue + } - startTime := time.Now() - fDemo, err := p.downloadReplay(demo) - if err != nil { - switch e := err.(type) { - case DemoNotFoundError: - if tMatch.Date.Before(time.Now().UTC().AddDate(0, 0, -30)) { - log.Infof("[DP] demo expired for match %d", tMatch.ID) - } else { - log.Infof("[DP] demo 404 not found for match %d. Trying again later.", demo.MatchId) - } - continue - default: - log.Errorf("[DP] Unable to download demo for %d: %v", demo.MatchId, e) - continue - } - } - downloadTime := time.Since(startTime) - - tStats, err := tMatch.QueryStats().WithPlayers().All(context.Background()) - if err != nil { - log.Errorf("[DP] Failed to find players for match %d: %v", demo.MatchId, err) - continue - } - - eqMap := make(map[uint64][]*struct { - Eq int - HitGroup int - Dmg uint - To uint64 - }) - ecoMap := make(map[uint64][]*struct { - Round int - EqV int - Bank int - Spent int - }, 0) - demoParser := demoinfocs.NewParser(fDemo) - - // onPlayerHurt - demoParser.RegisterEventHandler(func(e events.PlayerHurt) { - if e.Attacker == nil || e.Player == nil || e.Weapon == nil || !demoParser.GameState().IsMatchStarted() { - return - } - - tAttacker := p.getMatchPlayerBySteamID(tStats, e.Attacker.SteamID64) - if e.Attacker.Team == e.Player.Team { - tAttacker.DmgTeam += uint(e.HealthDamageTaken) + startTime := time.Now() + fDemo, err := p.downloadDecompressReplay(demo) + if err != nil { + if _, ok := err.(DemoNotFoundError); ok { + if tMatch.Date.Before(time.Now().UTC().AddDate(0, 0, -30)) { + log.Infof("[DP] demo expired for match %d", tMatch.ID) } else { - tAttacker.DmgEnemy += uint(e.HealthDamageTaken) + log.Infof("[DP] demo 404 not found for match %d. Trying again later.", demo.MatchId) } + continue + } else { + log.Errorf("[DP] Unable to download demo for %d: %v", demo.MatchId, err) + continue + } + } + downloadTime := time.Since(startTime) - if _, ok := eqMap[e.Attacker.SteamID64]; !ok { - eqMap[e.Attacker.SteamID64] = make([]*struct { - Eq int - HitGroup int - Dmg uint - To uint64 - }, 0) + tStats, err := tMatch.QueryStats().WithPlayers().All(context.Background()) + if err != nil { + log.Errorf("[DP] Failed to find players for match %d: %v", demo.MatchId, err) + continue + } + + eqMap := make(map[uint64][]*struct { + Eq int + HitGroup int + Dmg uint + To uint64 + }) + ecoMap := make(map[uint64][]*struct { + Round int + EqV int + Bank int + Spent int + }, 0) + demoParser := demoinfocs.NewParser(fDemo) + + // onPlayerHurt + demoParser.RegisterEventHandler(func(e events.PlayerHurt) { + if e.Attacker == nil || e.Player == nil || e.Weapon == nil || !demoParser.GameState().IsMatchStarted() { + return + } + + tAttacker := p.getMatchPlayerBySteamID(tStats, e.Attacker.SteamID64) + if e.Attacker.Team == e.Player.Team { + tAttacker.DmgTeam += uint(e.HealthDamageTaken) + } else { + tAttacker.DmgEnemy += uint(e.HealthDamageTaken) + } + + if _, ok := eqMap[e.Attacker.SteamID64]; !ok { + eqMap[e.Attacker.SteamID64] = make([]*struct { + Eq int + HitGroup int + Dmg uint + To uint64 + }, 0) + } + + found := false + for _, di := range eqMap[e.Attacker.SteamID64] { + if di.Eq == int(e.Weapon.Type) && di.HitGroup == int(e.HitGroup) { + di.Dmg += uint(e.HealthDamageTaken) + found = true } + } - found := false - for _, di := range eqMap[e.Attacker.SteamID64] { - if di.Eq == int(e.Weapon.Type) && di.HitGroup == int(e.HitGroup) { - di.Dmg += uint(e.HealthDamageTaken) - found = true + if !found { + eqMap[e.Attacker.SteamID64] = append(eqMap[e.Attacker.SteamID64], &struct { + Eq int + HitGroup int + Dmg uint + To uint64 + }{Eq: int(e.Weapon.Type), HitGroup: int(e.HitGroup), Dmg: uint(e.HealthDamageTaken), To: e.Player.SteamID64}) + } + }) + + // onRoundEnd + demoParser.RegisterEventHandler(func(e events.RoundEnd) { + gs := demoParser.GameState() + if !gs.IsMatchStarted() { + return + } + + // track eco + for _, p := range gs.Participants().Playing() { + ecoMap[p.SteamID64] = append(ecoMap[p.SteamID64], &struct { + Round int + EqV int + Bank int + Spent int + }{Round: gs.TotalRoundsPlayed(), EqV: p.EquipmentValueCurrent(), Bank: p.Money(), Spent: p.MoneySpentThisRound()}) + } + }) + + // onPlayerFlashed + demoParser.RegisterEventHandler(func(e events.PlayerFlashed) { + if e.Attacker == nil || e.Player == nil || !demoParser.GameState().IsMatchStarted() { + return + } + + tAttacker := p.getMatchPlayerBySteamID(tStats, e.Attacker.SteamID64) + + // team flash + if e.Attacker.Team == e.Player.Team && e.Attacker.SteamID64 != e.Player.SteamID64 { + tAttacker.FlashTotalTeam++ + tAttacker.FlashDurationTeam += e.Player.FlashDuration + } + + // own flash + if e.Attacker.SteamID64 == e.Player.SteamID64 { + tAttacker.FlashTotalSelf++ + tAttacker.FlashDurationSelf += e.Player.FlashDuration + } + + // enemy flash + if e.Attacker.Team != e.Player.Team { + tAttacker.FlashTotalEnemy++ + tAttacker.FlashDurationEnemy += e.Player.FlashDuration + } + }) + + // onMatchStart + demoParser.RegisterEventHandler(func(e events.MatchStart) { + gs := demoParser.GameState() + + for _, demoPlayer := range gs.Participants().Playing() { + if demoPlayer != nil && demoPlayer.SteamID64 != 0 { + tMatchPlayer := p.getMatchPlayerBySteamID(tStats, demoPlayer.SteamID64) + + tMatchPlayer.Crosshair = demoPlayer.CrosshairCode() + switch demoPlayer.Color() { + case common.Yellow: + tMatchPlayer.Color = stats.ColorYellow + break + case common.Green: + tMatchPlayer.Color = stats.ColorGreen + break + case common.Purple: + tMatchPlayer.Color = stats.ColorPurple + break + case common.Blue: + tMatchPlayer.Color = stats.ColorBlue + break + case common.Orange: + tMatchPlayer.Color = stats.ColorOrange + break + default: + tMatchPlayer.Color = stats.ColorGrey } } + } + }) - if !found { - eqMap[e.Attacker.SteamID64] = append(eqMap[e.Attacker.SteamID64], &struct { - Eq int - HitGroup int - Dmg uint - To uint64 - }{Eq: int(e.Weapon.Type), HitGroup: int(e.HitGroup), Dmg: uint(e.HealthDamageTaken), To: e.Player.SteamID64}) - } - }) + // onRankUpdate + demoParser.RegisterEventHandler(func(e events.RankUpdate) { + if e.SteamID64() != 0 { + tMatchPlayer := p.getMatchPlayerBySteamID(tStats, e.SteamID64()) - // onRoundEnd - demoParser.RegisterEventHandler(func(e events.RoundEnd) { - gs := demoParser.GameState() - if !gs.IsMatchStarted() { - return - } + tMatchPlayer.RankOld = e.RankOld + tMatchPlayer.RankNew = e.RankNew + } + }) - // track eco - for _, p := range gs.Participants().Playing() { - ecoMap[p.SteamID64] = append(ecoMap[p.SteamID64], &struct { - Round int - EqV int - Bank int - Spent int - }{Round: gs.TotalRoundsPlayed(), EqV: p.EquipmentValueCurrent(), Bank: p.Money(), Spent: p.MoneySpentThisRound()}) - } - }) + err = demoParser.ParseToEnd() + if err != nil { + log.Errorf("[DP] Error parsing replay: %v", err) + continue + } - // onPlayerFlashed - demoParser.RegisterEventHandler(func(e events.PlayerFlashed) { - if e.Attacker == nil || e.Player == nil || !demoParser.GameState().IsMatchStarted() { - return - } + err = tMatch.Update().SetMap(demoParser.Header().MapName).SetDemoParsed(true).Exec(context.Background()) + if err != nil { + log.Errorf("[DP] Unable to update match %d in database: %v", demo.MatchId, err) + continue + } - tAttacker := p.getMatchPlayerBySteamID(tStats, e.Attacker.SteamID64) + for _, tMatchPlayer := range tStats { + if tMatchPlayer.Color == "" { + tMatchPlayer.Color = stats.ColorGrey + } - // team flash - if e.Attacker.Team == e.Player.Team && e.Attacker.SteamID64 != e.Player.SteamID64 { - tAttacker.FlashTotalTeam++ - tAttacker.FlashDurationTeam += e.Player.FlashDuration - } - - // own flash - if e.Attacker.SteamID64 == e.Player.SteamID64 { - tAttacker.FlashTotalSelf++ - tAttacker.FlashDurationSelf += e.Player.FlashDuration - } - - // enemy flash - if e.Attacker.Team != e.Player.Team { - tAttacker.FlashTotalEnemy++ - tAttacker.FlashDurationEnemy += e.Player.FlashDuration - } - }) - - // onMatchStart - demoParser.RegisterEventHandler(func(e events.MatchStart) { - gs := demoParser.GameState() - - for _, demoPlayer := range gs.Participants().Playing() { - if demoPlayer != nil && demoPlayer.SteamID64 != 0 { - tMatchPlayer := p.getMatchPlayerBySteamID(tStats, demoPlayer.SteamID64) - - tMatchPlayer.Crosshair = demoPlayer.CrosshairCode() - switch demoPlayer.Color() { - case common.Yellow: - tMatchPlayer.Color = stats.ColorYellow - break - case common.Green: - tMatchPlayer.Color = stats.ColorGreen - break - case common.Purple: - tMatchPlayer.Color = stats.ColorPurple - break - case common.Blue: - tMatchPlayer.Color = stats.ColorBlue - break - case common.Orange: - tMatchPlayer.Color = stats.ColorOrange - break - default: - tMatchPlayer.Color = stats.ColorGrey - } - } - } - }) - - // onRankUpdate - demoParser.RegisterEventHandler(func(e events.RankUpdate) { - if e.SteamID64() != 0 { - tMatchPlayer := p.getMatchPlayerBySteamID(tStats, e.SteamID64()) - - tMatchPlayer.RankOld = e.RankOld - tMatchPlayer.RankNew = e.RankNew - } - }) - - err = demoParser.ParseToEnd() + nMatchPLayer, err := tMatchPlayer.Update(). + SetDmgTeam(tMatchPlayer.DmgTeam). + SetDmgEnemy(tMatchPlayer.DmgEnemy). + SetUdHe(tMatchPlayer.UdHe). + SetUdFlash(tMatchPlayer.UdFlash). + SetUdSmoke(tMatchPlayer.UdSmoke). + SetUdFlames(tMatchPlayer.UdFlames). + SetRankOld(tMatchPlayer.RankOld). + SetRankNew(tMatchPlayer.RankNew). + SetColor(tMatchPlayer.Color). + SetCrosshair(tMatchPlayer.Crosshair). + SetFlashDurationTeam(tMatchPlayer.FlashDurationTeam). + SetFlashDurationSelf(tMatchPlayer.FlashDurationSelf). + SetFlashDurationEnemy(tMatchPlayer.FlashDurationEnemy). + SetFlashTotalEnemy(tMatchPlayer.FlashTotalEnemy). + SetFlashTotalSelf(tMatchPlayer.FlashTotalSelf). + SetFlashTotalTeam(tMatchPlayer.FlashTotalTeam). + SetDmgTeam(tMatchPlayer.DmgTeam). + SetDmgEnemy(tMatchPlayer.DmgEnemy). + Save(context.Background()) if err != nil { - log.Errorf("[DP] Error parsing replay: %v", err) + log.Errorf("[DP] Unable to update stats %d in database: %v", tMatchPlayer.PlayerStats, err) continue } - err = tMatch.Update().SetMap(demoParser.Header().MapName).SetDemoParsed(true).Exec(context.Background()) - if err != nil { - log.Errorf("[DP] Unable to update match %d in database: %v", demo.MatchId, err) - continue - } - - for _, tMatchPlayer := range tStats { - if tMatchPlayer.Color == "" { - tMatchPlayer.Color = stats.ColorGrey - } - - nMatchPLayer, err := tMatchPlayer.Update(). - SetDmgTeam(tMatchPlayer.DmgTeam). - SetDmgEnemy(tMatchPlayer.DmgEnemy). - SetUdHe(tMatchPlayer.UdHe). - SetUdFlash(tMatchPlayer.UdFlash). - SetUdSmoke(tMatchPlayer.UdSmoke). - SetUdFlames(tMatchPlayer.UdFlames). - SetRankOld(tMatchPlayer.RankOld). - SetRankNew(tMatchPlayer.RankNew). - SetColor(tMatchPlayer.Color). - SetCrosshair(tMatchPlayer.Crosshair). - SetFlashDurationTeam(tMatchPlayer.FlashDurationTeam). - SetFlashDurationSelf(tMatchPlayer.FlashDurationSelf). - SetFlashDurationEnemy(tMatchPlayer.FlashDurationEnemy). - SetFlashTotalEnemy(tMatchPlayer.FlashTotalEnemy). - SetFlashTotalSelf(tMatchPlayer.FlashTotalSelf). - SetFlashTotalTeam(tMatchPlayer.FlashTotalTeam). - SetDmgTeam(tMatchPlayer.DmgTeam). - SetDmgEnemy(tMatchPlayer.DmgEnemy). - Save(context.Background()) + for _, eqDmg := range eqMap[tMatchPlayer.PlayerStats] { + err := p.db.WeaponStats.Create().SetStat(nMatchPLayer).SetDmg(eqDmg.Dmg).SetVictim(eqDmg.To).SetHitGroup(eqDmg.HitGroup).SetEqType(eqDmg.Eq).Exec(context.Background()) if err != nil { - log.Errorf("[DP] Unable to update stats %d in database: %v", tMatchPlayer.PlayerStats, err) - continue - } - - for _, eqDmg := range eqMap[tMatchPlayer.PlayerStats] { - err := p.db.WeaponStats.Create().SetStat(nMatchPLayer).SetDmg(eqDmg.Dmg).SetVictim(eqDmg.To).SetHitGroup(eqDmg.HitGroup).SetEqType(eqDmg.Eq).Exec(context.Background()) - if err != nil { - log.Errorf("[DP] Unable to create WeaponStat: %v", err) - } - } - - for _, eco := range ecoMap[tMatchPlayer.PlayerStats] { - err := p.db.RoundStats.Create().SetStat(nMatchPLayer).SetRound(uint(eco.Round)).SetBank(uint(eco.Bank)).SetEquipment(uint(eco.EqV)).SetSpent(uint(eco.Spent)).Exec(context.Background()) - if err != nil { - log.Errorf("[DP] Unable to create RoundStat: %v", err) - } + log.Errorf("[DP] Unable to create WeaponStat: %v", err) } } - log.Infof("[DP] parsed match %d (took %s/%s)", demo.MatchId, downloadTime, time.Since(startTime)) - - err = demoParser.Close() - if err != nil { - log.Errorf("[DP] Unable close demo file for match %d: %v", demo.MatchId, err) + for _, eco := range ecoMap[tMatchPlayer.PlayerStats] { + err := p.db.RoundStats.Create().SetStat(nMatchPLayer).SetRound(uint(eco.Round)).SetBank(uint(eco.Bank)).SetEquipment(uint(eco.EqV)).SetSpent(uint(eco.Spent)).Exec(context.Background()) + if err != nil { + log.Errorf("[DP] Unable to create RoundStat: %v", err) + } } } + + log.Infof("[DP] parsed match %d (took %s/%s)", demo.MatchId, downloadTime, time.Since(startTime)) + + err = demoParser.Close() + if err != nil { + log.Errorf("[DP] Unable close demo file for match %d: %v", demo.MatchId, err) + } } }