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 })); }
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); });