Skip to content

Commit

Permalink
feat: implements new api from blitz
Browse files Browse the repository at this point in the history
  • Loading branch information
orteney committed Mar 17, 2024
1 parent 08c6ba2 commit 0189000
Show file tree
Hide file tree
Showing 12 changed files with 361 additions and 362 deletions.
26 changes: 26 additions & 0 deletions bin/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// ignore_for_file: avoid_print

import 'package:sebastian/data/blitz/blitz_build_mapper.dart';
import 'package:sebastian/data/blitz/blitz_data_source.dart';
import 'package:sebastian/data/repositories/build_repository.dart';
import 'package:sebastian/domain/core/role.dart';

Future<void> main(List<String> arguments) async {
final repository = BuildRepository(
BlitzDataSource(logEnabled: true),
BlitzBuildMapper(),
);

try {
final builds = await repository.getBuilds(
1,
role: Role.mid,
);

for (var build in builds.builds) {
print(build);
}
} catch (e) {
print(e);
}
}
115 changes: 77 additions & 38 deletions lib/data/blitz/blitz_build_mapper.dart
Original file line number Diff line number Diff line change
@@ -1,61 +1,78 @@
import 'package:collection/collection.dart';

import 'package:sebastian/data/blitz/models/blitz_builds_response.dart';
import 'package:sebastian/domain/builds/build_info.dart';

class BlitzBuildMapper {
BuildInfo call(BlitzBuild blitzBuild) {
blitzBuild.keystone.sortBy((element) => element.pickRate as num);
final keyStone = blitzBuild.keystone.last;

return BuildInfo(
keystoneId: blitzBuild.primaryRune,
keystoneId: keyStone.keystoneId,
winRate: ((blitzBuild.wins / blitzBuild.games) * 100).roundToDouble(),
numMatches: blitzBuild.games,
itemBuild: _mapBuildItems(
blitzBuild.mythicId,
blitzBuild.startingItems,
blitzBuild.coreItems,
blitzBuild.completedItems,
blitzBuild.situationalItems,
),
summonerSpells: blitzBuild.summonerSpells.first.summonerSpellIds,
runes: _mapBlitzRunes(blitzBuild.primaryRune, blitzBuild.runes),
skillPath: blitzBuild.skillOrders.firstOrNull?.skillOrder,
runes: _mapBlitzRunes(keyStone, blitzBuild.runes, blitzBuild.shards),
skillPath: blitzBuild.skillOrders?.firstOrNull?.skillOrder,
skillOrder: null,
);
}

Runes _mapBlitzRunes(int primaryRune, List<BlitzRune> runes) {
final List<List<BlitzRune>> sortedRunes = [[], [], [], [], [], [], [], []];

Runes _mapBlitzRunes(
BlitzKeystone keystone,
List<BlitzRunes> runes,
BlitzShards shards,
) {
final List<List<BlitzRunes>> sortedRunes = [[], [], [], [], []];
for (var rune in runes) {
if (rune.index < 3 && rune.treeId != keystone.treeId || rune.index > 4) {
continue;
}

sortedRunes[rune.index].add(rune);
}

final primaryPath = sortedRunes[0].first.treeId!;
for (var runes in sortedRunes) {
runes.sortBy<num>((element) => element.pickRate);
}

final firstRune = sortedRunes[0].last;
final primaryTree = <int>[
primaryRune,
sortedRunes[0].first.runeId,
sortedRunes[1].first.runeId,
sortedRunes[2].first.runeId,
keystone.keystoneId,
firstRune.runeId,
sortedRunes[1].last.runeId,
sortedRunes[2].last.runeId,
];

final subRune1 = sortedRunes[3].first;
final subRune2 = sortedRunes[4].firstWhere(
final subRune1 = sortedRunes[3].last;
final subRune2 = sortedRunes[4].lastWhere(
(rune) => rune.runeId != subRune1.runeId && rune.treeId == subRune1.treeId,
orElse: () => sortedRunes[4].first,
orElse: () => sortedRunes[4].last,
);
final subPath = subRune1.treeId!;
final subPath = subRune1.treeId;
final subTree = <int>[
subRune1.runeId,
subRune2.runeId,
];

shards.offenseShard.sortBy((element) => element.pickRate as num);
shards.flexShard.sortBy((element) => element.pickRate as num);
shards.defenseShard.sortBy((element) => element.pickRate as num);

final statTree = <int>[
sortedRunes[5].first.runeId,
sortedRunes[6].first.runeId,
sortedRunes[7].first.runeId,
int.parse(shards.offenseShard.last.shardId),
int.parse(shards.flexShard.last.shardId),
int.parse(shards.defenseShard.last.shardId),
];

return Runes(
primaryPath: primaryPath,
primaryPath: firstRune.treeId,
primary: primaryTree,
subPath: subPath,
sub: subTree,
Expand All @@ -64,35 +81,48 @@ class BlitzBuildMapper {
}

ItemBuild _mapBuildItems(
int mythicId,
List<BlitzStartingItem> startingItems,
List<BlitzItemSet> coreItems,
List<BlitzItem> completedItems,
List<BlitzItemStat> situationalItems,
List<BlitzStartingItems> startingItems,
List<BlitzCoreItem> coreItems,
List<BlitzSituationalItem> situationalItems,
) {
final coreBuild = coreItems.first.itemIds;
startingItems.sortBy((element) => element.pickRate as num);
coreItems.sortBy((element) => element.pickRate as num);
situationalItems.sortBy((element) => element.pickRate as num);

final startingBuild = startingItems.last.itemIds.map((e) => int.parse(e)).toList();

final coreBuild = coreItems.last.itemIds.split(',').map((e) => int.parse(e)).toList();
final coreBoots = coreBuild.firstWhereOrNull((element) => _boots.contains(element));
if (coreBoots != null) {
situationalItems.removeWhere((element) => _boots.contains(element.itemId));
}

final finalItems = (completedItems.toList()
..removeWhere(
(element) => coreBuild.contains(element.itemId) || (coreBoots != null && _boots.contains(element.itemId)),
)
..sort((a, b) => a.averageIndex.compareTo(b.averageIndex)))
.map<int>((e) => e.itemId);
// Add final support item to core build
if (startingBuild.contains(_worldAtlasId)) {
for (var item in situationalItems.reversed) {
if (_finalItemsFromWorldAtlas.contains(item.itemId)) {
coreBuild.add(item.itemId);
break;
}
}
}

final finalBuild = (coreBuild.toList()..addAll(finalItems)).take(6).toList();
final finalBuild = {
...coreBuild,
...situationalItems.reversed.map((e) => e.itemId),
}.take(6).toList();

final situational = (situationalItems.toList()..removeWhere((element) => finalBuild.contains(element.itemId)))
.take(6)
final situational = situationalItems.reversed
.where((element) => !finalBuild.contains(element.itemId))
.take(10)
.map((e) => e.itemId)
.toList();

return ItemBuild(
startBuild: startingItems.first.startingItemIds,
startBuild: startingBuild,
coreBuild: coreBuild,
finalBuild: finalBuild,
situationalItems: situational,
buildPath: [],
);
}
}
Expand All @@ -108,3 +138,12 @@ const _boots = [
3117,
2422,
];

const _worldAtlasId = 3865;
const _finalItemsFromWorldAtlas = [
3869,
3870,
3871,
3876,
3877,
];
98 changes: 39 additions & 59 deletions lib/data/blitz/blitz_data_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,34 @@ import 'dart:convert';
import 'package:http/http.dart' as http;

import 'package:sebastian/data/blitz/models/all_champions_stats.dart';
import 'package:sebastian/data/blitz/models/blitz_builds_response.dart';
import 'package:sebastian/data/blitz/models/blitz_primary_role_response.dart';
import 'package:sebastian/data/blitz/models/blitz_builds_response.dart';
import 'package:sebastian/data/blitz/models/request_variables.dart';
import 'package:sebastian/data/utils/http_logger.dart';

class BlitzDataSource {
BlitzDataSource();
final bool logEnabled;

BlitzDataSource({this.logEnabled = false});

Future<List<BlitzBuild>> getBuilds(BuildRequestVariables variables) async {
const query = r'''
query ChampionBuilds($championId:Int! $queue:Queue! $role:Role! $key:ChampionBuildKey $opponentChampionId:Int){
championBuildStats(championId:$championId queue:$queue role:$role key:$key opponentChampionId:$opponentChampionId){
championId
opponentChampionId
queue
role
builds{
wins
games
mythicId
mythicAverageIndex
primaryRune
startingItems{games wins startingItemIds}
coreItems{games wins itemIds}
completedItems{games index averageIndex itemId wins}
situationalItems{games wins itemId averageIndex}
runes{games index runeId wins treeId}
skillOrders{games wins skillOrder}
summonerSpells{games wins summonerSpellIds}
}
}
query ChampionBuilds($championId:String! $queue:String! $role:String){
executeDatabricksQuery(game:LEAGUE queryName:"prod_champion_builds" params:[
{name:"individual_position",value:$role}
{name:"queue_id",value:$queue}
{name:"champion_id",value:$championId}
]
)
{payload}
}''';

final responseJson = await _request({
final responseJson = await _requestDataLake({
'query': query,
'variables': json.encode(variables.toJson()),
});

return BlitzBuildResponse.fromJson(responseJson).data.championBuildStats.builds;
}

Future<List<BlitzBuild>> getAramBuilds(BuildRequestVariables variables) async {
const query = r'''
query ChampionBuilds($championId:Int! $queue:Queue! $key:ChampionBuildKey $opponentChampionId:Int){
championBuildStats(championId:$championId queue:$queue key:$key opponentChampionId:$opponentChampionId){
championId
opponentChampionId
queue
role
builds{
wins
games
mythicId
mythicAverageIndex
primaryRune
startingItems{games wins startingItemIds}
coreItems{games wins itemIds}
completedItems{games index averageIndex itemId wins}
situationalItems{games wins itemId averageIndex}
runes{games index runeId wins treeId}
skillOrders{games wins skillOrder}
summonerSpells{games wins summonerSpellIds}
}
}
}''';

final responseJson = await _request({
'query': query,
'variables': json.encode(variables.toJson()),
});

return BlitzBuildResponse.fromJson(responseJson).data.championBuildStats.builds;
return BlitzBuildResponse.fromJson(responseJson).builds;
}

Future<BlitzRole> getPrimaryRole(int championId) async {
Expand Down Expand Up @@ -113,7 +69,31 @@ query AllChampionsStats($queue:Queue){

final responseBody = response.body;

response.log(responseBody);
if (logEnabled) {
response.log(responseBody);
}

if (response.statusCode < 200 || response.statusCode >= 300) {
throw Exception(responseBody);
}

final jsonDecoded = json.decode(responseBody);

if (jsonDecoded['errors'] != null) {
throw Exception(jsonDecoded['errors']);
}

return jsonDecoded;
}

Future<dynamic> _requestDataLake(Map<String, dynamic>? queryParameters) async {
final response = await http.get(Uri.https('datalake-server.iesdev.com', 'graphql', queryParameters));

final responseBody = response.body;

if (logEnabled) {
response.log(responseBody);
}

if (response.statusCode < 200 || response.statusCode >= 300) {
throw Exception(responseBody);
Expand Down
Loading

0 comments on commit 0189000

Please sign in to comment.