1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-12-22 09:34:21 +00:00

Restructure again!

This commit is contained in:
Steffo 2022-08-06 05:07:10 +02:00
parent 26c02d9c2e
commit 824d2246de
Signed by: steffo
GPG key ID: 6965406171929D01
33 changed files with 486 additions and 630 deletions

View file

@ -16,7 +16,7 @@ itertools = { version = "0.10.3" } # Not using this yet
# exec
pretty_env_logger = { version = "0.4.0", optional = true }
glob = { version = "0.3.0", optional = true }
# schema
# data
serde = { version = "1.0.140", features = ["derive"] }
serde_json = { version = "1.0.82" }
# search
@ -29,7 +29,7 @@ tokio = { version = "1.20.1", features = ["rt-multi-thread", "macros"], optiona
# matrix
[features]
# schema = [] # Always included
# data = [] # Always included
exec = ["pretty_env_logger", "glob"]
search = ["tantivy"]
telegram = ["search", "teloxide", "reqwest", "tokio"]
@ -39,7 +39,3 @@ telegram = ["search", "teloxide", "reqwest", "tokio"]
[lib]
name = "patched_porobot"
path = "src/lib.rs"
[[bin]]
name = "patched_porobot_telegram"
path = "src/telegram/bin.rs"

View file

@ -0,0 +1,43 @@
//! This module defines [BundleMetadata], the contents of `metadata.json`.
use std::fs::File;
use std::path::Path;
use crate::data::outcomes::{LoadingError, LoadingResult};
/// A parsed `metadata.json` file from a Data Dragon Bundle.
///
/// The specification defines more fields, but they are missing from the output files.
///
/// > ```json
/// > {
/// > "locales": ["{string}", ],
/// > "clientHash": "{string}"
/// > "gameplayDataHash": "{string}",
/// > "timestamp": "{YYYYMMDDhhmm}",
/// > "patchlineRef": "{string}"
/// > }
/// > ```
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct BundleMetadata {
/// [Vec] of locales included in the bundle.
///
/// The specification defines that there can be multiple, but currently I've never seen more (or less) than one.
pub locales: Vec<String>
}
impl BundleMetadata {
/// Load a `metadata.json` file to create a [LocalizedGlobalsVecs] instance.
pub fn load(path: &Path) -> LoadingResult<Self> {
let file = File::open(path)
.map_err(LoadingError::Loading)?;
let data = serde_json::de::from_reader::<File, Self>(file)
.map_err(LoadingError::Parsing)?;
Ok(data)
}
/// Get a reference to the first (and probably only) locale defined in BundleMetadata.
pub fn locale(&self) -> Option<&String> {
self.locales.get(0)
}
}

View file

@ -0,0 +1,3 @@
//! This module defines structs common to all Data Dragon Bundles.
pub mod metadata;

View file

@ -0,0 +1,216 @@
//! This module defines [LocalizedGlobalsVecs] and [LocalizedGlobalsIndexes], structs representing the data contained in the `globals.json` files.
use std::fs::File;
use std::path::Path;
use crate::data::outcomes::{LoadingError, LoadingResult};
use super::vocabterm::{LocalizedVocabTermVec, LocalizedVocabTermIndex};
use super::keyword::{LocalizedCardKeywordVec, LocalizedCardKeywordIndex};
use super::region::{LocalizedCardRegionVec, LocalizedCardRegionIndex};
use super::speed::{LocalizedSpellSpeedVec, LocalizedSpellSpeedIndex};
use super::rarity::{LocalizedCardRarityVec, LocalizedCardRarityIndex};
use super::set::{LocalizedCardSetVec, LocalizedCardSetIndex};
/// A parsed `globals.json` file from a Legends of Runeterra Core Bundle.
///
/// It contains a list of all vocabulary terms, keywords, regions, spell speeds, and rarities present in Legends of Runeterra.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct LocalizedGlobalsVecs {
#[serde(rename = "vocabTerms")]
pub vocab_terms: LocalizedVocabTermVec,
pub keywords: LocalizedCardKeywordVec,
pub regions: LocalizedCardRegionVec,
#[serde(rename = "spellSpeeds")]
pub spell_speeds: LocalizedSpellSpeedVec,
pub rarities: LocalizedCardRarityVec,
pub sets: LocalizedCardSetVec,
}
/// An instance of [LocalizedGlobalsVecs] which had its own fields indexed in [HashMap]s, using the respective identifiers as map keys.
///
/// It contains a indexed list of all vocabulary terms, keywords, regions, spell speeds, and rarities present in Legends of Runeterra.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LocalizedGlobalsIndexes {
pub vocab_terms: LocalizedVocabTermIndex,
pub keywords: LocalizedCardKeywordIndex,
pub regions: LocalizedCardRegionIndex,
pub spell_speeds: LocalizedSpellSpeedIndex,
pub rarities: LocalizedCardRarityIndex,
pub sets: LocalizedCardSetIndex,
}
impl LocalizedGlobalsVecs {
/// Load a `globals.json` file to create a [LocalizedGlobalsVecs] instance.
pub fn load(path: &Path) -> LoadingResult<Self> {
let file = File::open(path)
.map_err(LoadingError::Loading)?;
let data = serde_json::de::from_reader::<File, Self>(file)
.map_err(LoadingError::Parsing)?;
Ok(data)
}
}
impl From<LocalizedGlobalsVecs> for LocalizedGlobalsIndexes {
fn from(o: LocalizedGlobalsVecs) -> Self {
Self {
vocab_terms: {
let mut hm = LocalizedVocabTermIndex::new();
for obj in o.vocab_terms {
hm.insert(obj.vocabterm.clone(), obj);
}
hm
},
keywords: {
let mut hm = LocalizedCardKeywordIndex::new();
for obj in o.keywords {
hm.insert(obj.keyword, obj);
}
hm
},
regions: {
let mut hm = LocalizedCardRegionIndex::new();
for obj in o.regions {
hm.insert(obj.region, obj);
}
hm
},
spell_speeds: {
let mut hm = LocalizedSpellSpeedIndex::new();
for obj in o.spell_speeds {
hm.insert(obj.spell_speed, obj);
}
hm
},
rarities: {
let mut hm = LocalizedCardRarityIndex::new();
for obj in o.rarities {
hm.insert(obj.rarity, obj);
}
hm
},
sets: {
let mut hm = LocalizedCardSetIndex::new();
for obj in o.sets {
hm.insert(obj.set, obj);
}
hm
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::data::setbundle::keyword::CardKeyword;
use crate::data::setbundle::rarity::CardRarity;
use crate::data::setbundle::region::CardRegion;
use crate::data::setbundle::set::CardSet;
use crate::data::setbundle::speed::SpellSpeed;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, LocalizedGlobalsVecs>(r#"
{
"vocabTerms": [
{
"description": "When you summon this, it gets its allegiance bonus if the top card of your deck matches its region.",
"name": "Allegiance",
"nameRef": "Allegiance"
}
],
"keywords": [
{
"description": "Inflicts damage beyond what would kill the target(s) to the enemy Nexus.",
"name": "Overwhelm",
"nameRef": "SpellOverwhelm"
}
],
"regions": [
{
"abbreviation": "NX",
"iconAbsolutePath": "http://dd.b.pvp.net/3_11_0/core/en_us/img/regions/icon-noxus.png",
"name": "Noxus",
"nameRef": "Noxus"
}
],
"spellSpeeds": [
{
"name": "Slow",
"nameRef": "Slow"
}
],
"rarities": [
{
"name": "COMMON",
"nameRef": "Common"
}
],
"sets": [
{
"iconAbsolutePath": "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png",
"name": "Call of the Mountain",
"nameRef": "Set3"
}
]
}
"#).unwrap(),
LocalizedGlobalsVecs {
vocab_terms: vec![
vocabterm::LocalizedVocabTerm {
vocabterm: "Allegiance".to_string(),
name: "Allegiance".to_string(),
description: "When you summon this, it gets its allegiance bonus if the top card of your deck matches its region.".to_string(),
}
],
keywords: vec![
keyword::LocalizedCardKeyword {
keyword: CardKeyword::SpellOverwhelm,
name: "Overwhelm".to_string(),
description: "Inflicts damage beyond what would kill the target(s) to the enemy Nexus.".to_string(),
}
],
regions: vec![
region::LocalizedCardRegion {
region: CardRegion::Noxus,
name: "Noxus".to_string(),
abbreviation: "NX".to_string(),
icon_png: "http://dd.b.pvp.net/3_11_0/core/en_us/img/regions/icon-noxus.png".to_string(),
}
],
spell_speeds: vec![
speed::LocalizedSpellSpeed {
spell_speed: SpellSpeed::Slow,
name: "Slow".to_string(),
}
],
rarities: vec![
rarity::LocalizedCardRarity {
rarity: CardRarity::Common,
name: "COMMON".to_string(),
}
],
sets: vec![
set::LocalizedCardSet {
set: CardSet::CallOfTheMountain,
name: "Call of the Mountain".to_string(),
icon_png: "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png".to_string(),
}
]
}
)
}
}

View file

@ -1,10 +1,11 @@
//! This module defines [CoreKeyword].
use crate::schema::setbundle::CardKeyword;
use std::collections::HashMap;
use crate::data::setbundle::keyword::CardKeyword;
/// A Legends of Runeterra [CardKeyword], and its associated localization.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreKeyword {
pub struct LocalizedCardKeyword {
/// The [CardKeyword] these strings refer to.
#[serde(rename = "nameRef")]
pub keyword: CardKeyword,
@ -16,24 +17,27 @@ pub struct CoreKeyword {
pub description: String,
}
/// How [LocalizedCardKeyword]s appear in `global.json` files.
pub type LocalizedCardKeywordVec = Vec<LocalizedCardKeyword>;
/// An index of [LocalizedCardKeyword]s, with [LocalizedCardKeyword::keyword]s as keys.
pub type LocalizedCardKeywordIndex = HashMap<CardKeyword, LocalizedCardKeyword>;
#[cfg(test)]
mod tests {
use crate::schema::setbundle::CardKeyword;
use super::CoreKeyword;
use super::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreKeyword>(r#"
serde_json::de::from_str::<'static, LocalizedCardKeyword>(r#"
{
"description": "Inflicts damage beyond what would kill the target(s) to the enemy Nexus.",
"name": "Overwhelm",
"nameRef": "SpellOverwhelm"
}
"#).unwrap(),
CoreKeyword {
LocalizedCardKeyword {
keyword: CardKeyword::SpellOverwhelm,
name: "Overwhelm".to_string(),
description: "Inflicts damage beyond what would kill the target(s) to the enemy Nexus.".to_string(),

View file

@ -0,0 +1,45 @@
//! This module defines the types used in Data Dragon [Core Bundles](https://developer.riotgames.com/docs/lor#data-dragon_core-bundles).
use std::path::Path;
use super::anybundle::metadata::BundleMetadata;
use super::outcomes::{LoadingError, LoadingResult};
pub mod globals;
pub mod vocabterm;
pub mod keyword;
pub mod region;
pub mod speed;
pub mod rarity;
pub mod set;
/// A parsed [Core Bundle](https://developer.riotgames.com/docs/lor#data-dragon_core-bundles).
pub struct CoreBundle {
/// The contents of the `metadata.json` file.
pub metadata: BundleMetadata,
/// The contents of the `[locale]/data/globals-[locale].json` file.
pub globals: globals::LocalizedGlobalsVecs,
}
impl CoreBundle {
/// Load a Core Bundle directory to create a [CoreBundle] instance.
pub fn load(bundle_path: &Path) -> LoadingResult<Self> {
let metadata = BundleMetadata::load(
&bundle_path
.join("metadata.json")
)?;
let locale = metadata.locale().ok_or(LoadingError::Using)?;
let globals = globals::LocalizedGlobalsVecs::load(
&bundle_path
.join(&locale)
.join("data")
.join(format!("globals-{}.json", &locale))
)?;
Ok(CoreBundle {metadata, globals})
}
}

View file

@ -1,10 +1,11 @@
//! This module defines [CoreRarity].
use crate::schema::setbundle::CardRarity;
use std::collections::HashMap;
use crate::data::setbundle::rarity::CardRarity;
/// A Legends of Runeterra [CardRarity], and its associated localization.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreRarity {
pub struct LocalizedCardRarity {
/// The [CardRarity] these strings refer to.
#[serde(rename = "nameRef")]
pub rarity: CardRarity,
@ -13,23 +14,26 @@ pub struct CoreRarity {
pub name: String,
}
/// How [LocalizedCardRarity]s appear in `global.json` files.
pub type LocalizedCardRarityVec = Vec<LocalizedCardRarity>;
/// An index of [LocalizedCardRarity]s, with [LocalizedCardRarity::rarity]s as keys.
pub type LocalizedCardRarityIndex = HashMap<CardRarity, LocalizedCardRarity>;
#[cfg(test)]
mod tests {
use crate::schema::setbundle::CardRarity;
use super::CoreRarity;
use super::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreRarity>(r#"
serde_json::de::from_str::<'static, LocalizedCardRarity>(r#"
{
"name": "COMMON",
"nameRef": "Common"
}
"#).unwrap(),
CoreRarity {
LocalizedCardRarity {
rarity: CardRarity::Common,
name: "COMMON".to_string(),
}

View file

@ -1,10 +1,11 @@
//! This module defines [CoreRegion].
use crate::schema::setbundle::CardRegion;
use std::collections::HashMap;
use crate::data::setbundle::region::CardRegion;
/// A Legends of Runeterra [CardRegion], and its associated localization.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreRegion {
pub struct LocalizedCardRegion {
/// The [CardRegion] these strings refer to.
#[serde(rename = "nameRef")]
pub region: CardRegion,
@ -22,17 +23,20 @@ pub struct CoreRegion {
pub icon_png: String,
}
/// How [LocalizedCardRegion]s appear in `global.json` files.
pub type LocalizedCardRegionVec = Vec<LocalizedCardRegion>;
/// An index of [LocalizedCardRegion]s, with [LocalizedCardRegion::region]s as keys.
pub type LocalizedCardRegionIndex = HashMap<CardRegion, LocalizedCardRegion>;
#[cfg(test)]
mod tests {
use crate::schema::setbundle::CardRegion;
use super::CoreRegion;
use super::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreRegion>(r#"
serde_json::de::from_str::<'static, LocalizedCardRegion>(r#"
{
"abbreviation": "NX",
"iconAbsolutePath": "http://dd.b.pvp.net/3_11_0/core/en_us/img/regions/icon-noxus.png",
@ -40,7 +44,7 @@ mod tests {
"nameRef": "Noxus"
}
"#).unwrap(),
CoreRegion {
LocalizedCardRegion {
region: CardRegion::Noxus,
name: "Noxus".to_string(),
abbreviation: "NX".to_string(),

View file

@ -1,10 +1,11 @@
//! This module defines [CoreSet].
use crate::schema::setbundle::CardSet;
use std::collections::HashMap;
use crate::data::setbundle::set::CardSet;
/// A Legends of Runeterra [CardSet], and its associated localization.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreSet {
pub struct LocalizedCardSet {
/// The [CardSet] these strings refer to.
#[serde(rename = "nameRef")]
pub set: CardSet,
@ -17,24 +18,27 @@ pub struct CoreSet {
pub icon_png: String,
}
/// How [LocalizedCardSet]s appear in `global.json` files.
pub type LocalizedCardSetVec = Vec<LocalizedCardSet>;
/// An index of [LocalizedCardSet]s, with [LocalizedCardSet::set]s as keys.
pub type LocalizedCardSetIndex = HashMap<CardSet, LocalizedCardSet>;
#[cfg(test)]
mod tests {
use crate::schema::setbundle::CardSet;
use super::CoreSet;
use super::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreSet>(r#"
serde_json::de::from_str::<'static, LocalizedCardSet>(r#"
{
"iconAbsolutePath": "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png",
"name": "Call of the Mountain",
"nameRef": "Set3"
}
"#).unwrap(),
CoreSet {
LocalizedCardSet {
set: CardSet::CallOfTheMountain,
name: "Call of the Mountain".to_string(),
icon_png: "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png".to_string(),

View file

@ -1,10 +1,11 @@
//! This module defines [CoreSpellSpeed].
use crate::schema::setbundle::SpellSpeed;
use std::collections::HashMap;
use crate::data::setbundle::speed::SpellSpeed;
/// A Legends of Runeterra [SpellSpeed], and its associated localization.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreSpellSpeed {
pub struct LocalizedSpellSpeed {
/// The [SpellSpeed] these strings refer to.
#[serde(rename = "nameRef")]
pub spell_speed: SpellSpeed,
@ -13,23 +14,26 @@ pub struct CoreSpellSpeed {
pub name: String,
}
/// How [LocalizedSpellSpeed]s appear in `global.json` files.
pub type LocalizedSpellSpeedVec = Vec<LocalizedSpellSpeed>;
/// An index of [LocalizedSpellSpeed]s, with [LocalizedSpellSpeed::spell_speed]s as keys.
pub type LocalizedSpellSpeedIndex = HashMap<SpellSpeed, LocalizedSpellSpeed>;
#[cfg(test)]
mod tests {
use crate::schema::setbundle::SpellSpeed;
use super::CoreSpellSpeed;
use super::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreSpellSpeed>(r#"
serde_json::de::from_str::<'static, LocalizedSpellSpeed>(r#"
{
"name": "Slow",
"nameRef": "Slow"
}
"#).unwrap(),
CoreSpellSpeed {
LocalizedSpellSpeed {
spell_speed: SpellSpeed::Slow,
name: "Slow".to_string(),
}

View file

@ -1,16 +1,14 @@
//! This module defines [CoreVocabTerm].
use std::collections::HashMap;
use std::hash::Hash;
/// A Legends of Runeterra vocabulary term, and its associated localization.
///
/// I'm not sure where these are used, other than in in-game tooltips.
///
/// TODO: Find out where these are used.
/// Vocabulary terms are used in [XML tags of card descriptions](crate::data::setbundle::card::Card::localized_description_xml) to provide tooltips about game mechanics.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreVocabTerm {
pub struct LocalizedVocabTerm {
/// The internal name used by the vocabulary term.
///
/// TODO: Map these to an enum.
#[serde(rename = "nameRef")]
pub vocabterm: String,
@ -21,22 +19,27 @@ pub struct CoreVocabTerm {
pub description: String,
}
/// How [LocalizedVocabTerm]s appear in `global.json` files.
pub type LocalizedVocabTermVec = Vec<LocalizedVocabTerm>;
/// An index of [LocalizedVocabTerm]s, with [LocalizedVocabTerm::vocabterm]s as keys.
pub type LocalizedVocabTermIndex = HashMap<String, LocalizedVocabTerm>;
#[cfg(test)]
mod tests {
use super::CoreVocabTerm;
use super::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreVocabTerm>(r#"
serde_json::de::from_str::<'static, LocalizedVocabTerm>(r#"
{
"description": "When you summon this, it gets its allegiance bonus if the top card of your deck matches its region.",
"name": "Allegiance",
"nameRef": "Allegiance"
}
"#).unwrap(),
CoreVocabTerm {
LocalizedVocabTerm {
vocabterm: "Allegiance".to_string(),
name: "Allegiance".to_string(),
description: "When you summon this, it gets its allegiance bonus if the top card of your deck matches its region.".to_string(),

View file

@ -3,3 +3,4 @@
pub mod corebundle;
pub mod setbundle;
pub mod anybundle;
pub mod outcomes;

8
src/data/outcomes.rs Normal file
View file

@ -0,0 +1,8 @@
pub enum LoadingError {
Checking,
Loading(std::io::Error),
Parsing(serde_json::Error),
Using,
}
pub type LoadingResult<T> = Result<T, LoadingError>;

View file

@ -1,8 +1,13 @@
//! Module defining [Card].
use std::collections::HashMap;
use super::*;
use super::r#type::CardType;
use super::art::CardArt;
use super::keyword::CardKeyword;
use super::rarity::CardRarity;
use super::region::CardRegion;
use super::speed::SpellSpeed;
use super::set::CardSet;
/// A single Legends of Runeterra card as represented in a `set.json` file.
///
@ -141,7 +146,6 @@ pub struct Card {
pub supertype: String,
}
impl Card {
/// Get references to the cards associated with this one, given an [HashMap] of cards indexed by code.
pub fn associated_cards<'c, 'hm: 'c>(&'c self, hashmap: &'hm HashMap<String, Card>) -> impl Iterator<Item=Option<&'hm Card>> + 'c {

View file

@ -1,9 +1,6 @@
//! Module defining [CardKeyword].
use std::collections::HashMap;
use crate::schema::corebundle::CoreKeyword;
use crate::data::corebundle::keyword::{LocalizedCardKeyword, LocalizedCardKeywordIndex};
/// A keyword which cards can have.
///
@ -337,12 +334,13 @@ pub enum CardKeyword {
Unsupported,
}
impl CardKeyword {
/// Get localized text about the keyword from [crate::schema::corebundle] data.
/// Get the [LocalizedCardKeyword] associated with this [CardKeyword].
///
/// Returns `None` if no matching [CoreKeyword] was found, for example for [CardKeyword::Unsupported] keywords.
pub fn localized<'hm>(&self, hm: &'hm HashMap<CardKeyword, CoreKeyword>) -> Option<&'hm CoreKeyword> {
/// Returns [Option::None] if no matching [LocalizedCardKeyword] was found, for example for [CardKeyword::Unsupported] keywords.
///
/// Equivalent to calling [LocalizedCardKeywordIndex::get].
pub fn localized<'hm>(&self, hm: &'hm LocalizedCardKeywordIndex) -> Option<&'hm LocalizedCardKeyword> {
hm.get(&self)
}
}

53
src/data/setbundle/mod.rs Normal file
View file

@ -0,0 +1,53 @@
//! This module defines the types used in Data Dragon [Set Bundles](https://developer.riotgames.com/docs/lor#data-dragon_set-bundles).
use std::fs::File;
use std::path::Path;
use super::anybundle::metadata::BundleMetadata;
use super::outcomes::{LoadingError, LoadingResult};
pub mod card;
pub mod art;
pub mod r#type;
pub mod rarity;
pub mod region;
pub mod set;
pub mod speed;
pub mod keyword;
/// A parsed [Set Bundle](https://developer.riotgames.com/docs/lor#data-dragon_set-bundles).
pub struct SetBundle {
/// The contents of the `metadata.json` file.
pub metadata: BundleMetadata,
/// The contents of the `[locale]/data/globals-[locale].json` file.
pub cards: Vec<card::Card>,
}
impl SetBundle {
/// Load a Set Bundle directory to create a [SetBundle] instance.
pub fn load(bundle_path: &Path) -> LoadingResult<Self> {
let metadata = BundleMetadata::load(
&bundle_path
.join("metadata.json")
)?;
let locale = metadata.locale().ok_or(LoadingError::Using)?;
let mut filename = bundle_path.file_name().ok_or(LoadingError::Checking)?.to_os_string();
filename.push(".json");
let cards = File::open(
&bundle_path
.join(&locale)
.join("data")
.join(filename)
).map_err(LoadingError::Loading)?;
let cards = serde_json::de::from_reader::<File, Vec<card::Card>>(cards)
.map_err(LoadingError::Parsing)?;
Ok(SetBundle {metadata, cards})
}
}

View file

@ -1,9 +1,6 @@
//! Module defining [CardRarity].
use std::collections::HashMap;
use crate::schema::corebundle::CoreRarity;
use crate::data::corebundle::rarity::{LocalizedCardRarity, LocalizedCardRarityIndex};
/// A possible [super::Card] rarity.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
@ -24,12 +21,13 @@ pub enum CardRarity {
Champion,
}
impl CardRarity {
/// Get localized text about the rarity from [crate::schema::corebundle] data.
/// Get the [LocalizedCardRarity] associated with this [CardRarity].
///
/// Returns `None` if no matching [CoreRarity] was found, for example if the hashmap is incomplete.
pub fn localized<'hm>(&self, hm: &'hm HashMap<CardRarity, CoreRarity>) -> Option<&'hm CoreRarity> {
/// Returns [Option::None] if no matching [LocalizedCardRarity] was found, for example rarities missing from the index.
///
/// Equivalent to calling [LocalizedCardRarityIndex::get].
pub fn localized<'hm>(&self, hm: &'hm LocalizedCardRarityIndex) -> Option<&'hm LocalizedCardRarity> {
hm.get(&self)
}
}

View file

@ -1,9 +1,6 @@
//! Module defining [CardRegion].
use std::collections::HashMap;
use crate::schema::corebundle::CoreRegion;
use crate::data::corebundle::region::{LocalizedCardRegion, LocalizedCardRegionIndex};
/// A region to which [super::Card]s can belong to.
///
@ -45,12 +42,13 @@ pub enum CardRegion {
Unsupported,
}
impl CardRegion {
/// Get localized text about the region from [crate::schema::corebundle] data.
/// Get the [LocalizedCardRegion] associated with this [CardRegion].
///
/// Returns `None` if no matching [CoreRegion] was found, for example for [CardRegion::Unsupported] regions.
pub fn localized<'hm>(&self, hm: &'hm HashMap<CardRegion, CoreRegion>) -> Option<&'hm CoreRegion> {
/// Returns [Option::None] if no matching [LocalizedCardRegion] was found, for example for [CardRegion::Unsupported] regions.
///
/// Equivalent to calling [LocalizedCardRegionIndex::get].
pub fn localized<'hm>(&self, hm: &'hm LocalizedCardRegionIndex) -> Option<&'hm LocalizedCardRegion> {
hm.get(&self)
}
}

View file

@ -1,9 +1,6 @@
//! Module defining [CardSet].
use std::collections::HashMap;
use crate::schema::corebundle::CoreSet;
use crate::data::corebundle::set::{LocalizedCardSet, LocalizedCardSetIndex};
/// The release set a [super::Card] may belong to.
///
@ -44,12 +41,13 @@ pub enum CardSet {
Unsupported,
}
impl CardSet {
/// Get localized text about the set from [crate::schema::corebundle] data.
/// Get the [LocalizedCardSet] associated with this [CardSet].
///
/// Returns `None` if no matching [CoreSet] was found, for example for [CardSet::Unsupported] sets.
pub fn localized<'hm>(&self, hm: &'hm HashMap<CardSet, CoreSet>) -> Option<&'hm CoreSet> {
/// Returns [Option::None] if no matching [LocalizedCardSet] was found, for example for [CardSet::Unsupported] sets.
///
/// Equivalent to calling [LocalizedCardSetIndex::get].
pub fn localized<'hm>(&self, hm: &'hm LocalizedCardSetIndex) -> Option<&'hm LocalizedCardSet> {
hm.get(&self)
}
}

View file

@ -1,9 +1,6 @@
//! Module defining [SpellSpeed].
use std::collections::HashMap;
use crate::schema::corebundle::CoreSpellSpeed;
use crate::data::corebundle::speed::{LocalizedSpellSpeed, LocalizedSpellSpeedIndex};
/// A possible spell speed.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
@ -19,12 +16,13 @@ pub enum SpellSpeed {
Burst,
}
impl SpellSpeed {
/// Get localized text about the speed from [crate::schema::corebundle] data.
/// Get the [LocalizedSpellSpeed] associated with this [SpellSpeed].
///
/// Returns `None` if no matching [CoreSpellSpeed] was found, for example if the hashmap is incomplete.
pub fn localized<'hm>(&self, hm: &'hm HashMap<SpellSpeed, CoreSpellSpeed>) -> Option<&'hm CoreSpellSpeed> {
/// Returns [Option::None] if no matching [LocalizedSpellSpeed] was found, for example spell speeds missing from the index.
///
/// Equivalent to calling [LocalizedSpellSpeedIndex::get].
pub fn localized<'hm>(&self, hm: &'hm LocalizedSpellSpeedIndex) -> Option<&'hm LocalizedSpellSpeed> {
hm.get(&self)
}
}

View file

@ -1,5 +1,4 @@
pub mod schema;
pub mod load;
pub mod data;
#[cfg(feature = "search")]
pub mod search;

View file

@ -1,100 +0,0 @@
//! This module provides ways to load official data files from Riot Games' [Core Bundles](https://developer.riotgames.com/docs/lor#data-dragon_core-bundles) into Rust structs.
use std::collections::HashMap;
use std::io::Read;
use crate::schema::corebundle::*;
use crate::schema::setbundle::*;
/// Deserialize a `globals.json` file into a [CoreGlobals] struct.
pub fn globalsjson_to_coreglobals<R>(r: R) -> serde_json::Result<CoreGlobals>
where R: Read
{
serde_json::de::from_reader::<R, CoreGlobals>(r)
}
/// Convert a [Vec] of [CoreVocabTerm]s into a [HashMap] of [CoreVocabTerm]s, indexed by their [CoreVocabTerm::vocabterm].
pub fn vocabtermvec_to_vocabtermhashmap(v: Vec<CoreVocabTerm>) -> HashMap<String, CoreVocabTerm> {
let mut hm = HashMap::<String, CoreVocabTerm>::new();
for vocabterm in v {
hm.insert(vocabterm.vocabterm.clone(), vocabterm);
}
hm
}
/// Convert a [Vec] of [CoreKeyword]s into a [HashMap] of [CoreKeyword]s, indexed by their [CoreKeyword::keyword].
pub fn keywordvec_to_keywordhashmap(v: Vec<CoreKeyword>) -> HashMap<CardKeyword, CoreKeyword> {
let mut hm = HashMap::<CardKeyword, CoreKeyword>::new();
for keyword in v {
hm.insert(keyword.keyword, keyword);
}
hm
}
/// Convert a [Vec] of [CoreRegion]s into a [HashMap] of [CoreRegion]s, indexed by their [CoreRegion::region].
pub fn regionvec_to_regionhashmap(v: Vec<CoreRegion>) -> HashMap<CardRegion, CoreRegion> {
let mut hm = HashMap::<CardRegion, CoreRegion>::new();
for region in v {
hm.insert(region.region, region);
}
hm
}
/// Convert a [Vec] of [CoreSpellSpeed]s into a [HashMap] of [CoreSpellSpeed]s, indexed by their [CoreSpellSpeed::spell_speed].
pub fn spellspeedvec_to_spellspeedhashmap(v: Vec<CoreSpellSpeed>) -> HashMap<SpellSpeed, CoreSpellSpeed> {
let mut hm = HashMap::<SpellSpeed, CoreSpellSpeed>::new();
for spell_speed in v {
hm.insert(spell_speed.spell_speed, spell_speed);
}
hm
}
/// Convert a [Vec] of [CoreRarity]s into a [HashMap] of [CoreRarity]s, indexed by their [CoreRarity::spell_speed].
pub fn rarityvec_to_rarityhashmap(v: Vec<CoreRarity>) -> HashMap<CardRarity, CoreRarity> {
let mut hm = HashMap::<CardRarity, CoreRarity>::new();
for rarity in v {
hm.insert(rarity.rarity, rarity);
}
hm
}
/// Convert a [Vec] of [CoreSet]s into a [HashMap] of [CoreSet]s, indexed by their [CoreSet::set].
pub fn setvec_to_sethashmap(v: Vec<CoreSet>) -> HashMap<CardSet, CoreSet> {
let mut hm = HashMap::<CardSet, CoreSet>::new();
for set in v {
hm.insert(set.set, set);
}
hm
}
/// A [CoreGlobals] struct where items are [HashMap]s mapping identifiers to the data they belong to.
pub struct MappedGlobals {
pub vocab_terms: HashMap<String, CoreVocabTerm>,
pub keywords: HashMap<CardKeyword, CoreKeyword>,
pub regions: HashMap<CardRegion, CoreRegion>,
pub spell_speeds: HashMap<SpellSpeed, CoreSpellSpeed>,
pub rarities: HashMap<CardRarity, CoreRarity>,
pub sets: HashMap<CardSet, CoreSet>,
}
/// Trait allowing easy conversion from [CoreGlobals] to [MappedGlobals].
impl From<CoreGlobals> for MappedGlobals {
fn from(cg: CoreGlobals) -> Self {
MappedGlobals {
vocab_terms: vocabtermvec_to_vocabtermhashmap(cg.vocab_terms),
keywords: keywordvec_to_keywordhashmap(cg.keywords),
regions: regionvec_to_regionhashmap(cg.regions),
spell_speeds: spellspeedvec_to_spellspeedhashmap(cg.spell_speeds),
rarities: rarityvec_to_rarityhashmap(cg.rarities),
sets: setvec_to_sethashmap(cg.sets),
}
}
}

View file

@ -1,4 +0,0 @@
//! This module provides ways to load official data files from Riot Games' [Data Dragon](https://developer.riotgames.com/docs/lor#data-dragon) into Rust structs.
pub mod corebundle;
pub mod setbundle;

View file

@ -1,239 +0,0 @@
//! This module provides ways to load official data files from Riot Games' [Set Bundles](https://developer.riotgames.com/docs/lor#data-dragon_set-bundles) into Rust structs.
use std::collections::HashMap;
use std::io::Read;
use crate::schema::setbundle::*;
/// Deserialize a `set.json` file into a [Vec] of [Card]s.
pub fn setjson_to_cardvec<R>(r: R) -> serde_json::Result<Vec<Card>>
where R: Read
{
serde_json::de::from_reader::<R, Vec<Card>>(r)
}
/// Convert a [Vec] of [Card]s (probably from [setjson_to_vec]) into a [HashMap] of [Card]s, indexed by their [Card::code].
pub fn cardvec_to_cardhashmap(v: Vec<Card>) -> HashMap<String, Card> {
let mut hm = HashMap::<String, Card>::new();
for card in v {
hm.insert(card.code.clone(), card);
}
hm
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use std::collections::HashMap;
use crate::schema::setbundle::*;
use super::cardvec_to_cardhashmap;
use super::setjson_to_cardvec;
const TEST_SETJSON: &str = r#"
[
{
"associatedCards": [],
"associatedCardRefs": [],
"assets": [
{
"gameAbsolutePath": "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012.png",
"fullAbsolutePath": "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012-full.png"
}
],
"regions": [
"Ionia"
],
"regionRefs": [
"Ionia"
],
"attack": 0,
"cost": 2,
"health": 0,
"description": "Give an ally +2|+0 or +0|+3 this round.",
"descriptionRaw": "Give an ally +2|+0 or +0|+3 this round.",
"levelupDescription": "",
"levelupDescriptionRaw": "",
"flavorText": "\"Never fear change. It will question you, test your limits. It is our greatest teacher.\" - Karma",
"artistName": "SIXMOREVODKA",
"name": "Twin Disciplines",
"cardCode": "01IO012",
"keywords": [
"Burst"
],
"keywordRefs": [
"Burst"
],
"spellSpeed": "Burst",
"spellSpeedRef": "Burst",
"rarity": "COMMON",
"rarityRef": "Common",
"subtypes": [],
"supertype": "",
"type": "Spell",
"collectible": true,
"set": "Set1"
},
{
"associatedCards": [],
"associatedCardRefs": [],
"assets": [
{
"gameAbsolutePath": "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012T2.png",
"fullAbsolutePath": "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012T2-full.png"
}
],
"regions": [
"Ionia"
],
"regionRefs": [
"Ionia"
],
"attack": 0,
"cost": 2,
"health": 0,
"description": "Give an ally +0|+3 this round.",
"descriptionRaw": "Give an ally +0|+3 this round.",
"levelupDescription": "",
"levelupDescriptionRaw": "",
"flavorText": "",
"artistName": "SIXMOREVODKA",
"name": "Discipline of Fortitude",
"cardCode": "01IO012T2",
"keywords": [
"Burst"
],
"keywordRefs": [
"Burst"
],
"spellSpeed": "Burst",
"spellSpeedRef": "Burst",
"rarity": "None",
"rarityRef": "None",
"subtypes": [],
"supertype": "",
"type": "Spell",
"collectible": false,
"set": "Set1"
}
]
"#;
fn expected_card_1() -> Card {
Card {
code: "01IO012".to_string(),
name: "Twin Disciplines".to_string(),
r#type: CardType::Spell,
set: CardSet::Foundations,
rarity: CardRarity::Common,
collectible: true,
regions: vec![
CardRegion::Ionia,
],
localized_regions: vec![
"Ionia".to_string(),
],
art: vec![
CardArt {
card_png: "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012.png".to_string(),
full_png: "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012-full.png".to_string(),
}
],
attack: 0,
cost: 2,
health: 0,
spell_speed: SpellSpeed::Burst,
localized_spell_speed: "Burst".to_string(),
keywords: vec![
CardKeyword::Burst,
],
localized_keywords: vec![
"Burst".to_string(),
],
localized_description_xml: "Give an ally +2|+0 or +0|+3 this round.".to_string(),
localized_description_text: "Give an ally +2|+0 or +0|+3 this round.".to_string(),
localized_levelup_xml: "".to_string(),
localized_levelup_text: "".to_string(),
associated_card_codes: vec![],
associated_card_names_localized: vec![],
localized_flavor_text: r#""Never fear change. It will question you, test your limits. It is our greatest teacher." - Karma"#.to_string(),
artist_name: "SIXMOREVODKA".to_string(),
subtypes: vec![],
supertype: "".to_string(),
}
}
fn expected_card_2() -> Card {
Card {
code: "01IO012T2".to_string(),
name: "Discipline of Fortitude".to_string(),
r#type: CardType::Spell,
set: CardSet::Foundations,
rarity: CardRarity::None,
collectible: false,
regions: vec![
CardRegion::Ionia,
],
localized_regions: vec![
"Ionia".to_string(),
],
art: vec![
CardArt {
card_png: "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012T2.png".to_string(),
full_png: "http://dd.b.pvp.net/3_11_0/set1/en_us/img/cards/01IO012T2-full.png".to_string(),
}
],
attack: 0,
cost: 2,
health: 0,
spell_speed: SpellSpeed::Burst,
localized_spell_speed: "Burst".to_string(),
keywords: vec![
CardKeyword::Burst,
],
localized_keywords: vec![
"Burst".to_string(),
],
localized_description_xml: "Give an ally +0|+3 this round.".to_string(),
localized_description_text: "Give an ally +0|+3 this round.".to_string(),
localized_levelup_xml: "".to_string(),
localized_levelup_text: "".to_string(),
associated_card_codes: vec![],
associated_card_names_localized: vec![],
localized_flavor_text: "".to_string(),
artist_name: "SIXMOREVODKA".to_string(),
subtypes: vec![],
supertype: "".to_string(),
}
}
fn expected_vec() -> Vec<Card> {
vec![expected_card_1(), expected_card_2()]
}
fn expected_hashmap() -> HashMap<String, Card> {
let mut hm = HashMap::<String, Card>::new();
hm.insert("01IO012".to_string(), expected_card_1());
hm.insert("01IO012T2".to_string(), expected_card_2());
hm
}
#[test]
fn test_setjson_to_cardvec() {
assert_eq!(
setjson_to_cardvec(TEST_SETJSON.as_bytes()).unwrap(),
expected_vec()
)
}
#[test]
fn test_cardvec_to_cardhashmap() {
assert_eq!(
cardvec_to_cardhashmap(expected_vec()),
expected_hashmap()
)
}
}

View file

@ -1,134 +0,0 @@
use crate::schema::corebundle::CoreSet;
use super::keyword::CoreKeyword;
use super::rarity::CoreRarity;
use super::region::CoreRegion;
use super::speed::CoreSpellSpeed;
use super::vocabterm::CoreVocabTerm;
/// A complete `globals.json` file.
///
/// It contains a list of all vocabulary terms, [CardKeyword]s, [CardRegion]s, [SpellSpeed]s, and [CardRarity]s present in the game.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CoreGlobals {
/// A [Vec] of all [CoreVocabTerm]s in the game.
#[serde(rename = "vocabTerms")]
pub vocab_terms: Vec<CoreVocabTerm>,
/// A [Vec] of all [CoreKeyword]s in the game.
pub keywords: Vec<CoreKeyword>,
/// A [Vec] of all [CoreRegion]s in the game.
pub regions: Vec<CoreRegion>,
/// A [Vec] of all [CoreSpellSpeed]s in the game.
#[serde(rename = "spellSpeeds")]
pub spell_speeds: Vec<CoreSpellSpeed>,
/// A [Vec] of all [CoreRarity]s in the game.
pub rarities: Vec<CoreRarity>,
/// A [Vec] of all [CardSet]s in the game.
pub sets: Vec<CoreSet>,
}
#[cfg(test)]
mod tests {
use crate::schema::corebundle::*;
use crate::schema::setbundle::*;
#[test]
fn deserialize() {
assert_eq!(
serde_json::de::from_str::<'static, CoreGlobals>(r#"
{
"vocabTerms": [
{
"description": "When you summon this, it gets its allegiance bonus if the top card of your deck matches its region.",
"name": "Allegiance",
"nameRef": "Allegiance"
}
],
"keywords": [
{
"description": "Inflicts damage beyond what would kill the target(s) to the enemy Nexus.",
"name": "Overwhelm",
"nameRef": "SpellOverwhelm"
}
],
"regions": [
{
"abbreviation": "NX",
"iconAbsolutePath": "http://dd.b.pvp.net/3_11_0/core/en_us/img/regions/icon-noxus.png",
"name": "Noxus",
"nameRef": "Noxus"
}
],
"spellSpeeds": [
{
"name": "Slow",
"nameRef": "Slow"
}
],
"rarities": [
{
"name": "COMMON",
"nameRef": "Common"
}
],
"sets": [
{
"iconAbsolutePath": "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png",
"name": "Call of the Mountain",
"nameRef": "Set3"
}
]
}
"#).unwrap(),
CoreGlobals {
vocab_terms: vec![
CoreVocabTerm {
vocabterm: "Allegiance".to_string(),
name: "Allegiance".to_string(),
description: "When you summon this, it gets its allegiance bonus if the top card of your deck matches its region.".to_string(),
}
],
keywords: vec![
CoreKeyword {
keyword: CardKeyword::SpellOverwhelm,
name: "Overwhelm".to_string(),
description: "Inflicts damage beyond what would kill the target(s) to the enemy Nexus.".to_string(),
}
],
regions: vec![
CoreRegion {
region: CardRegion::Noxus,
name: "Noxus".to_string(),
abbreviation: "NX".to_string(),
icon_png: "http://dd.b.pvp.net/3_11_0/core/en_us/img/regions/icon-noxus.png".to_string(),
}
],
spell_speeds: vec![
CoreSpellSpeed {
spell_speed: SpellSpeed::Slow,
name: "Slow".to_string(),
}
],
rarities: vec![
CoreRarity {
rarity: CardRarity::Common,
name: "COMMON".to_string(),
}
],
sets: vec![
CoreSet {
set: CardSet::CallOfTheMountain,
name: "Call of the Mountain".to_string(),
icon_png: "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png".to_string(),
}
]
}
)
}
}

View file

@ -1,18 +0,0 @@
//! This module defines the types used in Data Dragon's [Core Bundle](https://developer.riotgames.com/docs/lor#data-dragon_core-bundles) `globals.json` files.
pub use globals::CoreGlobals;
pub use keyword::CoreKeyword;
pub use rarity::CoreRarity;
pub use region::CoreRegion;
pub use set::CoreSet;
pub use speed::CoreSpellSpeed;
pub use vocabterm::CoreVocabTerm;
mod globals;
mod vocabterm;
mod keyword;
mod region;
mod speed;
mod rarity;
mod set;

View file

@ -1,20 +0,0 @@
//! This module defines the types used in Data Dragon's [Set Bundle](https://developer.riotgames.com/docs/lor#data-dragon_set-bundles) `set.json` files.
pub use art::CardArt;
pub use card::Card;
pub use keyword::CardKeyword;
pub use r#type::CardType;
pub use rarity::CardRarity;
pub use region::CardRegion;
pub use set::CardSet;
pub use speed::SpellSpeed;
mod card;
mod art;
mod r#type;
mod rarity;
mod region;
mod set;
mod speed;
mod keyword;

View file

@ -6,8 +6,9 @@ use tantivy::query::{QueryParser, QueryParserError};
use tantivy::schema::{Schema, TextOptions};
use tantivy::tokenizer::TextAnalyzer;
use itertools::Itertools;
use crate::load::corebundle::MappedGlobals;
use crate::schema::setbundle::{Card, CardType};
use crate::data::corebundle::CoreBundle;
use crate::data::setbundle::r#type::CardType;
use crate::data::setbundle::card::Card;
/// Create a new [tantivy::tokenizer::TextAnalyzer] for card text.
@ -92,7 +93,7 @@ pub fn card_schema() -> Schema {
/// Create a new [tantivy::Document] using a [Card] in a specific [locale](MappedGlobals] as base.
pub fn card_to_document(schema: &Schema, locale: &MappedGlobals, card: Card) -> Document {
pub fn card_to_document(schema: &Schema, cb: &CoreBundle, card: Card) -> Document {
use tantivy::*;
let f_code = schema.get_field("code").expect("schema to have a 'code' field");
@ -129,17 +130,17 @@ pub fn card_to_document(schema: &Schema, locale: &MappedGlobals, card: Card) ->
f_name => card.name,
f_type => c_type,
f_set => card.set
.localized(&locale.sets)
.localized(&cb.globals.sets)
.map(|cs| cs.name.to_owned())
.unwrap_or_else(String::new),
f_rarity => card.rarity
.localized(&locale.rarities)
.localized(&cb.globals.rarities)
.map(|cr| cr.name.to_owned())
.unwrap_or_else(String::new),
f_collectible => if card.collectible {1u64} else {0u64},
f_regions => card.regions.iter()
.map(|region| region
.localized(&locale.regions)
.localized(&cb.globals.regions)
.map(|cr| cr.name.to_owned())
.unwrap_or_else(String::new)
).join(" "),
@ -147,12 +148,12 @@ pub fn card_to_document(schema: &Schema, locale: &MappedGlobals, card: Card) ->
f_cost => card.cost,
f_health => card.health,
f_spellspeed => card.spell_speed
.localized(&locale.spell_speeds)
.localized(&cb.globals.spell_speeds)
.map(|ss| ss.name.to_owned())
.unwrap_or_else(String::new),
f_keywords => card.keywords.iter()
.map(|keyword| keyword
.localized(&locale.keywords)
.localized(&cb.globals.keywords)
.map(|ck| ck.name.to_owned())
.unwrap_or_else(String::new))
.join(" "),

View file

@ -1,7 +0,0 @@
use log::*;
#[tokio::main]
async fn main() {
pretty_env_logger::init();
}

View file

@ -7,13 +7,10 @@
use std::collections::HashMap;
use itertools::Itertools;
use teloxide::utils::html::escape;
use crate::load::corebundle::MappedGlobals;
use crate::schema::corebundle::{CoreRegion, CoreSet};
use crate::schema::setbundle::{Card, CardRegion, CardSet, CardType};
/// Render a [Card] to a [String] formatted with [Telegram Bot HTML](https://core.telegram.org/bots/api#html-style).
pub fn display_card(card: &Card, mg: &MappedGlobals) -> String {
pub fn display_card(card: &, mg: &MappedGlobals) -> String {
let title = format!(r#"<a href="{}"><b><i>{}</b></i></a>"#, &card.main_art().card_png, escape(&card.name));
let stats = match &card.r#type {

View file

@ -1,2 +1 @@
pub(crate) mod display;
mod bin;