pub mod legacy {
use bytes::{BufMut, BytesMut};
use crate::codec::{Decode, DecodeResult, Encode, EncodeResult, Reader};
use crate::error::EncodeError;
use crate::nbt::RawNbt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ItemStack {
pub id: i16,
pub count: i8,
pub damage: i16,
pub nbt: Option<RawNbt>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct Slot(pub Option<ItemStack>);
impl Slot {
pub const EMPTY: Slot = Slot(None);
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
#[inline]
pub fn item(&self) -> Option<&ItemStack> {
self.0.as_ref()
}
}
impl Decode for Slot {
#[inline]
fn decode(r: &mut Reader<'_>) -> DecodeResult<Self> {
let id = r.read_i16()?;
if id == -1 {
return Ok(Slot(None));
}
Ok(Slot(Some(ItemStack {
id,
count: r.read_i8()?,
damage: r.read_i16()?,
nbt: RawNbt::read_optional(r)?,
})))
}
}
impl Encode for Slot {
#[inline]
fn encode(&self, w: &mut BytesMut) -> EncodeResult {
match &self.0 {
None => w.put_i16(-1),
Some(it) => {
if it.id == -1 {
return Err(EncodeError::Invalid(
"item id -1 is reserved for empty slots",
));
}
w.put_i16(it.id);
w.put_i8(it.count);
w.put_i16(it.damage);
RawNbt::write_optional(&it.nbt, w);
}
}
Ok(())
}
}
}
pub mod modern {
use bytes::{BufMut, BytesMut};
use crate::codec::{Decode, DecodeResult, Encode, EncodeResult, McWrite, Reader};
use crate::nbt::RawNbt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ItemStack {
pub id: i32,
pub count: i8,
pub nbt: Option<RawNbt>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct Slot(pub Option<ItemStack>);
impl Slot {
pub const EMPTY: Slot = Slot(None);
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
#[inline]
pub fn item(&self) -> Option<&ItemStack> {
self.0.as_ref()
}
}
impl Decode for Slot {
#[inline]
fn decode(r: &mut Reader<'_>) -> DecodeResult<Self> {
if !r.read_bool()? {
return Ok(Slot(None));
}
Ok(Slot(Some(ItemStack {
id: r.read_varint()?,
count: r.read_i8()?,
nbt: RawNbt::read_optional(r)?,
})))
}
}
impl Encode for Slot {
#[inline]
fn encode(&self, w: &mut BytesMut) -> EncodeResult {
match &self.0 {
None => w.put_bool(false),
Some(it) => {
w.put_bool(true);
w.put_varint(it.id);
w.put_i8(it.count);
RawNbt::write_optional(&it.nbt, w);
}
}
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codec::{Encode, decode_exact};
use bytes::{Bytes, BytesMut};
#[test]
fn legacy_known_answers() {
let b = Bytes::from_static(&[0xff, 0xff]);
assert_eq!(decode_exact::<legacy::Slot>(&b), Ok(legacy::Slot::EMPTY));
let b = Bytes::from_static(&[0x00, 0x01, 0x40, 0x00, 0x00, 0x00]);
let s = decode_exact::<legacy::Slot>(&b).unwrap();
let it = s.item().unwrap();
assert_eq!(
(it.id, it.count, it.damage, it.nbt.is_none()),
(1, 64, 0, true)
);
let mut w = BytesMut::new();
s.encode(&mut w).unwrap();
assert_eq!(&w[..], &b[..]);
let b = Bytes::from_static(&[0x01, 0x14, 0x01, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x00]);
let s = decode_exact::<legacy::Slot>(&b).unwrap();
assert_eq!(s.item().unwrap().nbt.as_ref().unwrap().as_bytes().len(), 4);
}
#[test]
fn modern_known_answers() {
let b = Bytes::from_static(&[0x00]);
assert_eq!(decode_exact::<modern::Slot>(&b), Ok(modern::Slot::EMPTY));
let b = Bytes::from_static(&[0x01, 0xac, 0x02, 0x10, 0x00]);
let s = decode_exact::<modern::Slot>(&b).unwrap();
let it = s.item().unwrap();
assert_eq!((it.id, it.count), (300, 16));
}
}