aboutsummaryrefslogtreecommitdiff
path: root/src/bt.rs
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2019-12-20 18:04:24 +0100
committerDaniel Schadt <kingdread@gmx.de>2019-12-20 18:04:24 +0100
commit9f4a4eaa06f3d0136de9088c0e60a0c077248c91 (patch)
tree4ab0e0c9f5910643ac6404c390e6aa6fad4ca470 /src/bt.rs
parent087580b3c269dbc5b2298ff6f4590f010279d339 (diff)
downloadkondou-9f4a4eaa06f3d0136de9088c0e60a0c077248c91.tar.gz
kondou-9f4a4eaa06f3d0136de9088c0e60a0c077248c91.tar.bz2
kondou-9f4a4eaa06f3d0136de9088c0e60a0c077248c91.zip
remove hard coded palette IDs
Now that the API actually returns the proper palette IDs, we can use those values instead of relying on the hard coded values. This also gets rid of the make_table script that was mostly hackish anyway, and the lazy static HashMap.
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)
}