Base
This commit is contained in:
commit
23ffc50659
16 changed files with 3112 additions and 0 deletions
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/obsessed-yanqing.iml" filepath="$PROJECT_DIR$/.idea/obsessed-yanqing.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
11
.idea/obsessed-yanqing.iml
Normal file
11
.idea/obsessed-yanqing.iml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="CPP_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
2016
Cargo.lock
generated
Normal file
2016
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
252
src/commands/character.rs
Normal file
252
src/commands/character.rs
Normal file
|
@ -0,0 +1,252 @@
|
|||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::format;
|
||||
use std::future::Future;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use async_recursion::async_recursion;
|
||||
use poise::{BoxFuture, ReplyHandle};
|
||||
use poise::futures_util::FutureExt;
|
||||
use serenity::builder::{CreateButton, CreateComponents, CreateEmbed, CreateEmbedFooter, CreateInteractionResponseData};
|
||||
use serenity::model::application::component::ButtonStyle;
|
||||
use serenity::model::application::interaction::InteractionResponseType;
|
||||
use serenity::model::application::interaction::message_component::MessageComponentInteraction;
|
||||
use serenity::model::channel::Message;
|
||||
use serenity::utils::{Color, MessageBuilder};
|
||||
use crate::data::{Context, Error};
|
||||
use crate::data::allcharacters::{Characters, get_nearest_characters};
|
||||
use crate::data::character::{Character, Description, get_character_data, Review};
|
||||
use crate::data::description::{Content2, get_all_texts};
|
||||
use crate::data::proscons::get_proscons_texts;
|
||||
use crate::utils::color_manager::get_element_color;
|
||||
use crate::utils::emote_manager::{get_element_emote, get_path_emote};
|
||||
|
||||
enum CharacterTab {
|
||||
Home,
|
||||
Review,
|
||||
}
|
||||
|
||||
async fn create_menu(ctx: Context<'_>, chars: Vec<Characters>) -> ReplyHandle {
|
||||
ctx.send(|a| {
|
||||
a.content("Select the right character").components(|c| {
|
||||
c.create_action_row(|row| {
|
||||
row.create_select_menu(|menu| {
|
||||
menu.custom_id("select_character");
|
||||
menu.placeholder("Character");
|
||||
menu.options(|f| {
|
||||
chars.into_iter().for_each(|char| {
|
||||
f.create_option(|o| o.label(char.name).value(char.slug));
|
||||
});
|
||||
f
|
||||
})
|
||||
})
|
||||
})
|
||||
}).ephemeral(true)
|
||||
}).await.unwrap()
|
||||
}
|
||||
|
||||
async fn get_character_home(character: &Character) -> Option<CreateEmbed> {
|
||||
let desc_data = &character.description;
|
||||
let desc = match desc_data {
|
||||
None => { "".to_string() }
|
||||
Some(data) => {
|
||||
let all_texts: Vec<String> = get_all_texts(&data).unwrap();
|
||||
let a = all_texts.get(0).cloned();
|
||||
match a {
|
||||
None => { "".to_string() }
|
||||
Some(b) => { b }
|
||||
}
|
||||
}
|
||||
};
|
||||
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{}\n\n{}",
|
||||
":star:".repeat(character.rarity.parse().unwrap_or(4)),
|
||||
character.default_role,
|
||||
desc))
|
||||
.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()
|
||||
)
|
||||
}
|
||||
|
||||
async fn get_character_review(character: &Character) -> Option<CreateEmbed> {
|
||||
let cons_data = &character.cons;
|
||||
let cons = match cons_data {
|
||||
None => { "".to_string() }
|
||||
Some(data) => {
|
||||
let mut all_texts: Vec<String> = get_proscons_texts(&data).unwrap_or(vec![]).into_iter().map(|x| format!("• {}", x)).collect();
|
||||
all_texts.join("\n")
|
||||
}
|
||||
};
|
||||
|
||||
let pros_data = &character.pros;
|
||||
let pros = match pros_data {
|
||||
None => { "".to_string() }
|
||||
Some(data) => {
|
||||
let mut all_texts: Vec<String> = get_proscons_texts(&data).unwrap_or(vec![]).into_iter().map(|x| format!("• {}", x)).collect();
|
||||
all_texts.join("\n")
|
||||
}
|
||||
};
|
||||
|
||||
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(":green_circle: Pros", pros, false)
|
||||
.field(":red_circle: Cons", cons, 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();
|
||||
|
||||
// Home Button
|
||||
{
|
||||
match current_tab {
|
||||
CharacterTab::Home => { home_button.style(ButtonStyle::Success); }
|
||||
_ => { home_button.style(ButtonStyle::Primary); }
|
||||
};
|
||||
home_button.label("Home");
|
||||
home_button.custom_id(CharacterTab::Home.to_button_id());
|
||||
all_buttons.push(home_button);
|
||||
}
|
||||
|
||||
|
||||
// Review Button
|
||||
{
|
||||
match current_tab {
|
||||
CharacterTab::Review => { review_button.style(ButtonStyle::Success); }
|
||||
_ => { review_button.style(ButtonStyle::Primary); }
|
||||
};
|
||||
match &char.review {
|
||||
None => { review_button.disabled(true); }
|
||||
Some(_) => { review_button.disabled(false); }
|
||||
};
|
||||
review_button.label("Review");
|
||||
review_button.custom_id(CharacterTab::Review.to_button_id());
|
||||
all_buttons.push(review_button);
|
||||
}
|
||||
|
||||
|
||||
f.create_action_row(|r| {
|
||||
all_buttons.into_iter().for_each(|b| {
|
||||
r.add_button(b);
|
||||
});
|
||||
r
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
async fn menu_handler(ctx: Context<'_>, interaction: Arc<MessageComponentInteraction>, character: Character, mut tab: CharacterTab) {
|
||||
let mut looping = false;
|
||||
loop {
|
||||
let character_embed = match tab {
|
||||
CharacterTab::Home => {
|
||||
get_character_home(&character).await
|
||||
}
|
||||
CharacterTab::Review => {
|
||||
get_character_review(&character).await
|
||||
}
|
||||
};
|
||||
match looping {
|
||||
true => {
|
||||
interaction
|
||||
.edit_original_interaction_response(&ctx, |d| {
|
||||
match character_embed {
|
||||
None => {}
|
||||
Some(_) => { d.set_embed(character_embed.unwrap()); }
|
||||
}
|
||||
d.content("");
|
||||
d.components(|f| create_character_tabs_button(&mut *f, &character, &tab))
|
||||
}).await.unwrap();
|
||||
}
|
||||
false => {
|
||||
interaction
|
||||
.create_interaction_response(&ctx, |r| {
|
||||
r.interaction_response_data(|d| {
|
||||
match character_embed {
|
||||
None => {}
|
||||
Some(_) => { d.set_embed(character_embed.unwrap()); }
|
||||
}
|
||||
d.content("");
|
||||
d.ephemeral(true);
|
||||
d.components(|f| create_character_tabs_button(&mut *f, &character, &tab))
|
||||
})
|
||||
}).await.unwrap();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let x = interaction.get_interaction_response(&ctx).await.unwrap().await_component_interaction(&ctx).timeout(Duration::from_secs(10 * 60)).await;
|
||||
|
||||
match x {
|
||||
None => {}
|
||||
Some(x) => {
|
||||
looping = true;
|
||||
tab = match x.data.custom_id.as_str() {
|
||||
"charactertab_home" => CharacterTab::Home,
|
||||
"charactertab_review" => CharacterTab::Review,
|
||||
_ => CharacterTab::Home
|
||||
};
|
||||
x.defer(ctx).await.expect("TODO: panic message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn choice_interaction_handler(ctx: Context<'_>, message: &ReplyHandle<'_>, tab: CharacterTab) {
|
||||
let message = message.clone().into_message().await.unwrap();
|
||||
let interaction =
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
let character_string = &interaction.data.values[0];
|
||||
let character = get_character_data(character_string.to_string()).await.unwrap();
|
||||
menu_handler(ctx, interaction, character, CharacterTab::Home).await;
|
||||
}
|
||||
|
||||
impl CharacterTab {
|
||||
fn to_button_id(&self) -> &'static str {
|
||||
match self {
|
||||
CharacterTab::Home => "charactertab_home",
|
||||
CharacterTab::Review => "charactertab_review"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays your or another user's account creation date
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn character(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Character to Search"] user: String,
|
||||
) -> Result<(), Error> {
|
||||
match get_nearest_characters(user).await {
|
||||
None => { ctx.say(format!("Error occured")).await? }
|
||||
Some(characters) => {
|
||||
let handler = create_menu(ctx, characters).await;
|
||||
choice_interaction_handler(ctx, &handler, CharacterTab::Home).await;
|
||||
handler
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
1
src/commands/mod.rs
Normal file
1
src/commands/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod character;
|
63
src/data/allcharacters.rs
Normal file
63
src/data/allcharacters.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
use std::cmp::Ordering;
|
||||
use levenshtein::levenshtein;
|
||||
use crate::data::core::{PrydwenCompatible, PrydwenResponse};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct PrydwenAllCharacters {
|
||||
pub all_characters: AllCharacters,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AllCharacters {
|
||||
pub nodes: Vec<Characters>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Characters {
|
||||
pub id: String,
|
||||
pub unit_id: i64,
|
||||
pub slug: String,
|
||||
pub name: String,
|
||||
pub rarity: String,
|
||||
pub element: String,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
|
||||
impl PrydwenCompatible for PrydwenAllCharacters{}
|
||||
|
||||
pub async fn get_nearest_characters(name: String) -> Option<Vec<Characters>> {
|
||||
let mut characters = get_all_characters().await?;
|
||||
characters.nodes.sort_by(|a, b | {
|
||||
match a.name.to_lowercase().contains(name.to_lowercase().as_str()) {
|
||||
true => {
|
||||
match b.name.to_lowercase().contains(name.to_lowercase().as_str()) {
|
||||
true => return Ordering::Equal,
|
||||
false => return Ordering::Less
|
||||
}
|
||||
}
|
||||
false => {
|
||||
match b.name.to_lowercase().contains(name.to_lowercase().as_str()){
|
||||
true => return Ordering::Greater,
|
||||
false => return levenshtein(a.name.to_lowercase().as_str(), name.to_lowercase().as_str()).partial_cmp(&levenshtein(b.name.to_lowercase().as_str(), name.to_lowercase().as_str())).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
characters.nodes.truncate(5);
|
||||
Some(characters.nodes)
|
||||
}
|
||||
|
||||
async fn get_all_characters() -> Option<AllCharacters> {
|
||||
let data = reqwest::get("https://www.prydwen.gg/page-data/star-rail/characters/page-data.json").await.ok()?.json::<PrydwenResponse<PrydwenAllCharacters>>().await;
|
||||
match data {
|
||||
Ok(d) => {
|
||||
Some(d.result.data.all_characters)
|
||||
}
|
||||
Err(_) => None
|
||||
}
|
||||
}
|
492
src/data/character.rs
Normal file
492
src/data/character.rs
Normal file
|
@ -0,0 +1,492 @@
|
|||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use serde_json::Value;
|
||||
use crate::data::core::{PrydwenCompatible, PrydwenResponse};
|
||||
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PrydwenCharacter {
|
||||
pub current_unit: CharacterWrapper,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CharacterWrapper {
|
||||
pub nodes: Vec<Character>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Character {
|
||||
pub id: String,
|
||||
pub updated_at: String,
|
||||
pub created_at: String,
|
||||
pub unit_id: i64,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub small_image: SmallImage,
|
||||
pub full_image: FullImage,
|
||||
pub description: Option<Description>,
|
||||
pub default_role: String,
|
||||
pub affiliation: String,
|
||||
pub rarity: String,
|
||||
pub element: String,
|
||||
pub path: String,
|
||||
pub stats: Stats,
|
||||
pub ascension_materials: AscensionMaterials,
|
||||
pub skills: Vec<Skill>,
|
||||
pub eidolon: Vec<Eidolon>,
|
||||
pub traces: Vec<Trace>,
|
||||
pub traces_small: Vec<TracesSmall>,
|
||||
pub review: Option<Review>,
|
||||
pub pros: Option<Pros>,
|
||||
pub cons: Option<Cons>,
|
||||
pub voice_actors: VoiceActors,
|
||||
pub ratings: Ratings,
|
||||
pub energy_ultimate: String,
|
||||
pub build_data: Option<Vec<BuildDaum>>,
|
||||
pub videos: Value,
|
||||
pub teams: Option<Vec<Team>>,
|
||||
pub character_builder_info: CharacterBuilderInfo,
|
||||
pub tier_category: String,
|
||||
pub release_date: Option<String>,
|
||||
pub is_released: bool,
|
||||
pub is_new: Value,
|
||||
pub is_updated: Value,
|
||||
pub hide_skills: bool,
|
||||
pub is_review_pending: bool,
|
||||
pub available_in_cbt3: Option<bool>,
|
||||
pub show_build: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SmallImage {
|
||||
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 FullImage {
|
||||
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 Description {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Stats {
|
||||
#[serde(rename = "hp_base")]
|
||||
pub hp_base: f64,
|
||||
#[serde(rename = "def_base")]
|
||||
pub def_base: f64,
|
||||
#[serde(rename = "atk_base")]
|
||||
pub atk_base: f64,
|
||||
#[serde(rename = "speed_base")]
|
||||
pub speed_base: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AscensionMaterials {
|
||||
#[serde(rename = "mats_1")]
|
||||
pub mats_1: String,
|
||||
#[serde(rename = "mats_2")]
|
||||
pub mats_2: String,
|
||||
#[serde(rename = "mats_3")]
|
||||
pub mats_3: String,
|
||||
#[serde(rename = "mats_4")]
|
||||
pub mats_4: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Skill {
|
||||
pub skill_id: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: String,
|
||||
pub enhanced_name: Value,
|
||||
pub tags: Option<String>,
|
||||
pub description_level1: DescriptionLevel1,
|
||||
#[serde(rename = "descriptionLevel1Enhanced")]
|
||||
pub description_level1enhanced: Value,
|
||||
pub has_enhanced_version: Value,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DescriptionLevel1 {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Eidolon {
|
||||
pub eidolon_id: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "upgrade1Name")]
|
||||
pub upgrade1name: String,
|
||||
#[serde(rename = "upgrade1Desc")]
|
||||
pub upgrade1desc: Upgrade1Desc,
|
||||
#[serde(rename = "upgrade2Name")]
|
||||
pub upgrade2name: String,
|
||||
#[serde(rename = "upgrade2Desc")]
|
||||
pub upgrade2desc: Upgrade2Desc,
|
||||
#[serde(rename = "upgrade3Name")]
|
||||
pub upgrade3name: String,
|
||||
#[serde(rename = "upgrade3Desc")]
|
||||
pub upgrade3desc: Upgrade3Desc,
|
||||
#[serde(rename = "upgrade4Name")]
|
||||
pub upgrade4name: String,
|
||||
#[serde(rename = "upgrade4Desc")]
|
||||
pub upgrade4desc: Upgrade4Desc,
|
||||
#[serde(rename = "upgrade5Name")]
|
||||
pub upgrade5name: String,
|
||||
#[serde(rename = "upgrade5Desc")]
|
||||
pub upgrade5desc: Upgrade5Desc,
|
||||
#[serde(rename = "upgrade6Name")]
|
||||
pub upgrade6name: String,
|
||||
#[serde(rename = "upgrade6Desc")]
|
||||
pub upgrade6desc: Upgrade6Desc,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Upgrade1Desc {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Upgrade2Desc {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Upgrade3Desc {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Upgrade4Desc {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Upgrade5Desc {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Upgrade6Desc {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Trace {
|
||||
pub req: String,
|
||||
pub desc: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "sub_nodes")]
|
||||
pub sub_nodes: Vec<SubNode>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SubNode {
|
||||
pub req: String,
|
||||
pub stat: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TracesSmall {
|
||||
pub req: String,
|
||||
pub stat: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Review {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Pros {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Cons {
|
||||
pub raw: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VoiceActors {
|
||||
pub en: String,
|
||||
pub kr: String,
|
||||
pub jpn: String,
|
||||
pub cn: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Ratings {
|
||||
#[serde(rename = "story_early")]
|
||||
pub story_early: String,
|
||||
#[serde(rename = "story_late")]
|
||||
pub story_late: String,
|
||||
pub sim: String,
|
||||
pub bosses: String,
|
||||
pub farming: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BuildDaum {
|
||||
#[serde(rename = "relic_1")]
|
||||
pub relic_1: String,
|
||||
#[serde(rename = "relic_2")]
|
||||
pub relic_2: String,
|
||||
pub planar: String,
|
||||
#[serde(rename = "cone_1")]
|
||||
pub cone_1: String,
|
||||
#[serde(rename = "cone_2")]
|
||||
pub cone_2: String,
|
||||
#[serde(rename = "cone_3")]
|
||||
pub cone_3: String,
|
||||
#[serde(rename = "cone_4")]
|
||||
pub cone_4: String,
|
||||
#[serde(rename = "cone_5")]
|
||||
pub cone_5: String,
|
||||
#[serde(rename = "cone_6")]
|
||||
pub cone_6: Option<String>,
|
||||
pub body: Vec<Body>,
|
||||
pub feet: Vec<Foot>,
|
||||
pub rope: Vec<Rope>,
|
||||
pub sphere: Vec<Sphere>,
|
||||
pub comments: String,
|
||||
pub substats: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Body {
|
||||
pub stat: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Foot {
|
||||
pub stat: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Rope {
|
||||
pub stat: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Sphere {
|
||||
pub stat: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Team {
|
||||
pub name: String,
|
||||
#[serde(rename = "member_1")]
|
||||
pub member_1: String,
|
||||
#[serde(rename = "member_2")]
|
||||
pub member_2: String,
|
||||
#[serde(rename = "member_3")]
|
||||
pub member_3: String,
|
||||
#[serde(rename = "member_4")]
|
||||
pub member_4: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CharacterBuilderInfo {
|
||||
pub trace_stat1: TraceStat1,
|
||||
pub trace_stat2: TraceStat2,
|
||||
pub trace_stat3: TraceStat3,
|
||||
pub trace_stat_major1: TraceStatMajor1,
|
||||
pub trace_stat_major2: TraceStatMajor2,
|
||||
pub trace_stat_major3: TraceStatMajor3,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TraceStat1 {
|
||||
pub stat: String,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TraceStat2 {
|
||||
pub stat: String,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TraceStat3 {
|
||||
pub stat: String,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TraceStatMajor1 {
|
||||
pub stat: String,
|
||||
pub value: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TraceStatMajor2 {
|
||||
pub stat: String,
|
||||
pub value: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TraceStatMajor3 {
|
||||
pub stat: String,
|
||||
pub value: i64,
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl PrydwenCompatible for PrydwenCharacter {}
|
||||
|
||||
|
||||
pub async fn get_character_data(name: String) -> Option<Character> {
|
||||
let data_response = reqwest::get(format!("https://www.prydwen.gg/page-data/star-rail/characters/{}/page-data.json", name)).await.ok()?;
|
||||
let d = data_response.text().await.ok()?;
|
||||
let js = &mut serde_json::Deserializer::from_str(d.as_str());
|
||||
let data : Result<PrydwenResponse<PrydwenCharacter>, _> = serde_path_to_error::deserialize(js);
|
||||
match data {
|
||||
Ok(d) => {
|
||||
Some(d.result.data.current_unit.nodes.get(0).unwrap().clone())
|
||||
}
|
||||
Err(err) => {
|
||||
let path = err.path().to_string();
|
||||
println!("{}", path);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
26
src/data/core.rs
Normal file
26
src/data/core.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PrydwenResponse<T: PrydwenCompatible> {
|
||||
pub component_chunk_name: String,
|
||||
pub path: String,
|
||||
pub result: Result<T>,
|
||||
pub static_query_hashes: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Result<T: PrydwenCompatible> {
|
||||
pub data: T,
|
||||
pub page_context: PageContext
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PageContext {
|
||||
contentfulId: Option<String>
|
||||
}
|
||||
|
||||
pub trait PrydwenCompatible {
|
||||
}
|
77
src/data/description.rs
Normal file
77
src/data/description.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use serde_json::Value;
|
||||
use crate::data::character::{Cons, Description, Pros, Review};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Root {
|
||||
pub data: Data,
|
||||
pub content: Vec<Content>,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Data {
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content {
|
||||
pub data: Data,
|
||||
pub content: Vec<Content2>,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content2 {
|
||||
pub data: Data,
|
||||
pub marks: Vec<Value>,
|
||||
pub value: String,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
pub trait RawText {
|
||||
fn get_raw(&self) -> &str;
|
||||
}
|
||||
|
||||
impl RawText for &Description {
|
||||
fn get_raw(&self) -> &str {
|
||||
self.raw.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl RawText for &Review {
|
||||
fn get_raw(&self) -> &str {
|
||||
self.raw.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl RawText for &Cons {
|
||||
fn get_raw(&self) -> &str {
|
||||
self.raw.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl RawText for &Pros {
|
||||
fn get_raw(&self) -> &str {
|
||||
self.raw.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_all_texts<T:RawText>(desc: &T) -> Option<Vec<String>> {
|
||||
let js = &mut serde_json::Deserializer::from_str(desc.get_raw());
|
||||
let data : Result<Root, _> = serde_path_to_error::deserialize(js);
|
||||
match data {
|
||||
Ok(d) => {
|
||||
Some(d.content.into_iter().map(|x| x.content.into_iter().map(|y| y.value)).flatten().collect())
|
||||
}
|
||||
Err(err) => {
|
||||
let path = err.path().to_string();
|
||||
println!("{}", path);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
10
src/data/mod.rs
Normal file
10
src/data/mod.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
pub struct Data {} // User data, which is stored and accessible in all command invocations
|
||||
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||
pub type Context<'a> = poise::Context<'a, Data, Error>;
|
||||
|
||||
pub mod core;
|
||||
pub mod allcharacters;
|
||||
pub mod character;
|
||||
pub mod description;
|
||||
pub mod proscons;
|
||||
|
87
src/data/proscons.rs
Normal file
87
src/data/proscons.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use serde_json::Value;
|
||||
use crate::data::character::{Cons, Pros};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Root {
|
||||
pub data: Data,
|
||||
pub content: Vec<Content>,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Data {
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content {
|
||||
pub data: Data,
|
||||
pub content: Vec<Content2>,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content2 {
|
||||
pub data: Data,
|
||||
#[serde(default)]
|
||||
pub marks: Vec<Value>,
|
||||
pub value: Option<String>,
|
||||
pub node_type: String,
|
||||
#[serde(default)]
|
||||
pub content: Vec<Content3>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content3 {
|
||||
pub data: Data,
|
||||
pub content: Vec<Content4>,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content4 {
|
||||
pub data: Data,
|
||||
pub marks: Vec<Value>,
|
||||
pub value: String,
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
|
||||
pub trait ProsCons {
|
||||
fn get_raw(&self) -> &str;
|
||||
}
|
||||
|
||||
impl ProsCons for &Cons {
|
||||
fn get_raw(&self) -> &str {
|
||||
self.raw.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl ProsCons for &Pros {
|
||||
fn get_raw(&self) -> &str {
|
||||
self.raw.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_proscons_texts<T:ProsCons>(desc: &T) -> Option<Vec<String>> {
|
||||
let js = &mut serde_json::Deserializer::from_str(desc.get_raw());
|
||||
let data : Result<Root, _> = serde_path_to_error::deserialize(js);
|
||||
match data {
|
||||
Ok(d) => {
|
||||
Some(d.content.into_iter().map(|x| x.content.into_iter().map(|y| y.content.into_iter().map(|z| z.content.into_iter().map(|w| w.value)).flatten()).flatten()).flatten().collect())
|
||||
}
|
||||
Err(err) => {
|
||||
let path = err.path().to_string();
|
||||
println!("{}", path);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
27
src/utils/color_manager.rs
Normal file
27
src/utils/color_manager.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use std::collections::HashMap;
|
||||
use serenity::utils::Color;
|
||||
|
||||
pub fn get_element_color(name: &String) -> Color {
|
||||
let mut color_map = HashMap::new();
|
||||
color_map.insert("Physical", Color::new(9934743));
|
||||
color_map.insert("Fire", Color::new(15615805));
|
||||
color_map.insert("Ice", Color::new(2527955));
|
||||
color_map.insert("Lightning", Color::new(12999390));
|
||||
color_map.insert("Wind", Color::new(6410131));
|
||||
color_map.insert("Quantum", Color::new(6313929));
|
||||
color_map.insert("Imaginary", Color::new(15982903));
|
||||
color_map.get(name.as_str()).unwrap_or(&Color::new(0)).to_owned()
|
||||
}
|
||||
|
||||
|
||||
pub fn get_path_color(name: &String) -> Color {
|
||||
let mut color_map = HashMap::new();
|
||||
color_map.insert("Abundance", Color::new(6410131));
|
||||
color_map.insert("Destruction", Color::new(9934743));
|
||||
color_map.insert("Erudition", Color::new(12999390));
|
||||
color_map.insert("Harmony", Color::new(2527955));
|
||||
color_map.insert("Hunt", Color::new(15615805));
|
||||
color_map.insert("Nihility", Color::new(6313929));
|
||||
color_map.insert("Preservation", Color::new(15982903));
|
||||
color_map.get(name.as_str()).unwrap_or(&Color::new(0)).to_owned()
|
||||
}
|
25
src/utils/emote_manager.rs
Normal file
25
src/utils/emote_manager.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
pub fn get_element_emote(name: &String) -> &'static str {
|
||||
let mut emote_map = HashMap::new();
|
||||
emote_map.insert("Physical", "<:ele_physical:1102553011928186901>");
|
||||
emote_map.insert("Fire", "<:ele_fire:1102553084523196470>");
|
||||
emote_map.insert("Ice", "<:ele_ice:1102553257009750046>");
|
||||
emote_map.insert("Lightning", "<:ele_lightning:1102553255692738640>");
|
||||
emote_map.insert("Wind", "<:ele_wind:1102553253733998643>");
|
||||
emote_map.insert("Quantum", "<:ele_quantum:1102553252278583326>");
|
||||
emote_map.insert("Imaginary", "<:ele_imaginary:1102551584057069649>");
|
||||
emote_map.get(name.as_str()).unwrap_or(&"").to_owned()
|
||||
}
|
||||
|
||||
pub fn get_path_emote(name: &String) -> &'static str {
|
||||
let mut emote_map = HashMap::new();
|
||||
emote_map.insert("Abundance", "<:path_abundance:1102554507986088038>");
|
||||
emote_map.insert("Destruction", "<:path_destruction:1102554505511448646>");
|
||||
emote_map.insert("Erudition", "<:path_erudition:1102554503527530597>");
|
||||
emote_map.insert("Harmony","<:path_harmony:1102554501518471249>");
|
||||
emote_map.insert("Hunt", "<:path_hunt:1102554500352458812>");
|
||||
emote_map.insert("Nihility", "<:path_nihility:1102554499085778964>");
|
||||
emote_map.insert("Preservation", "<:path_preservation:1102554496757927968>");
|
||||
emote_map.get(name.as_str()).unwrap_or(&"").to_owned()
|
||||
}
|
3
src/utils/mod.rs
Normal file
3
src/utils/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod color_manager;
|
||||
pub mod emote_manager;
|
||||
|
Loading…
Reference in a new issue