First Version of Drunk-Venti-Rust
This commit is contained in:
commit
c8a846cd5a
22 changed files with 1620 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
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
|
25
Cargo.toml
Normal file
25
Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "drunk-venti-rust"
|
||||||
|
version = "1.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Evann Regnault"]
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serenity = { version = "0.10.9", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "unstable_discord_api", "collector"] }
|
||||||
|
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
reqwest = "0.11.7"
|
||||||
|
serde_derive = "1.0.132"
|
||||||
|
serde = "1.0.132"
|
||||||
|
serde_json = {version = "1.0.73", features = ["indexmap"]}
|
||||||
|
levenshtein = "1.0.5"
|
||||||
|
regex = "1.5.4"
|
||||||
|
linked-hash-map = "0.5.4"
|
||||||
|
getset = "0.1.2"
|
||||||
|
mongodb = "2.1.0"
|
||||||
|
futures = "0.3.19"
|
||||||
|
rand = "0.8.4"
|
||||||
|
dotenv = "0.15.0"
|
||||||
|
dotenv_codegen = "0.15.0"
|
91
src/data/artifacts.rs
Normal file
91
src/data/artifacts.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
use serenity::builder::CreateEmbed;
|
||||||
|
use crate::data::domains::Domain;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Set {
|
||||||
|
pub goblet: Option<Box<str>>,
|
||||||
|
pub plume: Option<Box<str>>,
|
||||||
|
pub circlet: Option<Box<str>>,
|
||||||
|
pub flower: Option<Box<str>>,
|
||||||
|
pub sands: Option<Box<str>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Artifact {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub set_piece: Vec<u32>,
|
||||||
|
pub sets: Set,
|
||||||
|
pub bonuses: Vec<Box<str>>,
|
||||||
|
pub rarity: Vec<u8>,
|
||||||
|
pub domain: Option<Box<str>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Artifact{
|
||||||
|
pub async fn get(artifact: &str) -> Artifact {
|
||||||
|
let url = format!("http://localhost:3000/api/artifacts/{}", artifact);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Artifact>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/artifacts");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn search(artifact: &str) -> Vec<Artifact> {
|
||||||
|
let url = format!("http://localhost:3000/api/artifacts/search/{}", artifact);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Artifact>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn to_embed(&self) -> CreateEmbed {
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
|
||||||
|
embed.title(format!("{} | {}", self.name, ":star:".repeat(self.rarity.get(0).expect("").to_owned() as usize)));
|
||||||
|
|
||||||
|
embed.thumbnail(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/artifacts/{}_circlet.png", self.id));
|
||||||
|
|
||||||
|
for i in 0..self.set_piece.len(){
|
||||||
|
embed.field(format!("{}-Pieces", self.set_piece.get(i).expect("No such piece set")),
|
||||||
|
format!("{}", self.bonuses.get(i).expect("Mo such effects")),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match &self.domain {
|
||||||
|
Some(d) => {
|
||||||
|
let domain = Domain::get(d).await;
|
||||||
|
embed.field("Domain", domain.name(), true);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
return self.id.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
return self.name.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_artifacts() {
|
||||||
|
for a in Artifact::get_all().await {
|
||||||
|
println!("{}", a);
|
||||||
|
let arti = Artifact::get(&a).await;
|
||||||
|
println!("Name : {}\nCirclet : {}\nBonuses {:?}", arti.name, arti.sets.goblet.unwrap_or(Box::from("")), arti.bonuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
61
src/data/builds.rs
Normal file
61
src/data/builds.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RoleWeapon {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub refine: Option<Vec<u8>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RoleStat {
|
||||||
|
pub sands: Box<str>,
|
||||||
|
pub goblet: Box<str>,
|
||||||
|
pub circlet: Box<str>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Role{
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub recommended: bool,
|
||||||
|
pub weapons: Vec<RoleWeapon>,
|
||||||
|
pub artifacts: Vec<Vec<Box<str>>>,
|
||||||
|
pub main_stats: RoleStat,
|
||||||
|
pub sub_stats: Vec<Box<str>>,
|
||||||
|
pub talent: Vec<Box<str>>,
|
||||||
|
pub tip: Box<str>,
|
||||||
|
pub note: Box<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Builds {
|
||||||
|
pub roles: Vec<Role>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builds {
|
||||||
|
pub(crate) async fn get(build: &str) -> Builds {
|
||||||
|
let url = format!("http://localhost:3000/api/builds/{}", build);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Builds>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/builds");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn test_builds() {
|
||||||
|
for a in Builds::get_all().await {
|
||||||
|
println!("------------------");
|
||||||
|
let builds = Builds::get(&a).await;
|
||||||
|
println!("Roles for {} : {:?}\n", a, builds.roles.into_iter().map(|x| x.name).collect::<Vec<Box<str>>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
76
src/data/characters.rs
Normal file
76
src/data/characters.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
use crate::data::builds::{Role};
|
||||||
|
use crate::data::elements::Element;
|
||||||
|
use crate::data::items::Item;
|
||||||
|
use crate::data::shared_structs::{Ascension, WeaponType};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CharacterStats {
|
||||||
|
pub hp: u64,
|
||||||
|
pub atk: u64,
|
||||||
|
pub def: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CharacterMaterials {
|
||||||
|
pub book: Vec<Item>,
|
||||||
|
pub material: Vec<Item>,
|
||||||
|
pub boss: Item
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Character {
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub rarity: u8,
|
||||||
|
pub element: Element,
|
||||||
|
pub weapon: WeaponType,
|
||||||
|
pub ascension: Vec<Ascension>,
|
||||||
|
pub stats: CharacterStats,
|
||||||
|
pub material: CharacterMaterials,
|
||||||
|
pub builds: Vec<Role>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Character {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let x = serde_json::to_string(self).expect("str");
|
||||||
|
serde_json::from_str::<Character>(x.as_str()).expect("An error occurred")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Character {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn get(character: &str) -> Character {
|
||||||
|
let url = format!("http://localhost:3000/api/characters/{}", character);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Character>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/characters");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn search(character: &str) -> Vec<Character> {
|
||||||
|
let url = format!("http://localhost:3000/api/characters/search/{}", character);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Character>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn test_character () {
|
||||||
|
for a in Character::get_all().await {
|
||||||
|
println!("{}", a);
|
||||||
|
let char = Character::get(&a).await;
|
||||||
|
println!("Name : {}", char.name);
|
||||||
|
}
|
||||||
|
}
|
70
src/data/domains.rs
Normal file
70
src/data/domains.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DomainMonster {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DomainReward {
|
||||||
|
pub adventure_exp: Box<str>,
|
||||||
|
pub mora: Box<str>,
|
||||||
|
pub friendship_exp: Box<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DomainDifficulty {
|
||||||
|
pub s: u64,
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub ar: u8,
|
||||||
|
pub level: u8,
|
||||||
|
pub reward: DomainReward,
|
||||||
|
pub monsters: Vec<DomainMonster>,
|
||||||
|
pub disorder: Vec<Box<str>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Domain {
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub domains: Vec<DomainDifficulty>,
|
||||||
|
pub artifacts: Vec<Box<str>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Domain {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn get(domain: &str) -> Domain {
|
||||||
|
let url = format!("http://localhost:3000/api/domains/{}", domain);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Domain>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/domains");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
return self.name.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn test_domains () {
|
||||||
|
for a in Domain::get_all().await {
|
||||||
|
println!("{}", a);
|
||||||
|
let domain = Domain::get(&a).await;
|
||||||
|
println!("Name : {}", domain.name);
|
||||||
|
}
|
||||||
|
}
|
32
src/data/elements.rs
Normal file
32
src/data/elements.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Element {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub simple_name: Box<str>,
|
||||||
|
pub color: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element{
|
||||||
|
async fn get(element: &str) -> Element {
|
||||||
|
let url = format!("http://localhost:3000/api/elements/{}", element);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Element>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/elements");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_elem() {
|
||||||
|
println!("All elems : {:?}", Element::get_all().await);
|
||||||
|
|
||||||
|
let geo = Element::get("geo").await;
|
||||||
|
println!("Name : {}\nColor : #{:x}", geo.name, geo.color);
|
||||||
|
}
|
62
src/data/events.rs
Normal file
62
src/data/events.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Event {
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub image: Option<Box<str>>,
|
||||||
|
pub start: Box<str>,
|
||||||
|
pub end: Box<str>,
|
||||||
|
pub url: Option<Box<str>>,
|
||||||
|
pub start_timestamp: u64,
|
||||||
|
pub end_timestamp: u64,
|
||||||
|
pub show_on_home: Option<bool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Event {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let x = serde_json::to_string(&self).expect("");
|
||||||
|
serde_json::from_str::<Event>(x.as_str()).expect("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl Event {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn get_current() -> Vec<Event> {
|
||||||
|
let url = format!("http://localhost:3000/api/events/current");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn get_upcoming() -> Vec<Event> {
|
||||||
|
let url = format!("http://localhost:3000/api/events/upcoming");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
async fn get_all() -> Vec<Event> {
|
||||||
|
let url = format!("http://localhost:3000/api/events");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Event>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn test_events() {
|
||||||
|
let upcoming = Event::get_upcoming().await;
|
||||||
|
println!("UPCOMING EVENTS\n--------");
|
||||||
|
for event in upcoming {
|
||||||
|
println!("Name : {}", event.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = Event::get_current().await;
|
||||||
|
println!("CURRENT EVENTS\n--------");
|
||||||
|
for event in current {
|
||||||
|
println!("Name : {}", event.name);
|
||||||
|
}
|
||||||
|
}
|
43
src/data/items.rs
Normal file
43
src/data/items.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Item {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub day: Option<Vec<Box<str>>>,
|
||||||
|
pub rarity: Option<u8>,
|
||||||
|
pub parent: Option<Box<str>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Item{
|
||||||
|
async fn get(item: &str) -> Item {
|
||||||
|
let url = format!("http://localhost:3000/api/items/{}", item);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Item>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/items");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
async fn search(item: &str) -> Vec<Item> {
|
||||||
|
let url = format!("http://localhost:3000/api/items/search/{}", item);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Item>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_items() {
|
||||||
|
println!("List all items : {:?}", Item::get_all().await);
|
||||||
|
|
||||||
|
let item = Item::get("relic_from_guyun").await;
|
||||||
|
println!("Name : {}\nDays : {:?}", item.name, item.day.unwrap_or(vec![]));
|
||||||
|
|
||||||
|
let item = Item::get("mora").await;
|
||||||
|
println!("Name : {}\nDays : {:?}", item.name, item.day.unwrap_or(vec![]));
|
||||||
|
}
|
20
src/data/mod.rs
Normal file
20
src/data/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
pub mod elements;
|
||||||
|
pub mod artifacts;
|
||||||
|
pub mod items;
|
||||||
|
pub mod weapons;
|
||||||
|
pub mod builds;
|
||||||
|
pub mod characters;
|
||||||
|
pub mod events;
|
||||||
|
pub mod shared_structs;
|
||||||
|
pub mod domains;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn test() {
|
||||||
|
elements::test_elem().await;
|
||||||
|
artifacts::test_artifacts().await;
|
||||||
|
items::test_items().await;
|
||||||
|
weapons::test_weapons().await;
|
||||||
|
builds::test_builds().await;
|
||||||
|
characters::test_character().await;
|
||||||
|
events::test_events().await;
|
||||||
|
}
|
24
src/data/shared_structs.rs
Normal file
24
src/data/shared_structs.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
use crate::data::items::Item;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct WeaponType {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct AscensionItem {
|
||||||
|
pub item: Item,
|
||||||
|
pub amount: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Ascension {
|
||||||
|
pub items: Vec<AscensionItem>,
|
||||||
|
pub mora: u64
|
||||||
|
}
|
121
src/data/weapons.rs
Normal file
121
src/data/weapons.rs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
use reqwest::Url;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
use serenity::builder::CreateEmbed;
|
||||||
|
use regex::Regex;
|
||||||
|
use crate::data::shared_structs::Ascension;
|
||||||
|
use crate::data::shared_structs::WeaponType;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Skill {
|
||||||
|
pub name: Option<Box<str>>,
|
||||||
|
pub description: Option<Box<str>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Secondary {
|
||||||
|
pub name: Option<Box<str>>,
|
||||||
|
pub stats: Option<Vec<Option<f64>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Extras {
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub name: Box<str>,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub weapon_type: Box<str>,
|
||||||
|
pub rarity: u8,
|
||||||
|
pub description: Box<str>,
|
||||||
|
pub skill: Skill,
|
||||||
|
pub secondary: Secondary,
|
||||||
|
pub atk: Vec<Option<f64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Weapon {
|
||||||
|
pub name: Box<str>,
|
||||||
|
pub id: Box<str>,
|
||||||
|
pub rarity: u8,
|
||||||
|
pub atk: u64,
|
||||||
|
pub secondary: Box<str>,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub weapon_type: WeaponType,
|
||||||
|
pub source: Box<str>,
|
||||||
|
pub ascension: Vec<Ascension>,
|
||||||
|
pub extras: Extras,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Weapon {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn get(weapon: &str) -> Weapon {
|
||||||
|
let url = format!("http://localhost:3000/api/weapons/{}", weapon);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Weapon>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn get_all() -> Vec<Box<str>> {
|
||||||
|
let url = format!("http://localhost:3000/api/weapons");
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Box<str>>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn search(weapon: &str) -> Vec<Weapon> {
|
||||||
|
let url = format!("http://localhost:3000/api/weapons/search/{}", weapon);
|
||||||
|
let url = Url::parse(&*url).expect("Can't convert url");
|
||||||
|
return reqwest::get(url).await.expect("Can't access Url").json::<Vec<Weapon>>().await.expect("Wrong json format");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
return &self.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
return &self.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn to_embed(&self) -> CreateEmbed {
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed.title(format!("{} | {}", self.name, ":star:".repeat(self.rarity as usize)));
|
||||||
|
|
||||||
|
embed.description(format!("{}", self.extras.description));
|
||||||
|
|
||||||
|
embed.thumbnail(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/weapons/{}.png", self.id));
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
match self.extras.skill.name.as_ref() {
|
||||||
|
Some(t) => {
|
||||||
|
let re = Regex::new("(<|</)span(?: [^>]*)?>").expect("Unknown regex");
|
||||||
|
embed.field(format!("Passive : {}", t),
|
||||||
|
format!("{}",
|
||||||
|
re.replace_all(self.extras.skill.description.as_ref()
|
||||||
|
.unwrap_or(&Box::from(""))
|
||||||
|
.to_string().as_str(), "**")).replace("\\n","\n"),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
embed.field("Main Stat", format!("{}", self.secondary), true);
|
||||||
|
embed.field("Source", format!("{}", self.source), true);
|
||||||
|
embed.field("\u{200b}", "\u{200b}", true);
|
||||||
|
embed.field("Type", format!("{}", self.weapon_type.name), true);
|
||||||
|
embed.field("Ascension Item", format!("{}", self.ascension.get(0).expect("").items.get(0).expect("").item.name), true);
|
||||||
|
embed.field("\u{200b}", "\u{200b}", true);
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_weapons() {
|
||||||
|
for w in Weapon::get_all().await {
|
||||||
|
println!("------------------");
|
||||||
|
println!("{}", w);
|
||||||
|
}
|
||||||
|
}
|
44
src/interactions/genshin/artifacts.rs
Normal file
44
src/interactions/genshin/artifacts.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use linked_hash_map::LinkedHashMap;
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::model::interactions::{InteractionApplicationCommandCallbackDataFlags, InteractionResponseType};
|
||||||
|
use serenity::model::interactions::application_command::{ApplicationCommandInteraction, ApplicationCommandInteractionDataOption};
|
||||||
|
use serenity::model::interactions::message_component::{MessageComponentInteraction};
|
||||||
|
use crate::data::artifacts::Artifact;
|
||||||
|
use crate::interactions::utils::create_action_row_basic;
|
||||||
|
|
||||||
|
pub async fn genshin_artifact_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &ApplicationCommandInteractionDataOption) {
|
||||||
|
|
||||||
|
let weapon = opt.options.get(0).expect("No argument for command Genshin artifact")
|
||||||
|
.value.as_ref().expect("").as_str().expect("Not a string");
|
||||||
|
|
||||||
|
let artifacts = Artifact::search(weapon).await;
|
||||||
|
let mut artifact_list: LinkedHashMap<String, String> = LinkedHashMap::new();
|
||||||
|
|
||||||
|
for a in artifacts {
|
||||||
|
artifact_list.insert(a.id().to_string(), a.name().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ar = create_action_row_basic(artifact_list, "artifact");
|
||||||
|
|
||||||
|
command.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.content("Select an Artifact")
|
||||||
|
.components(|c| c.add_action_row(ar))
|
||||||
|
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
})
|
||||||
|
}).await.expect("Message didn't got sent");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn show_artifact_embed(ctx: &Context, command: &MessageComponentInteraction, artifact_name: String){
|
||||||
|
let artifact = Artifact::get(artifact_name.as_str()).await;
|
||||||
|
let embed = artifact.to_embed().await;
|
||||||
|
command.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.embeds(vec!(embed).into_iter())
|
||||||
|
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
})
|
||||||
|
}).await.expect("Interaction failed");
|
||||||
|
}
|
416
src/interactions/genshin/build.rs
Normal file
416
src/interactions/genshin/build.rs
Normal file
|
@ -0,0 +1,416 @@
|
||||||
|
use std::borrow::{Borrow};
|
||||||
|
use linked_hash_map::LinkedHashMap;
|
||||||
|
use serenity::builder::{CreateActionRow, CreateButton, CreateEmbed};
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::model::interactions::{InteractionApplicationCommandCallbackDataFlags, InteractionResponseType};
|
||||||
|
use serenity::model::interactions::application_command::{ApplicationCommandInteraction, ApplicationCommandInteractionDataOption};
|
||||||
|
use serenity::model::interactions::message_component::{ButtonStyle, MessageComponentInteraction};
|
||||||
|
use crate::data::artifacts::Artifact;
|
||||||
|
use crate::data::builds::{Builds, Role};
|
||||||
|
use crate::data::characters::Character;
|
||||||
|
use crate::data::weapons::Weapon;
|
||||||
|
use crate::interactions::utils::create_action_row_basic;
|
||||||
|
|
||||||
|
pub async fn genshin_build_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &ApplicationCommandInteractionDataOption) {
|
||||||
|
let char = opt.options.get(0).expect("No argument for command Genshin builds")
|
||||||
|
.value.as_ref().expect("").as_str().expect("Not a string");
|
||||||
|
|
||||||
|
let characters = Character::search(char).await;
|
||||||
|
let mut character_list: LinkedHashMap<String, String> = LinkedHashMap::new();
|
||||||
|
|
||||||
|
for c in characters {
|
||||||
|
character_list.insert(c.id.to_string(), c.name.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ar = create_action_row_basic(character_list, "build");
|
||||||
|
|
||||||
|
command.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.content("Select a Character")
|
||||||
|
.components(|c| c.add_action_row(ar))
|
||||||
|
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
})
|
||||||
|
}).await.expect("Message didn't got sent");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_menu(arg: &str) -> bool {
|
||||||
|
match arg {
|
||||||
|
"home" | "artifacts" | "weapons" | "notes" => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn build_interact(ctx: &Context, interaction: &MessageComponentInteraction, arguments: String) {
|
||||||
|
let mut args = arguments.split("_");
|
||||||
|
let command = args.next();
|
||||||
|
|
||||||
|
|
||||||
|
match command.expect("") {
|
||||||
|
c if is_menu(c) => {
|
||||||
|
let role_index = args.next().expect("").parse::<usize>().expect("");
|
||||||
|
let character_name = args.collect::<Vec<_>>().join("_");
|
||||||
|
let character = Character::get(character_name.as_str()).await;
|
||||||
|
let builds = Builds::get(character_name.as_str()).await;
|
||||||
|
let role = builds.roles.get(role_index).expect("");
|
||||||
|
let ar = nav_button(character_name, role_index);
|
||||||
|
|
||||||
|
let embed = match c {
|
||||||
|
"home" => home_embed(role, character).await,
|
||||||
|
"artifacts" => artifact_embed(role, character).await,
|
||||||
|
"weapons" => weapons_embed(role, character).await,
|
||||||
|
"notes" => note_embed(role, character).await,
|
||||||
|
_ => CreateEmbed::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
interaction.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.add_embed(embed)
|
||||||
|
.components(|c| c.add_action_row(ar))
|
||||||
|
})
|
||||||
|
}).await.expect("Can't send response");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut character = args.collect::<Vec<_>>().join("_");
|
||||||
|
character = [command.expect(""), character.as_str()].join("_");
|
||||||
|
character = character.strip_suffix("_").unwrap_or(character.as_str()).parse().unwrap();
|
||||||
|
build_select(&ctx, &interaction, character).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nav_button(character_name: String, role_index: usize) -> CreateActionRow {
|
||||||
|
let mut ar = CreateActionRow::default();
|
||||||
|
|
||||||
|
let mut btn_home = CreateButton::default();
|
||||||
|
btn_home
|
||||||
|
.custom_id(format!("build_home_{}_{}", role_index, character_name))
|
||||||
|
.style(ButtonStyle::Primary)
|
||||||
|
.label("Home");
|
||||||
|
|
||||||
|
let mut btn_artifacts = CreateButton::default();
|
||||||
|
btn_artifacts
|
||||||
|
.custom_id(format!("build_artifacts_{}_{}", role_index, character_name))
|
||||||
|
.style(ButtonStyle::Primary)
|
||||||
|
.label("Artifacts");
|
||||||
|
|
||||||
|
let mut btn_weapons = CreateButton::default();
|
||||||
|
btn_weapons
|
||||||
|
.custom_id(format!("build_weapons_{}_{}", role_index, character_name))
|
||||||
|
.style(ButtonStyle::Primary)
|
||||||
|
.label("Weapons");
|
||||||
|
|
||||||
|
let mut btn_notes = CreateButton::default();
|
||||||
|
btn_notes
|
||||||
|
.custom_id(format!("build_notes_{}_{}", role_index, character_name))
|
||||||
|
.style(ButtonStyle::Primary)
|
||||||
|
.label("Notes");
|
||||||
|
|
||||||
|
let mut btn_builds = CreateButton::default();
|
||||||
|
btn_builds
|
||||||
|
.custom_id(format!("build_{}", character_name))
|
||||||
|
.style(ButtonStyle::Success)
|
||||||
|
.label("Other builds");
|
||||||
|
|
||||||
|
ar.add_button(btn_home);
|
||||||
|
ar.add_button(btn_artifacts);
|
||||||
|
ar.add_button(btn_weapons);
|
||||||
|
ar.add_button(btn_notes);
|
||||||
|
ar.add_button(btn_builds);
|
||||||
|
|
||||||
|
ar
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn build_select(ctx: &Context, command: &MessageComponentInteraction, character: String) {
|
||||||
|
let char = Character::get(character.as_str()).await;
|
||||||
|
|
||||||
|
let roles = &char.builds;
|
||||||
|
|
||||||
|
let roles = roles.into_iter().map(|c| c.name.to_string()).collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let mut rolemap = LinkedHashMap::<String, String>::new();
|
||||||
|
for i in 0..roles.len() {
|
||||||
|
rolemap.insert(format!("{}_{}", i, character), roles.get(i).expect("").to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ar = create_action_row_basic(rolemap, "build_home");
|
||||||
|
|
||||||
|
command.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.components(|c| c.add_action_row(ar))
|
||||||
|
.create_embed(|e| {
|
||||||
|
e.title(format!("{}", char.name))
|
||||||
|
.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", char.id))
|
||||||
|
.color(char.element.color)
|
||||||
|
.description("Select a build !")
|
||||||
|
.footer(|f| {
|
||||||
|
f.text(format!("Data from : https://paimon.moe/characters/{}", char.id))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).await.expect("Can't send response");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn home_embed(role: &Role, character: Character) -> CreateEmbed {
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed.title(format!("{} | {}", character.name, role.name));
|
||||||
|
embed.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", character.id));
|
||||||
|
embed.color(character.element.color);
|
||||||
|
|
||||||
|
match role.weapons.get(0) {
|
||||||
|
Some(t) => {
|
||||||
|
embed.field("Best Weapon",
|
||||||
|
Weapon::get(t.id.borrow()).await.name,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
embed.field("Best Weapon", "TBD", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.field("Skill Order",
|
||||||
|
role.talent.to_owned().into_iter().map(|t| format!("- {}\n", t))
|
||||||
|
.collect::<Vec<String>>().join("").strip_suffix("\n").expect(""),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
match role.artifacts.get(0) {
|
||||||
|
Some(a) => {
|
||||||
|
let mut artifact_string: Vec<String> = vec![];
|
||||||
|
let str;
|
||||||
|
match a.len() {
|
||||||
|
1 => {
|
||||||
|
let artifact_name = match a.get(0).expect("").to_string().as_str() {
|
||||||
|
"+18%_atk_set" => "+18% Atk Set".to_string(),
|
||||||
|
t => Artifact::get(t).await.name.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
str = format!("(4) {}", artifact_name);
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
for art in a {
|
||||||
|
let artifact_name = match art.to_string().as_str() {
|
||||||
|
"+18%_atk_set" => "+18% Atk Set".to_string(),
|
||||||
|
t => Artifact::get(t).await.name.to_string(),
|
||||||
|
};
|
||||||
|
artifact_string.push(format!("(2) {}", artifact_name));
|
||||||
|
}
|
||||||
|
str = artifact_string.join(" & ");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
artifact_string.push("Choose 2 sets :".to_string());
|
||||||
|
for art in a {
|
||||||
|
let artifact_name = match art.to_string().as_str() {
|
||||||
|
"+18%_atk_set" => "+18% Atk Set".to_string(),
|
||||||
|
t => Artifact::get(t).await.name.to_string(),
|
||||||
|
};
|
||||||
|
artifact_string.push(format!("(2) {}", artifact_name));
|
||||||
|
}
|
||||||
|
str = artifact_string.join(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
embed.field("Best Artifacts", str, false);
|
||||||
|
}
|
||||||
|
_ => { embed.field("Best Artifacts", "TBD", false); }
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.field("Circlet", &role.main_stats.circlet, true);
|
||||||
|
embed.field("Goblet", &role.main_stats.goblet, true);
|
||||||
|
embed.field("Sands", &role.main_stats.sands, true);
|
||||||
|
|
||||||
|
embed.footer(|f| {
|
||||||
|
f.text(format!("Data from : https://paimon.moe/characters/{}", character.id))
|
||||||
|
});
|
||||||
|
|
||||||
|
embed
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async fn artifact_embed(role: &Role, character: Character) -> CreateEmbed {
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed.title(format!("{} | {}", character.name, role.name));
|
||||||
|
|
||||||
|
match role.artifacts.get(0) {
|
||||||
|
Some(t) if t.get(0).expect("").to_string() != "TBD" => {
|
||||||
|
embed.thumbnail(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/artifacts/{}_circlet.png", t.get(0).expect("")));
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
embed.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", character.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.color(character.element.color);
|
||||||
|
|
||||||
|
let mut all_artefacts_string: Vec<String> = vec![];
|
||||||
|
for i in 0..role.artifacts.len() {
|
||||||
|
match role.artifacts.get(i) {
|
||||||
|
Some(a) => {
|
||||||
|
let mut artifact_string: Vec<String> = vec![];
|
||||||
|
let str;
|
||||||
|
match a.len() {
|
||||||
|
1 => {
|
||||||
|
let artifact_name = match a.get(0).expect("").to_string().as_str() {
|
||||||
|
"+18%_atk_set" => "+18% Atk Set".to_string(),
|
||||||
|
t => Artifact::get(t).await.name.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
str = format!("(4) {}", artifact_name);
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
for art in a {
|
||||||
|
let artifact_name = match art.to_string().as_str() {
|
||||||
|
"+18%_atk_set" => "+18% Atk Set".to_string(),
|
||||||
|
t => Artifact::get(t).await.name.to_string(),
|
||||||
|
};
|
||||||
|
artifact_string.push(format!("(2) {}", artifact_name));
|
||||||
|
}
|
||||||
|
str = artifact_string.join(" & ");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
artifact_string.push("Choose 2 sets :".to_string());
|
||||||
|
for art in a {
|
||||||
|
let artifact_name = match art.to_string().as_str() {
|
||||||
|
"+18%_atk_set" => "+18% Atk Set".to_string(),
|
||||||
|
t => Artifact::get(t).await.name.to_string(),
|
||||||
|
};
|
||||||
|
artifact_string.push(format!("(2) {}", artifact_name));
|
||||||
|
}
|
||||||
|
str = artifact_string.join(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all_artefacts_string.push(format!("- {}", str));
|
||||||
|
}
|
||||||
|
_ => { all_artefacts_string.push(format!("- TBD")); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if all_artefacts_string.len() > 0 {
|
||||||
|
embed.field("Best Artifacts", all_artefacts_string.join("\n"), false);
|
||||||
|
} else {
|
||||||
|
embed.field("Best Artifacts", "- TBD", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.field("Sub-stats", {
|
||||||
|
format!("- {}", role.sub_stats.join("\n-"))
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
embed.field("Circlet", &role.main_stats.circlet, true);
|
||||||
|
embed.field("Goblet", &role.main_stats.goblet, true);
|
||||||
|
embed.field("Sands", &role.main_stats.sands, true);
|
||||||
|
|
||||||
|
embed.footer(|f| {
|
||||||
|
f.text(format!("Data from : https://paimon.moe/characters/{}", character.id))
|
||||||
|
});
|
||||||
|
|
||||||
|
embed
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn weapons_embed(role: &Role, character: Character) -> CreateEmbed {
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed.title(format!("{} | {}", character.name, role.name));
|
||||||
|
|
||||||
|
match role.weapons.get(0) {
|
||||||
|
Some(t) if t.id.to_string() != "TBD" => {
|
||||||
|
embed.thumbnail(format!("https://raw.githubusercontent.com/MadeBaruna/paimon-moe/main/static/images/weapons/{}.png", t.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
embed.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", character.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.color(character.element.color);
|
||||||
|
|
||||||
|
let mut all_weapons_string: Vec<String> = vec![];
|
||||||
|
for i in 0..role.weapons.len() {
|
||||||
|
match role.weapons.get(i) {
|
||||||
|
Some(a) if a.id.to_string() != "TBD" => {
|
||||||
|
let weapon = Weapon::get(a.id.borrow()).await;
|
||||||
|
all_weapons_string.push(format!("- {}", weapon.name));
|
||||||
|
}
|
||||||
|
_ => { all_weapons_string.push(format!("- TBD")); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if all_weapons_string.len() > 0 {
|
||||||
|
embed.field("Best Weapons", all_weapons_string.join("\n"), false);
|
||||||
|
} else {
|
||||||
|
embed.field("Best Weapons", "- TBD", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
embed.footer(|f| {
|
||||||
|
f.text(format!("Data from : https://paimon.moe/characters/{}", character.id))
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
embed
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn note_embed(role: &Role, character: Character) -> CreateEmbed {
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed.title(format!("{} | {}", character.name, &role.name));
|
||||||
|
embed.thumbnail(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/characters/{}.png", character.id));
|
||||||
|
embed.color(character.element.color);
|
||||||
|
|
||||||
|
match &role.note {
|
||||||
|
n=> {
|
||||||
|
let x = n.split("\n");
|
||||||
|
let mut first = true;
|
||||||
|
let mut add_before = "";
|
||||||
|
for note_paragraph in x.collect::<Vec<&str>>() {
|
||||||
|
if note_paragraph.len() == 0 {continue};
|
||||||
|
if note_paragraph.len() < 64 && add_before.len() == 0{
|
||||||
|
add_before = note_paragraph;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if add_before.len() > 0 {
|
||||||
|
let note_paragraph = format!("**{}**\n{}", add_before, note_paragraph);
|
||||||
|
embed.field(if first { "Notes" } else { "\u{200b}" }, note_paragraph, false);
|
||||||
|
add_before = "";
|
||||||
|
} else {
|
||||||
|
embed.field(if first { "Notes" } else { "\u{200b}" }, note_paragraph, false);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match &role.tip {
|
||||||
|
n=> {
|
||||||
|
let x = n.split("\n");
|
||||||
|
let mut first = true;
|
||||||
|
let mut add_before = "";
|
||||||
|
for tip_paragraph in x.collect::<Vec<&str>>() {
|
||||||
|
if tip_paragraph.len() == 0 {continue};
|
||||||
|
if tip_paragraph.len() < 64 {
|
||||||
|
add_before = tip_paragraph;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if add_before.len() > 0 {
|
||||||
|
let tip_paragraph = format!("**{}**\n{}", add_before, tip_paragraph);
|
||||||
|
embed.field(if first { "Tips" } else { "\u{200b}" }, tip_paragraph, false);
|
||||||
|
add_before = "";
|
||||||
|
} else {
|
||||||
|
embed.field(if first { "Tips" } else { "\u{200b}" }, tip_paragraph, false);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
embed.footer(|f| {
|
||||||
|
f.text(format!("Data from : https://paimon.moe/characters/{}", character.id))
|
||||||
|
});
|
||||||
|
|
||||||
|
embed
|
||||||
|
}
|
21
src/interactions/genshin/mod.rs
Normal file
21
src/interactions/genshin/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
|
||||||
|
use crate::interactions::genshin::artifacts::genshin_artifact_interaction;
|
||||||
|
use crate::interactions::genshin::build::genshin_build_interaction;
|
||||||
|
use crate::interactions::genshin::weapons::genshin_weapon_interaction;
|
||||||
|
|
||||||
|
pub mod build;
|
||||||
|
pub mod weapons;
|
||||||
|
pub mod artifacts;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn genshin_interaction(ctx: Context, command: ApplicationCommandInteraction) {
|
||||||
|
let sub_command = command.data.options.get(0).expect("No command provided");
|
||||||
|
match sub_command.name.as_str() {
|
||||||
|
"builds" => genshin_build_interaction(&ctx, &command, sub_command).await,
|
||||||
|
"artifact" => genshin_artifact_interaction(&ctx, &command, sub_command).await,
|
||||||
|
"weapon" => genshin_weapon_interaction(&ctx, &command, sub_command).await,
|
||||||
|
_ => println!("Unknown Command")
|
||||||
|
}
|
||||||
|
}
|
45
src/interactions/genshin/weapons.rs
Normal file
45
src/interactions/genshin/weapons.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use linked_hash_map::LinkedHashMap;
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
|
||||||
|
use serenity::model::interactions::application_command::ApplicationCommandInteractionDataOption;
|
||||||
|
use serenity::model::interactions::InteractionResponseType;
|
||||||
|
use serenity::model::prelude::InteractionApplicationCommandCallbackDataFlags;
|
||||||
|
use serenity::model::prelude::message_component::MessageComponentInteraction;
|
||||||
|
use crate::data::weapons::Weapon;
|
||||||
|
use crate::interactions::utils::create_action_row_basic;
|
||||||
|
|
||||||
|
pub async fn genshin_weapon_interaction(ctx: &Context, command: &ApplicationCommandInteraction, opt: &ApplicationCommandInteractionDataOption) {
|
||||||
|
|
||||||
|
let weapon = opt.options.get(0).expect("No argument for command Genshin build")
|
||||||
|
.value.as_ref().expect("").as_str().expect("Not a string");
|
||||||
|
|
||||||
|
let weapons = Weapon::search(weapon).await;
|
||||||
|
let mut weapon_list: LinkedHashMap<String, String> = LinkedHashMap::new();
|
||||||
|
|
||||||
|
for w in weapons {
|
||||||
|
weapon_list.insert(w.id().to_string(), w.name().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ar = create_action_row_basic(weapon_list, "weapon");
|
||||||
|
|
||||||
|
command.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.content("Select a Weapon")
|
||||||
|
.components(|c| c.add_action_row(ar))
|
||||||
|
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
})
|
||||||
|
}).await.expect("The response didn't get sent");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn show_weapon_embed(ctx: &Context, command: &MessageComponentInteraction, weapon_name: String){
|
||||||
|
let weapon = Weapon::get(weapon_name.as_str()).await;
|
||||||
|
command.create_interaction_response(&ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::UpdateMessage)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.embeds(vec!(weapon.to_embed()).into_iter())
|
||||||
|
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
})
|
||||||
|
}).await.expect("The message didn't got sent");
|
||||||
|
}
|
30
src/interactions/mod.rs
Normal file
30
src/interactions/mod.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
pub mod status_message;
|
||||||
|
pub mod genshin;
|
||||||
|
|
||||||
|
#[path = "../data/mod.rs"]
|
||||||
|
mod data;
|
||||||
|
#[path = "../utils/mod.rs"]
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::model::interactions::{InteractionApplicationCommandCallbackDataFlags, InteractionResponseType};
|
||||||
|
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
|
||||||
|
|
||||||
|
pub async fn pong(ctx : Context, command : ApplicationCommandInteraction) {
|
||||||
|
let res = command.create_interaction_response(ctx.http, |res| {
|
||||||
|
res.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|response| {
|
||||||
|
response.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
.content("An error has occurred")
|
||||||
|
})
|
||||||
|
}).await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(e) =>{
|
||||||
|
println!("An error has occured : {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
src/interactions/status_message.rs
Normal file
177
src/interactions/status_message.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
use rand::Rng;
|
||||||
|
use serenity::{
|
||||||
|
client::{
|
||||||
|
Context
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use serenity::builder::CreateEmbed;
|
||||||
|
use serenity::model::id::{ChannelId, MessageId};
|
||||||
|
|
||||||
|
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
|
||||||
|
use serenity::model::interactions::InteractionApplicationCommandCallbackDataFlags;
|
||||||
|
use serenity::model::prelude::{InteractionResponseType};
|
||||||
|
use serenity::utils::Colour;
|
||||||
|
use crate::interactions::data::events::Event;
|
||||||
|
use crate::utils::mongo::{add_discord_status_message, get_all_status_messages, get_discord_status_message, StatusMessage};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn copy_embed(from: &Vec<CreateEmbed>) -> Vec<CreateEmbed> {
|
||||||
|
let mut cln: Vec<CreateEmbed> = vec![];
|
||||||
|
for x in from {
|
||||||
|
cln.push(x.clone());
|
||||||
|
}
|
||||||
|
cln
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_status_message(ctx: Context) {
|
||||||
|
let forever = tokio::task::spawn(async move {
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(60*60));
|
||||||
|
loop {
|
||||||
|
let mut x = get_all_status_messages().await;
|
||||||
|
x.reverse();
|
||||||
|
|
||||||
|
let embeds = create_status_embed().await;
|
||||||
|
for sm in x {
|
||||||
|
let msg = ChannelId::from(sm.channel_id as u64).message(&ctx.http, sm.message_id as u64).await;
|
||||||
|
match msg {
|
||||||
|
Ok(mut m) => {
|
||||||
|
let copies = copy_embed(&embeds);
|
||||||
|
m.edit(&ctx.http, |f| {
|
||||||
|
f.set_embeds(copies)
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interval.tick().await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
forever.await.expect("Stopped for some reasons");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn create_status_interaction(ctx: Context, command: ApplicationCommandInteraction) {
|
||||||
|
let embeds = create_status_embed().await;
|
||||||
|
let channel_option = &command.data.resolved.channels;
|
||||||
|
let channel_id = channel_option.keys().next().expect("No options passed");
|
||||||
|
|
||||||
|
let message = get_discord_status_message(&command.guild_id.expect("Not in guild").as_u64().to_owned()).await;
|
||||||
|
match message {
|
||||||
|
Some(e) => {
|
||||||
|
let rm = ChannelId::from(e.channel_id as u64)
|
||||||
|
.message(&ctx.http, MessageId::from(e.message_id as u64))
|
||||||
|
.await;
|
||||||
|
match rm {
|
||||||
|
msg if rm.is_ok() => {
|
||||||
|
msg.unwrap().delete(&ctx.http).await.unwrap();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = channel_id.send_message(&ctx.http, |f| {
|
||||||
|
f.add_embeds(embeds)
|
||||||
|
}).await.expect("Can't send Message");
|
||||||
|
|
||||||
|
let sm = StatusMessage {
|
||||||
|
message_id: *msg.id.as_u64() as i64,
|
||||||
|
channel_id: *msg.channel_id.as_u64() as i64,
|
||||||
|
guild_id: *command.guild_id.expect("Not in guild").as_u64() as i64,
|
||||||
|
};
|
||||||
|
|
||||||
|
add_discord_status_message(sm).await;
|
||||||
|
|
||||||
|
|
||||||
|
command.create_interaction_response(&ctx.http, |r| {
|
||||||
|
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.create_embed(|e| {
|
||||||
|
e.title("Command Successful !");
|
||||||
|
e.color(Colour::new(0x00ff00));
|
||||||
|
e.description(format!("Status message created !"))
|
||||||
|
})
|
||||||
|
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
||||||
|
})
|
||||||
|
}).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_status_embed() -> Vec<CreateEmbed> {
|
||||||
|
let mut embeds: Vec<CreateEmbed> = vec![];
|
||||||
|
|
||||||
|
let mut current = Event::get_current().await;
|
||||||
|
let mut others = current.clone();
|
||||||
|
|
||||||
|
let mut question_marks = format!("");
|
||||||
|
|
||||||
|
let mut upcoming = Event::get_upcoming().await;
|
||||||
|
|
||||||
|
current = current.into_iter().filter(|p| p.show_on_home.unwrap_or(false)).collect::<Vec<Event>>();
|
||||||
|
others = others.into_iter().filter(|p| !p.show_on_home.unwrap_or(false)).collect::<Vec<Event>>();
|
||||||
|
|
||||||
|
|
||||||
|
upcoming = upcoming.into_iter().filter(|p| p.show_on_home.unwrap_or(false)).collect::<Vec<Event>>();
|
||||||
|
let upcoming_event: Option<&Event> = upcoming.get(0);
|
||||||
|
|
||||||
|
for e in current {
|
||||||
|
question_marks = format!("{}?", question_marks);
|
||||||
|
let mut embed = CreateEmbed::default();
|
||||||
|
embed.title(e.name);
|
||||||
|
embed.color(Colour::new(rand::thread_rng().gen_range(0x000000..0xffffff)));
|
||||||
|
|
||||||
|
match &e.image {
|
||||||
|
Some(url) => {
|
||||||
|
embed.image(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/events/{}", url));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
match e.url {
|
||||||
|
Some(t) => { embed.url(format!("{}{}", t, question_marks)); }
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
embed.description(format!("Ends : <t:{}:R>", e.end_timestamp));
|
||||||
|
embeds.push(embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Other events embed
|
||||||
|
let mut other_embed = CreateEmbed::default();
|
||||||
|
other_embed.title("Other Events");
|
||||||
|
other_embed.color(Colour::new(rand::thread_rng().gen_range(0x000000..0xffffff)));
|
||||||
|
|
||||||
|
for e in others {
|
||||||
|
other_embed.field(e.name, format!("Ends : <t:{}:R>", e.end_timestamp), false);
|
||||||
|
}
|
||||||
|
embeds.push(other_embed);
|
||||||
|
|
||||||
|
match upcoming_event {
|
||||||
|
Some(e) => {
|
||||||
|
let mut upcoming_embed = CreateEmbed::default();
|
||||||
|
question_marks = format!("{}?", question_marks);
|
||||||
|
upcoming_embed.title(&e.name);
|
||||||
|
upcoming_embed.description(format!("Starts : <t:{}:R>", e.start_timestamp));
|
||||||
|
upcoming_embed.color(Colour::new(rand::thread_rng().gen_range(0x000000..0xffffff)));
|
||||||
|
|
||||||
|
match &e.image {
|
||||||
|
Some(url) => {
|
||||||
|
upcoming_embed.image(format!("https://github.com/MadeBaruna/paimon-moe/raw/main/static/images/events/{}", url));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
match &e.url {
|
||||||
|
Some(url) => { upcoming_embed.url(format!("{}{}", url, question_marks)); }
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
embeds.push(upcoming_embed);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
embeds
|
||||||
|
}
|
164
src/main.rs
Normal file
164
src/main.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
mod interactions;
|
||||||
|
mod data;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use dotenv::dotenv;
|
||||||
|
use serenity::{
|
||||||
|
async_trait,
|
||||||
|
model::{
|
||||||
|
gateway::Ready,
|
||||||
|
interactions::{
|
||||||
|
application_command::{
|
||||||
|
ApplicationCommand,
|
||||||
|
ApplicationCommandOptionType,
|
||||||
|
},
|
||||||
|
Interaction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use serenity::client::bridge::gateway::GatewayIntents;
|
||||||
|
use serenity::model::gateway::Activity;
|
||||||
|
use crate::interactions::genshin::artifacts::show_artifact_embed;
|
||||||
|
use crate::interactions::genshin::build::build_interact;
|
||||||
|
use crate::interactions::genshin::weapons::show_weapon_embed;
|
||||||
|
use crate::interactions::status_message::update_status_message;
|
||||||
|
|
||||||
|
struct Handler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl EventHandler for Handler {
|
||||||
|
async fn ready(&self, _ctx: Context, _bot: Ready) {
|
||||||
|
println!("{} connected!", _bot.user.name);
|
||||||
|
update_status_message(_ctx.clone()).await;
|
||||||
|
_ctx.set_activity(Activity::playing("Drinking")).await;
|
||||||
|
|
||||||
|
let x = ApplicationCommand::get_global_application_commands(&_ctx.http).await.unwrap();
|
||||||
|
for i in x {
|
||||||
|
match i.name.as_str() {
|
||||||
|
"genshin" => (),
|
||||||
|
"createstatusmessage" => (),
|
||||||
|
_ => {
|
||||||
|
let _result_delete = ApplicationCommand::delete_global_application_command(&_ctx.http, i.id).await;
|
||||||
|
match _result_delete {
|
||||||
|
Ok(()) => { println!("Deleted command {}", i.name) }
|
||||||
|
Err(f) => { println!("An error occurred deleting {} : {}", i.name, f) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = ApplicationCommand::create_global_application_command(&_ctx.http, |command| {
|
||||||
|
command.name("genshin").description("Get Informations about Genshin Impact.").create_option(|option| {
|
||||||
|
option.name("builds")
|
||||||
|
.description("Shows builds for a Genshin Impact Characters")
|
||||||
|
.kind(ApplicationCommandOptionType::SubCommand)
|
||||||
|
.create_sub_option(|so| {
|
||||||
|
so.name("character").description("Character to get builds for")
|
||||||
|
.kind(ApplicationCommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option.name("weapon")
|
||||||
|
.description("Shows infos on a Genshin Impact weapon.")
|
||||||
|
.kind(ApplicationCommandOptionType::SubCommand)
|
||||||
|
.create_sub_option(|so| {
|
||||||
|
so.name("name").description("Weapon you want infos on.")
|
||||||
|
.kind(ApplicationCommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option.name("artifact")
|
||||||
|
.description("Shows infos on a Genshin Impact artifact set.")
|
||||||
|
.kind(ApplicationCommandOptionType::SubCommand)
|
||||||
|
.create_sub_option(|so| {
|
||||||
|
so.name("artifact")
|
||||||
|
.description("Artifact Set you want infos on.")
|
||||||
|
.kind(ApplicationCommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).await;
|
||||||
|
if x.is_err() {
|
||||||
|
println!("{}", x.unwrap_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationCommand::create_global_application_command(&_ctx.http, |command| {
|
||||||
|
command.name("createstatusmessage").create_option(|opt| {
|
||||||
|
opt.name("channel").description("Channel where to put the status message")
|
||||||
|
.kind(ApplicationCommandOptionType::Channel)
|
||||||
|
.required(true)
|
||||||
|
}).description("Creates a status message of all the current events on Genshin Impact")
|
||||||
|
}).await.expect("Can't create the createstatusmessage command");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async fn interaction_create(&self, _ctx: Context, _interaction: Interaction) {
|
||||||
|
if let Interaction::ApplicationCommand(command) = _interaction {
|
||||||
|
match command.data.name.as_str() {
|
||||||
|
// Ping command
|
||||||
|
"genshin" => interactions::genshin::genshin_interaction(_ctx, command).await,
|
||||||
|
"createstatusmessage" => interactions::status_message::create_status_interaction(_ctx, command).await,
|
||||||
|
// Unknown command
|
||||||
|
_ => interactions::pong(_ctx, command).await
|
||||||
|
}
|
||||||
|
} else if let Interaction::MessageComponent(component) = _interaction {
|
||||||
|
let mut args = component.data.custom_id.split("_");
|
||||||
|
let command = args.next();
|
||||||
|
match command.unwrap() {
|
||||||
|
"weapon" => {
|
||||||
|
let weapon = args.collect::<Vec<_>>().join("_");
|
||||||
|
show_weapon_embed(&_ctx, &component, weapon).await;
|
||||||
|
}
|
||||||
|
"artifact" => {
|
||||||
|
let artifact = args.collect::<Vec<_>>().join("_");
|
||||||
|
show_artifact_embed(&_ctx, &component, artifact).await;
|
||||||
|
}
|
||||||
|
"build" => {
|
||||||
|
let character = args.collect::<Vec<_>>().join("_");
|
||||||
|
build_interact(&_ctx, &component, character).await;
|
||||||
|
}
|
||||||
|
_ => println!("Unknown interaction")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("ERROR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
dotenv().ok();
|
||||||
|
let mut token= "".to_string();
|
||||||
|
for (k, v) in env::vars() {
|
||||||
|
if k.eq("DISCORD_TOKEN") {
|
||||||
|
token = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let application_id: u64 = "860553396578811914".parse().expect("Wrong format");
|
||||||
|
|
||||||
|
let needed_intents = [
|
||||||
|
GatewayIntents::GUILDS,
|
||||||
|
GatewayIntents::GUILD_MESSAGES,
|
||||||
|
GatewayIntents::GUILD_EMOJIS,
|
||||||
|
GatewayIntents::GUILD_WEBHOOKS,
|
||||||
|
GatewayIntents::GUILD_INTEGRATIONS
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut client = Client::builder(token)
|
||||||
|
.event_handler(Handler)
|
||||||
|
.intents(GatewayIntents::from_iter(needed_intents.into_iter()))
|
||||||
|
.application_id(application_id)
|
||||||
|
.await
|
||||||
|
.expect("Error creating the client");
|
||||||
|
|
||||||
|
if let Err(why) = client.start().await {
|
||||||
|
println!("Client error {}", why);
|
||||||
|
}
|
||||||
|
}
|
22
src/utils/mod.rs
Normal file
22
src/utils/mod.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use linked_hash_map::LinkedHashMap;
|
||||||
|
use serenity::builder::{CreateActionRow, CreateButton};
|
||||||
|
use serenity::model::interactions::message_component::ButtonStyle;
|
||||||
|
|
||||||
|
pub mod mongo;
|
||||||
|
|
||||||
|
pub fn create_action_row_basic (dict: LinkedHashMap<String, String>, command: &str) -> CreateActionRow {
|
||||||
|
let mut buttons: Vec<CreateButton> = vec!();
|
||||||
|
for d in dict {
|
||||||
|
let mut b = CreateButton::default();
|
||||||
|
b.custom_id(format!("{}_{}", command, &d.0));
|
||||||
|
b.label(d.1);
|
||||||
|
b.style(ButtonStyle::Primary);
|
||||||
|
buttons.push(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ar = CreateActionRow::default();
|
||||||
|
for btn in buttons {
|
||||||
|
ar.add_button(btn);
|
||||||
|
}
|
||||||
|
ar
|
||||||
|
}
|
67
src/utils/mongo.rs
Normal file
67
src/utils/mongo.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use mongodb::bson::{Bson, doc, Document, from_bson, to_bson};
|
||||||
|
use mongodb::{Client, Collection, options::ClientOptions};
|
||||||
|
use futures::stream::{TryStreamExt};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct StatusMessage {
|
||||||
|
pub(crate) guild_id: i64,
|
||||||
|
pub(crate) message_id: i64,
|
||||||
|
pub(crate) channel_id: i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn add_discord_status_message(status_message: StatusMessage) -> bool {
|
||||||
|
let client = get_mongo_client().await;
|
||||||
|
|
||||||
|
let serialized = to_bson(&status_message).expect("Can't serialize status_message");
|
||||||
|
let document = serialized.as_document().unwrap();
|
||||||
|
|
||||||
|
let collection: Collection<Document> = client.database("drunk_venti").collection("StatusMessages");
|
||||||
|
let updated = collection.update_one(doc! {"guild_id": status_message.guild_id}, doc! {"$set" : document}, None).await;
|
||||||
|
let is_ok = &updated.is_ok();
|
||||||
|
match updated.unwrap() {
|
||||||
|
e if e.matched_count == 0 => {
|
||||||
|
let inserted = collection.insert_one(document, None).await;
|
||||||
|
inserted.is_ok()
|
||||||
|
}
|
||||||
|
_ => *is_ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn get_discord_status_message(gid: &u64) -> Option<StatusMessage> {
|
||||||
|
let client = get_mongo_client().await;
|
||||||
|
|
||||||
|
let status_messages: Collection<Document> = client.database("drunk_venti").collection("StatusMessages");
|
||||||
|
|
||||||
|
let infos = status_messages.find_one(doc! {"guild_id" : *gid as i64}, None).await.expect("Can't find one");
|
||||||
|
|
||||||
|
|
||||||
|
match infos {
|
||||||
|
Some(i) => {
|
||||||
|
let m_infos: StatusMessage = from_bson(Bson::Document(i)).expect("Can't get");
|
||||||
|
return Some(m_infos);
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub async fn get_all_status_messages() -> Vec<StatusMessage> {
|
||||||
|
let client = get_mongo_client().await;
|
||||||
|
|
||||||
|
let collection: Collection<StatusMessage> = client.database("drunk_venti").collection::<StatusMessage>("StatusMessages");
|
||||||
|
let documents = collection.find(None, None).await.expect("Can't get everything");
|
||||||
|
let all_docs: Vec<StatusMessage> = documents.try_collect().await.unwrap_or_else(|_| vec![]);
|
||||||
|
return all_docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
async fn get_mongo_client() -> Client {
|
||||||
|
let mut client_options = ClientOptions::parse("mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&directConnection=true&ssl=false").await.expect("Can't connect to db");
|
||||||
|
client_options.app_name = Some("Drunk Venti".to_string());
|
||||||
|
client_options.default_database = Some("drunk_venti".to_string());
|
||||||
|
|
||||||
|
Client::with_options(client_options).expect("Can't add options")
|
||||||
|
}
|
Loading…
Reference in a new issue