Build Tab
This commit is contained in:
parent
1414d8b6f7
commit
7de38097eb
5 changed files with 349 additions and 6 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -800,7 +800,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "obsessed-yanqing"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
dependencies = [
|
||||
"levenshtein",
|
||||
"poise",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "obsessed-yanqing"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Evann Regnault"]
|
||||
license = "MIT"
|
||||
|
|
|
@ -2,11 +2,13 @@ use std::sync::Arc;
|
|||
use std::time::Duration;
|
||||
use poise::ReplyHandle;
|
||||
use serenity::builder::{CreateButton, CreateComponents, CreateEmbed, CreateEmbedFooter};
|
||||
use serenity::futures::future::join_all;
|
||||
use serenity::model::application::component::ButtonStyle;
|
||||
use serenity::model::application::interaction::message_component::MessageComponentInteraction;
|
||||
use crate::data::{Context, Error};
|
||||
use crate::data::allcharacters::{Characters, get_nearest_characters};
|
||||
use crate::data::character::{Character, get_character_data};
|
||||
use crate::data::cones::get_light_cone;
|
||||
use crate::data::description::get_all_texts;
|
||||
use crate::data::proscons::get_proscons_texts;
|
||||
use crate::utils::color_manager::get_element_color;
|
||||
|
@ -15,6 +17,7 @@ use crate::utils::emote_manager::{get_element_emote, get_path_emote};
|
|||
enum CharacterTab {
|
||||
Home,
|
||||
Review,
|
||||
Gear(usize),
|
||||
}
|
||||
|
||||
async fn create_menu(ctx: Context<'_>, chars: Vec<Characters>) -> ReplyHandle {
|
||||
|
@ -97,10 +100,58 @@ async fn get_character_review(character: &Character) -> Option<CreateEmbed> {
|
|||
)
|
||||
}
|
||||
|
||||
async fn get_character_build(character: &Character, index: usize) -> Option<CreateEmbed> {
|
||||
let chosen_build = character.build_data.as_ref().expect("No builds").get(index).expect("Build doesnt exist");
|
||||
|
||||
let clone = chosen_build.clone();
|
||||
let light_cones = join_all(clone.cones.into_iter().map(|c| async { get_light_cone(c.cone).await.expect("Cone")})).await;
|
||||
|
||||
Some(
|
||||
CreateEmbed::default()
|
||||
.title(format!("{} {} {}", get_element_emote(&character.element), character.name, get_path_emote(&character.path)))
|
||||
.set_footer(CreateEmbedFooter::default().text("Data from https://www.prydwen.gg/").to_owned())
|
||||
.description(format!("{}\n{}",
|
||||
":star:".repeat(character.rarity.parse().unwrap_or(4)),
|
||||
character.default_role))
|
||||
.field(&chosen_build.name.as_str(), &chosen_build.comments.as_str(), false)
|
||||
|
||||
|
||||
// STUFF
|
||||
.field("Relic Sets", chosen_build.relics.iter().enumerate().map(|(i, f)| match f.relic_2.len() {
|
||||
0 => format!("{}. {}", i+1, f.relic),
|
||||
_ => format!("{}. {} + {}", i+1, f.relic, f.relic_2)
|
||||
}).collect::<Vec<String>>().join("\n"), false)
|
||||
|
||||
.field("Planetary Sets", chosen_build.planars.iter().enumerate().map(|(i, f)| format!("{}. {}", i+1, f.planar)).collect::<Vec<String>>().join("\n"), false)
|
||||
|
||||
.field("Light Cones", light_cones.iter().enumerate().map(|(i, c)| format!("{}. {}", i+1, c.name)).collect::<Vec<String>>().join("\n"), false)
|
||||
|
||||
|
||||
// STATS
|
||||
.field("Body", chosen_build.body.iter().map(|f| format!("{}",f.stat)).collect::<Vec<String>>().join(" / "), true)
|
||||
.field("Feet", chosen_build.feet.iter().map(|f| format!("{}",f.stat)).collect::<Vec<String>>().join(" / "), true)
|
||||
.field("\u{200B}", "\u{200B}", true)
|
||||
.field("Planar Sphere", chosen_build.sphere.iter().map(|f| format!("{}",f.stat)).collect::<Vec<String>>().join(" / "), true)
|
||||
.field("Link Rope", chosen_build.rope.iter().map(|f| format!("{}",f.stat)).collect::<Vec<String>>().join(" / "), true)
|
||||
.field("\u{200B}", "\u{200B}", true)
|
||||
|
||||
.field("Substats", &chosen_build.substats, false)
|
||||
|
||||
// TRACES
|
||||
.field("Skill Priority", &chosen_build.skill_priority, false)
|
||||
.field("Major Traces Priority", &chosen_build.traces_priority, false)
|
||||
|
||||
.color(get_element_color(&character.element))
|
||||
.thumbnail(format!("https://www.prydwen.gg{}", character.small_image.local_file.child_image_sharp.gatsby_image_data.images.fallback.src))
|
||||
.to_owned()
|
||||
)
|
||||
}
|
||||
|
||||
fn create_character_tabs_button<'a>(f: &'a mut CreateComponents, char: &Character, current_tab: &CharacterTab) -> &'a mut CreateComponents {
|
||||
let mut all_buttons: Vec<CreateButton> = vec![];
|
||||
let mut home_button: CreateButton = CreateButton::default();
|
||||
let mut review_button: CreateButton = CreateButton::default();
|
||||
let mut gear_button: CreateButton = CreateButton::default();
|
||||
|
||||
// Home Button
|
||||
{
|
||||
|
@ -129,6 +180,33 @@ fn create_character_tabs_button<'a>(f: &'a mut CreateComponents, char: &Characte
|
|||
all_buttons.push(review_button);
|
||||
}
|
||||
|
||||
// Gear Button
|
||||
{
|
||||
match current_tab {
|
||||
CharacterTab::Gear(_) => { gear_button.style(ButtonStyle::Success); }
|
||||
_ => { gear_button.style(ButtonStyle::Primary); }
|
||||
};
|
||||
|
||||
match &char.build_data {
|
||||
None => {
|
||||
gear_button.label("Gear");
|
||||
gear_button.disabled(true);
|
||||
}
|
||||
Some(_) => {
|
||||
gear_button.disabled(false);
|
||||
match current_tab {
|
||||
CharacterTab::Gear(n) => {
|
||||
gear_button.label(format!("Gear {}/{}", n+1, char.build_data.as_ref().expect("").len()));
|
||||
}
|
||||
_ => {gear_button.label("Gear");}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gear_button.custom_id(CharacterTab::Gear(1).to_button_id());
|
||||
all_buttons.push(gear_button);
|
||||
}
|
||||
|
||||
|
||||
f.create_action_row(|r| {
|
||||
all_buttons.into_iter().for_each(|b| {
|
||||
|
@ -149,6 +227,12 @@ async fn menu_handler(ctx: Context<'_>, interaction: Arc<MessageComponentInterac
|
|||
CharacterTab::Review => {
|
||||
get_character_review(&character).await
|
||||
}
|
||||
CharacterTab::Gear(n) => {
|
||||
let builds = character.build_data.as_ref().expect("No builds");
|
||||
let n : usize = n % builds.len();
|
||||
tab = CharacterTab::Gear(n);
|
||||
get_character_build(&character, n).await
|
||||
}
|
||||
};
|
||||
match looping {
|
||||
true => {
|
||||
|
@ -178,14 +262,14 @@ async fn menu_handler(ctx: Context<'_>, interaction: Arc<MessageComponentInterac
|
|||
d.components(|f| create_character_tabs_button(&mut *f, &character, &tab))
|
||||
})
|
||||
}).await {
|
||||
Ok(_) => {interaction.delete_followup_message(&ctx, interaction.message.id).await.unwrap();}
|
||||
Ok(_) => { interaction.delete_followup_message(&ctx, interaction.message.id).await.unwrap(); }
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let x = match interaction.get_interaction_response(&ctx).await {
|
||||
Ok(x) => {x}
|
||||
Ok(x) => { x }
|
||||
Err(_) => return
|
||||
};
|
||||
|
||||
|
@ -198,6 +282,12 @@ async fn menu_handler(ctx: Context<'_>, interaction: Arc<MessageComponentInterac
|
|||
tab = match x.data.custom_id.as_str() {
|
||||
"charactertab_home" => CharacterTab::Home,
|
||||
"charactertab_review" => CharacterTab::Review,
|
||||
"charactertab_gear" => {
|
||||
match tab {
|
||||
CharacterTab::Gear(n) => CharacterTab::Gear(n+1),
|
||||
_ => CharacterTab::Gear(0)
|
||||
}
|
||||
},
|
||||
_ => CharacterTab::Home
|
||||
};
|
||||
x.defer(ctx).await.expect("TODO: panic message");
|
||||
|
@ -212,7 +302,7 @@ async fn choice_interaction_handler(ctx: Context<'_>, message: &ReplyHandle<'_>)
|
|||
match message.await_component_interaction(&ctx).timeout(Duration::from_secs(60 * 3)).await {
|
||||
Some(x) => {
|
||||
x
|
||||
},
|
||||
}
|
||||
None => {
|
||||
message.reply(&ctx, "Timed out").await.unwrap();
|
||||
return;
|
||||
|
@ -227,7 +317,8 @@ impl CharacterTab {
|
|||
fn to_button_id(&self) -> &'static str {
|
||||
match self {
|
||||
CharacterTab::Home => "charactertab_home",
|
||||
CharacterTab::Review => "charactertab_review"
|
||||
CharacterTab::Review => "charactertab_review",
|
||||
CharacterTab::Gear(_) => "charactertab_gear"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
251
src/data/cones.rs
Normal file
251
src/data/cones.rs
Normal file
|
@ -0,0 +1,251 @@
|
|||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use crate::data::core::{PrydwenCompatible, PrydwenResponse};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PrydwenCone {
|
||||
pub all_characters: AllCharacters,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AllCharacters {
|
||||
pub nodes: Vec<Cone>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Cone {
|
||||
pub id: String,
|
||||
pub updated_at: String,
|
||||
pub created_at: String,
|
||||
pub cone_id: i64,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub image: Option<Image>,
|
||||
pub small_image: SmallImage,
|
||||
pub rarity: String,
|
||||
#[serde(default)]
|
||||
pub source: Option<Vec<String>>,
|
||||
pub release_date: String,
|
||||
pub path: String,
|
||||
pub stats: Stats,
|
||||
pub character_builder_cone_info: CharacterBuilderConeInfo,
|
||||
pub skill_name: String,
|
||||
pub skill_description: SkillDescription,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Image {
|
||||
pub local_file: LocalFile,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LocalFile {
|
||||
pub child_image_sharp: ChildImageSharp,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ChildImageSharp {
|
||||
pub gatsby_image_data: GatsbyImageData,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GatsbyImageData {
|
||||
pub layout: String,
|
||||
pub background_color: String,
|
||||
pub images: Images,
|
||||
pub width: i64,
|
||||
pub height: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Images {
|
||||
pub fallback: Fallback,
|
||||
pub sources: Vec<Source>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Fallback {
|
||||
pub src: String,
|
||||
pub src_set: String,
|
||||
pub sizes: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Source {
|
||||
pub src_set: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: String,
|
||||
pub sizes: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SmallImage {
|
||||
pub local_file: LocalFile2,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LocalFile2 {
|
||||
pub child_image_sharp: ChildImageSharp2,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ChildImageSharp2 {
|
||||
pub gatsby_image_data: GatsbyImageData2,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GatsbyImageData2 {
|
||||
pub layout: String,
|
||||
pub background_color: String,
|
||||
pub images: Images2,
|
||||
pub width: i64,
|
||||
pub height: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Images2 {
|
||||
pub fallback: Fallback2,
|
||||
pub sources: Vec<Source2>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Fallback2 {
|
||||
pub src: String,
|
||||
pub src_set: String,
|
||||
pub sizes: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Source2 {
|
||||
pub src_set: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: String,
|
||||
pub sizes: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Stats {
|
||||
pub hp: Hp,
|
||||
pub atk: Atk,
|
||||
pub def: Def,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Hp {
|
||||
#[serde(rename = "value_level_1")]
|
||||
pub value_level_1: String,
|
||||
#[serde(rename = "value_level_max")]
|
||||
pub value_level_max: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Atk {
|
||||
#[serde(rename = "value_level_1")]
|
||||
pub value_level_1: String,
|
||||
#[serde(rename = "value_level_max")]
|
||||
pub value_level_max: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Def {
|
||||
#[serde(rename = "value_level_1")]
|
||||
pub value_level_1: String,
|
||||
#[serde(rename = "value_level_max")]
|
||||
pub value_level_max: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CharacterBuilderConeInfo {
|
||||
pub cone_custom_stat1: ConeCustomStat1,
|
||||
pub cone_custom_stat2: ConeCustomStat2,
|
||||
pub cone_custom_stat3: ConeCustomStat3,
|
||||
pub cone_custom_stat4: ConeCustomStat4,
|
||||
pub comment: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConeCustomStat1 {
|
||||
pub stat: String,
|
||||
#[serde(rename = "value_1")]
|
||||
pub value_1: i64,
|
||||
#[serde(rename = "value_5")]
|
||||
pub value_5: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConeCustomStat2 {
|
||||
pub stat: String,
|
||||
#[serde(rename = "value_1")]
|
||||
pub value_1: i64,
|
||||
#[serde(rename = "value_5")]
|
||||
pub value_5: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConeCustomStat3 {
|
||||
pub stat: String,
|
||||
#[serde(rename = "value_1")]
|
||||
pub value_1: i64,
|
||||
#[serde(rename = "value_5")]
|
||||
pub value_5: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConeCustomStat4 {
|
||||
pub stat: String,
|
||||
#[serde(rename = "value_1")]
|
||||
pub value_1: i64,
|
||||
#[serde(rename = "value_5")]
|
||||
pub value_5: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SkillDescription {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
impl PrydwenCompatible for PrydwenCone {}
|
||||
|
||||
pub async fn get_light_cone(name: String) -> Option<Cone> {
|
||||
let data_response = reqwest::get("https://www.prydwen.gg/page-data/star-rail/light-cones/page-data.json").await.ok()?;
|
||||
let d = data_response.text().await.ok()?;
|
||||
let js = &mut serde_json::Deserializer::from_str(d.as_str());
|
||||
let data : Result<PrydwenResponse<PrydwenCone>, _> = serde_path_to_error::deserialize(js);
|
||||
match data {
|
||||
Ok(d) => {
|
||||
Some(d.result.data.all_characters.nodes.into_iter().filter(|f| f.slug.eq(name.as_str())).collect::<Vec<Cone>>().get(0).expect(format!("Cannot find {}", name).as_str()).clone())
|
||||
}
|
||||
Err(err) => {
|
||||
let path = err.path().to_string();
|
||||
println!("{}", path);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,4 +7,5 @@ pub mod allcharacters;
|
|||
pub mod character;
|
||||
pub mod description;
|
||||
pub mod proscons;
|
||||
pub mod cones;
|
||||
|
||||
|
|
Loading…
Reference in a new issue