2018-06-16 10:48:46 +02:00
|
|
|
use indexmap::IndexMap;
|
2019-09-30 17:56:03 +02:00
|
|
|
use lazy_static::lazy_static;
|
2021-03-13 23:02:26 +01:00
|
|
|
use serde_derive::Deserialize;
|
2019-09-30 17:56:03 +02:00
|
|
|
use serde_json::{json, Value};
|
2021-03-14 10:52:27 +01:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::sync::Mutex;
|
2018-06-16 10:48:46 +02:00
|
|
|
|
2021-03-14 14:25:37 +01:00
|
|
|
use crate::data_source::{DataSource, Stat};
|
2021-03-13 23:02:26 +01:00
|
|
|
use crate::ChampInfo;
|
2021-05-13 14:38:31 +02:00
|
|
|
use crate::Champion;
|
2018-06-16 10:48:46 +02:00
|
|
|
|
2021-03-13 23:02:26 +01:00
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct BuildResponse {
|
2021-03-14 11:21:49 +01:00
|
|
|
lol: Lol,
|
2021-03-13 23:02:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct Lol {
|
|
|
|
#[serde(rename = "championsReport")]
|
2021-03-14 11:21:49 +01:00
|
|
|
champions_report: Vec<ChampionReport>,
|
2021-03-13 23:02:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct ChampionReport {
|
|
|
|
champion_id: u32,
|
|
|
|
role: String,
|
|
|
|
patch: String,
|
2021-03-14 11:21:49 +01:00
|
|
|
stats: Stats,
|
2021-03-13 23:02:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct Stats {
|
|
|
|
starting_items: Build,
|
2021-03-14 09:49:18 +01:00
|
|
|
core_builds: Build,
|
|
|
|
big_item_builds: Build,
|
|
|
|
skills: Build,
|
|
|
|
most_common_starting_items: Build,
|
|
|
|
most_common_core_builds: Build,
|
|
|
|
most_common_big_item_builds: Build,
|
2021-03-14 11:21:49 +01:00
|
|
|
most_common_skills: Build,
|
2021-03-13 23:02:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct Build {
|
|
|
|
build: Vec<u32>,
|
|
|
|
win_rate: f64,
|
2021-03-14 11:21:49 +01:00
|
|
|
games: u32,
|
2021-03-13 23:02:26 +01:00
|
|
|
}
|
|
|
|
|
2021-03-14 10:52:27 +01:00
|
|
|
#[derive(Deserialize, Debug, Clone)]
|
|
|
|
struct ChampStat {
|
|
|
|
champion_id: Option<u32>,
|
|
|
|
stats: Option<Info>,
|
|
|
|
matchups: Option<Vec<Info>>,
|
|
|
|
#[serde(rename = "winRate")]
|
|
|
|
win_rate: Option<f64>,
|
|
|
|
games: Option<u32>,
|
|
|
|
kda: Option<f64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug, Clone)]
|
|
|
|
struct Info {
|
2021-03-14 11:21:49 +01:00
|
|
|
id: String,
|
2021-03-14 10:52:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
lazy_static! {
|
2021-03-14 11:01:37 +01:00
|
|
|
static ref CHAMPIONS_REPORT: Mutex<Vec<ChampionReport>> = Mutex::new(Vec::new());
|
2021-03-14 10:52:27 +01:00
|
|
|
static ref CHAMPIONS_STATS: Mutex<HashMap<String, ChampStat>> = Mutex::new(HashMap::new());
|
|
|
|
}
|
|
|
|
|
2018-06-16 10:48:46 +02:00
|
|
|
pub struct CGGDataSource;
|
2019-09-30 17:56:03 +02:00
|
|
|
|
|
|
|
impl CGGDataSource {
|
2021-03-13 23:02:26 +01:00
|
|
|
fn make_item_set(&self, build: &Build, label: &str) -> Value {
|
2019-09-30 17:56:03 +02:00
|
|
|
json!({
|
2021-03-14 09:49:18 +01:00
|
|
|
"items": build.build.iter().map(|x| json!({"id": x.to_string(), "count": 1})).collect::<Vec<Value>>(),
|
2021-03-13 23:02:26 +01:00
|
|
|
"type": format!("{} ({:.2}% - {} games)", label, build.win_rate * 100., build.games)
|
2019-09-30 17:56:03 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-03-14 11:21:49 +01:00
|
|
|
fn make_item_set_from_list(&self, build: &Build, label: &str, skills: &Build) -> Value {
|
|
|
|
let key_order = skills
|
|
|
|
.build
|
|
|
|
.iter()
|
|
|
|
.map(|x| x.to_string())
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join("");
|
2021-03-14 09:49:18 +01:00
|
|
|
|
|
|
|
self.make_item_set(build, [label, &key_order.as_str()].join(" ").as_str())
|
2019-09-30 17:56:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 16:43:29 +01:00
|
|
|
fn extract_json(pattern: &str, page: &str) -> String {
|
2021-03-14 17:17:29 +01:00
|
|
|
let json = page[page.find(pattern).unwrap() + pattern.len()..].to_owned();
|
2021-03-14 18:10:51 +01:00
|
|
|
json[..json.find("};").unwrap() + 1].replace("undefined", "null")
|
2021-03-14 16:43:29 +01:00
|
|
|
}
|
|
|
|
|
2018-06-16 10:48:46 +02:00
|
|
|
impl DataSource for CGGDataSource {
|
2019-09-30 17:56:03 +02:00
|
|
|
fn get_alias(&self) -> &str {
|
|
|
|
"CGG"
|
|
|
|
}
|
|
|
|
|
2021-03-14 09:49:18 +01:00
|
|
|
fn get_timeout(&self) -> u64 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
2021-05-13 14:38:31 +02:00
|
|
|
fn get_champs_with_positions(
|
|
|
|
&self,
|
|
|
|
client: &ureq::Agent,
|
|
|
|
_champion: &Champion,
|
|
|
|
) -> IndexMap<u32, Vec<String>> {
|
2021-03-14 11:21:49 +01:00
|
|
|
let req = client.get("https://champion.gg").call().unwrap();
|
2021-03-14 10:52:27 +01:00
|
|
|
let page = &req.into_string().unwrap();
|
|
|
|
|
2021-03-13 23:02:26 +01:00
|
|
|
let datas: BuildResponse =
|
2021-03-14 16:43:29 +01:00
|
|
|
serde_json::from_str(&extract_json("window.__PRELOADED_STATE__ = ", &page)).unwrap();
|
2021-03-14 10:52:27 +01:00
|
|
|
|
2021-03-14 11:21:49 +01:00
|
|
|
let champs_stats: HashMap<String, ChampStat> =
|
2021-03-14 17:17:29 +01:00
|
|
|
serde_json::from_str(&extract_json("window.__FLASH_CMS_APOLLO_STATE__ = ", &page))
|
|
|
|
.unwrap();
|
2021-03-14 10:52:27 +01:00
|
|
|
for entry in champs_stats.iter() {
|
2021-03-14 11:21:49 +01:00
|
|
|
CHAMPIONS_STATS
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
2021-03-14 14:57:31 +01:00
|
|
|
.insert(entry.0.to_owned(), entry.1.to_owned());
|
2021-03-14 10:52:27 +01:00
|
|
|
}
|
2018-06-16 10:48:46 +02:00
|
|
|
|
2021-03-16 10:53:16 +01:00
|
|
|
let mut champions: IndexMap<u32, Vec<String>> = IndexMap::new();
|
2021-03-13 23:02:26 +01:00
|
|
|
for champ in &datas.lol.champions_report {
|
2021-03-16 10:53:16 +01:00
|
|
|
let id = champ.champion_id;
|
2021-03-14 09:24:09 +01:00
|
|
|
if champions.contains_key(&id) {
|
2021-03-14 14:57:31 +01:00
|
|
|
let mut roles = champions.get(&id).unwrap().to_owned();
|
|
|
|
roles.push(champ.role.to_owned());
|
2021-03-14 12:30:04 +01:00
|
|
|
champions.insert(id, roles);
|
|
|
|
} else {
|
2021-03-14 14:57:31 +01:00
|
|
|
champions.insert(id, vec![champ.role.to_owned()]);
|
2021-03-14 14:25:37 +01:00
|
|
|
}
|
2018-06-16 10:48:46 +02:00
|
|
|
}
|
|
|
|
|
2021-03-14 11:01:37 +01:00
|
|
|
for report in datas.lol.champions_report {
|
2021-03-14 11:21:49 +01:00
|
|
|
CHAMPIONS_REPORT.lock().unwrap().push(report);
|
2021-03-13 23:02:26 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 11:13:54 +01:00
|
|
|
champions
|
2018-06-16 10:48:46 +02:00
|
|
|
}
|
|
|
|
|
2019-09-30 17:56:03 +02:00
|
|
|
fn get_champ_data_with_win_pourcentage(
|
|
|
|
&self,
|
2021-03-13 23:02:26 +01:00
|
|
|
champ: &ChampInfo,
|
2021-03-15 23:11:40 +01:00
|
|
|
positions: &[String],
|
2021-03-13 23:02:26 +01:00
|
|
|
_client: &ureq::Agent,
|
2021-03-15 23:00:20 +01:00
|
|
|
) -> Vec<(String, Vec<Value>, Stat)> {
|
|
|
|
let mut data = vec![];
|
|
|
|
for position in positions {
|
|
|
|
let mut some_champ: Option<&ChampionReport> = None;
|
|
|
|
let reports = CHAMPIONS_REPORT.lock().unwrap();
|
|
|
|
for champion in reports.iter() {
|
2021-03-17 09:13:19 +01:00
|
|
|
if champion.champion_id.to_string() == champ.key && champion.role == *position {
|
2021-03-15 23:00:20 +01:00
|
|
|
some_champ = Some(champion);
|
|
|
|
break;
|
2021-03-14 10:52:27 +01:00
|
|
|
}
|
|
|
|
}
|
2021-03-15 23:00:20 +01:00
|
|
|
if let Some(champ) = some_champ {
|
|
|
|
let mut blocks = vec![];
|
|
|
|
|
|
|
|
blocks.push(self.make_item_set_from_list(
|
|
|
|
&champ.stats.starting_items,
|
|
|
|
"Highest % Win Starting Items | Skills: ",
|
|
|
|
&champ.stats.skills,
|
|
|
|
));
|
|
|
|
blocks.push(
|
|
|
|
self.make_item_set(&champ.stats.core_builds, "Highest % Win Core Build Path:"),
|
|
|
|
);
|
|
|
|
blocks.push(
|
|
|
|
self.make_item_set(&champ.stats.big_item_builds, "Highest % Win Big Items:"),
|
|
|
|
);
|
|
|
|
|
|
|
|
blocks.push(self.make_item_set_from_list(
|
|
|
|
&champ.stats.most_common_starting_items,
|
|
|
|
"Most Frequent Starting Items | Skills: ",
|
|
|
|
&champ.stats.most_common_skills,
|
|
|
|
));
|
|
|
|
blocks.push(self.make_item_set(
|
|
|
|
&champ.stats.most_common_core_builds,
|
|
|
|
"Most Frequent Build Path",
|
|
|
|
));
|
|
|
|
blocks.push(self.make_item_set(
|
|
|
|
&champ.stats.most_common_big_item_builds,
|
|
|
|
"Most Frequent Big Items:",
|
|
|
|
));
|
|
|
|
|
|
|
|
let mut key: String = String::new();
|
|
|
|
let champs_stats = CHAMPIONS_STATS.lock().unwrap();
|
|
|
|
for val in champs_stats.values() {
|
|
|
|
if val.champion_id.is_some() && val.champion_id.unwrap() == champ.champion_id {
|
|
|
|
key = val.stats.as_ref().unwrap().id.to_owned();
|
|
|
|
}
|
|
|
|
}
|
2021-03-14 10:52:27 +01:00
|
|
|
|
2021-03-15 23:00:20 +01:00
|
|
|
let stat = champs_stats.get(&key).unwrap();
|
|
|
|
data.push((
|
|
|
|
position.to_owned(),
|
|
|
|
blocks,
|
|
|
|
Stat {
|
|
|
|
win_rate: stat.win_rate.unwrap(),
|
|
|
|
games: stat.games.unwrap(),
|
|
|
|
kda: stat.kda.unwrap(),
|
2021-03-17 09:13:19 +01:00
|
|
|
patch: champ.patch.to_owned(),
|
2021-03-15 23:00:20 +01:00
|
|
|
},
|
|
|
|
));
|
|
|
|
}
|
2018-06-16 10:48:46 +02:00
|
|
|
}
|
2021-03-15 23:00:20 +01:00
|
|
|
data
|
2018-06-16 10:48:46 +02:00
|
|
|
}
|
|
|
|
}
|