use crate::{Error, payload::{Decode, Encode}, Payload}; use std::io::{Read, Seek, SeekFrom}; use crate::payload::{SeStringChunkKind, SeInteractableKind}; #[derive(Debug, Clone, PartialEq)] pub struct ItemPayload { pub id: u32, pub hq: bool, pub name: Option, } impl ItemPayload { const HQ_THRESHOLD: u32 = 1_000_000; } impl Decode for ItemPayload { fn decode(mut reader: R, chunk_len: usize) -> Result { let mut id = Self::read_integer(&mut reader)?; let hq = id > Self::HQ_THRESHOLD; if hq { id -= Self::HQ_THRESHOLD; } let name = if reader.stream_position().map_err(Error::from)? + 3 < chunk_len as u64 { reader.seek(SeekFrom::Current(3)).map_err(Error::from)?; // unk let name_len = Self::read_integer(&mut reader)?; let mut name_bytes = vec![0; name_len as usize]; reader.read_exact(&mut name_bytes).map_err(Error::from)?; Some(String::from_utf8(name_bytes).map_err(Error::from)?) } else { None }; Ok(Self { id, hq, name, }) } } impl Encode for ItemPayload { fn encode(&self) -> Vec { use std::iter::once; let actual_id = if self.hq { self.id + Self::HQ_THRESHOLD } else { self.id }; let id = Self::make_integer(actual_id); let name_bytes = self.name.as_ref().map(|x| x.as_bytes()); let mut chunk_len = 4 + id.len(); if let Some(name_bytes) = &name_bytes { chunk_len += 1 + 1 + name_bytes.len(); } let name_chain: Vec = match name_bytes { Some(bs) => once(0xFF) .chain(once((bs.len() + 1) as u8)) .chain(bs.iter().copied()) .collect(), None => Vec::new(), }; once(Payload::START_BYTE) .chain(once(SeStringChunkKind::Interactable.as_u8())) .chain(once(chunk_len as u8)) .chain(once(SeInteractableKind::ItemLink.as_u8())) .chain(id.into_iter()) .chain(once(0x02)) .chain(once(0x01)) .chain(name_chain.into_iter()) .chain(once(Payload::END_BYTE)) .collect() } }