aboutsummaryrefslogtreecommitdiff
path: root/src/bt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bt.rs')
-rw-r--r--src/bt.rs111
1 files changed, 30 insertions, 81 deletions
diff --git a/src/bt.rs b/src/bt.rs
index cf95f3c..8cda030 100644
--- a/src/bt.rs
+++ b/src/bt.rs
@@ -1,4 +1,4 @@
-use super::api::{Api, ApiError, Skill, Specialization};
+use super::api::{Api, ApiError, Profession, Skill, Specialization};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::{convert::TryFrom, error::Error, fmt, str::FromStr};
@@ -11,7 +11,6 @@ pub enum ChatlinkError {
error_froms! { ChatlinkError,
err: ApiError => ChatlinkError::ApiError(err),
_err: base64::DecodeError => ChatlinkError::MalformedInput,
- _err: num_enum::TryFromPrimitiveError<Profession> => ChatlinkError::MalformedInput,
_err: num_enum::TryFromPrimitiveError<TraitChoice> => ChatlinkError::MalformedInput,
_err: num_enum::TryFromPrimitiveError<Legend> => ChatlinkError::MalformedInput,
}
@@ -34,48 +33,6 @@ impl Error for ChatlinkError {
}
}
-/// The profession of the template.
-///
-/// Can be cast to an `u8` to get the right ID for building chat links.
-#[repr(u8)]
-#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
-pub enum Profession {
- Guardian = 1,
- Warrior = 2,
- Engineer = 3,
- Ranger = 4,
- Thief = 5,
- Elementalist = 6,
- Mesmer = 7,
- Necromancer = 8,
- Revenant = 9,
-}
-
-impl fmt::Display for Profession {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self, f)
- }
-}
-
-impl FromStr for Profession {
- type Err = ();
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "Guardian" => Ok(Profession::Guardian),
- "Warrior" => Ok(Profession::Warrior),
- "Engineer" => Ok(Profession::Engineer),
- "Ranger" => Ok(Profession::Ranger),
- "Thief" => Ok(Profession::Thief),
- "Elementalist" => Ok(Profession::Elementalist),
- "Mesmer" => Ok(Profession::Mesmer),
- "Necromancer" => Ok(Profession::Necromancer),
- "Revenant" => Ok(Profession::Revenant),
- _ => Err(()),
- }
- }
-}
-
/// Represents the selected trait.
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
@@ -176,6 +133,12 @@ pub const SKILL_COUNT: usize = 5;
pub const TRAITLINE_COUNT: usize = 3;
pub const LEGEND_COUNT: usize = 4;
+/// The code for the revenant profession.
+pub const CODE_REVENANT: u32 = 9;
+
+pub const EMPTY_SKILLS: [Option<Skill>; SKILL_COUNT] = [None, None, None, None, None];
+pub const EMPTY_TRAITLINES: [Option<Traitline>; TRAITLINE_COUNT] = [None,None, None];
+
/// Represents a build template.
///
/// This struct is made with the same limitations as the game imposes. That is, even though the
@@ -201,8 +164,8 @@ impl BuildTemplate {
pub fn empty(profession: Profession) -> BuildTemplate {
BuildTemplate {
profession,
- skills: [None, None, None, None, None],
- traitlines: [None, None, None],
+ skills: EMPTY_SKILLS,
+ traitlines: EMPTY_TRAITLINES,
extra_data: ExtraData::None,
}
}
@@ -239,8 +202,8 @@ impl BuildTemplate {
}
/// Returns the profession of this build.
- pub fn profession(&self) -> Profession {
- self.profession
+ pub fn profession(&self) -> &Profession {
+ &self.profession
}
/// Returns the skills of this build.
@@ -273,7 +236,7 @@ impl BuildTemplate {
/// The returned link is ready to be copy-and-pasted into Guild Wars 2.
pub fn chatlink(&self) -> String {
let mut bytes = vec![0x0Du8];
- let prof_byte = self.profession() as u8;
+ let prof_byte = self.profession().code as u8;
bytes.push(prof_byte);
for traitline in self.traitlines().iter() {
@@ -295,7 +258,10 @@ impl BuildTemplate {
bytes.push(0);
}
Some(s) => {
- let palette_id = skill_id_to_palette_id(s.id);
+ let palette_id = self
+ .profession()
+ .skill_id_to_palette_id(s.id)
+ .unwrap_or(0);
bytes.push((palette_id & 0xFF) as u8);
bytes.push(((palette_id >> 8) & 0xFF) as u8);
}
@@ -338,9 +304,9 @@ impl BuildTemplate {
}
bytes.remove(0);
- let profession = Profession::try_from(bytes.remove(0))?;
+ let profession = code_to_profession(api, bytes.remove(0) as u32)?;
- let mut traitlines = BuildTemplate::empty(profession).traitlines;
+ let mut traitlines = EMPTY_TRAITLINES;
for i in traitlines.iter_mut() {
let spec_id = bytes.remove(0);
let trait_choices = bytes.remove(0);
@@ -355,14 +321,16 @@ impl BuildTemplate {
*i = Some((spec, [c_0, c_1, c_2]));
}
- let mut skills = BuildTemplate::empty(profession).skills;
+ let mut skills = EMPTY_SKILLS;
for i in skills.iter_mut() {
// Terrestrial
let byte_1 = bytes.remove(0);
let byte_2 = bytes.remove(0);
let palette_id = byte_1 as u32 | (byte_2 as u32) << 8;
if palette_id != 0 {
- let skill_id = palette_id_to_skill_id(palette_id);
+ let skill_id = profession
+ .palette_id_to_skill_id(palette_id)
+ .ok_or(ChatlinkError::MalformedInput)?;
let skill = api.get_skills(&[skill_id])?.remove(0);
*i = Some(skill);
}
@@ -372,8 +340,8 @@ impl BuildTemplate {
bytes.remove(0);
}
- let extra_data = match profession {
- Profession::Revenant => {
+ let extra_data = match profession.code {
+ CODE_REVENANT => {
let mut legends = [Legend::None; LEGEND_COUNT];
for i in legends.iter_mut() {
*i = Legend::try_from(bytes.remove(0))?;
@@ -392,29 +360,10 @@ impl BuildTemplate {
}
}
-lazy_static! {
- static ref PALETTE_MAPPING: Vec<(u32, u32)> =
- serde_json::from_str(include_str!("skill_palette.json")).unwrap();
-}
-
-// Those functions do linear searches, but the list only has about 400 items, which should be okay.
-// If performance becomes an issue, we can always create hash tables or do a binary search,
-// however, since we need both directions, we would need double the memory to keep the second map.
-
-fn skill_id_to_palette_id(input: u32) -> u32 {
- for (skill, palette) in PALETTE_MAPPING.iter() {
- if *skill == input {
- return *palette;
- }
- }
- 0
-}
-
-fn palette_id_to_skill_id(input: u32) -> u32 {
- for (skill, palette) in PALETTE_MAPPING.iter() {
- if *palette == input {
- return *skill;
- }
- }
- 0
+fn code_to_profession(api: &mut Api, code: u32) -> Result<Profession, ChatlinkError> {
+ let professions = api.get_all_professions()?;
+ professions
+ .into_iter()
+ .find(|p| p.code == code)
+ .ok_or(ChatlinkError::MalformedInput)
}