#![macro_use]
use std::fmt;
use std::io::{Read, Write};
use anyhow::{bail, ensure, Context};
use bitvec::prelude::BitVec;
use num::{One, Zero};
use paste::paste;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use vek::Vec3;
use crate::block_pos::BlockPos;
use crate::ident::Ident;
use crate::nbt::Compound;
use crate::protocol::{
BoundedArray, BoundedInt, BoundedString, ByteAngle, Decode, Encode, NbtBridge, RawBytes,
VarInt, VarLong,
};
use crate::text::Text;
pub trait EncodePacket: fmt::Debug {
fn encode_packet(&self, w: &mut impl Write) -> anyhow::Result<()>;
}
pub trait DecodePacket: Sized + fmt::Debug {
fn decode_packet(r: &mut impl Read) -> anyhow::Result<Self>;
}
macro_rules! def_struct {
(
$(#[$struct_attrs:meta])*
$name:ident {
$(
$(#[$field_attrs:meta])*
$field:ident: $typ:ty
),* $(,)?
}
) => {
#[derive(Clone, Debug)]
$(#[$struct_attrs])*
pub struct $name {
$(
$(#[$field_attrs])*
pub $field: $typ,
)*
}
impl Encode for $name {
fn encode(&self, _w: &mut impl Write) -> anyhow::Result<()> {
$(
Encode::encode(&self.$field, _w)
.context(concat!("failed to write field `", stringify!($field), "` from struct `", stringify!($name), "`"))?;
)*
Ok(())
}
}
impl Decode for $name {
fn decode(_r: &mut impl Read) -> anyhow::Result<Self> {
$(
let $field: $typ = Decode::decode(_r)
.context(concat!("failed to read field `", stringify!($field), "` from struct `", stringify!($name), "`"))?;
)*
Ok(Self {
$(
$field,
)*
})
}
}
}
}
macro_rules! def_enum {
(
$(#[$enum_attrs:meta])*
$name:ident: $tag_ty:ty {
$(
$(#[$variant_attrs:meta])*
$variant:ident$(: $typ:ty)? = $lit:literal
),* $(,)?
}
) => {
#[derive(Clone, Debug)]
$(#[$enum_attrs])*
pub enum $name {
$(
$(#[$variant_attrs])*
$variant$(($typ))?,
)*
}
impl Encode for $name {
fn encode(&self, _w: &mut impl Write) -> anyhow::Result<()> {
match self {
$(
if_typ_is_empty_pat!($($typ)?, $name::$variant, $name::$variant(val)) => {
<$tag_ty>::encode(&$lit.into(), _w)
.context(concat!("failed to write enum tag for `", stringify!($name), "`"))?;
if_typ_is_empty_expr!($($typ)?, Ok(()), {
Encode::encode(val, _w)
.context(concat!("failed to write variant `", stringify!($variant), "` from enum `", stringify!($name), "`"))
})
},
)*
#[allow(unreachable_patterns)]
_ => unreachable!("uninhabited enum?")
}
}
}
impl Decode for $name {
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
let tag_ctx = concat!("failed to read enum tag for `", stringify!($name), "`");
let tag = <$tag_ty>::decode(r).context(tag_ctx)?.into();
match tag {
$(
$lit => {
if_typ_is_empty_expr!($($typ)?, Ok($name::$variant), {
$(
let res: $typ = Decode::decode(r)
.context(concat!("failed to read variant `", stringify!($variant), "` from enum `", stringify!($name), "`"))?;
Ok($name::$variant(res))
)?
})
}
)*
_ => bail!(concat!("bad tag value for enum `", stringify!($name), "`"))
}
}
}
}
}
macro_rules! if_typ_is_empty_expr {
(, $t:expr, $f:expr) => {
$t
};
($typ:ty, $t:expr, $f:expr) => {
$f
};
}
macro_rules! if_typ_is_empty_pat {
(, $t:pat, $f:pat) => {
$t
};
($typ:ty, $t:pat, $f:pat) => {
$f
};
}
macro_rules! def_bitfield {
(
$(#[$struct_attrs:meta])*
$name:ident: $inner_ty:ty {
$(
$(#[$bit_attrs:meta])*
$bit:ident = $offset:literal
),* $(,)?
}
) => {
#[derive(Clone, Copy, PartialEq, Eq)]
$(#[$struct_attrs])*
pub struct $name($inner_ty);
impl $name {
pub fn new(
$(
$bit: bool,
)*
) -> Self {
let mut res = Self(Default::default());
paste! {
$(
res = res.[<set_ $bit:snake>]($bit);
)*
}
res
}
paste! {
$(
#[doc = "Gets the " $bit " bit on this bitfield.\n"]
$(#[$bit_attrs])*
pub fn $bit(self) -> bool {
self.0 & <$inner_ty>::one() << <$inner_ty>::from($offset) != <$inner_ty>::zero()
}
#[doc = "Sets the " $bit " bit on this bitfield.\n"]
$(#[$bit_attrs])*
#[must_use]
pub fn [<set_ $bit:snake>](self, $bit: bool) -> Self {
let mask = <$inner_ty>::one() << <$inner_ty>::from($offset);
if $bit {
Self(self.0 | mask)
} else {
Self(self.0 & !mask)
}
}
)*
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct(stringify!($name));
paste! {
$(
s.field(stringify!($bit), &self. $bit());
)*
}
s.finish()
}
}
impl Encode for $name {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
self.0.encode(w)
}
}
impl Decode for $name {
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
<$inner_ty>::decode(r).map(Self)
}
}
}
}
macro_rules! def_packet_group {
(
$(#[$attrs:meta])*
$group_name:ident {
$($packet:ident = $id:literal),* $(,)?
}
) => {
#[derive(Clone)]
$(#[$attrs])*
pub enum $group_name {
$($packet($packet)),*
}
$(
impl From<$packet> for $group_name {
fn from(p: $packet) -> Self {
Self::$packet(p)
}
}
impl EncodePacket for $packet {
fn encode_packet(&self, w: &mut impl Write) -> anyhow::Result<()> {
VarInt($id).encode(w).context("failed to write packet ID")?;
self.encode(w)
}
}
impl DecodePacket for $packet {
fn decode_packet(r: &mut impl Read) -> anyhow::Result<Self> {
let packet_id = VarInt::decode(r).context("failed to read packet ID")?.0;
ensure!(
$id == packet_id,
"bad packet ID (expected {}, got {packet_id}",
$id
);
Self::decode(r)
}
}
)*
impl DecodePacket for $group_name {
fn decode_packet(r: &mut impl Read) -> anyhow::Result<Self> {
let packet_id = VarInt::decode(r)
.context(concat!("failed to read ", stringify!($group_name), " packet ID"))?.0;
match packet_id {
$(
$id => {
let pkt = $packet::decode(r)?;
Ok(Self::$packet(pkt))
}
)*
id => bail!(concat!("unknown ", stringify!($group_name), " packet ID {}"), id),
}
}
}
impl EncodePacket for $group_name {
fn encode_packet(&self, w: &mut impl Write) -> anyhow::Result<()> {
match self {
$(
Self::$packet(pkt) => {
VarInt($id)
.encode(w)
.context(concat!(
"failed to write ",
stringify!($group_name),
" packet ID for ",
stringify!($packet_name)
))?;
pkt.encode(w)
}
)*
}
}
}
impl fmt::Debug for $group_name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut t = f.debug_tuple(stringify!($group_name));
match self {
$(
Self::$packet(pkt) => t.field(pkt),
)*
};
t.finish()
}
}
}
}
pub mod c2s;
pub mod s2c;
def_struct! {
#[derive(PartialEq, Serialize, Deserialize)]
Property {
name: String,
value: String,
#[serde(skip_serializing_if = "Option::is_none")]
signature: Option<String>
}
}
def_struct! {
PublicKeyData {
timestamp: u64,
public_key: Vec<u8>,
signature: Vec<u8>,
}
}
#[cfg(test)]
pub(crate) mod test {
use super::*;
def_struct! {
TestPacket {
first: String,
second: Vec<u16>,
third: u64
}
}
def_packet_group! {
TestPacketGroup {
TestPacket = 12345,
}
}
}