private async Task DecideIsTraining(Match match)
        {
            var ma = await _db.Matches.IgnoreQueryFilters().Include(m => m.PlayerData).SingleAsync(m => m.MatchId == match.MatchId);

            ma.IsTraining = ma.PlayerData.All(p => p.Team == match.Winner) ||
                            ma.PlayerData.All(p => p.Team != match.Winner);
            _db.Entry(ma).State = EntityState.Modified;
            await _db.SaveChangesAsync();
        }
        private async Task <Duel> CreateDuel(Match match, int order, int winner, float time)
        {
            Duel duel = new Duel
            {
                MatchId   = match.MatchId,
                Order     = order,
                Winner    = winner,
                TimeStamp = time
            };

            _db.Duels.Add(duel);
            await _db.SaveChangesAsync();

            return(duel);
        }
        private async Task <Match> CreateMatch(int winner, float duration, int lastWave)
        {
            Match match = new Match
            {
                Winner     = winner,
                Duration   = duration,
                LastWave   = lastWave,
                Date       = DateTime.Now,
                IsTraining = true
            };

            _db.Matches.Add(match);
            await _db.SaveChangesAsync();

            return(match);
        }
        private async Task ModifyRatings(List <PlayerMatchData> playerMatchDatas, Match match)
        {
            var l = new List <Player>();

            foreach (var pl in playerMatchDatas)
            {
                l.Add(await _db.Players
                      .Include(p => p.Matches)
                      .ThenInclude(m => m.Match.PlayerData)
                      .SingleAsync(player => player.SteamId == pl.PlayerId));
            }
            foreach (var p in l.Select(p => p.Matches.Single(m => m.MatchId == match.MatchId)))
            {
                p.RatingChange = p.CalculateRatingChange();
            }
            await _db.SaveChangesAsync();
        }
        private async Task <PlayerMatchData> CreatePlayerMatchData(Player player, Match match, string fraction, int team,
                                                                   bool abandoned, int earnedTangos, int earnedGold)
        {
            PlayerMatchData result = new PlayerMatchData
            {
                Player       = player,
                Match        = match,
                Abandoned    = abandoned,
                Team         = team,
                Fraction     = await GetOrCreateFraction(fraction),
                EarnedTangos = earnedTangos,
                EarnedGold   = earnedGold
            };

            _db.Entry(player).State          = EntityState.Modified;
            _db.Entry(match).State           = EntityState.Modified;
            _db.Entry(result.Fraction).State = EntityState.Modified;
            _db.PlayerMatchData.Add(result);

            await _db.SaveChangesAsync();

            return(result);
        }
        public async Task <ActionResult> SaveMatchData(int?winner, string playerDataString, float duration,
                                                       int lastWave, string duelDataString)
        {
            if (!winner.HasValue || string.IsNullOrEmpty(playerDataString))
            {
                return(Json(new MissingArgumentFailure()));
            }

            //Creating Match
            Match match = await CreateMatch(winner.Value, duration, lastWave);

            //Adding Duels
            if (!string.IsNullOrEmpty(duelDataString))
            {
                Dictionary <int, Dictionary <String, float> > duelData = null;
                try
                {
                    duelData = JsonConvert.DeserializeObject <Dictionary <int, Dictionary <String, float> > >(duelDataString);
                }
                catch (Exception)
                {
                    try
                    {
                        var data = JsonConvert.DeserializeObject <List <Dictionary <String, float> > >(duelDataString);
                        for (int i = 0; i < data.Count; i++)
                        {
                            duelData[i + 1] = data[i];
                        }
                    }
                    catch (Exception) { }
                }
                if (duelData != null)
                {
                    foreach (var pair in duelData)
                    {
                        var  order = pair.Key;
                        var  data  = pair.Value;
                        Duel duel  = await CreateDuel(match, order, (int)data["winner"], data["time"]);
                    }
                }
            }

            //Adding player Data
            var playerData =
                JsonConvert.DeserializeObject <Dictionary <long, Dictionary <string, string> > >(playerDataString);
            List <Player>          players          = new List <Player>();
            List <PlayerMatchData> playerMatchDatas = new List <PlayerMatchData>();

            foreach (var pair in playerData)
            {
                long steamId = pair.Key;
                Dictionary <string, string> decodedData = pair.Value;
                Player player = await GetOrCreatePlayer(steamId);

                PlayerMatchData playerMatchData = await CreatePlayerMatchData(player,
                                                                              match,
                                                                              decodedData["fraction"],
                                                                              int.Parse(decodedData["team"]),
                                                                              bool.Parse(decodedData["abandoned"]),
                                                                              int.Parse(decodedData["earned_tangos"]),
                                                                              int.Parse(decodedData["earned_gold"]));

                List <PlayerUnitRelation> playerUnitRelations =
                    await CreatePlayerUnitRelations(playerMatchData, decodedData);

                players.Add(player);
                playerMatchDatas.Add(playerMatchData);
            }
            await DecideIsTraining(match);
            await ModifyRatings(playerMatchDatas, match);

            await _steamApi.UpdatePlayerInformation(players.Select(p => p.SteamId));

            return(Json(new { Success = true }));
        }
Esempio n. 7
0
        public async Task <ActionResult> SaveMatchData(int?winner, string playerDataString, float duration,
                                                       int lastWave, string duelDataString)
        {
            if (!winner.HasValue || string.IsNullOrWhiteSpace(playerDataString))
            {
                return(Json(new MissingArgumentFailure()));
            }

            try
            {
                var strategy = _db.Database.CreateExecutionStrategy();
                var matchId  = await strategy.ExecuteAsync(async() =>
                {
                    using var transaction = await _db.Database.BeginTransactionAsync();
                    //Creating Match
                    Match match = new Match
                    {
                        Winner     = winner.Value,
                        Duration   = duration,
                        LastWave   = lastWave,
                        Date       = DateTime.UtcNow,
                        IsTraining = true,
                        Duels      = new List <Duel>(),
                        PlayerData = new List <PlayerMatchData>()
                    };
                    _db.Matches.Add(match);
                    await _db.SaveChangesAsync();
                    using var loggingContext = new LoggingContext($"#{match.MatchId}");
                    LoggingUtil.Log($"Adding Match {match.MatchId}");

                    //Adding Duels
                    int createdDuels = 0;
                    if (duelDataString.TryToJson(out JsonDocument duelDocument) &&
                        duelDocument.RootElement.ValueKind == JsonValueKind.Object)
                    {
                        foreach (var duelProp in duelDocument.RootElement.EnumerateObject())
                        {
                            var order      = int.Parse(duelProp.Name);
                            var time       = duelProp.Value.GetFloatOrDefault("time");
                            var duelWinner = duelProp.Value.GetIntOrDefault("winner");
                            Duel duel      = new Duel
                            {
                                Match     = match,
                                MatchId   = match.MatchId,
                                Order     = order,
                                Winner    = duelWinner,
                                TimeStamp = time
                            };
                            match.Duels.Add(duel);
                            _db.Duels.Add(duel);
                            createdDuels += 1;
                        }
                    }
                    else
                    {
                        LoggingUtil.Warn($"No duel data available for Game");
                    }
                    await _db.SaveChangesAsync();

                    //Adding player Data
                    var playerObjs = playerDataString.ToJsonElement();
                    var steamIds   = playerObjs.EnumerateObject().Select(p => long.Parse(p.Name)).ToList();
                    var players    = await _db.GetOrCreateAsync(
                        steamIds,
                        p => p.SteamId,
                        steamId => new Player
                    {
                        SteamId = steamId,
                        Matches = new List <PlayerMatchData>()
                    },
                        query: players => players
                        .Include(p => p.Matches)
                        .ThenInclude(m => m.Match)
                        ); // We request the match history to calculate the rating change
                    try
                    {
                        var steamInfo = await _steamApi.RequestPlayerInformation(steamIds);
                        players.ForEach(p => p.Update(steamInfo[p.SteamId]));
                    }
                    catch (Exception)
                    {
                        LoggingUtil.Warn("Couldn't retrieve steam info.");
                    }
                    await _db.SaveChangesAsync();


                    // Enter player match data
                    var playerData = new List <PlayerMatchData>();
                    foreach (var(steamId, player) in steamIds.Zip(players))
                    {
                        var data        = playerObjs.GetProperty(steamId.ToString());
                        var rawUnitData = data.GetProperty("unit_data");
                        var unitData    = new Dictionary <string, UnitData>();
                        if (rawUnitData.ValueKind == JsonValueKind.Object)
                        {
                            unitData = ExtractPlayerUnitData(rawUnitData);
                        }
                        else
                        {
                            LoggingUtil.Warn($"No unit data for {steamId}");
                        }
                        var newData = new PlayerMatchData
                        {
                            Player       = player,
                            PlayerId     = steamId,
                            Match        = match,
                            MatchId      = match.MatchId,
                            Abandoned    = data.GetBoolOrDefault("abandoned"),
                            Team         = data.GetIntOrDefault("team"),
                            FractionName = data.GetValueOrDefault("fraction"),
                            EarnedTangos = data.GetIntOrDefault("earned_tangos"),
                            EarnedGold   = data.GetIntOrDefault("earned_gold"),
                            UnitData     = unitData
                        };
                        player.Matches.Add(newData);
                        match.PlayerData.Add(newData);
                        playerData.Add(newData);
                    }
                    // Retrieve exp for units
                    var unitNames   = playerData.SelectMany(p => p.UnitData.Object.Keys).Distinct().ToList();
                    var units       = await _db.GetOrCreateAsync(unitNames, u => u.Name, name => CreateUnitOrBuilder(name));
                    var experiences = units.ToDictionary(u => u.Name, u => u.Experience);
                    // Check whether this is a training match
                    match.IsTraining = DecideIsTraining(match, playerData);
                    // Update ratings and statistics
                    foreach (var pd in playerData)
                    {
                        pd.CalculateStats(experiences);
                        pd.RatingChange = pd.CalculateRatingChange();  // this requires having all player histories loaded
                    }
                    _db.PlayerMatchData.AddRange(playerData);
                    await _db.SaveChangesAsync();
                    lock (_dbLock)
                    {
                        transaction.Commit();
                    }
                    LoggingUtil.Log($"Succesfully saved; Wave {lastWave}; Duration {duration}; Players: {players.Count}; Duels: {createdDuels}; IsTraining: {match.IsTraining}");
                    return(match.MatchId);
                });