77 lines
2.3 KiB
Rust
77 lines
2.3 KiB
Rust
use crate::{Error, payload::{Decode, Encode}, Payload};
|
|
use std::io::{Read, Seek, SeekFrom};
|
|
use crate::payload::{SeStringChunkKind, SeInteractableKind};
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub struct ItemPayload {
|
|
pub id: u32,
|
|
pub hq: bool,
|
|
pub name: Option<String>,
|
|
}
|
|
|
|
impl ItemPayload {
|
|
const HQ_THRESHOLD: u32 = 1_000_000;
|
|
}
|
|
|
|
impl Decode for ItemPayload {
|
|
fn decode<R: Read + Seek>(mut reader: R, chunk_len: usize) -> Result<Self, Error> {
|
|
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<u8> {
|
|
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<u8> = 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()
|
|
}
|
|
}
|