aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2020-04-27 16:05:17 +0200
committerDaniel Schadt <kingdread@gmx.de>2020-04-27 16:05:17 +0200
commit0d4677dbd830fec0ccc3ebc33d438783dc9d4912 (patch)
tree38a90f611b09212d112323f287c7ec38f0f1f412 /src
parent7af05afb2cf80af097fd034fef0fcdaeb399eb6d (diff)
downloadevtclib-0d4677dbd830fec0ccc3ebc33d438783dc9d4912.tar.gz
evtclib-0d4677dbd830fec0ccc3ebc33d438783dc9d4912.tar.bz2
evtclib-0d4677dbd830fec0ccc3ebc33d438783dc9d4912.zip
rework Log::players/npcs
Since we know that we're only returning Agents which are Players, we can save downstream users some time and also provide access to the &Player. Ideally, we'd want something like PlayerAgent, or Agent<Player>, but that not only incurrs code duplication (in the first case), it'd also mean cloning the player data (second case), as we couldn't just return a reference into the pool with all agents. For now, this is still the better option, until other ways have been explored. Maybe cloning here wouldn't be too bad, but we'd also run into the issue that we cannot use record unpacking for records that have different generic parameters, so going from Agent<AgentKind> to Agent<Player> would mean manually copying over all record fields. We now no longer need the matches! macro, as we can simply use AgentKind::as_{player,character}.
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs128
1 files changed, 88 insertions, 40 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 637f1b2..51c1394 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,27 +28,6 @@ pub use event::{Event, EventKind};
pub mod gamedata;
pub use gamedata::Boss;
-/// A macro that returns `true` when the given expression matches the pattern.
-///
-/// ```rust
-/// assert!(matches!(Some(4), Some(_)));
-/// assert!(!matches!(Some(2), None));
-/// ```
-macro_rules! matches {
- ($expression:expr, $($pattern:pat)|*) => (
- match $expression {
- $($pattern)|+ => true,
- _ => false,
- }
- );
- ($expression:expr, $pattern:pat if $condi:expr) => (
- match $expression {
- $pattern if $condi => true,
- _ => false,
- }
- );
-}
-
#[derive(Error, Debug)]
pub enum EvtcError {
#[error("invalid data has been provided")]
@@ -57,18 +36,79 @@ pub enum EvtcError {
Utf8Error(#[from] std::string::FromUtf8Error),
}
+/// Player-specific agent data.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Player {
+ profession: u32,
+ elite: u32,
+ character_name: String,
+ account_name: String,
+ subgroup: u8,
+}
+
+/// Gadget-specific agent data.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Gadget {
+ id: u16,
+ name: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Character {
+ id: u16,
+ name: String,
+}
+
/// The type of an agent.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AgentKind {
- Player {
- profession: u32,
- elite: u32,
- character_name: String,
- account_name: String,
- subgroup: u8,
- },
- Gadget(u16, String),
- Character(u16, String),
+ Player(Player),
+ Gadget(Gadget),
+ Character(Character),
+}
+
+impl AgentKind {
+ /// Accesses the inner [`Player`][Player] struct, if available.
+ pub fn as_player(&self) -> Option<&Player> {
+ if let AgentKind::Player(ref player) = *self {
+ Some(player)
+ } else {
+ None
+ }
+ }
+
+ /// Determines whether this `AgentKind` contains a player.
+ pub fn is_player(&self) -> bool {
+ self.as_player().is_some()
+ }
+
+ /// Accesses the inner [`Gadget`][Gadget] struct, if available.
+ pub fn as_gadget(&self) -> Option<&Gadget> {
+ if let AgentKind::Gadget(ref gadget) = *self {
+ Some(gadget)
+ } else {
+ None
+ }
+ }
+
+ /// Determines whether this `AgentKind` contains a gadget.
+ pub fn is_gadget(&self) -> bool {
+ self.as_gadget().is_some()
+ }
+
+ /// Accesses the inner [`Character`][Character] struct, if available.
+ pub fn as_character(&self) -> Option<&Character> {
+ if let AgentKind::Character(ref character) = *self {
+ Some(character)
+ } else {
+ None
+ }
+ }
+
+ /// Determines whether this `AgentKind` contains a player.
+ pub fn is_character(&self) -> bool {
+ self.as_character().is_some()
+ }
}
/// An agent.
@@ -107,9 +147,15 @@ impl Agent {
.take_while(|c| *c != 0)
.collect::<Vec<_>>())?;
if raw_agent.is_character() {
- AgentKind::Character(raw_agent.prof as u16, name)
+ AgentKind::Character(Character {
+ id: raw_agent.prof as u16,
+ name,
+ })
} else {
- AgentKind::Gadget(raw_agent.prof as u16, name)
+ AgentKind::Gadget(Gadget {
+ id: raw_agent.prof as u16,
+ name,
+ })
}
} else if raw_agent.is_player() {
let first = raw_agent
@@ -126,13 +172,13 @@ impl Agent {
.take_while(|c| *c != 0)
.collect::<Vec<_>>();
let third = raw_agent.name[first.len() + second.len() + 2] - b'0';
- AgentKind::Player {
+ AgentKind::Player(Player {
profession: raw_agent.prof,
elite: raw_agent.is_elite,
character_name: String::from_utf8(first)?,
account_name: String::from_utf8(second)?,
subgroup: third,
- }
+ })
} else {
return Err(EvtcError::InvalidData);
};
@@ -186,17 +232,17 @@ impl Log {
}
/// Return an iterator over all agents that represent player characters.
- pub fn players(&self) -> impl Iterator<Item = &Agent> {
+ pub fn players(&self) -> impl Iterator<Item = (&Agent, &Player)> {
self.agents
.iter()
- .filter(|a| matches!(a.kind, AgentKind::Player { .. }))
+ .filter_map(|a| a.kind().as_player().map(|p| (a, p)))
}
/// Return an iterator over all agents that are NPCs.
- pub fn npcs(&self) -> impl Iterator<Item = &Agent> {
+ pub fn npcs(&self) -> impl Iterator<Item = (&Agent, &Character)> {
self.agents
.iter()
- .filter(|a| matches!(a.kind, AgentKind::Character(..)))
+ .filter_map(|a| a.kind().as_character().map(|c| (a, c)))
}
/// Return the boss agent.
@@ -205,7 +251,8 @@ impl Log {
/// and Xera.
pub fn boss(&self) -> &Agent {
self.npcs()
- .find(|n| matches!(n.kind, AgentKind::Character(x, _) if x == self.boss_id))
+ .find(|(_, c)| c.id == self.boss_id)
+ .map(|t| t.0)
.expect("Boss has no agent!")
}
@@ -220,7 +267,8 @@ impl Log {
vec![self.boss_id]
};
self.npcs()
- .filter(|a| matches!(a.kind, AgentKind::Character(x, _) if boss_ids.contains(&x)))
+ .filter(|(_, c)| boss_ids.contains(&c.id))
+ .map(|t| t.0)
.collect()
}