aoaddons 0.2.0

Simple library for creating addons for albion online game in multiple programing languages.
Documentation
mod decode;
mod error;
mod layout;
mod codes;
#[cfg(test)]
mod tests;

pub use decode::*;
use error::*;
pub use layout::*;

use std::collections::HashMap;
use std::io::Cursor;

pub struct Photon {
    fragments: HashMap<u32, Vec<ReliableFragment>>,
}

impl Photon {
    pub fn new() -> Self {
        Self {
            fragments: HashMap::new(),
        }
    }

    pub fn try_decode(
        &mut self,
        payload: &[u8],
    ) -> PhotonDecodeResult<Vec<PhotonDecodeResult<Message>>> {
        let mut cursor = Cursor::new(payload);
        Ok(
            (0..Decode::<PhotonHeader>::decode(&mut cursor)?.command_count)
                .into_iter()
                .map(|_| {
                    Decode::<Command>::decode(&mut cursor).map_or_else(
                        |e| Some(Err(e)),
                        |command| match command {
                            Command::SendReliable(c) | Command::SendUnreliable(c) => Some(
                                match Decode::<Message>::decode(&mut cursor) {
                                    Ok(m) => Ok(m),
                                    Err(e) => {
                                        let msg_header_len = 2;
                                        cursor.set_position(cursor.position() + c.msg_len as u64 - msg_header_len);
                                        Err(e)
                                    }
                                }
                            ),
                            Command::SendReliableFragment(fragment) => {
                                self.fragments
                                    .entry(fragment.sequence_number)
                                    .or_insert(vec![])
                                    .push(fragment.clone());
                                self.decode_reliable_fragment(&fragment).map(|msg| {
                                    self.fragments.remove(&fragment.sequence_number).unwrap();
                                    msg.map_err(|e| e.extend("Fragment".into()))
                                })
                            }
                            _ => None,
                        },
                    )
                })
                .filter_map(|v| v)
                .collect(),
        )
    }

    #[allow(dead_code)]
    pub fn decode(&mut self, payload: &[u8]) -> Vec<Message> {
        if let Ok(messages) = self.try_decode(payload) {
            return messages.into_iter().filter_map(Result::ok).collect();
        }
        vec![]
    }

    fn decode_reliable_fragment(
        &mut self,
        fragment: &ReliableFragment,
    ) -> Option<PhotonDecodeResult<Message>> {
        if let Some(fragments) = self.fragments.get(&fragment.sequence_number) {
            if fragments.len() == fragment.fragment_count as usize {
                let mut buf = Vec::<u8>::new();
                for fragment in fragments {
                    buf.extend(fragment.payload.iter());
                }
                let mut c = Cursor::new(&buf[..]);
                return Some(
                    match Decode::<Message>::decode(&mut c) {
                        Ok(m) => Ok(m),
                        Err(e) => {
                            let msg_header_len = 2;
                            c.set_position(c.position() + fragment.reliable_command.msg_len as u64 - msg_header_len);
                            Err(e)
                        }
                    }
                );
            }
        }
        None
    }
}