public async Task <Wn8ExpectedValues> GetXvmWn8ExpectedValuesAsync() { Log.Debug("Obtendo os WN8 da XVM"); const string url = "https://static.modxvm.com/wn8-data-exp/json/wn8exp.json"; var content = await GetContent("Wn8XVM.json", url, WebCacheAge, false, Encoding.UTF8); var json = content.Content; var ev = new Wn8ExpectedValues(); var j = JObject.Parse(json); var h = j["header"]; ev.Source = (string)h["source"]; ev.Version = (string)h["version"]; var d = j["data"]; foreach (var dd in d.Children()) { ev.Add(new Wn8TankExpectedValues { TankId = (long)dd["IDNum"], Def = (double)dd["expDef"], Frag = (double)dd["expFrag"], Spot = (double)dd["expSpot"], Damage = (double)dd["expDamage"], WinRate = (double)dd["expWinRate"] / 100.0 }); } return(ev); }
/// <summary> /// Calculate all properties /// </summary> /// <param name="wn8ExpectedValues">The reference tanks</param> public void Calculate(Wn8ExpectedValues wn8ExpectedValues) { PruneTanks(wn8ExpectedValues); Performance.ExpectedValues = wn8ExpectedValues; Performance.CalculateAllTanks(); TotalTime = Performance.GetTime(); TotalBattles = Performance.GetBattles(); TotalWinRate = Performance.GetWinRate(); TotalTier = Performance.GetTier(); TotalWn8 = Performance.GetWn8(); MonthTime = Performance.GetTime(ReferencePeriod.Month); MonthBattles = Performance.GetBattles(ReferencePeriod.Month); MonthWinRate = Performance.GetWinRate(ReferencePeriod.Month); MonthTier = Performance.GetTier(ReferencePeriod.Week); MonthWn8 = Performance.GetWn8(ReferencePeriod.Month); WeekTime = Performance.GetTime(ReferencePeriod.Week); WeekBattles = Performance.GetBattles(ReferencePeriod.Week); WeekWinRate = Performance.GetWinRate(ReferencePeriod.Week); WeekTier = Performance.GetTier(ReferencePeriod.Week); WeekWn8 = Performance.GetWn8(ReferencePeriod.Week); Tier10TotalBattles = Performance.GetBattles(ReferencePeriod.All, 10); Tier10TotalTime = Performance.GetTime(ReferencePeriod.All, 10); Tier10TotalWinRate = Performance.GetWinRate(ReferencePeriod.All, 10); Tier10TotalWn8 = Performance.GetWn8(ReferencePeriod.All, 10); Tier10MonthBattles = Performance.GetBattles(ReferencePeriod.Month, 10); Tier10MonthTime = Performance.GetTime(ReferencePeriod.Month, 10); Tier10MonthWinRate = Performance.GetWinRate(ReferencePeriod.Month, 10); Tier10MonthWn8 = Performance.GetWn8(ReferencePeriod.Month, 10); }
private static void TestWN8Calculation() { string connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString; DbProvider provider = new DbProvider(connectionString); Wn8ExpectedValues expected = provider.GetWn8ExpectedValues(Platform.XBOX); Dictionary <long, TankPlayerStatistics> fakePlayed = new Dictionary <long, TankPlayerStatistics>(); foreach (Wn8TankExpectedValues e in expected.AllTanks) { fakePlayed.Add(e.TankId, new TankPlayerStatistics { Battles = 100000, DamageDealt = (long)(e.Damage * 100000), Wins = (long)(e.WinRate * 100000), Kills = (long)(e.Frag * 100000), Spotted = (long)(e.Spot * 100000), DroppedCapturePoints = (long)(e.Def * 100000) }); } // Teste do geral double wn8 = expected.CalculateWn8(fakePlayed); Log.Info($"WN8 de Referência: {wn8} - Deve ser proximo de 1565"); // Teste de um jogador (eu!) Stopwatch sw = Stopwatch.StartNew(); Player p = provider.GetPlayer(1763298, true); p.Calculate(expected); sw.Stop(); Log.Info($"All: {p.TotalWn8:N0} on {p.TotalBattles:N0} @ {p.TotalWinRate:P2} on Tier {p.TotalTier:N1}"); Log.Info($"Month: {p.MonthWn8:N0} on {p.MonthBattles:N0} @ {p.MonthWinRate:P2} on Tier {p.MonthTier:N1}"); Log.Info($"Week: {p.WeekWn8:N0} on {p.WeekBattles:N0} @ {p.WeekWinRate:P2} on Tier {p.WeekTier:N1}"); Log.Debug($"In {sw.Elapsed.TotalMilliseconds:N0}ms"); foreach (KeyValuePair <long, TankPlayerStatistics> t in p.Performance.Month) { Wn8TankExpectedValues td = expected[t.Key]; if (td.Tier < 10) { continue; } Log.Debug($"{td.Name}: {t.Value.Wn8:N0}"); } // Teste de dano esperado para um tanque qualquer (T110E5) sw = Stopwatch.StartNew(); Wn8TankExpectedValues te = expected[10785]; double damageAverage = te.GetTargetDamage(Wn8Rating.Average); double damageGood = te.GetTargetDamage(Wn8Rating.Good); double damageGreat = te.GetTargetDamage(Wn8Rating.Great); double damageUnicum = te.GetTargetDamage(Wn8Rating.Unicum); sw.Stop(); Log.Debug($"Target Damages em {sw.Elapsed.TotalMilliseconds:N1}ms: {damageAverage:N0}; {damageGood:N0}; {damageGreat:N0}; {damageUnicum:N0}"); }
/// <summary> /// Calculate performance metrics on the player /// </summary> /// <param name="wn8ExpectedValues"></param> public void CalculatePerformance(Wn8ExpectedValues wn8ExpectedValues) { if (Tanks.Length == 0) { return; } // Only tanks that I know about Tanks = Tanks.Where(t => wn8ExpectedValues.Exists(t.TankId) && t.All.Battles > 0).ToArray(); if (Tanks.Length == 0) { return; } Battles = Tanks.Sum(t => t.All.Battles); WinRate = Tanks.Sum(t => t.All.Wins) * 1.0 / Battles; AvgTier = Tanks.Sum(t => wn8ExpectedValues[t.TankId].Tier * t.All.Battles) * 1.0 / Battles; Wn8 = wn8ExpectedValues.CalculateWn8(Tanks.ToDictionary(t => t.TankId, t => (TankPlayerWn8Statistics)t.All)); Tier10Tanks = Tanks.Where(t => wn8ExpectedValues[t.TankId].Tier == 10).ToArray(); if (Tier10Tanks.Length == 0) { return; } Tier10Battles = Tier10Tanks.Sum(t => t.All.Battles); Tier10WinRate = Tier10Tanks.Sum(t => t.All.Wins) * 1.0 / Tier10Battles; Tier10Wn8 = wn8ExpectedValues.CalculateWn8(Tier10Tanks.ToDictionary(t => t.TankId, t => (TankPlayerWn8Statistics)t.All)); Tier10DirectDamage = Tier10Tanks.Sum(t => t.All.DamageDealt) * 1.0 / Tier10Battles; }
/// <summary> /// Salva os valores esperados no BD, e dispara a atualização local /// </summary> public void Set(Wn8ExpectedValues ev, bool computeConsoleValues) { Log.DebugFormat("Salvando Wn8 Expected Values BD..."); var sw = Stopwatch.StartNew(); Execute(transaction => { Set(ev, computeConsoleValues, transaction); }); Log.DebugFormat("Salva Wn8 Expected Values no BD em {0}.", sw.Elapsed); }
private static void Set(Wn8ExpectedValues ev, SqlTransaction t) { DateTime now = DateTime.UtcNow; using (var cmd = new SqlCommand("Tanks.SetWn8ExpectedLoad", t.Connection, t)) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 5 * 60; cmd.Parameters.AddWithValue("@date", now.Date); cmd.Parameters.AddWithValue("@source", ev.Source); cmd.Parameters.AddWithValue("@version", ev.Version); cmd.Parameters.AddWithValue("@moment", now); cmd.ExecuteNonQuery(); } using (var cmd = new SqlCommand("Tanks.SetWn8ExpectedValues", t.Connection, t)) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 5 * 60; foreach (var v in ev.AllTanks) { cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("@date", now.Date); cmd.Parameters.AddWithValue("@source", ev.Source); cmd.Parameters.AddWithValue("@version", ev.Version); cmd.Parameters.AddWithValue("@tankId", v.TankId); cmd.Parameters.AddWithValue("@def", v.Def); cmd.Parameters.AddWithValue("@frag", v.Frag); cmd.Parameters.AddWithValue("@spot", v.Spot); cmd.Parameters.AddWithValue("@damage", v.Damage); cmd.Parameters.AddWithValue("@winRate", v.WinRate); cmd.ExecuteNonQuery(); } } // Dispara o completamento da tabela using (var cmd = new SqlCommand("Tanks.CompleteWn8Expected", t.Connection, t)) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 5 * 60; cmd.ExecuteNonQuery(); } }
private void PruneTanks(Wn8ExpectedValues wn8ExpectedValues) { void CompleteOnDictionary(IDictionary <long, TankPlayerStatistics> dic) { foreach (var kv in dic) { var t = wn8ExpectedValues[kv.Key]; if (t == null) { continue; } kv.Value.Platform = t.Platform; kv.Value.TankId = t.TankId; kv.Value.Name = t.Name; kv.Value.Tag = t.Tag; kv.Value.Tier = t.Tier; kv.Value.Type = t.Type; kv.Value.Nation = t.Nation; kv.Value.IsPremium = t.IsPremium; } } CompleteOnDictionary(Performance.All); CompleteOnDictionary(Performance.Month); CompleteOnDictionary(Performance.Week); void CleanIncompleteTanks(IDictionary <long, TankPlayerStatistics> dic) { var toRemove = new HashSet <long>(); foreach (var kv in dic) { if (kv.Value.TankId == 0) { toRemove.Add(kv.Key); } } foreach (var tankId in toRemove) { dic.Remove(tankId); } } CleanIncompleteTanks(Performance.All); CleanIncompleteTanks(Performance.Month); CleanIncompleteTanks(Performance.Week); }
private static void RetrievePlayer(Player player, Fetcher fetcher, DbProvider provider, DbRecorder recorder, IReadOnlyDictionary <long, Tank> allTanks, Wn8ExpectedValues wn8Expected, Putter putter) { var tanks = fetcher.GetTanksForPlayer(player.Plataform, player.Id); var validTanks = tanks.Where(t => allTanks.ContainsKey(t.TankId)).ToArray(); recorder.Set(validTanks); var played = provider.GetWn8RawStatsForPlayer(player.Plataform, player.Id); player.Performance = played; player.Calculate(wn8Expected); player.Moment = DateTime.UtcNow; player.Origin = PlayerDataOrigin.Self; var previous = provider.GetPlayer(player.Id, player.Date, true); if (previous != null) { if (player.Check(previous, true)) { Log.Warn($"Player {player.Name}.{player.Id}@{player.Plataform} was patched."); } } if (player.CanSave()) { recorder.Set(player); if (!player.IsPatched) { _ = Task.Run(() => { try { putter?.Put(player); } catch (Exception ex) { Log.Error($"Error putting player {player.Id} on the remote site.", ex); } }); } } else { Log.Warn($"Player {player.Name}.{player.Id}@{player.Plataform} has to much zero data."); } }
/// <summary> /// Exporta o WN8 esperado /// </summary> public static void CalculateWn8Expected() { string connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString; DbProvider provider = new DbProvider(connectionString); FtpPutter putter = new FtpPutter(ConfigurationManager.AppSettings["PsFtpFolder"], ConfigurationManager.AppSettings["PsFtpUser"], ConfigurationManager.AppSettings["PsFtpPassworld"]); string resultDirectory = ConfigurationManager.AppSettings["PsResultDirectory"]; Wn8ExpectedValues wn8 = provider.GetWn8ExpectedValues(Platform.PS); if (wn8 != null) { string json = JsonConvert.SerializeObject(wn8, Formatting.Indented); string file = Path.Combine(resultDirectory, "MoE", $"{wn8.Date:yyyy-MM-dd}.WN8.json"); File.WriteAllText(file, json, Encoding.UTF8); Log.DebugFormat("Salvo o WN8 Expected em '{0}'", file); putter.PutMoe(file); Log.Debug("Feito uploado do WN8"); } }
private static void Set(Wn8ExpectedValues ev, bool computeConsoleValues, SqlTransaction t) { var now = DateTime.UtcNow; using (var cmd = new SqlCommand("Tanks.SetWn8ExpectedLoad", t.Connection, t)) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 5 * 60; cmd.Parameters.AddWithValue("@date", now.Date); cmd.Parameters.AddWithValue("@source", ev.Source); cmd.Parameters.AddWithValue("@version", ev.Version); cmd.Parameters.AddWithValue("@moment", now); cmd.ExecuteNonQuery(); } var setProcedure = ev.Source switch { Wn8ExpectedValuesSources.Xvm => "Tanks.[SetWn8PcExpectedValues]", Wn8ExpectedValuesSources.WotcStat => "Tanks.[SetWn8ConsoleExpectedValues]", _ => throw new ArgumentOutOfRangeException(nameof(ev.Source), ev.Source, @"Source not supported"), }; using (var cmd = new SqlCommand(setProcedure, t.Connection, t)) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 5 * 60; foreach (var v in ev.AllTanks) { cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("@date", now.Date); cmd.Parameters.AddWithValue("@source", ev.Source); cmd.Parameters.AddWithValue("@version", ev.Version); cmd.Parameters.AddWithValue("@tankId", v.TankId); cmd.Parameters.AddWithValue("@def", v.Def); cmd.Parameters.AddWithValue("@frag", v.Frag); cmd.Parameters.AddWithValue("@spot", v.Spot); cmd.Parameters.AddWithValue("@damage", v.Damage); cmd.Parameters.AddWithValue("@winRate", v.WinRate); cmd.ExecuteNonQuery(); } } if (computeConsoleValues) { var computeProcedure = ev.Source switch { Wn8ExpectedValuesSources.Xvm => "Tanks.[CalculateWn8ConsoleExpectedFromXvm]", Wn8ExpectedValuesSources.WotcStat => string.Empty, // no need to compute anything _ => throw new ArgumentOutOfRangeException(nameof(ev.Source), ev.Source, @"Source not supported"), }; if (!string.IsNullOrWhiteSpace(computeProcedure)) { using var cmd = new SqlCommand(computeProcedure, t.Connection, t); cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 5 * 60; cmd.ExecuteNonQuery(); } } }
private static void RetrievePlayer(Player player, Fetcher fetcher, Fetcher externalFetcher, DbProvider provider, DbRecorder recorder, IReadOnlyDictionary <long, Tank> allTanks, Wn8ExpectedValues wn8Expected, Putter putter) { Task <Player> externalTask = null; if (externalFetcher != null) { externalTask = externalFetcher.GetPlayerWn8Async((Player)player.Clone()); } var tanks = fetcher.GetTanksForPlayer(player.Plataform, player.Id); var validTanks = tanks.Where(t => allTanks.ContainsKey(t.TankId)).ToArray(); recorder.Set(validTanks); var played = provider.GetWn8RawStatsForPlayer(player.Plataform, player.Id); player.Performance = played; player.Calculate(wn8Expected); player.Moment = DateTime.UtcNow; player.Origin = PlayerDataOrigin.Self; var previous = provider.GetPlayer(player.Id, player.Date, true); if (previous != null) { if (player.Check(previous, true)) { Log.Warn($"Player {player.Name}.{player.Id}@{player.Plataform} was patched."); } } if (player.CanSave()) { recorder.Set(player); if (!player.IsPatched) { putter?.Put(player); } } else { Log.Warn($"Player {player.Name}.{player.Id}@{player.Plataform} has to much zero data."); } // Se foi feita a chamada na API externa, espero o retorno, que será ignorado; mas serviu para popular o BD do parceiro. externalTask?.Wait(); }
public TanksWn8(Wn8ExpectedValues ev) { _ev = ev; Tanks = ev.AllTanks.OrderByDescending(t => t.Tier).ThenBy(t => t.Type) .ThenBy(t => t.Nation).ThenBy(t => t.Nation).ToArray(); }