public async Task <IHttpActionResult> GetAbilityDraftMatch(long id) { AbilityDraftMatch abilityDraftMatch = await db.AbilityDraftMatches.Include(m => m.Players.Select(p => p.Abilities)) .Include(m => m.Players.Select(p => p.Hero.Roles)).SingleOrDefaultAsync(m => m.MatchId == id); if (abilityDraftMatch == null) { var gameFetcher = ServiceLocator.GetInstance().GetService <IGameFetcher>(); try { abilityDraftMatch = await gameFetcher.FetchGame(id.ToString()); } catch (GameFetcherException e) { return(InternalServerError(e)); } //if we did not get a match from our game fetcher than as far as we know it doesn't exist and return notfound if (abilityDraftMatch == null) { return(NotFound()); } //add the fetched game to the database and update stats related to this match var matchDetailUpdater = new MatchDetailUpdater(ServiceLocator.GetInstance().GetService <IDataSource>(), ServiceLocator.GetInstance().GetService <IStatUpdater>()); await matchDetailUpdater.UpdateDataSourceAndStats(abilityDraftMatch); } var dto = AbilityDraftMatchDataTransferObject.CreateAbilityDraftMatchDataTransferObject(abilityDraftMatch); return(Ok(dto)); }
private async Task <HeroAbilityStat> CreateNewHeroAbilityStat(AbilityDraftMatch match, Player player, Ability ability) { //lookup existing hero and ability from datasource. These should be in there because we add the match to the datasource before updating stats. var existingHero = await dataSource.LookupHero(player.Hero.HeroId); var existingAbility = await dataSource.LookupAbility(ability.AbilityId); if (existingHero == null) { throw new StatUpdaterException("An existing hero with heroId " + player.Hero.HeroId + " could not be found."); } if (existingAbility == null) { throw new StatUpdaterException("An existing ability with abilityId " + ability.AbilityId + " could not be found."); } existingHero.EntityState = ModelEntityState.Unchanged; existingAbility.EntityState = ModelEntityState.Unchanged; return(new HeroAbilityStat { HeroId = existingHero.HeroId, AbilityId = existingAbility.AbilityId, Matches = 1, Wins = PlayerWonMatch(match, player) ? 1 : 0, Hero = existingHero, Ability = existingAbility, EntityState = ModelEntityState.Added }); }
public async Task UpdateStats(AbilityDraftMatch match) { foreach (Player player in match.Players) { foreach (Ability ability in player.Abilities) { var existingHeroAbilityStat = await dataSource.LookupHeroAbilityStat(player.Hero.HeroId, ability.AbilityId); if (existingHeroAbilityStat == null) { var newStat = await CreateNewHeroAbilityStat(match, player, ability); await AddHeroAbilityStat(newStat); } else { existingHeroAbilityStat.Matches++; existingHeroAbilityStat.Wins = PlayerWonMatch(match, player) ? existingHeroAbilityStat.Wins + 1 : existingHeroAbilityStat.Wins; existingHeroAbilityStat.EntityState = ModelEntityState.Modified; await UpdateHeroAbilityStat(existingHeroAbilityStat); } } } }
public async Task UpdateDataSourceAndStats(AbilityDraftMatch match) { match.EntityState = ModelEntityState.Added; var addedAbilities = new List <Ability>(); //some abilities such as talents can be learned by multiple heroes in the same match so we need to make sure //we dont add that ability multiple times from the same match. foreach (var player in match.Players) { player.EntityState = ModelEntityState.Added; var foundHero = await dataSource.LookupHero(player.Hero.HeroId); player.Hero.EntityState = foundHero == null ? ModelEntityState.Added : ModelEntityState.Unchanged; //add it if not found else leave it unchanged. foreach (var ability in player.Abilities.ToList()) { //lookup ability in abilities added this match first, else lookup in datasource. var foundAbility = addedAbilities.FirstOrDefault(a => a.AbilityId == ability.AbilityId); if (foundAbility == null) { foundAbility = await dataSource.LookupAbility(ability.AbilityId); if (foundAbility != null) { foundAbility.EntityState = ModelEntityState.Unchanged; //if we got the item from the database we don't want it to be readded. addedAbilities.Add(foundAbility); //add it to local list so we don't have to lookup from datasource multiple times. } } if (foundAbility != null) //if ability exists in datasource or abilities added this game. { player.Abilities.Remove(ability); //remove the object that has the same abilityid and replace it with the one that is either already in the //datasource or has been set up to be added to the datasource. This prevents 2 objects in the datasource with the same abilityId. player.Abilities.Add(foundAbility); } else { ability.EntityState = ModelEntityState.Added; addedAbilities.Add(ability); } } } bool matchSuccessfullyAdded = true; try { await this.dataSource.AddEntity <AbilityDraftMatch>(match); } catch (DataSourceException) { //if there's an issue adding the match to the datastore then we don't update stats with this match. matchSuccessfullyAdded = false; throw; } if (matchSuccessfullyAdded) //don't update stats if the match wasn't added successfully otherwise in future when we add the match again we might count stats twice. { try { await this.statUpdater.UpdateStats(match); } catch (StatUpdaterException) { throw; } } }
public async Task <AbilityDraftMatch> ToLocalAbilityDraftMatch(AbiltiyDraftGameJSON json) { var match = new AbilityDraftMatch { MatchId = json.match_id, StartTime = json.start_time, DurationSeconds = json.duration, ServerCluster = json.cluster, PatchNumber = json.patch, SkillLevel = json.skill, GameMode = json.game_mode, DireKillScore = json.dire_score, RadiantKillScore = json.radiant_score, RadiantWin = json.radiant_win, Players = new HashSet <Dota2HeroStats.Models.Player>() }; foreach (JSONModels.Player player in json.players) { var p = new Dota2HeroStats.Models.Player { MatchId = player.match_id, PlayerSlot = player.player_slot, AccountId = player.account_id, IsRadiant = player.isRadiant, Item_0 = player.item_0, Item_1 = player.item_1, Item_2 = player.item_2, Item_3 = player.item_3, Item_4 = player.item_4, Item_5 = player.item_5, Backpack_0 = player.backpack_0, Backpack_1 = player.backpack_1, Backpack_2 = player.backpack_2, HeroLevel = player.level, Kills = player.kills, Deaths = player.deaths, Assists = player.assists, LastHits = player.last_hits ?? 0, Denies = player.denies ?? 0, GoldPerMin = player.gold_per_min ?? 0, XpPerMin = player.xp_per_min ?? 0, HeroDamage = player.hero_damage ?? 0, HeroHealing = player.hero_healing ?? 0, TowerDamage = player.tower_damage ?? 0, Abilities = new HashSet <Dota2HeroStats.Models.Ability>() }; //Lookup heroid in database to see if it already exists and if so retrieve it. var hero = await LookupHero(player.hero_id); if (hero != null) { p.Hero = hero; } else { p.Hero = new Hero { HeroId = player.hero_id, Name = "unknown", LocalizedName = "unknown", PrimaryAttr = "unknown", AttackType = "unknown", Legs = 0, Roles = new HashSet <Role>() }; } //Lookup and add each ability if it exists. if (player.ability_upgrades_arr != null)//some older matches dont have a record of these and will be null. { var distinctAbilities = player.ability_upgrades_arr.Distinct(); foreach (int abilityId in distinctAbilities) { var ability = await LookupAbility(abilityId); if (ability != null) { p.Abilities.Add(ability); } else { p.Abilities.Add(new Ability { AbilityId = abilityId, Name = "unknown", Img = "unknown", IsUltimate = false }); } } } match.Players.Add(p); } return(match); }
private static bool PlayerWonMatch(AbilityDraftMatch match, Player player) { return((match.RadiantWin && player.IsRadiant) || (!match.RadiantWin && !player.IsRadiant)); }
public async Task UpdateStats(AbilityDraftMatch match) { await Task.WhenAll(StatUpdaters.Select(updater => updater.UpdateStats(match)).ToArray()); }
public static AbilityDraftMatchDataTransferObject CreateAbilityDraftMatchDataTransferObject(AbilityDraftMatch match) { return(new AbilityDraftMatchDataTransferObject { MatchId = match.MatchId, StartTime = match.StartTime, DurationSeconds = match.DurationSeconds, ServerCluster = match.ServerCluster, PatchNumber = match.PatchNumber, SkillLevel = match.SkillLevel, GameMode = match.GameMode, DireKillScore = match.DireKillScore, RadiantKillScore = match.RadiantKillScore, RadiantWin = match.RadiantWin, Players = match.Players.Select(p => PlayerDataTransferObject.CreatePlayerDataTransferObject(p)).ToList() }); }