use serde::Serialize;
use std::str::{FromStr, Split};
pub struct MEStringParser<'a> {
split: Split<'a, char>,
}
impl<'a> MEStringParser<'a> {
pub fn new(value: &'a str) -> Option<MEStringParser<'a>> {
if !value.starts_with("20;4;") {
return None;
}
let split = value[5..].split(';');
Some(MEStringParser { split })
}
pub fn next_str(&mut self) -> Option<String> {
let next = self.split.next()?;
Some(next.to_string())
}
pub fn parse_next<F: FromStr>(&mut self) -> Option<F> {
let next = self.split.next()?;
next.parse::<F>().ok()
}
pub fn next_bool(&mut self) -> Option<bool> {
let next = self.split.next()?;
if next == "True" {
Some(true)
} else if next == "False" {
Some(false)
} else {
None
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct PlayerClass {
pub name: String,
pub level: u8,
pub exp: f32,
pub promotions: u32,
}
pub fn parse_player_class(value: String) -> Option<PlayerClass> {
let mut parser = MEStringParser::new(&value)?;
let name = parser.next_str()?;
let level = parser.parse_next()?;
let exp = parser.parse_next()?;
let promotions = parser.parse_next()?;
Some(PlayerClass {
name,
level,
exp,
promotions,
})
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct PlayerCharacter {
pub kit_name: String,
pub name: String,
pub tint1: u16,
pub tint2: u16,
pub pattern: u16,
pub pattern_color: u16,
pub phong: u16,
pub emissive: u16,
pub skin_tone: u16,
pub seconds_played: u32,
pub timestamp_year: u32,
pub timestamp_month: u32,
pub timestamp_day: u32,
pub timestamp_seconds: u32,
pub powers: String,
pub hotkeys: String,
pub weapons: String,
pub weapon_mods: String,
pub deployed: bool,
pub leveled_up: bool,
}
pub fn parse_player_character(value: String) -> Option<PlayerCharacter> {
let mut parser = MEStringParser::new(&value)?;
let kit_name: String = parser.next_str()?;
let name: String = parser.parse_next()?;
let tint1: u16 = parser.parse_next()?;
let tint2: u16 = parser.parse_next()?;
let pattern: u16 = parser.parse_next()?;
let pattern_color: u16 = parser.parse_next()?;
let phong: u16 = parser.parse_next()?;
let emissive: u16 = parser.parse_next()?;
let skin_tone: u16 = parser.parse_next()?;
let seconds_played: u32 = parser.parse_next()?;
let timestamp_year: u32 = parser.parse_next()?;
let timestamp_month: u32 = parser.parse_next()?;
let timestamp_day = parser.parse_next()?;
let timestamp_seconds: u32 = parser.parse_next()?;
let powers: String = parser.next_str()?;
let hotkeys: String = parser.next_str()?;
let weapons: String = parser.next_str()?;
let weapon_mods: String = parser.next_str()?;
let deployed: bool = parser.next_bool()?;
let leveled_up: bool = parser.next_bool()?;
Some(PlayerCharacter {
kit_name,
name,
tint1,
tint2,
pattern,
pattern_color,
phong,
emissive,
skin_tone,
seconds_played,
timestamp_year,
timestamp_month,
timestamp_day,
timestamp_seconds,
powers,
hotkeys,
weapons,
weapon_mods,
deployed,
leveled_up,
})
}
#[cfg(test)]
mod test {
use crate::utils::parsing::MEStringParser;
#[test]
fn test_a() {
let value = "20;4;AABB;123;DWADA";
let mut parser = MEStringParser::new(value).unwrap();
assert_eq!(parser.next_str().unwrap(), "AABB");
assert_eq!(parser.parse_next::<u16>().unwrap(), 123);
assert_eq!(parser.next_str().unwrap(), "DWADA");
}
}