aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs121
-rw-r--r--src/raw/parser.rs53
2 files changed, 109 insertions, 65 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 010944f..a3bf64d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -133,6 +133,68 @@ pub struct Agent {
master_agent: Option<u64>,
}
+impl Agent {
+ /// Parse a raw agent.
+ pub fn from_raw(raw_agent: &raw::Agent) -> Result<Agent, EvtcError> {
+ let kind = if raw_agent.is_character() {
+ AgentKind::Character(raw_agent.prof as u16)
+ } else if raw_agent.is_gadget() {
+ AgentKind::Gadget(raw_agent.prof as u16)
+ } else if raw_agent.is_player() {
+ AgentKind::Player {
+ profession: raw_agent.prof,
+ elite: raw_agent.is_elite,
+ }
+ } else {
+ return Err(EvtcError::InvalidData);
+ };
+
+ let name = if raw_agent.is_player() {
+ let first = raw_agent
+ .name
+ .iter()
+ .cloned()
+ .take_while(|c| *c != 0)
+ .collect::<Vec<_>>();
+ let second = raw_agent
+ .name
+ .iter()
+ .cloned()
+ .skip(first.len() + 1)
+ .take_while(|c| *c != 0)
+ .collect::<Vec<_>>();
+ let third = raw_agent.name[first.len() + second.len() + 2] - b'0';
+ AgentName::Player {
+ character_name: String::from_utf8(first)?,
+ account_name: String::from_utf8(second)?,
+ subgroup: third,
+ }
+ } else {
+ let name = raw_agent
+ .name
+ .iter()
+ .cloned()
+ .take_while(|c| *c != 0)
+ .collect::<Vec<_>>();
+ AgentName::Single(String::from_utf8(name)?)
+ };
+
+ Ok(Agent {
+ addr: raw_agent.addr,
+ kind,
+ toughness: raw_agent.toughness,
+ concentration: raw_agent.concentration,
+ healing: raw_agent.healing,
+ condition: raw_agent.condition,
+ name,
+ instance_id: 0,
+ first_aware: 0,
+ last_aware: u64::max_value(),
+ master_agent: None,
+ })
+ }
+}
+
/// A fully processed log file.
#[derive(Debug, Clone)]
pub struct Log {
@@ -243,64 +305,7 @@ fn setup_agents(data: &raw::Evtc) -> Result<Vec<Agent>, EvtcError> {
let mut agents = Vec::with_capacity(data.agents.len());
for raw_agent in &data.agents {
- let kind = if raw_agent.is_character() {
- AgentKind::Character(raw_agent.prof as u16)
- } else if raw_agent.is_gadget() {
- AgentKind::Gadget(raw_agent.prof as u16)
- } else if raw_agent.is_player() {
- AgentKind::Player {
- profession: raw_agent.prof,
- elite: raw_agent.is_elite,
- }
- } else {
- return Err(EvtcError::InvalidData);
- };
-
- let name = if raw_agent.is_player() {
- let first = raw_agent
- .name
- .iter()
- .cloned()
- .take_while(|c| *c != 0)
- .collect::<Vec<_>>();
- let second = raw_agent
- .name
- .iter()
- .cloned()
- .skip(first.len() + 1)
- .take_while(|c| *c != 0)
- .collect::<Vec<_>>();
- let third = raw_agent.name[first.len() + second.len() + 2] - b'0';
- AgentName::Player {
- character_name: String::from_utf8(first)?,
- account_name: String::from_utf8(second)?,
- subgroup: third,
- }
- } else {
- let name = raw_agent
- .name
- .iter()
- .cloned()
- .take_while(|c| *c != 0)
- .collect::<Vec<_>>();
- AgentName::Single(String::from_utf8(name)?)
- };
-
- let agent = Agent {
- addr: raw_agent.addr,
- kind,
- toughness: raw_agent.toughness,
- concentration: raw_agent.concentration,
- healing: raw_agent.healing,
- condition: raw_agent.condition,
- name,
- instance_id: 0,
- first_aware: 0,
- last_aware: u64::max_value(),
- master_agent: None,
- };
-
- agents.push(agent);
+ agents.push(Agent::from_raw(raw_agent)?);
}
Ok(agents)
}
diff --git a/src/raw/parser.rs b/src/raw/parser.rs
index a3a1cd5..fa3b36c 100644
--- a/src/raw/parser.rs
+++ b/src/raw/parser.rs
@@ -97,6 +97,16 @@ pub struct Evtc {
pub events: Vec<CbtEvent>,
}
+/// A partially-parsed EVTC file, containing everything but the events.
+/// This can speed up parsing for applications which can work with the header.
+#[derive(Clone, Debug)]
+pub struct PartialEvtc {
+ pub header: Header,
+ pub skill_count: u32,
+ pub agents: Vec<Agent>,
+ pub skills: Vec<Skill>,
+}
+
quick_error! {
#[derive(Debug)]
pub enum ParseError {
@@ -391,25 +401,54 @@ pub fn parse_event_rev1<T: Read>(input: &mut T) -> ParseResult<CbtEvent> {
is_offcycle,
})
}
-/// Parse a complete EVTC file.
+
+
+
+/// Parse a partial EVTC file.
///
/// * `input` - Input stream.
-pub fn parse_file<T: Read>(input: &mut T) -> ParseResult<Evtc> {
+pub fn parse_partial_file<T: Read>(input: &mut T) -> ParseResult<PartialEvtc> {
let header = parse_header(input)?;
let agents = parse_agents(input, header.agent_count)?;
let skill_count = input.read_u32::<LittleEndian>()?;
let skills = parse_skills(input, skill_count)?;
- let events = match header.revision {
+
+ Ok(PartialEvtc {
+ header,
+ skill_count,
+ agents,
+ skills,
+ })
+}
+
+
+
+/// Finish a partial EVTC by reading the events.
+///
+/// * `partial` - The partial EVTC.
+/// * `input` - The input stream.
+pub fn finish_parsing<T: Read>(partial: PartialEvtc, input: &mut T) -> ParseResult<Evtc> {
+ let events = match partial.header.revision {
0 => parse_events(input, parse_event_rev0)?,
1 => parse_events(input, parse_event_rev1)?,
x => return Err(ParseError::UnknownRevision(x)),
};
Ok(Evtc {
- header,
- skill_count,
- agents,
- skills,
+ header: partial.header,
+ skill_count: partial.skill_count,
+ agents: partial.agents,
+ skills: partial.skills,
events,
})
}
+
+
+
+/// Parse a complete EVTC file.
+///
+/// * `input` - Input stream.
+pub fn parse_file<T: Read>(input: &mut T) -> ParseResult<Evtc> {
+ let partial = parse_partial_file(input)?;
+ finish_parsing(partial, input)
+}