ARAM balance data from aramonly.com

This commit is contained in:
2026-04-29 01:21:18 +02:00
parent 076c0a9a8d
commit 61eee88078
4 changed files with 141 additions and 119 deletions
+2 -39
View File
@@ -24,46 +24,9 @@ public partial class ChampionViewModel(ChampionData data) : ObservableObject
{
StringBuilder sb = new();
sb.AppendLine(data.Name);
foreach (KeyValuePair<string, double> kv in data.AramBalance)
if (data.AramBalance.HasValue)
{
switch (kv.Key)
{
case "dmg_dealt":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Dmg Dealt: {0:+#0%;-#0%}", kv.Value - 1);
break;
case "dmg_taken":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Dmg Taken: {0:+#0%;-#0%}", kv.Value - 1);
break;
case "healing":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Healing: {0:+#0%;-#0%}", kv.Value - 1);
break;
case "energyregen_mod":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Energy Regen: {0:+#0%;-#0%}", kv.Value - 1);
break;
case "tenacity":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Tenacity: {0:+#0%;-#0%}", kv.Value - 1);
break;
case "shielding":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Shielding: {0:+#0%;-#0%}", kv.Value - 1);
break;
case "ability_haste":
sb.AppendFormat("Ability Haste: {0}", kv.Value);
break;
case "total_as":
if (kv.Value == 1) { continue; }
sb.AppendFormat("Total AS: {0}", kv.Value);
break;
default:
sb.AppendFormat("{0}: {1}", kv.Key, kv.Value);
break;
}
sb.AppendLine();
data.AramBalance.Value.ToDisplayString(sb);
}
return sb.ToString();
}
+2 -2
View File
@@ -175,13 +175,13 @@ public partial class MainViewModel : ObservableObject, IDisposable
foreach (int championId in championIds)
{
ChampionData? championData = await _client.GetChampionByIdAsync(championId);
if (championData is null)
if (championData is null || championData.Name is null)
{
continue;
}
string imagePath = await ResourceService.GetChampionIconPathAsync(championId);
ChampionViewModel vm = new(championData with { AramBalance = _aramBalanceService.GetAramStats(championData.Id) })
ChampionViewModel vm = new(championData with { AramBalance = _aramBalanceService.GetAramChampion(championData.Name) })
{
IsNeededForChallenge = _needChampionIds.Contains(championData.Id),
ImagePath = imagePath,
+135 -77
View File
@@ -1,27 +1,17 @@
using System.Text.Json;
using CliWrap;
using CliWrap.Buffered;
using MoonSharp.Interpreter;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace LeagueAPI.ARAM;
public record class WikiChampion(int Id, WikiChampionStats Stats);
public record class WikiChampionStats(Dictionary<string, double> Aram);
public class ARAMBalanceLookup : Dictionary<int, Dictionary<string, double>> { }
public class ARAMBalanceLookup : Dictionary<string, AramChampion> { }
public class ARAMBalanceService
{
private static readonly string URL = "https://wiki.leagueoflegends.com/en-us/rest.php/v1/page/Module:ChampionData%2Fdata";
private static readonly string ARAMONLY_URL = "https://www.aramonly.com/page-data/aram-changes/page-data.json";
private ARAMBalanceLookup _champions = [];
static ARAMBalanceService()
{
UserData.RegisterType<WikiChampion>();
UserData.RegisterType<WikiChampionStats>();
}
public async Task EnsureIsLoadedAsync()
{
if (_champions is not { Count: > 0 })
@@ -39,71 +29,139 @@ public class ARAMBalanceService
return;
}
Command curl = Cli.Wrap("curl")
.WithArguments(URL);
BufferedCommandResult result = await curl.ExecuteBufferedAsync();
string json = result.StandardOutput;
JsonDocument jsonDocument = JsonDocument.Parse(json);
string lua = jsonDocument.RootElement.GetProperty("source").GetString() ?? string.Empty;
DynValue champs = Script.RunString(lua);
if (champs.Type == DataType.Table)
{
Dictionary<string, WikiChampion> nameDictionary = [];
foreach (TablePair kv in champs.Table.Pairs)
{
if (kv.Key.Type is not DataType.String || kv.Value.Type is not DataType.Table)
{
continue;
}
string key = kv.Key.String;
Table championTable = kv.Value.Table;
DynValue idValue = championTable.Get("id");
DynValue statsValue = championTable.Get("stats");
Dictionary<string, double> aramStats = [];
if (statsValue.Type is DataType.Table)
{
DynValue aramValue = statsValue.Table.Get("aram");
if (aramValue.Type is DataType.Table)
{
foreach (TablePair aramKv in aramValue.Table.Pairs)
{
if (aramKv.Key.Type is DataType.String && aramKv.Value.Type is DataType.Number)
{
aramStats[aramKv.Key.String] = aramKv.Value.Number;
}
}
}
}
WikiChampion champ = new(idValue.Type is DataType.Number ? (int)idValue.Number : -1, new(aramStats));
nameDictionary.Add(key, champ);
}
_champions = [];
foreach (KeyValuePair<string, WikiChampion> kv in nameDictionary)
{
if (!_champions.TryGetValue(kv.Value.Id, out Dictionary<string, double>? value))
{
_champions[kv.Value.Id] = new(kv.Value.Stats.Aram);
}
else
{
kv.Value.Stats.Aram.ToList().ForEach(kv => value.Add(kv.Key, kv.Value));
}
}
ResourceService.SetARAMBalanceLookup(_champions);
}
await FetchFromAramonly();
}
public Dictionary<string, double> GetAramStats(int championId)
private async Task<bool> FetchFromAramonly()
{
using HttpClient _client = new();
using HttpResponseMessage response = await _client.GetAsync(ARAMONLY_URL);
if (!response.IsSuccessStatusCode)
{
return false;
}
string json = await response.Content.ReadAsStringAsync();
AramonlyComResponse? result = JsonSerializer.Deserialize<AramonlyComResponse?>(json);
AramChampion?[] nodes = result?.Result?.Data?.AllAramModifiersJson?.Nodes ?? [];
if (nodes is not { Length: > 0 })
{
return false;
}
_champions = [];
foreach (AramChampion? node in nodes)
{
if (node is null || !node.HasValue || !node.Value.Champion.HasValue)
{
continue;
}
string name = node.Value.Champion.Value.Name ?? string.Empty;
if (name == string.Empty)
{
continue;
}
_champions.Add(name, node.Value);
}
ResourceService.SetARAMBalanceLookup(_champions);
return true;
}
public AramChampion? GetAramChampion(string championName)
{
EnsureIsLoadedAsync().Wait();
return _champions.TryGetValue(championId, out Dictionary<string, double>? stats) ? stats : [];
return _champions.TryGetValue(championName, out AramChampion aramChampion) ? aramChampion : null;
}
}
public record struct AramonlyComResponse([property: JsonPropertyName("result")] AramonlyComResult? Result);
public record struct AramonlyComResult([property: JsonPropertyName("data")] AramonlyComData? Data);
public record struct AramonlyComData(
[property: JsonPropertyName("allAramModifiersJson")] AramonlyComModifiersJson? AllAramModifiersJson,
[property: JsonPropertyName("patchVersionJson")] PatchVersionJson? PatchVersionJson
);
public record struct AramonlyComModifiersJson([property: JsonPropertyName("nodes")] AramChampion?[]? Nodes);
public record struct AramChampion(
[property: JsonPropertyName("timestamp")] DateTime? Timestamp,
[property: JsonPropertyName("champion")] Champion? Champion,
[property: JsonPropertyName("aramDamageDealt")] double? AramDamageDealt,
[property: JsonPropertyName("aramDamageTaken")] double? AramDamageTaken,
[property: JsonPropertyName("aramHealing")] double? AramHealing,
[property: JsonPropertyName("aramShielding")] double? AramShielding,
[property: JsonPropertyName("aramTenacity")] double? AramTenacity,
[property: JsonPropertyName("aramAbilityHaste")] int? AramAbilityHaste,
[property: JsonPropertyName("aramAttackSpeed")] double? AramAttackSpeed,
[property: JsonPropertyName("aramEnergyRegen")] double? AramEnergyRegen
)
{
public readonly void ToDisplayString(StringBuilder sb)
{
// Damage Dealt
if (AramDamageDealt is not null and not 0 and not 1)
{
double value = (double)AramDamageDealt;
sb.AppendLine($"Dmg Dealt: {value - 1:+#0%;-#0%}");
}
// Damage Taken
if (AramDamageTaken is not null and not 0 and not 1)
{
double value = (double)AramDamageTaken;
sb.AppendLine($"Dmg Taken: {value - 1:+#0%;-#0%}");
}
// Healing
if (AramHealing is not null and not 0 and not 1)
{
double value = (double)AramHealing;
sb.AppendLine($"Healing: {value - 1:+#0%;-#0%}");
}
// Shielding
if (AramShielding is not null and not 0 and not 1)
{
double value = (double)AramShielding;
sb.AppendLine($"Shielding: {value - 1:+#0%;-#0%}");
}
// Tenacity
if (AramTenacity is not null and not 0 and not 1)
{
double value = (double)AramTenacity;
sb.AppendLine($"Tenacity: {value - 1:+#0%;-#0%}");
}
// Ability Haste (Raw value)
if (AramAbilityHaste is not null and not 0 and not 1)
{
double value = (double)AramAbilityHaste;
sb.AppendLine($"Ability Haste: {value}");
}
// Total AS (Raw value)
if (AramAttackSpeed is not null and not 0 and not 1)
{
double value = (double)AramAttackSpeed;
sb.AppendLine($"Total AS: {value}");
}
// Energy Regen (Percentage)
if (AramEnergyRegen is not null and not 0 and not 1)
{
double value = (double)AramEnergyRegen;
sb.AppendLine($"Energy Regen: {value - 1:+#0%;-#0%}");
}
}
}
public record struct Champion(
[property: JsonPropertyName("name")] string? Name,
[property: JsonPropertyName("sanitizedName")] string? SanitizedName
);
public record struct PatchVersionJson(
[property: JsonPropertyName("patchVersion")] string? PatchVersion
);
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using LeagueAPI.ARAM;
namespace LeagueAPI.Models.DDragon.Champions;
@@ -41,5 +42,5 @@ public record ChampionData
public ChampionDataStats? Stats { get; init; }
[JsonIgnore]
public Dictionary<string, double> AramBalance { get; set; } = [];
public AramChampion? AramBalance { get; set; }
}