From 134c9eb670095210672ec125c2df755fe7ec341e Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Tue, 28 Apr 2020 12:11:29 +0200 Subject: add Profession and EliteSpec enum In the high-level "Player" struct, dealing with the low-level numbers seems a bit off, especially because it means that applications have to keep a table of id-to-profession mappings anyway. We're already including a Boss enum for the same reasons, so we might as well include Profession and EliteSpec data - which is also not changing as frequently as Boss. --- src/gamedata.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 26 +++++++++++++++++----- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/gamedata.rs b/src/gamedata.rs index b7ffc11..b32b385 100644 --- a/src/gamedata.rs +++ b/src/gamedata.rs @@ -126,6 +126,74 @@ impl FromStr for Boss { /// into account. pub const XERA_PHASE2_ID: u16 = 0x3F9E; +/// An in-game profession. +/// +/// This only contains the 9 base professions. For elite specializations, see +/// [`EliteSpec`][EliteSpec]. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, FromPrimitive)] +pub enum Profession { + Guardian = 1, + Warrior = 2, + Engineer = 3, + Ranger = 4, + Thief = 5, + Elementalist = 6, + Mesmer = 7, + Necromancer = 8, + Revenant = 9, +} + +/// All possible elite specializations. +/// +/// Note that the numeric value of the enum variants correspond to the specialization ID in the API +/// as well. See [the official wiki](https://wiki.guildwars2.com/wiki/API:2/specializations) for +/// more information regarding the API usage. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, FromPrimitive)] +pub enum EliteSpec { + // Heart of Thorns elites: + Dragonhunter = 27, + Berserker = 18, + Scrapper = 43, + Druid = 5, + Daredevil = 7, + Tempest = 48, + Chronomancer = 40, + Reaper = 34, + Herald = 52, + + // Path of Fire elites: + Firebrand = 62, + Spellbreaker = 61, + Holosmith = 57, + Soulbeast = 55, + Deadeye = 58, + Weaver = 56, + Mirage = 59, + Scourge = 60, + Renegade = 63, +} + +impl EliteSpec { + /// Return the profession that this elite specialization belongs to. + /// + /// This value is hardcoded (and not expected to change), and does not require a network + /// connection or API access. + pub fn profession(self) -> Profession { + use EliteSpec::*; + match self { + Dragonhunter | Firebrand => Profession::Guardian, + Berserker | Spellbreaker => Profession::Warrior, + Scrapper | Holosmith => Profession::Engineer, + Druid | Soulbeast => Profession::Ranger, + Daredevil | Deadeye => Profession::Thief, + Tempest | Weaver => Profession::Elementalist, + Chronomancer | Mirage => Profession::Mesmer, + Reaper | Scourge => Profession::Necromancer, + Herald | Renegade => Profession::Revenant, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/lib.rs b/src/lib.rs index ee9146a..b884b05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ use std::marker::PhantomData; use getset::{CopyGetters, Getters}; +use num_traits::FromPrimitive; use thiserror::Error; pub mod raw; @@ -28,12 +29,16 @@ mod event; pub use event::{Event, EventKind}; pub mod gamedata; -pub use gamedata::Boss; +pub use gamedata::{Boss, EliteSpec, Profession}; #[derive(Error, Debug)] pub enum EvtcError { #[error("invalid data has been provided")] InvalidData, + #[error("invalid profession id: {0}")] + InvalidProfession(u32), + #[error("invalid elite specialization id: {0}")] + InvalidEliteSpec(u32), #[error("utf8 decoding error: {0}")] Utf8Error(#[from] std::string::FromUtf8Error), } @@ -43,11 +48,11 @@ pub enum EvtcError { pub struct Player { /// The player's profession. #[get_copy = "pub"] - profession: u32, + profession: Profession, - /// The player's elite specialization. + /// The player's elite specialization, if any is equipped. #[get_copy = "pub"] - elite: u32, + elite: Option, character_name: String, @@ -298,9 +303,18 @@ impl Agent { .take_while(|c| *c != 0) .collect::>(); let third = raw_agent.name[first.len() + second.len() + 2] - b'0'; + let elite = if raw_agent.is_elite == 0 { + None + } else { + Some( + EliteSpec::from_u32(raw_agent.is_elite) + .ok_or(EvtcError::InvalidEliteSpec(raw_agent.is_elite))?, + ) + }; AgentKind::Player(Player { - profession: raw_agent.prof, - elite: raw_agent.is_elite, + profession: Profession::from_u32(raw_agent.prof) + .ok_or(EvtcError::InvalidProfession(raw_agent.prof))?, + elite, character_name: String::from_utf8(first)?, account_name: String::from_utf8(second)?, subgroup: third, -- cgit v1.2.3