Valence protocol redesign (#177)

- Fix performance issues related to writing individual bytes instead of
using `Write::write_all`.
- Make manual implementations of `Encode` and `Decode` easier:
  - Remove `encoded_len` method from `Encode`
  - Split `Packet` trait into `EncodePacket` and `DecodePacket`.
  - Simplify derive macros.
This commit is contained in:
Ryan Johnson 2022-12-23 06:30:57 -08:00 committed by GitHub
parent 1f5ec6f94f
commit c26bbe7ec2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 683 additions and 994 deletions

View file

@ -6,8 +6,7 @@ description = "A simple Minecraft proxy for inspecting packets."
[dependencies] [dependencies]
valence_protocol = { path = "../valence_protocol", version = "0.1.0", features = ["compression"] } valence_protocol = { path = "../valence_protocol", version = "0.1.0", features = ["compression"] }
clap = { version = "3.2.8", features = ["derive"] } clap = { version = "4.0.30", features = ["derive"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
anyhow = "1" anyhow = "1"
chrono = "0.4.19"
regex = "1.6.0" regex = "1.6.0"

View file

@ -1,11 +1,11 @@
use std::error::Error; use std::error::Error;
use std::fmt::Write;
use std::io::ErrorKind; use std::io::ErrorKind;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
use std::{fmt, io}; use std::{fmt, io};
use anyhow::bail; use anyhow::bail;
use chrono::{DateTime, Utc};
use clap::Parser; use clap::Parser;
use regex::Regex; use regex::Regex;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
@ -21,7 +21,7 @@ use valence_protocol::packets::s2c::login::{LoginSuccess, S2cLoginPacket};
use valence_protocol::packets::s2c::play::S2cPlayPacket; use valence_protocol::packets::s2c::play::S2cPlayPacket;
use valence_protocol::packets::s2c::status::{PingResponse, StatusResponse}; use valence_protocol::packets::s2c::status::{PingResponse, StatusResponse};
use valence_protocol::types::HandshakeNextState; use valence_protocol::types::HandshakeNextState;
use valence_protocol::{Decode, Encode, Packet, PacketDecoder, PacketEncoder}; use valence_protocol::{DecodePacket, EncodePacket, PacketDecoder, PacketEncoder};
#[derive(Parser, Clone, Debug)] #[derive(Parser, Clone, Debug)]
#[clap(author, version, about)] #[clap(author, version, about)]
@ -48,9 +48,6 @@ struct Cli {
/// there is no limit. /// there is no limit.
#[clap(short, long)] #[clap(short, long)]
max_connections: Option<usize>, max_connections: Option<usize>,
/// Print a timestamp before each packet.
#[clap(short, long)]
timestamp: bool,
} }
struct State { struct State {
@ -59,12 +56,13 @@ struct State {
dec: PacketDecoder, dec: PacketDecoder,
read: OwnedReadHalf, read: OwnedReadHalf,
write: OwnedWriteHalf, write: OwnedWriteHalf,
buf: String,
} }
impl State { impl State {
pub async fn rw_packet<'a, P>(&'a mut self) -> anyhow::Result<P> pub async fn rw_packet<'a, P>(&'a mut self) -> anyhow::Result<P>
where where
P: Decode<'a> + Encode + Packet + fmt::Debug, P: DecodePacket<'a> + EncodePacket + fmt::Debug,
{ {
while !self.dec.has_next_packet()? { while !self.dec.has_next_packet()? {
self.dec.reserve(4096); self.dec.reserve(4096);
@ -84,24 +82,24 @@ impl State {
let bytes = self.enc.take(); let bytes = self.enc.take();
self.write.write_all(&bytes).await?; self.write.write_all(&bytes).await?;
self.buf.clear();
write!(&mut self.buf, "{pkt:?}")?;
let packet_name = self.buf.split_ascii_whitespace().next().unwrap();
if let Some(r) = &self.cli.include_regex { if let Some(r) = &self.cli.include_regex {
if !r.is_match(pkt.packet_name()) { if !r.is_match(packet_name) {
return Ok(pkt); return Ok(pkt);
} }
} }
if let Some(r) = &self.cli.exclude_regex { if let Some(r) = &self.cli.exclude_regex {
if r.is_match(pkt.packet_name()) { if r.is_match(packet_name) {
return Ok(pkt); return Ok(pkt);
} }
} }
if self.cli.timestamp { println!("{}", self.buf);
let now: DateTime<Utc> = Utc::now();
println!("{now} {pkt:#?}");
} else {
println!("{pkt:#?}");
}
Ok(pkt) Ok(pkt)
} }
@ -156,6 +154,7 @@ async fn handle_connection(client: TcpStream, cli: Arc<Cli>) -> anyhow::Result<(
dec: PacketDecoder::new(), dec: PacketDecoder::new(),
read: server_read, read: server_read,
write: client_write, write: client_write,
buf: String::new(),
}; };
let mut c2s = State { let mut c2s = State {
@ -164,6 +163,7 @@ async fn handle_connection(client: TcpStream, cli: Arc<Cli>) -> anyhow::Result<(
dec: PacketDecoder::new(), dec: PacketDecoder::new(),
read: client_read, read: client_read,
write: server_write, write: server_write,
buf: String::new(),
}; };
let handshake: Handshake = c2s.rw_packet().await?; let handshake: Handshake = c2s.rw_packet().await?;

View file

@ -835,7 +835,7 @@ impl<C: Config> LoadedChunk<C> {
let mut compression_scratch = vec![]; let mut compression_scratch = vec![];
let mut writer = let mut writer =
PacketWriter::new(&mut *lck, compression_threshold, &mut compression_scratch); PacketWriter::new(&mut lck, compression_threshold, &mut compression_scratch);
writer writer
.write_packet(&ChunkDataAndUpdateLightEncode { .write_packet(&ChunkDataAndUpdateLightEncode {

View file

@ -27,7 +27,7 @@ use valence_protocol::types::{
SyncPlayerPosLookFlags, SyncPlayerPosLookFlags,
}; };
use valence_protocol::{ use valence_protocol::{
BlockPos, Encode, Ident, ItemStack, Packet, RawBytes, Text, Username, VarInt, BlockPos, EncodePacket, Ident, ItemStack, RawBytes, Text, Username, VarInt,
}; };
use vek::Vec3; use vek::Vec3;
@ -344,7 +344,7 @@ impl<C: Config> Client<C> {
/// effect if the client is already disconnected. /// effect if the client is already disconnected.
pub fn queue_packet<P>(&mut self, pkt: &P) pub fn queue_packet<P>(&mut self, pkt: &P)
where where
P: Encode + Packet + fmt::Debug + ?Sized, P: EncodePacket + fmt::Debug + ?Sized,
{ {
if let Some(send) = &mut self.send { if let Some(send) = &mut self.send {
if let Err(e) = send.append_packet(pkt) { if let Err(e) = send.append_packet(pkt) {

View file

@ -1,11 +1,11 @@
use std::io::Write; use std::io::Write;
use valence_protocol::{write_packet, write_packet_compressed, Encode, Packet}; use valence_protocol::{encode_packet, encode_packet_compressed, EncodePacket};
pub trait WritePacket { pub trait WritePacket {
fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()> fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()>
where where
P: Encode + Packet + ?Sized; P: EncodePacket + ?Sized;
fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()>; fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()>;
} }
@ -13,7 +13,7 @@ pub trait WritePacket {
impl<W: WritePacket> WritePacket for &mut W { impl<W: WritePacket> WritePacket for &mut W {
fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()> fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
(*self).write_packet(packet) (*self).write_packet(packet)
} }
@ -23,35 +23,35 @@ impl<W: WritePacket> WritePacket for &mut W {
} }
} }
pub struct PacketWriter<'a, W> { pub struct PacketWriter<'a> {
writer: W, buf: &'a mut Vec<u8>,
threshold: Option<u32>, threshold: Option<u32>,
scratch: &'a mut Vec<u8>, scratch: &'a mut Vec<u8>,
} }
impl<'a, W: Write> PacketWriter<'a, W> { impl<'a> PacketWriter<'a> {
pub fn new(writer: W, threshold: Option<u32>, scratch: &'a mut Vec<u8>) -> PacketWriter<W> { pub fn new(buf: &'a mut Vec<u8>, threshold: Option<u32>, scratch: &'a mut Vec<u8>) -> Self {
Self { Self {
writer, buf,
threshold, threshold,
scratch, scratch,
} }
} }
} }
impl<W: Write> WritePacket for PacketWriter<'_, W> { impl WritePacket for PacketWriter<'_> {
fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()> fn write_packet<P>(&mut self, pkt: &P) -> anyhow::Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
if let Some(threshold) = self.threshold { if let Some(threshold) = self.threshold {
write_packet_compressed(&mut self.writer, threshold, self.scratch, packet) encode_packet_compressed(self.buf, pkt, threshold, self.scratch)
} else { } else {
write_packet(&mut self.writer, packet) encode_packet(self.buf, pkt)
} }
} }
fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()> { fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()> {
Ok(self.writer.write_all(bytes)?) Ok(self.buf.write_all(bytes)?)
} }
} }

View file

@ -9,7 +9,7 @@ use tokio::sync::OwnedSemaphorePermit;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tokio::time::timeout; use tokio::time::timeout;
use tracing::debug; use tracing::debug;
use valence_protocol::{Decode, Encode, Packet, PacketDecoder, PacketEncoder}; use valence_protocol::{DecodePacket, EncodePacket, PacketDecoder, PacketEncoder};
use crate::packet::WritePacket; use crate::packet::WritePacket;
use crate::server::byte_channel::{byte_channel, ByteReceiver, ByteSender, TryRecvError}; use crate::server::byte_channel::{byte_channel, ByteReceiver, ByteSender, TryRecvError};
@ -50,7 +50,7 @@ where
pub async fn send_packet<P>(&mut self, pkt: &P) -> Result<()> pub async fn send_packet<P>(&mut self, pkt: &P) -> Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
self.enc.append_packet(pkt)?; self.enc.append_packet(pkt)?;
let bytes = self.enc.take(); let bytes = self.enc.take();
@ -60,7 +60,7 @@ where
pub async fn recv_packet<'a, P>(&'a mut self) -> Result<P> pub async fn recv_packet<'a, P>(&'a mut self) -> Result<P>
where where
P: Decode<'a> + Packet, P: DecodePacket<'a>,
{ {
timeout(self.timeout, async { timeout(self.timeout, async {
while !self.dec.has_next_packet()? { while !self.dec.has_next_packet()? {
@ -196,7 +196,7 @@ pub struct PlayPacketSender {
impl PlayPacketSender { impl PlayPacketSender {
pub fn append_packet<P>(&mut self, pkt: &P) -> Result<()> pub fn append_packet<P>(&mut self, pkt: &P) -> Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
self.enc.append_packet(pkt) self.enc.append_packet(pkt)
} }
@ -207,7 +207,7 @@ impl PlayPacketSender {
pub fn prepend_packet<P>(&mut self, pkt: &P) -> Result<()> pub fn prepend_packet<P>(&mut self, pkt: &P) -> Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
self.enc.prepend_packet(pkt) self.enc.prepend_packet(pkt)
} }
@ -222,7 +222,7 @@ impl PlayPacketSender {
impl WritePacket for PlayPacketSender { impl WritePacket for PlayPacketSender {
fn write_packet<P>(&mut self, packet: &P) -> Result<()> fn write_packet<P>(&mut self, packet: &P) -> Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
self.append_packet(packet) self.append_packet(packet)
} }
@ -259,7 +259,7 @@ pub struct PlayPacketReceiver {
impl PlayPacketReceiver { impl PlayPacketReceiver {
pub fn try_next_packet<'a, P>(&'a mut self) -> Result<Option<P>> pub fn try_next_packet<'a, P>(&'a mut self) -> Result<Option<P>>
where where
P: Decode<'a> + Packet, P: DecodePacket<'a>,
{ {
self.dec.try_next_packet() self.dec.try_next_packet()
} }

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{quote, ToTokens}; use quote::quote;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{parse2, parse_quote, Data, DeriveInput, Error, Fields, Result}; use syn::{parse2, parse_quote, Data, DeriveInput, Error, Fields, Result};
@ -11,12 +11,6 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
let mut input = parse2::<DeriveInput>(item)?; let mut input = parse2::<DeriveInput>(item)?;
let name = input.ident; let name = input.ident;
let string_name = name.to_string();
let packet_id = find_packet_id_attr(&input.attrs)?
.into_iter()
.map(|l| l.to_token_stream())
.collect::<Vec<_>>();
if input.generics.lifetimes().count() > 1 { if input.generics.lifetimes().count() > 1 {
return Err(Error::new( return Err(Error::new(
@ -79,36 +73,15 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
Ok(quote! { Ok(quote! {
#[allow(unused_imports)] #[allow(unused_imports)]
impl #impl_generics ::valence_protocol::Decode<#lifetime> for #name #ty_generics impl #impl_generics ::valence_protocol::__private::Decode<#lifetime> for #name #ty_generics
#where_clause #where_clause
{ {
fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> { fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> {
use ::valence_protocol::__private::{Decode, Context, VarInt, ensure}; use ::valence_protocol::__private::{Decode, Context, ensure};
#(
let id = VarInt::decode(_r).context("failed to decode packet ID")?.0;
ensure!(id == #packet_id, "unexpected packet ID {} (expected {})", id, #packet_id);
)*
Ok(#decode_fields) Ok(#decode_fields)
} }
} }
#(
#[allow(unused_imports)]
impl #impl_generics ::valence_protocol::DerivedPacketDecode<#lifetime> for #name #ty_generics
#where_clause
{
const ID: i32 = #packet_id;
const NAME: &'static str = #string_name;
fn decode_without_id(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> {
use ::valence_protocol::__private::{Decode, Context, VarInt, ensure};
Ok(#decode_fields)
}
}
)*
}) })
} }
Data::Enum(enum_) => { Data::Enum(enum_) => {
@ -170,16 +143,11 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
Ok(quote! { Ok(quote! {
#[allow(unused_imports)] #[allow(unused_imports)]
impl #impl_generics ::valence_protocol::Decode<#lifetime> for #name #ty_generics impl #impl_generics ::valence_protocol::__private::Decode<#lifetime> for #name #ty_generics
#where_clause #where_clause
{ {
fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> { fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> {
use ::valence_protocol::__private::{Decode, Context, VarInt, bail, ensure}; use ::valence_protocol::__private::{Decode, Context, VarInt, bail};
#(
let id = VarInt::decode(_r).context("failed to decode packet ID")?.0;
ensure!(id == #packet_id, "unexpected packet ID {} (expected {})", id, #packet_id);
)*
let disc = VarInt::decode(_r).context("failed to decode enum discriminant")?.0; let disc = VarInt::decode(_r).context("failed to decode enum discriminant")?.0;
match disc { match disc {
@ -188,26 +156,6 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
} }
} }
} }
#(
#[allow(unused_imports)]
impl #impl_generics ::valence_protocol::DerivedPacketDecode<#lifetime> for #name #ty_generics
#where_clause
{
const ID: i32 = #packet_id;
const NAME: &'static str = #string_name;
fn decode_without_id(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> {
use ::valence_protocol::__private::{Decode, Context, VarInt, bail};
let disc = VarInt::decode(_r).context("failed to decode enum discriminant")?.0;
match disc {
#decode_arms
n => bail!("unexpected enum discriminant {}", disc),
}
}
}
)*
}) })
} }
Data::Union(u) => Err(Error::new( Data::Union(u) => Err(Error::new(
@ -216,3 +164,48 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
)), )),
} }
} }
pub fn derive_decode_packet(item: TokenStream) -> Result<TokenStream> {
let mut input = parse2::<DeriveInput>(item)?;
let Some(packet_id) = find_packet_id_attr(&input.attrs)? else {
return Err(Error::new(
input.ident.span(),
"cannot derive `DecodePacket` without `#[packet_id = ...]` helper attribute",
))
};
let lifetime = input
.generics
.lifetimes()
.next()
.map(|l| l.lifetime.clone())
.unwrap_or_else(|| parse_quote!('a));
add_trait_bounds(
&mut input.generics,
quote!(::valence_protocol::__private::Decode<#lifetime>),
);
let (impl_generics, ty_generics, where_clause) =
decode_split_for_impl(input.generics, lifetime.clone());
let name = input.ident;
Ok(quote! {
impl #impl_generics ::valence_protocol::__private::DecodePacket<#lifetime> for #name #ty_generics
#where_clause
{
const PACKET_ID: i32 = #packet_id;
fn decode_packet(r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> {
use ::valence_protocol::__private::{Decode, Context, VarInt, ensure};
let id = VarInt::decode(r).context("failed to decode packet ID")?.0;
ensure!(id == #packet_id, "unexpected packet ID {} (expected {})", id, #packet_id);
Self::decode(r)
}
}
})
}

View file

@ -1,5 +1,5 @@
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens}; use quote::quote;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{parse2, Data, DeriveInput, Error, Fields, LitInt, Result}; use syn::{parse2, Data, DeriveInput, Error, Fields, LitInt, Result};
@ -9,22 +9,16 @@ pub fn derive_encode(item: TokenStream) -> Result<TokenStream> {
let mut input = parse2::<DeriveInput>(item)?; let mut input = parse2::<DeriveInput>(item)?;
let name = input.ident; let name = input.ident;
let string_name = name.to_string();
let packet_id = find_packet_id_attr(&input.attrs)? add_trait_bounds(
.into_iter() &mut input.generics,
.map(|l| l.to_token_stream()) quote!(::valence_protocol::__private::Encode),
.collect::<Vec<_>>(); );
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
match input.data { match input.data {
Data::Struct(struct_) => { Data::Struct(struct_) => {
add_trait_bounds(
&mut input.generics,
quote!(::valence_protocol::__private::Encode),
);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let encode_fields = match &struct_.fields { let encode_fields = match &struct_.fields {
Fields::Named(fields) => fields Fields::Named(fields) => fields
.named .named
@ -49,87 +43,22 @@ pub fn derive_encode(item: TokenStream) -> Result<TokenStream> {
Fields::Unit => TokenStream::new(), Fields::Unit => TokenStream::new(),
}; };
let encoded_len_fields = match &struct_.fields {
Fields::Named(fields) => fields
.named
.iter()
.map(|f| {
let name = &f.ident;
quote! {
+ self.#name.encoded_len()
}
})
.collect(),
Fields::Unnamed(fields) => (0..fields.unnamed.len())
.map(|i| {
let lit = LitInt::new(&i.to_string(), Span::call_site());
quote! {
+ self.#lit.encoded_len()
}
})
.collect(),
Fields::Unit => TokenStream::new(),
};
Ok(quote! { Ok(quote! {
#[allow(unused_imports)] #[allow(unused_imports)]
impl #impl_generics ::valence_protocol::__private::Encode for #name #ty_generics impl #impl_generics ::valence_protocol::__private::Encode for #name #ty_generics
#where_clause #where_clause
{ {
fn encode(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> { fn encode(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> {
use ::valence_protocol::__private::{Encode, Context, VarInt}; use ::valence_protocol::__private::{Encode, Context};
#(
VarInt(#packet_id)
.encode(&mut _w)
.context("failed to encode packet ID")?;
)*
#encode_fields #encode_fields
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
use ::valence_protocol::__private::{Encode, Context, VarInt};
0 #(+ VarInt(#packet_id).encoded_len())* #encoded_len_fields
}
} }
#(
#[allow(unused_imports)]
impl #impl_generics ::valence_protocol::__private::DerivedPacketEncode for #name #ty_generics
#where_clause
{
const ID: i32 = #packet_id;
const NAME: &'static str = #string_name;
fn encode_without_id(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> {
use ::valence_protocol::__private::{Encode, Context, VarInt};
#encode_fields
Ok(())
}
fn encoded_len_without_id(&self) -> usize {
use ::valence_protocol::__private::{Encode, Context, VarInt};
0 #encoded_len_fields
}
}
)*
}) })
} }
Data::Enum(enum_) => { Data::Enum(enum_) => {
add_trait_bounds(
&mut input.generics,
quote!(::valence_protocol::__private::Encode),
);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let variants = pair_variants_with_discriminants(enum_.variants.into_iter())?; let variants = pair_variants_with_discriminants(enum_.variants.into_iter())?;
let encode_arms = variants let encode_arms = variants
@ -211,45 +140,6 @@ pub fn derive_encode(item: TokenStream) -> Result<TokenStream> {
}) })
.collect::<TokenStream>(); .collect::<TokenStream>();
let encoded_len_arms = variants
.iter()
.map(|(disc, variant)| {
let name = &variant.ident;
match &variant.fields {
Fields::Named(fields) => {
let fields = fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
quote! {
Self::#name { #(#fields,)* } => {
VarInt(#disc).encoded_len()
#(+ #fields.encoded_len())*
}
}
}
Fields::Unnamed(fields) => {
let fields = (0..fields.unnamed.len())
.map(|i| Ident::new(&format!("_{i}"), Span::call_site()))
.collect::<Vec<_>>();
quote! {
Self::#name(#(#fields,)*) => {
VarInt(#disc).encoded_len()
#(+ #fields.encoded_len())*
}
}
}
Fields::Unit => {
quote! {
Self::#name => VarInt(#disc).encoded_len(),
}
}
}
})
.collect::<TokenStream>();
Ok(quote! { Ok(quote! {
#[allow(unused_imports, unreachable_code)] #[allow(unused_imports, unreachable_code)]
impl #impl_generics ::valence_protocol::Encode for #name #ty_generics impl #impl_generics ::valence_protocol::Encode for #name #ty_generics
@ -258,53 +148,12 @@ pub fn derive_encode(item: TokenStream) -> Result<TokenStream> {
fn encode(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> { fn encode(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> {
use ::valence_protocol::__private::{Encode, VarInt, Context}; use ::valence_protocol::__private::{Encode, VarInt, Context};
#(
VarInt(#packet_id)
.encode(&mut _w)
.context("failed to encode packet ID")?;
)*
match self { match self {
#encode_arms #encode_arms
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn encoded_len(&self) -> usize {
use ::valence_protocol::__private::{Encode, Context, VarInt};
#(VarInt(#packet_id).encoded_len() +)* match self {
#encoded_len_arms
_ => unreachable!() as usize,
}
}
} }
#(
#[allow(unused_imports)]
impl #impl_generics ::valence_protocol::DerivedPacketEncode for #name #ty_generics
#where_clause
{
const ID: i32 = #packet_id;
const NAME: &'static str = #string_name;
fn encode_without_id(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> {
use ::valence_protocol::__private::{Encode, VarInt, Context};
match self {
#encode_arms
_ => unreachable!(),
}
}
fn encoded_len_without_id(&self) -> usize {
use ::valence_protocol::__private::{Encode, Context, VarInt};
match self {
#encoded_len_arms
_ => unreachable!(),
}
}
}
)*
}) })
} }
Data::Union(u) => Err(Error::new( Data::Union(u) => Err(Error::new(
@ -313,3 +162,41 @@ pub fn derive_encode(item: TokenStream) -> Result<TokenStream> {
)), )),
} }
} }
pub fn derive_encode_packet(item: TokenStream) -> Result<TokenStream> {
let mut input = parse2::<DeriveInput>(item)?;
let Some(packet_id) = find_packet_id_attr(&input.attrs)? else {
return Err(Error::new(
input.ident.span(),
"cannot derive `EncodePacket` without `#[packet_id = ...]` helper attribute",
))
};
add_trait_bounds(
&mut input.generics,
quote!(::valence_protocol::__private::Encode),
);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let name = input.ident;
Ok(quote! {
impl #impl_generics ::valence_protocol::__private::EncodePacket for #name #ty_generics
#where_clause
{
const PACKET_ID: i32 = #packet_id;
fn encode_packet(&self, mut w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> {
use ::valence_protocol::__private::{Encode, Context, VarInt};
VarInt(#packet_id)
.encode(&mut w)
.context("failed to encode packet ID")?;
self.encode(w)
}
}
})
}

View file

@ -4,17 +4,17 @@
//! See `valence_protocol`'s documentation for more information. //! See `valence_protocol`'s documentation for more information.
use proc_macro::TokenStream as StdTokenStream; use proc_macro::TokenStream as StdTokenStream;
use proc_macro2::{Span, TokenStream}; use proc_macro2::TokenStream;
use quote::{quote, ToTokens}; use quote::ToTokens;
use syn::{ use syn::{
parse2, parse_quote, Attribute, DeriveInput, Error, GenericParam, Generics, Lifetime, parse_quote, Attribute, Error, GenericParam, Generics, Lifetime, LifetimeDef, Lit, LitInt,
LifetimeDef, Lit, LitInt, Meta, Result, Variant, Meta, Result, Variant,
}; };
mod decode; mod decode;
mod encode; mod encode;
#[proc_macro_derive(Encode, attributes(packet_id, tag))] #[proc_macro_derive(Encode, attributes(tag))]
pub fn derive_encode(item: StdTokenStream) -> StdTokenStream { pub fn derive_encode(item: StdTokenStream) -> StdTokenStream {
match encode::derive_encode(item.into()) { match encode::derive_encode(item.into()) {
Ok(tokens) => tokens.into(), Ok(tokens) => tokens.into(),
@ -22,7 +22,15 @@ pub fn derive_encode(item: StdTokenStream) -> StdTokenStream {
} }
} }
#[proc_macro_derive(Decode, attributes(packet_id, tag))] #[proc_macro_derive(EncodePacket, attributes(packet_id))]
pub fn derive_encode_packet(item: StdTokenStream) -> StdTokenStream {
match encode::derive_encode_packet(item.into()) {
Ok(tokens) => tokens.into(),
Err(e) => e.into_compile_error().into(),
}
}
#[proc_macro_derive(Decode, attributes(tag))]
pub fn derive_decode(item: StdTokenStream) -> StdTokenStream { pub fn derive_decode(item: StdTokenStream) -> StdTokenStream {
match decode::derive_decode(item.into()) { match decode::derive_decode(item.into()) {
Ok(tokens) => tokens.into(), Ok(tokens) => tokens.into(),
@ -30,41 +38,14 @@ pub fn derive_decode(item: StdTokenStream) -> StdTokenStream {
} }
} }
#[proc_macro_derive(Packet)] #[proc_macro_derive(DecodePacket, attributes(packet_id))]
pub fn derive_packet(item: StdTokenStream) -> StdTokenStream { pub fn derive_decode_packet(item: StdTokenStream) -> StdTokenStream {
match derive_packet_inner(item.into()) { match decode::derive_decode_packet(item.into()) {
Ok(tokens) => tokens.into(), Ok(tokens) => tokens.into(),
Err(e) => e.into_compile_error().into(), Err(e) => e.into_compile_error().into(),
} }
} }
fn derive_packet_inner(item: TokenStream) -> Result<TokenStream> {
let input = parse2::<DeriveInput>(item)?;
if find_packet_id_attr(&input.attrs)?.is_none() {
return Err(Error::new(
Span::call_site(),
"cannot derive `Packet` without `#[packet_id = ...]` attribute. Consider implementing \
the trait manually",
));
}
let name = input.ident;
let string_name = name.to_string();
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
Ok(quote! {
impl #impl_generics ::valence_protocol::Packet for #name #ty_generics
#where_clause
{
fn packet_name(&self) -> &'static str {
#string_name
}
}
})
}
fn find_packet_id_attr(attrs: &[Attribute]) -> Result<Option<LitInt>> { fn find_packet_id_attr(attrs: &[Attribute]) -> Result<Option<LitInt>> {
for attr in attrs { for attr in attrs {
if let Meta::NameValue(nv) = attr.parse_meta()? { if let Meta::NameValue(nv) = attr.parse_meta()? {

View file

@ -4,7 +4,7 @@ use std::hash::Hash;
use std::iter::FusedIterator; use std::iter::FusedIterator;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use crate::to_binary_writer::encoded_len; use crate::to_binary_writer::written_size;
use crate::Value; use crate::Value;
/// A map type with [`String`] keys and [`Value`] values. /// A map type with [`String`] keys and [`Value`] values.
@ -20,18 +20,17 @@ type Map = std::collections::BTreeMap<String, Value>;
type Map = indexmap::IndexMap<String, Value>; type Map = indexmap::IndexMap<String, Value>;
impl Compound { impl Compound {
/// Returns the number of bytes that will be written with /// Returns the number of bytes that will be written when
/// [`to_binary_writer`] when called with this compound and root name. /// [`to_binary_writer`] is called with this compound and root name.
/// ///
/// If [`to_binary_writer`] results in `Ok`, the exact number of bytes /// If [`to_binary_writer`] results in `Ok`, the exact number of bytes
/// reported by this function will have been written. /// reported by this function will have been written. If the result is
/// /// `Err`, then the reported count will be greater than or equal to the
/// If the result is `Err`, then the reported count will be greater than or /// number of bytes that have actually been written.
/// equal to the number of bytes that have actually been written.
/// ///
/// [`to_binary_writer`]: crate::to_binary_writer() /// [`to_binary_writer`]: crate::to_binary_writer()
pub fn binary_encoded_len(&self, root_name: &str) -> usize { pub fn written_size(&self, root_name: &str) -> usize {
encoded_len(self, root_name) written_size(self, root_name)
} }
} }

View file

@ -94,7 +94,7 @@ fn correct_length() {
let mut buf = vec![]; let mut buf = vec![];
to_binary_writer(&mut buf, &c, "abc").unwrap(); to_binary_writer(&mut buf, &c, "abc").unwrap();
assert_eq!(c.binary_encoded_len("abc"), buf.len()); assert_eq!(c.written_size("abc"), buf.len());
} }
#[cfg(feature = "preserve_order")] #[cfg(feature = "preserve_order")]

View file

@ -22,7 +22,7 @@ pub fn to_binary_writer<W: Write>(writer: W, compound: &Compound, root_name: &st
Ok(()) Ok(())
} }
pub(crate) fn encoded_len(compound: &Compound, root_name: &str) -> usize { pub(crate) fn written_size(compound: &Compound, root_name: &str) -> usize {
fn value_len(val: &Value) -> usize { fn value_len(val: &Value) -> usize {
match val { match val {
Value::Byte(_) => 1, Value::Byte(_) => 1,

View file

@ -7,7 +7,6 @@ build = "build/main.rs"
[dependencies] [dependencies]
aes = { version = "0.7.5", optional = true } aes = { version = "0.7.5", optional = true }
anyhow = "1.0.66" anyhow = "1.0.66"
arrayvec = "0.7.2"
bitfield-struct = "0.1.7" bitfield-struct = "0.1.7"
byteorder = "1.4.3" byteorder = "1.4.3"
bytes = "1.2.1" bytes = "1.2.1"

View file

@ -5,12 +5,11 @@ use rand::Rng;
use valence_nbt::{compound, List}; use valence_nbt::{compound, List};
use valence_protocol::block::{BlockKind, BlockState, PropName, PropValue}; use valence_protocol::block::{BlockKind, BlockState, PropName, PropValue};
use valence_protocol::packets::s2c::play::{ use valence_protocol::packets::s2c::play::{
ChunkDataAndUpdateLight, ChunkDataAndUpdateLightEncode, SetTabListHeaderAndFooter, ChunkDataAndUpdateLight, ChunkDataAndUpdateLightEncode, SetTabListHeaderAndFooter, SpawnEntity,
TeleportEntity,
}; };
use valence_protocol::text::Color; use valence_protocol::text::Color;
use valence_protocol::{ use valence_protocol::{
write_packet, write_packet_compressed, ByteAngle, Decode, Encode, ItemKind, encode_packet, encode_packet_compressed, ByteAngle, Decode, Encode, ItemKind,
LengthPrefixedArray, PacketDecoder, PacketEncoder, TextFormat, VarInt, LengthPrefixedArray, PacketDecoder, PacketEncoder, TextFormat, VarInt,
}; };
@ -18,7 +17,7 @@ criterion_group! {
name = benches; name = benches;
config = Criterion::default() config = Criterion::default()
.measurement_time(Duration::from_secs(5)).confidence_level(0.99); .measurement_time(Duration::from_secs(5)).confidence_level(0.99);
targets = blocks, packets, var_int targets = blocks, packets, var_int, decode_array
} }
criterion_main!(benches); criterion_main!(benches);
@ -139,12 +138,16 @@ fn packets(c: &mut Criterion) {
threshold.", threshold.",
}; };
let teleport_entity_packet = TeleportEntity { let spawn_entity_packet = SpawnEntity {
entity_id: VarInt(123456), entity_id: VarInt(1234),
object_uuid: Default::default(),
kind: VarInt(5),
position: [123.0, 456.0, 789.0], position: [123.0, 456.0, 789.0],
yaw: ByteAngle(42), pitch: ByteAngle(200),
pitch: ByteAngle(69), yaw: ByteAngle(100),
on_ground: true, head_yaw: ByteAngle(50),
data: VarInt(i32::MIN),
velocity: [12, 34, 56],
}; };
c.bench_function("encode_chunk_data", |b| { c.bench_function("encode_chunk_data", |b| {
@ -171,12 +174,12 @@ fn packets(c: &mut Criterion) {
}); });
}); });
c.bench_function("encode_teleport_entity", |b| { c.bench_function("encode_spawn_entity", |b| {
b.iter(|| { b.iter(|| {
let encoder = black_box(&mut encoder); let encoder = black_box(&mut encoder);
encoder.clear(); encoder.clear();
encoder.append_packet(&teleport_entity_packet).unwrap(); encoder.append_packet(&spawn_entity_packet).unwrap();
black_box(encoder); black_box(encoder);
}); });
@ -208,12 +211,12 @@ fn packets(c: &mut Criterion) {
}); });
}); });
c.bench_function("encode_teleport_entity_compressed", |b| { c.bench_function("encode_spawn_entity_compressed", |b| {
b.iter(|| { b.iter(|| {
let encoder = black_box(&mut encoder); let encoder = black_box(&mut encoder);
encoder.clear(); encoder.clear();
encoder.append_packet(&teleport_entity_packet).unwrap(); encoder.append_packet(&spawn_entity_packet).unwrap();
black_box(encoder); black_box(encoder);
}); });
@ -222,7 +225,7 @@ fn packets(c: &mut Criterion) {
let mut decoder = PacketDecoder::new(); let mut decoder = PacketDecoder::new();
let mut packet_buf = vec![]; let mut packet_buf = vec![];
write_packet(&mut packet_buf, &chunk_data_packet).unwrap(); encode_packet(&mut packet_buf, &chunk_data_packet).unwrap();
c.bench_function("decode_chunk_data", |b| { c.bench_function("decode_chunk_data", |b| {
b.iter(|| { b.iter(|| {
@ -238,7 +241,7 @@ fn packets(c: &mut Criterion) {
}); });
packet_buf.clear(); packet_buf.clear();
write_packet(&mut packet_buf, &tab_list_header_footer_packet).unwrap(); encode_packet(&mut packet_buf, &tab_list_header_footer_packet).unwrap();
c.bench_function("decode_tab_list_header_footer", |b| { c.bench_function("decode_tab_list_header_footer", |b| {
b.iter(|| { b.iter(|| {
@ -254,14 +257,14 @@ fn packets(c: &mut Criterion) {
}); });
packet_buf.clear(); packet_buf.clear();
write_packet(&mut packet_buf, &teleport_entity_packet).unwrap(); encode_packet(&mut packet_buf, &spawn_entity_packet).unwrap();
c.bench_function("decode_teleport_entity", |b| { c.bench_function("decode_spawn_entity", |b| {
b.iter(|| { b.iter(|| {
let decoder = black_box(&mut decoder); let decoder = black_box(&mut decoder);
decoder.queue_slice(&packet_buf); decoder.queue_slice(&packet_buf);
decoder.try_next_packet::<TeleportEntity>().unwrap(); decoder.try_next_packet::<SpawnEntity>().unwrap();
black_box(decoder); black_box(decoder);
}); });
@ -272,7 +275,7 @@ fn packets(c: &mut Criterion) {
let mut scratch = vec![]; let mut scratch = vec![];
packet_buf.clear(); packet_buf.clear();
write_packet_compressed(&mut packet_buf, 256, &mut scratch, &chunk_data_packet).unwrap(); encode_packet_compressed(&mut packet_buf, &chunk_data_packet, 256, &mut scratch).unwrap();
c.bench_function("decode_chunk_data_compressed", |b| { c.bench_function("decode_chunk_data_compressed", |b| {
b.iter(|| { b.iter(|| {
@ -288,11 +291,11 @@ fn packets(c: &mut Criterion) {
}); });
packet_buf.clear(); packet_buf.clear();
write_packet_compressed( encode_packet_compressed(
&mut packet_buf, &mut packet_buf,
&tab_list_header_footer_packet,
256, 256,
&mut scratch, &mut scratch,
&tab_list_header_footer_packet,
) )
.unwrap(); .unwrap();
@ -310,14 +313,14 @@ fn packets(c: &mut Criterion) {
}); });
packet_buf.clear(); packet_buf.clear();
write_packet_compressed(&mut packet_buf, 256, &mut scratch, &teleport_entity_packet).unwrap(); encode_packet_compressed(&mut packet_buf, &spawn_entity_packet, 256, &mut scratch).unwrap();
c.bench_function("decode_teleport_entity_compressed", |b| { c.bench_function("decode_spawn_entity_compressed", |b| {
b.iter(|| { b.iter(|| {
let decoder = black_box(&mut decoder); let decoder = black_box(&mut decoder);
decoder.queue_slice(&packet_buf); decoder.queue_slice(&packet_buf);
decoder.try_next_packet::<TeleportEntity>().unwrap(); decoder.try_next_packet::<SpawnEntity>().unwrap();
black_box(decoder); black_box(decoder);
}); });
@ -353,3 +356,26 @@ fn var_int(c: &mut Criterion) {
) )
}); });
} }
fn decode_array(c: &mut Criterion) {
let floats = [123.0, 456.0, 789.0];
let mut buf = [0u8; 24];
floats.encode(buf.as_mut_slice()).unwrap();
c.bench_function("<[f64; 3]>::decode", |b| {
b.iter(|| {
let mut r = black_box(buf.as_slice());
let _ = black_box(<[f64; 3]>::decode(&mut r));
});
});
let bytes = [42; 4096];
c.bench_function("<[u8; 4096]>::decode", |b| {
b.iter(|| {
let mut r = black_box(bytes.as_slice());
let _ = black_box(<[u8; 4096]>::decode(&mut r));
})
});
}

View file

@ -17,10 +17,6 @@ impl<T: Encode, const N: usize> Encode for LengthPrefixedArray<T, N> {
VarInt(N as i32).encode(&mut w)?; VarInt(N as i32).encode(&mut w)?;
self.0.encode(w) self.0.encode(w)
} }
fn encoded_len(&self) -> usize {
VarInt(N as i32).encoded_len() + self.0.encoded_len()
}
} }
impl<'a, T: Decode<'a>, const N: usize> Decode<'a> for LengthPrefixedArray<T, N> { impl<'a, T: Decode<'a>, const N: usize> Decode<'a> for LengthPrefixedArray<T, N> {

View file

@ -53,10 +53,6 @@ impl Encode for BlockState {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
VarInt(self.0 as i32).encode(w) VarInt(self.0 as i32).encode(w)
} }
fn encoded_len(&self) -> usize {
VarInt(self.0 as i32).encoded_len()
}
} }
impl Decode<'_> for BlockState { impl Decode<'_> for BlockState {

View file

@ -55,10 +55,6 @@ impl Encode for BlockPos {
_ => bail!("out of range: {self:?}"), _ => bail!("out of range: {self:?}"),
} }
} }
fn encoded_len(&self) -> usize {
8
}
} }
impl Decode<'_> for BlockPos { impl Decode<'_> for BlockPos {

View file

@ -29,10 +29,6 @@ where
self.0.encode(w) self.0.encode(w)
} }
fn encoded_len(&self) -> usize {
self.0.encoded_len()
}
} }
impl<'a, T, const MIN: i128, const MAX: i128> Decode<'a> for BoundedInt<T, MIN, MAX> impl<'a, T, const MIN: i128, const MAX: i128> Decode<'a> for BoundedInt<T, MIN, MAX>
@ -82,10 +78,6 @@ where
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
self.0.as_ref().encoded_len()
}
} }
impl<'a, S, const MIN: usize, const MAX: usize> Decode<'a> for BoundedString<S, MIN, MAX> impl<'a, S, const MIN: usize, const MAX: usize> Decode<'a> for BoundedString<S, MIN, MAX>

View file

@ -29,10 +29,6 @@ impl Encode for ByteAngle {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.0.encode(w) self.0.encode(w)
} }
fn encoded_len(&self) -> usize {
self.0.encoded_len()
}
} }
impl Decode<'_> for ByteAngle { impl Decode<'_> for ByteAngle {

View file

@ -1,26 +0,0 @@
use std::io;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct ByteCounter(pub usize);
impl ByteCounter {
pub const fn new() -> Self {
Self(0)
}
}
impl io::Write for ByteCounter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0 += buf.len();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.0 += buf.len();
Ok(())
}
}

View file

@ -1,12 +1,10 @@
use std::io::Write;
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
use aes::cipher::{AsyncStreamCipher, NewCipher}; use aes::cipher::{AsyncStreamCipher, NewCipher};
use anyhow::{bail, ensure}; use anyhow::{bail, ensure};
use bytes::{Buf, BufMut, BytesMut}; use bytes::{Buf, BufMut, BytesMut};
use crate::var_int::{VarInt, VarIntDecodeError}; use crate::var_int::{VarInt, VarIntDecodeError};
use crate::{Decode, Encode, Packet, Result, MAX_PACKET_SIZE}; use crate::{DecodePacket, Encode, EncodePacket, Result, MAX_PACKET_SIZE};
/// The AES block cipher with a 128 bit key, using the CFB-8 mode of /// The AES block cipher with a 128 bit key, using the CFB-8 mode of
/// operation. /// operation.
@ -29,108 +27,93 @@ impl PacketEncoder {
Self::default() Self::default()
} }
pub fn append_packet<P>(&mut self, pkt: &P) -> Result<()>
where
P: Encode + Packet + ?Sized,
{
self.append_or_prepend_packet::<true>(pkt)
}
pub fn append_bytes(&mut self, bytes: &[u8]) { pub fn append_bytes(&mut self, bytes: &[u8]) {
self.buf.extend_from_slice(bytes) self.buf.extend_from_slice(bytes)
} }
pub fn prepend_packet<P>(&mut self, pkt: &P) -> Result<()> pub fn prepend_packet<P>(&mut self, pkt: &P) -> Result<()>
where where
P: Encode + Packet + ?Sized, P: EncodePacket + ?Sized,
{ {
self.append_or_prepend_packet::<false>(pkt) let start_len = self.buf.len();
self.append_packet(pkt)?;
let end_len = self.buf.len();
let total_packet_len = end_len - start_len;
// 1) Move everything back by the length of the packet.
// 2) Move the packet to the new space at the front.
// 3) Truncate the old packet away.
self.buf.put_bytes(0, total_packet_len);
self.buf.copy_within(..end_len, total_packet_len);
self.buf.copy_within(total_packet_len + start_len.., 0);
self.buf.truncate(end_len);
Ok(())
} }
fn append_or_prepend_packet<const APPEND: bool>( pub fn append_packet<P>(&mut self, pkt: &P) -> Result<()>
&mut self, where
pkt: &(impl Encode + Packet + ?Sized), P: EncodePacket + ?Sized,
) -> Result<()> { {
let data_len = pkt.encoded_len(); let start_len = self.buf.len();
#[cfg(debug_assertions)] pkt.encode_packet((&mut self.buf).writer())?;
{
use crate::byte_counter::ByteCounter;
let mut counter = ByteCounter::new(); let data_len = self.buf.len() - start_len;
pkt.encode(&mut counter)?;
let actual = counter.0;
assert_eq!(
actual,
data_len,
"actual encoded size of {} packet differs from reported size (actual = {actual}, \
reported = {data_len})",
pkt.packet_name()
);
}
#[cfg(feature = "compression")] #[cfg(feature = "compression")]
if let Some(threshold) = self.compression_threshold { if let Some(threshold) = self.compression_threshold {
use flate2::write::ZlibEncoder; use std::io::Read;
use flate2::bufread::ZlibEncoder;
use flate2::Compression; use flate2::Compression;
if data_len >= threshold as usize { if data_len > threshold as usize {
let mut z = ZlibEncoder::new(&mut self.compress_buf, Compression::new(4)); let mut z = ZlibEncoder::new(&self.buf[start_len..], Compression::new(4));
pkt.encode(&mut z)?;
drop(z);
let packet_len = VarInt(data_len as i32).encoded_len() + self.compress_buf.len();
ensure!(
packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);
// BytesMut doesn't implement io::Write for some reason.
let mut writer = (&mut self.buf).writer();
if APPEND {
VarInt(packet_len as i32).encode(&mut writer)?;
VarInt(data_len as i32).encode(&mut writer)?;
self.buf.extend_from_slice(&self.compress_buf);
} else {
let mut slice = move_forward_by(
&mut self.buf,
VarInt(packet_len as i32).encoded_len() + packet_len,
);
VarInt(packet_len as i32).encode(&mut slice)?;
VarInt(data_len as i32).encode(&mut slice)?;
slice.copy_from_slice(&self.compress_buf);
}
self.compress_buf.clear(); self.compress_buf.clear();
} else {
let packet_len = VarInt(0).encoded_len() + data_len; let data_len_size = VarInt(data_len as i32).written_size();
let packet_len = data_len_size + z.read_to_end(&mut self.compress_buf)?;
ensure!( ensure!(
packet_len <= MAX_PACKET_SIZE as usize, packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length" "packet exceeds maximum length"
); );
drop(z);
self.buf.truncate(start_len);
let mut writer = (&mut self.buf).writer(); let mut writer = (&mut self.buf).writer();
if APPEND { VarInt(packet_len as i32).encode(&mut writer)?;
VarInt(packet_len as i32).encode(&mut writer)?; VarInt(data_len as i32).encode(&mut writer)?;
VarInt(0).encode(&mut writer)?; // 0 for no compression on this packet. self.buf.extend_from_slice(&self.compress_buf);
pkt.encode(&mut writer)?; } else {
} else { let data_len_size = 1;
let mut slice = move_forward_by( let packet_len = data_len_size + data_len;
&mut self.buf,
VarInt(packet_len as i32).encoded_len() + packet_len,
);
VarInt(packet_len as i32).encode(&mut slice)?; ensure!(
VarInt(0).encode(&mut slice)?; packet_len <= MAX_PACKET_SIZE as usize,
pkt.encode(&mut slice)?; "packet exceeds maximum length"
} );
let packet_len_size = VarInt(packet_len as i32).written_size();
let data_prefix_len = packet_len_size + data_len_size;
self.buf.put_bytes(0, data_prefix_len);
self.buf
.copy_within(start_len..start_len + data_len, start_len + data_prefix_len);
let mut front = &mut self.buf[start_len..];
VarInt(packet_len as i32).encode(&mut front)?;
// Zero for no compression on this packet.
VarInt(0).encode(front)?;
} }
return Ok(()); return Ok(());
@ -143,27 +126,14 @@ impl PacketEncoder {
"packet exceeds maximum length" "packet exceeds maximum length"
); );
if APPEND { let packet_len_size = VarInt(packet_len as i32).written_size();
let mut writer = (&mut self.buf).writer();
VarInt(packet_len as i32).encode(&mut writer)?;
pkt.encode(&mut writer)?;
} else {
let mut slice = move_forward_by(
&mut self.buf,
VarInt(packet_len as i32).encoded_len() + packet_len,
);
VarInt(packet_len as i32).encode(&mut slice)?; self.buf.put_bytes(0, packet_len_size);
pkt.encode(&mut slice)?; self.buf
.copy_within(start_len..start_len + data_len, start_len + packet_len_size);
debug_assert!( let front = &mut self.buf[start_len..];
slice.is_empty(), VarInt(packet_len as i32).encode(front)?;
"actual size of {} packet differs from reported size (actual = {}, reported = {})",
pkt.packet_name(),
data_len - slice.len(),
data_len,
);
}
Ok(()) Ok(())
} }
@ -199,75 +169,98 @@ impl PacketEncoder {
} }
} }
/// Move the bytes in `bytes` forward by `count` bytes and return a pub fn encode_packet<P>(buf: &mut Vec<u8>, pkt: &P) -> Result<()>
/// mutable reference to the new space at the front.
fn move_forward_by(bytes: &mut BytesMut, count: usize) -> &mut [u8] {
let len = bytes.len();
bytes.put_bytes(0, count);
bytes.copy_within(..len, count);
&mut bytes[..count]
}
pub fn write_packet<W, P>(mut writer: W, packet: &P) -> Result<()>
where where
W: Write, P: EncodePacket + ?Sized,
P: Encode + Packet + ?Sized,
{ {
let packet_len = packet.encoded_len(); let start_len = buf.len();
pkt.encode_packet(&mut *buf)?;
let packet_len = buf.len() - start_len;
ensure!( ensure!(
packet_len <= MAX_PACKET_SIZE as usize, packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length" "packet exceeds maximum length"
); );
VarInt(packet_len as i32).encode(&mut writer)?; let packet_len_size = VarInt(packet_len as i32).written_size();
packet.encode(&mut writer)
buf.put_bytes(0, packet_len_size);
buf.copy_within(
start_len..start_len + packet_len,
start_len + packet_len_size,
);
let front = &mut buf[start_len..];
VarInt(packet_len as i32).encode(front)?;
Ok(())
} }
#[cfg(feature = "compression")] #[cfg(feature = "compression")]
pub fn write_packet_compressed<W, P>( pub fn encode_packet_compressed<P>(
mut writer: W, buf: &mut Vec<u8>,
pkt: &P,
threshold: u32, threshold: u32,
scratch: &mut Vec<u8>, scratch: &mut Vec<u8>,
packet: &P,
) -> Result<()> ) -> Result<()>
where where
W: Write, P: EncodePacket + ?Sized,
P: Encode + Packet + ?Sized,
{ {
use flate2::write::ZlibEncoder; use std::io::Read;
use flate2::bufread::ZlibEncoder;
use flate2::Compression; use flate2::Compression;
let data_len = packet.encoded_len(); let start_len = buf.len();
pkt.encode_packet(&mut *buf)?;
let data_len = buf.len() - start_len;
if data_len > threshold as usize { if data_len > threshold as usize {
let mut z = ZlibEncoder::new(&buf[start_len..], Compression::new(4));
scratch.clear(); scratch.clear();
let mut z = ZlibEncoder::new(&mut *scratch, Compression::new(4)); let data_len_size = VarInt(data_len as i32).written_size();
packet.encode(&mut z)?;
let packet_len = data_len_size + z.read_to_end(scratch)?;
ensure!(
packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);
drop(z); drop(z);
let packet_len = VarInt(data_len as i32).encoded_len() + scratch.len(); buf.truncate(start_len);
ensure!( VarInt(packet_len as i32).encode(&mut *buf)?;
packet_len <= MAX_PACKET_SIZE as usize, VarInt(data_len as i32).encode(&mut *buf)?;
"packet exceeds maximum length" buf.extend_from_slice(scratch);
);
VarInt(packet_len as i32).encode(&mut writer)?;
VarInt(data_len as i32).encode(&mut writer)?;
writer.write_all(scratch)?;
} else { } else {
let packet_len = VarInt(0).encoded_len() + data_len; let data_len_size = 1;
let packet_len = data_len_size + data_len;
ensure!( ensure!(
packet_len <= MAX_PACKET_SIZE as usize, packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length" "packet exceeds maximum length"
); );
VarInt(packet_len as i32).encode(&mut writer)?; let packet_len_size = VarInt(packet_len as i32).written_size();
VarInt(0).encode(&mut writer)?; // 0 for no compression on this packet.
packet.encode(&mut writer)?; let data_prefix_len = packet_len_size + data_len_size;
buf.put_bytes(0, data_prefix_len);
buf.copy_within(start_len..start_len + data_len, start_len + data_prefix_len);
let mut front = &mut buf[start_len..];
VarInt(packet_len as i32).encode(&mut front)?;
// Zero for no compression on this packet.
VarInt(0).encode(front)?;
} }
Ok(()) Ok(())
@ -292,7 +285,7 @@ impl PacketDecoder {
pub fn try_next_packet<'a, P>(&'a mut self) -> Result<Option<P>> pub fn try_next_packet<'a, P>(&'a mut self) -> Result<Option<P>>
where where
P: Decode<'a> + Packet, P: DecodePacket<'a>,
{ {
self.buf.advance(self.cursor); self.buf.advance(self.cursor);
self.cursor = 0; self.cursor = 0;
@ -318,6 +311,13 @@ impl PacketDecoder {
#[cfg(feature = "compression")] #[cfg(feature = "compression")]
let packet = if self.compression_enabled { let packet = if self.compression_enabled {
use std::io::Read;
use anyhow::Context;
use flate2::bufread::ZlibDecoder;
use crate::Decode;
let data_len = VarInt::decode(&mut r)?.0; let data_len = VarInt::decode(&mut r)?.0;
ensure!( ensure!(
@ -326,11 +326,6 @@ impl PacketDecoder {
); );
if data_len != 0 { if data_len != 0 {
use std::io::Read;
use anyhow::Context;
use flate2::bufread::ZlibDecoder;
self.decompress_buf.clear(); self.decompress_buf.clear();
self.decompress_buf.reserve_exact(data_len as usize); self.decompress_buf.reserve_exact(data_len as usize);
let mut z = ZlibDecoder::new(r).take(data_len as u64); let mut z = ZlibDecoder::new(r).take(data_len as u64);
@ -339,16 +334,16 @@ impl PacketDecoder {
.context("decompressing packet")?; .context("decompressing packet")?;
r = &self.decompress_buf; r = &self.decompress_buf;
P::decode(&mut r)? P::decode_packet(&mut r)?
} else { } else {
P::decode(&mut r)? P::decode_packet(&mut r)?
} }
} else { } else {
P::decode(&mut r)? P::decode_packet(&mut r)?
}; };
#[cfg(not(feature = "compression"))] #[cfg(not(feature = "compression"))]
let packet = P::decode(&mut r)?; let packet = P::decode_packet(&mut r)?;
ensure!( ensure!(
r.is_empty(), r.is_empty(),
@ -356,7 +351,7 @@ impl PacketDecoder {
r.len() r.len()
); );
let total_packet_len = VarInt(packet_len).encoded_len() + packet_len as usize; let total_packet_len = VarInt(packet_len).written_size() + packet_len as usize;
self.cursor = total_packet_len; self.cursor = total_packet_len;
Ok(Some(packet)) Ok(Some(packet))
@ -440,11 +435,12 @@ mod tests {
use crate::text::{Text, TextFormat}; use crate::text::{Text, TextFormat};
use crate::username::Username; use crate::username::Username;
use crate::var_long::VarLong; use crate::var_long::VarLong;
use crate::Decode;
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
const CRYPT_KEY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; const CRYPT_KEY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
#[derive(PartialEq, Debug, Encode, Decode, Packet)] #[derive(PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 42] #[packet_id = 42]
struct TestPacket<'a> { struct TestPacket<'a> {
a: bool, a: bool,
@ -507,6 +503,7 @@ mod tests {
enc.enable_encryption(&CRYPT_KEY); enc.enable_encryption(&CRYPT_KEY);
enc.append_packet(&TestPacket::new("third")).unwrap(); enc.append_packet(&TestPacket::new("third")).unwrap();
enc.prepend_packet(&TestPacket::new("fourth")).unwrap(); enc.prepend_packet(&TestPacket::new("fourth")).unwrap();
buf.unsplit(enc.take()); buf.unsplit(enc.take());
let mut dec = PacketDecoder::new(); let mut dec = PacketDecoder::new();

View file

@ -265,10 +265,6 @@ impl<S: Encode> Encode for Ident<S> {
fn encode(&self, w: impl Write) -> anyhow::Result<()> { fn encode(&self, w: impl Write) -> anyhow::Result<()> {
self.string.encode(w) self.string.encode(w)
} }
fn encoded_len(&self) -> usize {
self.string.encoded_len()
}
} }
impl<'a, S> Decode<'a> for Ident<S> impl<'a, S> Decode<'a> for Ident<S>

View file

@ -1,11 +1,11 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::io::Write; use std::io::Write;
use std::mem; use std::mem::MaybeUninit;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::{io, mem};
use anyhow::ensure; use anyhow::ensure;
use arrayvec::ArrayVec;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use uuid::Uuid; use uuid::Uuid;
use valence_nbt::Compound; use valence_nbt::Compound;
@ -19,9 +19,12 @@ impl Encode for bool {
Ok(w.write_u8(*self as u8)?) Ok(w.write_u8(*self as u8)?)
} }
fn encoded_len(&self) -> usize { fn write_slice(slice: &[bool], mut w: impl Write) -> io::Result<()> {
1 let bytes: &[u8] = unsafe { mem::transmute(slice) };
w.write_all(bytes)
} }
const HAS_WRITE_SLICE: bool = true;
} }
impl Decode<'_> for bool { impl Decode<'_> for bool {
@ -37,9 +40,11 @@ impl Encode for u8 {
Ok(w.write_u8(*self)?) Ok(w.write_u8(*self)?)
} }
fn encoded_len(&self) -> usize { fn write_slice(slice: &[u8], mut w: impl Write) -> io::Result<()> {
1 w.write_all(slice)
} }
const HAS_WRITE_SLICE: bool = true;
} }
impl Decode<'_> for u8 { impl Decode<'_> for u8 {
@ -53,9 +58,15 @@ impl Encode for i8 {
Ok(w.write_i8(*self)?) Ok(w.write_i8(*self)?)
} }
fn encoded_len(&self) -> usize { fn write_slice(slice: &[i8], mut w: impl Write) -> io::Result<()>
1 where
Self: Sized,
{
let bytes: &[u8] = unsafe { mem::transmute(slice) };
w.write_all(bytes)
} }
const HAS_WRITE_SLICE: bool = true;
} }
impl Decode<'_> for i8 { impl Decode<'_> for i8 {
@ -68,10 +79,6 @@ impl Encode for u16 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u16::<BigEndian>(*self)?) Ok(w.write_u16::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
2
}
} }
impl Decode<'_> for u16 { impl Decode<'_> for u16 {
@ -84,10 +91,6 @@ impl Encode for i16 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i16::<BigEndian>(*self)?) Ok(w.write_i16::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
2
}
} }
impl Decode<'_> for i16 { impl Decode<'_> for i16 {
@ -100,10 +103,6 @@ impl Encode for u32 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u32::<BigEndian>(*self)?) Ok(w.write_u32::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
4
}
} }
impl Decode<'_> for u32 { impl Decode<'_> for u32 {
@ -116,10 +115,6 @@ impl Encode for i32 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i32::<BigEndian>(*self)?) Ok(w.write_i32::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
4
}
} }
impl Decode<'_> for i32 { impl Decode<'_> for i32 {
@ -132,10 +127,6 @@ impl Encode for u64 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u64::<BigEndian>(*self)?) Ok(w.write_u64::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
8
}
} }
impl Decode<'_> for u64 { impl Decode<'_> for u64 {
@ -154,10 +145,6 @@ impl Encode for u128 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u128::<BigEndian>(*self)?) Ok(w.write_u128::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
16
}
} }
impl Decode<'_> for u128 { impl Decode<'_> for u128 {
@ -170,10 +157,6 @@ impl Encode for i128 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i128::<BigEndian>(*self)?) Ok(w.write_i128::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
16
}
} }
impl Decode<'_> for i128 { impl Decode<'_> for i128 {
@ -186,10 +169,6 @@ impl Encode for i64 {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i64::<BigEndian>(*self)?) Ok(w.write_i64::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
8
}
} }
impl Encode for f32 { impl Encode for f32 {
@ -201,10 +180,6 @@ impl Encode for f32 {
); );
Ok(w.write_f32::<BigEndian>(*self)?) Ok(w.write_f32::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
4
}
} }
impl Decode<'_> for f32 { impl Decode<'_> for f32 {
@ -224,10 +199,6 @@ impl Encode for f64 {
); );
Ok(w.write_f64::<BigEndian>(*self)?) Ok(w.write_f64::<BigEndian>(*self)?)
} }
fn encoded_len(&self) -> usize {
8
}
} }
impl Decode<'_> for f64 { impl Decode<'_> for f64 {
@ -244,30 +215,18 @@ impl<T: Encode + ?Sized> Encode for &T {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
(**self).encode(w) (**self).encode(w)
} }
fn encoded_len(&self) -> usize {
(**self).encoded_len()
}
} }
impl<T: Encode + ?Sized> Encode for &mut T { impl<T: Encode + ?Sized> Encode for &mut T {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
(**self).encode(w) (**self).encode(w)
} }
fn encoded_len(&self) -> usize {
(**self).encoded_len()
}
} }
impl<T: Encode + ?Sized> Encode for Box<T> { impl<T: Encode + ?Sized> Encode for Box<T> {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w) self.as_ref().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
} }
impl<'a, T: Decode<'a>> Decode<'a> for Box<T> { impl<'a, T: Decode<'a>> Decode<'a> for Box<T> {
@ -280,10 +239,6 @@ impl<T: Encode + ?Sized> Encode for Rc<T> {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w) self.as_ref().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
} }
impl<'a, T: Decode<'a>> Decode<'a> for Rc<T> { impl<'a, T: Decode<'a>> Decode<'a> for Rc<T> {
@ -296,10 +251,6 @@ impl<T: Encode + ?Sized> Encode for Arc<T> {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w) self.as_ref().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
} }
impl<'a, T: Decode<'a>> Decode<'a> for Arc<T> { impl<'a, T: Decode<'a>> Decode<'a> for Arc<T> {
@ -321,11 +272,6 @@ macro_rules! impl_tuple {
)* )*
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
let ($($ty,)*) = self;
0 $(+ $ty.encoded_len())*
}
} }
impl<'a, $($ty: Decode<'a>,)*> Decode<'a> for ($($ty,)*) { impl<'a, $($ty: Decode<'a>,)*> Decode<'a> for ($($ty,)*) {
@ -355,28 +301,42 @@ impl_tuple!(A B C D E F G H I J K L);
/// Like tuples, arrays are encoded and decoded without a VarInt length prefix. /// Like tuples, arrays are encoded and decoded without a VarInt length prefix.
impl<const N: usize, T: Encode> Encode for [T; N] { impl<const N: usize, T: Encode> Encode for [T; N] {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
if T::HAS_WRITE_SLICE {
return Ok(T::write_slice(self, w)?);
}
for t in self { for t in self {
t.encode(&mut w)?; t.encode(&mut w)?;
} }
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
self.iter().map(|t| t.encoded_len()).sum()
}
} }
impl<'a, const N: usize, T: Decode<'a>> Decode<'a> for [T; N] { impl<'a, const N: usize, T: Decode<'a>> Decode<'a> for [T; N] {
fn decode(r: &mut &'a [u8]) -> Result<Self> { fn decode(r: &mut &'a [u8]) -> Result<Self> {
// TODO: rewrite using std::array::try_from_fn when stabilized. // TODO: rewrite using std::array::try_from_fn when stabilized?
// TODO: specialization for [f64; 3] improved performance.
let mut elems = ArrayVec::new(); let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
for _ in 0..N {
elems.push(T::decode(r)?); for (i, elem) in data.iter_mut().enumerate() {
match T::decode(r) {
Ok(val) => {
elem.write(val);
}
Err(e) => {
// Call destructors for values decoded so far.
for elem in &mut data[..i] {
unsafe { elem.assume_init_drop() };
}
return Err(e);
}
}
} }
elems.into_inner().map_err(|_| unreachable!()) // All values in `data` are initialized.
unsafe { Ok(mem::transmute_copy(&data)) }
} }
} }
@ -404,17 +364,17 @@ impl<T: Encode> Encode for [T] {
); );
VarInt(len as i32).encode(&mut w)?; VarInt(len as i32).encode(&mut w)?;
if T::HAS_WRITE_SLICE {
return Ok(T::write_slice(self, w)?);
}
for t in self { for t in self {
t.encode(&mut w)?; t.encode(&mut w)?;
} }
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
let elems_len: usize = self.iter().map(|a| a.encoded_len()).sum();
VarInt(self.len().try_into().unwrap_or(i32::MAX)).encoded_len() + elems_len
}
} }
impl<'a> Decode<'a> for &'a [u8] { impl<'a> Decode<'a> for &'a [u8] {
@ -430,14 +390,18 @@ impl<'a> Decode<'a> for &'a [u8] {
} }
} }
impl<'a> Decode<'a> for &'a [i8] {
fn decode(r: &mut &'a [u8]) -> Result<Self> {
let unsigned_bytes = <&[u8]>::decode(r)?;
let signed_bytes: &[i8] = unsafe { mem::transmute(unsigned_bytes) };
Ok(signed_bytes)
}
}
impl<T: Encode> Encode for Vec<T> { impl<T: Encode> Encode for Vec<T> {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_slice().encode(w) self.as_slice().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_slice().encoded_len()
}
} }
impl<'a, T: Decode<'a>> Decode<'a> for Vec<T> { impl<'a, T: Decode<'a>> Decode<'a> for Vec<T> {
@ -478,10 +442,6 @@ impl Encode for str {
VarInt(self.len() as i32).encode(&mut w)?; VarInt(self.len() as i32).encode(&mut w)?;
Ok(w.write_all(self.as_bytes())?) Ok(w.write_all(self.as_bytes())?)
} }
fn encoded_len(&self) -> usize {
VarInt(self.len().try_into().unwrap_or(i32::MAX)).encoded_len() + self.len()
}
} }
impl<'a> Decode<'a> for &'a str { impl<'a> Decode<'a> for &'a str {
@ -502,10 +462,6 @@ impl Encode for String {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_str().encode(w) self.as_str().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_str().encoded_len()
}
} }
impl Decode<'_> for String { impl Decode<'_> for String {
@ -532,10 +488,6 @@ impl<T: Encode> Encode for Option<T> {
None => false.encode(w), None => false.encode(w),
} }
} }
fn encoded_len(&self) -> usize {
1 + self.as_ref().map_or(0, |t| t.encoded_len())
}
} }
impl<'a, T: Decode<'a>> Decode<'a> for Option<T> { impl<'a, T: Decode<'a>> Decode<'a> for Option<T> {
@ -554,10 +506,6 @@ where
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w) self.as_ref().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
} }
impl<'a, B> Decode<'a> for Cow<'a, B> impl<'a, B> Decode<'a> for Cow<'a, B>
@ -574,10 +522,6 @@ impl Encode for Uuid {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_u128().encode(w) self.as_u128().encode(w)
} }
fn encoded_len(&self) -> usize {
16
}
} }
impl<'a> Decode<'a> for Uuid { impl<'a> Decode<'a> for Uuid {
@ -590,10 +534,6 @@ impl Encode for Compound {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
Ok(valence_nbt::to_binary_writer(w, self, "")?) Ok(valence_nbt::to_binary_writer(w, self, "")?)
} }
fn encoded_len(&self) -> usize {
self.binary_encoded_len("")
}
} }
impl Decode<'_> for Compound { impl Decode<'_> for Compound {

View file

@ -42,10 +42,6 @@ impl Encode for Option<ItemStack> {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w) self.as_ref().encode(w)
} }
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
} }
impl<'a> Encode for Option<&'a ItemStack> { impl<'a> Encode for Option<&'a ItemStack> {
@ -63,17 +59,6 @@ impl<'a> Encode for Option<&'a ItemStack> {
} }
} }
} }
fn encoded_len(&self) -> usize {
match *self {
None => 1,
Some(s) => {
1 + s.item.encoded_len()
+ 1
+ s.nbt.as_ref().map(|nbt| nbt.encoded_len()).unwrap_or(1)
}
}
}
} }
impl Decode<'_> for Option<ItemStack> { impl Decode<'_> for Option<ItemStack> {
@ -106,10 +91,6 @@ impl Encode for ItemKind {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
VarInt(self.to_raw() as i32).encode(w) VarInt(self.to_raw() as i32).encode(w)
} }
fn encoded_len(&self) -> usize {
VarInt(self.to_raw() as i32).encoded_len()
}
} }
impl Decode<'_> for ItemKind { impl Decode<'_> for ItemKind {

View file

@ -44,7 +44,6 @@
//! //!
//! TODO //! TODO
#![forbid(unsafe_code)]
#![deny( #![deny(
rustdoc::broken_intra_doc_links, rustdoc::broken_intra_doc_links,
rustdoc::private_intra_doc_links, rustdoc::private_intra_doc_links,
@ -69,6 +68,7 @@
// Allows us to use our own proc macros internally. // Allows us to use our own proc macros internally.
extern crate self as valence_protocol; extern crate self as valence_protocol;
use std::io;
use std::io::Write; use std::io::Write;
pub use anyhow::{Error, Result}; pub use anyhow::{Error, Result};
@ -84,13 +84,11 @@ pub use raw_bytes::RawBytes;
pub use text::{Text, TextFormat}; pub use text::{Text, TextFormat};
pub use username::Username; pub use username::Username;
pub use uuid::Uuid; pub use uuid::Uuid;
pub use valence_derive::{Decode, Encode, Packet}; pub use valence_derive::{Decode, DecodePacket, Encode, EncodePacket};
pub use var_int::VarInt; pub use var_int::VarInt;
pub use var_long::VarLong; pub use var_long::VarLong;
pub use {uuid, valence_nbt as nbt}; pub use {uuid, valence_nbt as nbt};
use crate::byte_counter::ByteCounter;
/// The Minecraft protocol version this library currently targets. /// The Minecraft protocol version this library currently targets.
pub const PROTOCOL_VERSION: i32 = 760; pub const PROTOCOL_VERSION: i32 = 760;
@ -103,7 +101,6 @@ pub mod block;
mod block_pos; mod block_pos;
mod bounded; mod bounded;
mod byte_angle; mod byte_angle;
mod byte_counter;
mod codec; mod codec;
pub mod enchant; pub mod enchant;
pub mod entity_meta; pub mod entity_meta;
@ -117,7 +114,7 @@ pub mod text;
pub mod translation_key; pub mod translation_key;
pub mod types; pub mod types;
pub mod username; pub mod username;
mod var_int; pub mod var_int;
mod var_long; mod var_long;
/// Used only by proc macros. Not public API. /// Used only by proc macros. Not public API.
@ -125,7 +122,7 @@ mod var_long;
pub mod __private { pub mod __private {
pub use anyhow::{anyhow, bail, ensure, Context, Result}; pub use anyhow::{anyhow, bail, ensure, Context, Result};
pub use crate::{Decode, DerivedPacketDecode, DerivedPacketEncode, Encode, VarInt}; pub use crate::{Decode, DecodePacket, Encode, EncodePacket, VarInt};
} }
/// The maximum number of bytes in a single Minecraft packet. /// The maximum number of bytes in a single Minecraft packet.
@ -141,22 +138,15 @@ pub const MAX_PACKET_SIZE: i32 = 2097152;
/// implement `Encode`. Components are encoded in the order they appear in the /// implement `Encode`. Components are encoded in the order they appear in the
/// type definition. /// type definition.
/// ///
/// If a `#[packet_id = ...]` attribute is present, encoding the type begins by
/// writing the specified constant [`VarInt`] value before any of the
/// components.
///
/// For enums, the variant to encode is marked by a leading [`VarInt`] /// For enums, the variant to encode is marked by a leading [`VarInt`]
/// discriminant (tag). The discriminant value can be changed using the `#[tag = /// discriminant (tag). The discriminant value can be changed using the `#[tag =
/// ...]` attribute on the variant in question. Discriminant values are assigned /// ...]` attribute on the variant in question. Discriminant values are assigned
/// to variants using rules similar to regular enum discriminants. /// to variants using rules similar to regular enum discriminants.
/// ///
/// [`VarInt`]: var_int::VarInt
///
/// ``` /// ```
/// use valence_protocol::Encode; /// use valence_protocol::Encode;
/// ///
/// #[derive(Encode)] /// #[derive(Encode)]
/// #[packet_id = 42]
/// struct MyStruct<'a> { /// struct MyStruct<'a> {
/// first: i32, /// first: i32,
/// second: &'a str, /// second: &'a str,
@ -193,32 +183,22 @@ pub trait Encode {
/// the data that was written to the writer. The exact number of bytes /// the data that was written to the writer. The exact number of bytes
/// that were originally written must be consumed during the decoding. /// that were originally written must be consumed during the decoding.
/// ///
/// Additionally, this function must be pure. If no write error occurs,
/// successive calls to `encode` must write the same bytes to the writer
/// argument. This property can be broken by using internal mutability,
/// global state, or other tricks.
///
/// [`decode`]: Decode::decode /// [`decode`]: Decode::decode
fn encode(&self, w: impl Write) -> Result<()>; fn encode(&self, w: impl Write) -> Result<()>;
/// Returns the number of bytes that will be written when [`Self::encode`] /// Hack to get around the lack of specialization. Not public API.
/// is called. #[doc(hidden)]
/// fn write_slice(slice: &[Self], w: impl Write) -> io::Result<()>
/// If [`Self::encode`] returns `Ok`, then the exact number of bytes where
/// reported by this function must be written to the writer argument. Self: Sized,
/// {
/// If the result is `Err`, then the number of written bytes must be less let _ = (slice, w);
/// than or equal to the count returned by this function. unimplemented!("for internal use in valence_protocol only")
///
/// # Default Implementation
///
/// Calls [`Self::encode`] to count the number of written bytes. This is
/// always correct, but is not always the most efficient approach.
fn encoded_len(&self) -> usize {
let mut counter = ByteCounter::new();
let _ = self.encode(&mut counter);
counter.0
} }
/// Hack to get around the lack of specialization. Not public API.
#[doc(hidden)]
const HAS_WRITE_SLICE: bool = false;
} }
/// The `Decode` trait allows objects to be read from the Minecraft protocol. It /// The `Decode` trait allows objects to be read from the Minecraft protocol. It
@ -234,10 +214,6 @@ pub trait Encode {
/// implement `Decode`. Components are decoded in the order they appear in the /// implement `Decode`. Components are decoded in the order they appear in the
/// type definition. /// type definition.
/// ///
/// If a `#[packet_id = ...]` attribute is present, encoding the type begins by
/// reading the specified constant [`VarInt`] value before any of the
/// components.
///
/// For enums, the variant to decode is determined by a leading [`VarInt`] /// For enums, the variant to decode is determined by a leading [`VarInt`]
/// discriminant (tag). The discriminant value can be changed using the `#[tag = /// discriminant (tag). The discriminant value can be changed using the `#[tag =
/// ...]` attribute on the variant in question. Discriminant values are assigned /// ...]` attribute on the variant in question. Discriminant values are assigned
@ -247,7 +223,6 @@ pub trait Encode {
/// use valence_protocol::Decode; /// use valence_protocol::Decode;
/// ///
/// #[derive(PartialEq, Debug, Decode)] /// #[derive(PartialEq, Debug, Decode)]
/// #[packet_id = 5]
/// struct MyStruct { /// struct MyStruct {
/// first: i32, /// first: i32,
/// second: MyEnum, /// second: MyEnum,
@ -262,7 +237,7 @@ pub trait Encode {
/// Fourth, // tag = 26 /// Fourth, // tag = 26
/// } /// }
/// ///
/// let mut r: &[u8] = &[5, 0, 0, 0, 0, 26]; /// let mut r: &[u8] = &[0, 0, 0, 0, 26];
/// ///
/// let value = MyStruct::decode(&mut r).unwrap(); /// let value = MyStruct::decode(&mut r).unwrap();
/// let expected = MyStruct { /// let expected = MyStruct {
@ -283,60 +258,80 @@ pub trait Decode<'a>: Sized {
fn decode(r: &mut &'a [u8]) -> Result<Self>; fn decode(r: &mut &'a [u8]) -> Result<Self>;
} }
/// Marker for types that are encoded or decoded as complete packets. /// Like [`Encode`], but implementations must write a leading [`VarInt`] packet
/// ID before any other data.
/// ///
/// A complete packet is data starting with a [`VarInt`] packet ID. [`Encode`] /// # Deriving
/// and [`Decode`] implementations on `Self`, if present, are expected to handle ///
/// this leading `VarInt`. /// This trait can be implemented automatically by using the
pub trait Packet { /// [`EncodePacket`][macro] derive macro. The trait is implemented by writing
/// The name of this packet. /// the packet ID provided in the `#[packet_id = ...]` helper attribute followed
/// /// by a call to [`Encode::encode`].
/// This is usually the name of the type representing the packet without any ///
/// generic parameters or other decorations. /// ```
fn packet_name(&self) -> &'static str; /// use valence_protocol::{Encode, EncodePacket};
///
/// #[derive(Encode, EncodePacket)]
/// #[packet_id = 42]
/// struct MyStruct {
/// first: i32,
/// }
///
/// let value = MyStruct { first: 123 };
/// let mut buf = vec![];
///
/// value.encode_packet(&mut buf).unwrap();
/// println!("{buf:?}");
/// ```
///
/// [macro]: valence_derive::DecodePacket
pub trait EncodePacket {
/// The packet ID that is written when [`Self::encode_packet`] is called. A
/// negative value indicates that the packet ID is not statically known.
const PACKET_ID: i32 = -1;
/// Like [`Encode::encode`], but a leading [`VarInt`] packet ID must be
/// written first.
fn encode_packet(&self, w: impl Write) -> Result<()>;
} }
/// Packets which obtained [`Encode`] implementations via the [`Encode`][macro] /// Like [`Decode`], but implementations must read a leading [`VarInt`] packet
/// derive macro with the `#[packet_id = ...]` attribute. /// ID before any other data.
/// ///
/// Along with [`DerivedPacketDecode`], this trait can be occasionally useful /// # Deriving
/// for automating tasks such as defining large packet enums. Otherwise, this
/// trait should not be used and has thus been hidden from the documentation.
/// ///
/// [macro]: valence_derive::Encode /// This trait can be implemented automatically by using the
#[doc(hidden)] /// [`DecodePacket`][macro] derive macro. The trait is implemented by reading
pub trait DerivedPacketEncode: Encode { /// the packet ID provided in the `#[packet_id = ...]` helper attribute followed
/// The ID of this packet specified with `#[packet_id = ...]`. /// by a call to [`Decode::decode`].
const ID: i32; ///
/// The name of the type implementing this trait. /// ```
const NAME: &'static str; /// use valence_protocol::{Decode, DecodePacket};
///
/// #[derive(Decode, DecodePacket)]
/// #[packet_id = 42]
/// struct MyStruct {
/// first: i32,
/// }
///
/// let buf = [42, 0, 0, 0, 0];
/// let mut r = buf.as_slice();
///
/// let value = MyStruct::decode_packet(&mut r).unwrap();
///
/// assert_eq!(value.first, 0);
/// assert!(r.is_empty());
/// ```
///
/// [macro]: valence_protocol::DecodePacket
pub trait DecodePacket<'a>: Sized {
/// The packet ID that is read when [`Self::decode_packet`] is called. A
/// negative value indicates that the packet ID is not statically known.
const PACKET_ID: i32 = -1;
/// Like [`Encode::encode`], but does not write a leading [`VarInt`] packet /// Like [`Decode::decode`], but a leading [`VarInt`] packet ID must be read
/// ID. /// first.
fn encode_without_id(&self, w: impl Write) -> Result<()>; fn decode_packet(r: &mut &'a [u8]) -> Result<Self>;
/// Like [`Encode::encoded_len`], but does not count a leading [`VarInt`]
/// packet ID.
fn encoded_len_without_id(&self) -> usize;
}
/// Packets which obtained [`Decode`] implementations via the [`Decode`][macro]
/// derive macro with the `#[packet_id = ...]` attribute.
///
/// Along with [`DerivedPacketEncode`], this trait can be occasionally useful
/// for automating tasks such as defining large packet enums. Otherwise, this
/// trait should not be used and has thus been hidden from the documentation.
///
/// [macro]: valence_derive::Decode
#[doc(hidden)]
pub trait DerivedPacketDecode<'a>: Decode<'a> {
/// The ID of this packet specified with `#[packet_id = ...]`.
const ID: i32;
/// The name of the type implementing this trait.
const NAME: &'static str;
/// Like [`Decode::decode`], but does not decode a leading [`VarInt`] packet
/// ID.
fn decode_without_id(r: &mut &'a [u8]) -> Result<Self>;
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -344,7 +339,7 @@ pub trait DerivedPacketDecode<'a>: Decode<'a> {
mod derive_tests { mod derive_tests {
use super::*; use super::*;
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 1] #[packet_id = 1]
struct RegularStruct { struct RegularStruct {
foo: i32, foo: i32,
@ -352,30 +347,30 @@ mod derive_tests {
baz: f64, baz: f64,
} }
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 2] #[packet_id = 2]
struct UnitStruct; struct UnitStruct;
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 3] #[packet_id = 3]
struct EmptyStruct {} struct EmptyStruct {}
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 4] #[packet_id = 4]
struct TupleStruct(i32, bool, f64); struct TupleStruct(i32, bool, f64);
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 5] #[packet_id = 5]
struct StructWithGenerics<'z, T = ()> { struct StructWithGenerics<'z, T = ()> {
foo: &'z str, foo: &'z str,
bar: T, bar: T,
} }
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 6] #[packet_id = 6]
struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T); struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T);
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 7] #[packet_id = 7]
enum RegularEnum { enum RegularEnum {
Empty, Empty,
@ -383,11 +378,11 @@ mod derive_tests {
Fields { foo: i32, bar: bool, baz: f64 }, Fields { foo: i32, bar: bool, baz: f64 },
} }
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 8] #[packet_id = 8]
enum EmptyEnum {} enum EmptyEnum {}
#[derive(Encode, Decode, Packet)] #[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0xbeef] #[packet_id = 0xbeef]
enum EnumWithGenericsAndTags<'z, T = ()> { enum EnumWithGenericsAndTags<'z, T = ()> {
#[tag = 5] #[tag = 5]
@ -404,7 +399,7 @@ mod derive_tests {
#[allow(unconditional_recursion)] #[allow(unconditional_recursion)]
fn has_impls<'a, T>() fn has_impls<'a, T>()
where where
T: Encode + Decode<'a> + DerivedPacketEncode + DerivedPacketDecode<'a> + Packet, T: Encode + EncodePacket + Decode<'a> + DecodePacket<'a>,
{ {
has_impls::<RegularStruct>(); has_impls::<RegularStruct>();
has_impls::<UnitStruct>(); has_impls::<UnitStruct>();

View file

@ -35,59 +35,38 @@ macro_rules! packet_enum {
} }
)* )*
impl<$enum_life> crate::Encode for $enum_name<$enum_life> { impl<$enum_life> crate::EncodePacket for $enum_name<$enum_life> {
fn encode(&self, mut w: impl std::io::Write) -> crate::Result<()> { fn encode_packet(&self, mut w: impl std::io::Write) -> crate::Result<()> {
use crate::DerivedPacketEncode; use crate::{Encode, VarInt};
use crate::var_int::VarInt;
match self { match self {
$( $(
Self::$packet(pkt) => { Self::$packet(pkt) => {
VarInt($packet::ID).encode(&mut w)?; VarInt(<$packet as crate::EncodePacket>::PACKET_ID).encode(&mut w)?;
pkt.encode_without_id(w)?; pkt.encode(w)?;
} }
)* )*
} }
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
match self {
$(
Self::$packet(pkt) => {
pkt.encoded_len()
}
)*
}
}
} }
impl<$enum_life> crate::Decode<$enum_life> for $enum_name<$enum_life> { impl<$enum_life> crate::DecodePacket<$enum_life> for $enum_name<$enum_life> {
fn decode(r: &mut &$enum_life [u8]) -> crate::Result<Self> { fn decode_packet(r: &mut &$enum_life [u8]) -> crate::Result<Self> {
use crate::DerivedPacketDecode; use crate::{Decode, VarInt};
use crate::var_int::VarInt;
let id = VarInt::decode(r)?.0; let id = VarInt::decode(r)?.0;
Ok(match id { Ok(match id {
$( $(
$packet::ID => Self::$packet($packet::decode_without_id(r)?), <$packet as crate::DecodePacket>::PACKET_ID =>
Self::$packet($packet::decode(r)?),
)* )*
id => anyhow::bail!("unknown packet id {}", id), id => anyhow::bail!("unknown packet id {}", id),
}) })
} }
} }
impl<$enum_life> crate::Packet for $enum_name<$enum_life> {
fn packet_name(&self) -> &'static str {
match self {
$(
Self::$packet(pkt) => pkt.packet_name(),
)*
}
}
}
impl<$enum_life> std::fmt::Debug for $enum_name<$enum_life> { impl<$enum_life> std::fmt::Debug for $enum_name<$enum_life> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@ -120,59 +99,38 @@ macro_rules! packet_enum {
} }
)* )*
impl crate::Encode for $enum_name { impl crate::EncodePacket for $enum_name {
fn encode(&self, mut w: impl std::io::Write) -> crate::Result<()> { fn encode_packet(&self, mut w: impl std::io::Write) -> crate::Result<()> {
use crate::DerivedPacketEncode; use crate::{Encode, VarInt};
use crate::var_int::VarInt;
match self { match self {
$( $(
Self::$packet(pkt) => { Self::$packet(pkt) => {
VarInt($packet::ID).encode(&mut w)?; VarInt(<$packet as crate::EncodePacket>::PACKET_ID).encode(&mut w)?;
pkt.encode_without_id(w)?; pkt.encode(w)?;
} }
)* )*
} }
Ok(()) Ok(())
} }
fn encoded_len(&self) -> usize {
match self {
$(
Self::$packet(pkt) => {
pkt.encoded_len()
}
)*
}
}
} }
impl crate::Decode<'_> for $enum_name { impl crate::DecodePacket<'_> for $enum_name {
fn decode(r: &mut &[u8]) -> crate::Result<Self> { fn decode_packet(r: &mut &[u8]) -> crate::Result<Self> {
use crate::DerivedPacketDecode; use crate::{Decode, VarInt};
use crate::var_int::VarInt;
let id = VarInt::decode(r)?.0; let id = VarInt::decode(r)?.0;
Ok(match id { Ok(match id {
$( $(
$packet::ID => Self::$packet($packet::decode_without_id(r)?), <$packet as crate::DecodePacket>::PACKET_ID =>
Self::$packet($packet::decode(r)?),
)* )*
id => anyhow::bail!("unknown packet id {}", id), id => anyhow::bail!("unknown packet id {}", id),
}) })
} }
} }
impl crate::Packet for $enum_name {
fn packet_name(&self) -> &'static str {
match self {
$(
Self::$packet(pkt) => pkt.packet_name(),
)*
}
}
}
impl std::fmt::Debug for $enum_name { impl std::fmt::Debug for $enum_name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {

View file

@ -15,12 +15,12 @@ use crate::types::{
use crate::username::Username; use crate::username::Username;
use crate::var_int::VarInt; use crate::var_int::VarInt;
use crate::var_long::VarLong; use crate::var_long::VarLong;
use crate::{Decode, Encode, Packet}; use crate::{Decode, DecodePacket, Encode, EncodePacket};
pub mod handshake { pub mod handshake {
use super::*; use super::*;
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct Handshake<'a> { pub struct Handshake<'a> {
pub protocol_version: VarInt, pub protocol_version: VarInt,
@ -29,7 +29,7 @@ pub mod handshake {
pub next_state: HandshakeNextState, pub next_state: HandshakeNextState,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct HandshakeOwned { pub struct HandshakeOwned {
pub protocol_version: VarInt, pub protocol_version: VarInt,
@ -49,11 +49,11 @@ pub mod handshake {
pub mod status { pub mod status {
use super::*; use super::*;
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct StatusRequest; pub struct StatusRequest;
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x01] #[packet_id = 0x01]
pub struct PingRequest { pub struct PingRequest {
pub payload: u64, pub payload: u64,
@ -71,7 +71,7 @@ pub mod status {
pub mod login { pub mod login {
use super::*; use super::*;
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct LoginStart<'a> { pub struct LoginStart<'a> {
pub username: Username<&'a str>, pub username: Username<&'a str>,
@ -79,14 +79,14 @@ pub mod login {
pub profile_id: Option<Uuid>, pub profile_id: Option<Uuid>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x01] #[packet_id = 0x01]
pub struct EncryptionResponse<'a> { pub struct EncryptionResponse<'a> {
pub shared_secret: &'a [u8], pub shared_secret: &'a [u8],
pub sig_or_token: MsgSigOrVerifyToken<'a>, pub sig_or_token: MsgSigOrVerifyToken<'a>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x02] #[packet_id = 0x02]
pub struct LoginPluginResponse<'a> { pub struct LoginPluginResponse<'a> {
pub message_id: VarInt, pub message_id: VarInt,
@ -106,28 +106,28 @@ pub mod login {
pub mod play { pub mod play {
use super::*; use super::*;
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct ConfirmTeleport { pub struct ConfirmTeleport {
pub teleport_id: VarInt, pub teleport_id: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x01] #[packet_id = 0x01]
pub struct QueryBlockEntityTag { pub struct QueryBlockEntityTag {
pub transaction_id: VarInt, pub transaction_id: VarInt,
pub position: BlockPos, pub position: BlockPos,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x02] #[packet_id = 0x02]
pub struct ChangeDifficulty(pub Difficulty); pub struct ChangeDifficulty(pub Difficulty);
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x03] #[packet_id = 0x03]
pub struct MessageAcknowledgmentC2s<'a>(pub MessageAcknowledgment<'a>); pub struct MessageAcknowledgmentC2s<'a>(pub MessageAcknowledgment<'a>);
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x04] #[packet_id = 0x04]
pub struct ChatCommand<'a> { pub struct ChatCommand<'a> {
pub command: &'a str, pub command: &'a str,
@ -138,7 +138,7 @@ pub mod play {
pub acknowledgement: MessageAcknowledgment<'a>, pub acknowledgement: MessageAcknowledgment<'a>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x05] #[packet_id = 0x05]
pub struct ChatMessage<'a> { pub struct ChatMessage<'a> {
pub message: &'a str, pub message: &'a str,
@ -149,20 +149,20 @@ pub mod play {
pub acknowledgement: MessageAcknowledgment<'a>, pub acknowledgement: MessageAcknowledgment<'a>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x06] #[packet_id = 0x06]
pub struct ChatPreviewC2s { pub struct ChatPreviewC2s {
// TODO // TODO
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x07] #[packet_id = 0x07]
pub enum ClientCommand { pub enum ClientCommand {
PerformRespawn, PerformRespawn,
RequestStats, RequestStats,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x08] #[packet_id = 0x08]
pub struct ClientInformation<'a> { pub struct ClientInformation<'a> {
pub locale: &'a str, pub locale: &'a str,
@ -175,21 +175,21 @@ pub mod play {
pub allow_server_listings: bool, pub allow_server_listings: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x09] #[packet_id = 0x09]
pub struct CommandSuggestionsRequest<'a> { pub struct CommandSuggestionsRequest<'a> {
pub transaction_id: VarInt, pub transaction_id: VarInt,
pub text: &'a str, pub text: &'a str,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0a] #[packet_id = 0x0a]
pub struct ClickContainerButton { pub struct ClickContainerButton {
pub window_id: i8, pub window_id: i8,
pub button_id: i8, pub button_id: i8,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0b] #[packet_id = 0x0b]
pub struct ClickContainer { pub struct ClickContainer {
pub window_id: u8, pub window_id: u8,
@ -201,20 +201,20 @@ pub mod play {
pub carried_item: Option<ItemStack>, pub carried_item: Option<ItemStack>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0c] #[packet_id = 0x0c]
pub struct CloseContainerC2s { pub struct CloseContainerC2s {
pub window_id: i8, pub window_id: i8,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0d] #[packet_id = 0x0d]
pub struct PluginMessageC2s<'a> { pub struct PluginMessageC2s<'a> {
pub channel: Ident<&'a str>, pub channel: Ident<&'a str>,
pub data: RawBytes<'a>, pub data: RawBytes<'a>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0e] #[packet_id = 0x0e]
pub struct EditBook<'a> { pub struct EditBook<'a> {
pub slot: VarInt, pub slot: VarInt,
@ -222,14 +222,14 @@ pub mod play {
pub title: Option<&'a str>, pub title: Option<&'a str>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0f] #[packet_id = 0x0f]
pub struct QueryEntityTag { pub struct QueryEntityTag {
pub transaction_id: VarInt, pub transaction_id: VarInt,
pub entity_id: VarInt, pub entity_id: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x10] #[packet_id = 0x10]
pub struct Interact { pub struct Interact {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -237,7 +237,7 @@ pub mod play {
pub sneaking: bool, pub sneaking: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x11] #[packet_id = 0x11]
pub struct JigsawGenerate { pub struct JigsawGenerate {
pub position: BlockPos, pub position: BlockPos,
@ -245,24 +245,24 @@ pub mod play {
pub keep_jigsaws: bool, pub keep_jigsaws: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x12] #[packet_id = 0x12]
pub struct KeepAliveC2s { pub struct KeepAliveC2s {
pub id: u64, pub id: u64,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x13] #[packet_id = 0x13]
pub struct LockDifficulty(pub bool); pub struct LockDifficulty(pub bool);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x14] #[packet_id = 0x14]
pub struct SetPlayerPosition { pub struct SetPlayerPosition {
pub position: [f64; 3], pub position: [f64; 3],
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x15] #[packet_id = 0x15]
pub struct SetPlayerPositionAndRotation { pub struct SetPlayerPositionAndRotation {
pub position: [f64; 3], pub position: [f64; 3],
@ -271,7 +271,7 @@ pub mod play {
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x16] #[packet_id = 0x16]
pub struct SetPlayerRotation { pub struct SetPlayerRotation {
pub yaw: f32, pub yaw: f32,
@ -279,11 +279,11 @@ pub mod play {
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x17] #[packet_id = 0x17]
pub struct SetPlayerOnGround(pub bool); pub struct SetPlayerOnGround(pub bool);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x18] #[packet_id = 0x18]
pub struct MoveVehicleC2s { pub struct MoveVehicleC2s {
pub position: [f64; 3], pub position: [f64; 3],
@ -291,20 +291,20 @@ pub mod play {
pub pitch: f32, pub pitch: f32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x19] #[packet_id = 0x19]
pub struct PaddleBoat { pub struct PaddleBoat {
pub left_paddle_turning: bool, pub left_paddle_turning: bool,
pub right_paddle_turning: bool, pub right_paddle_turning: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1a] #[packet_id = 0x1a]
pub struct PickItem { pub struct PickItem {
pub slot_to_use: VarInt, pub slot_to_use: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1b] #[packet_id = 0x1b]
pub struct PlaceRecipe<'a> { pub struct PlaceRecipe<'a> {
pub window_id: i8, pub window_id: i8,
@ -312,7 +312,7 @@ pub mod play {
pub make_all: bool, pub make_all: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1c] #[packet_id = 0x1c]
pub enum PlayerAbilitiesC2s { pub enum PlayerAbilitiesC2s {
#[tag = 0b00] #[tag = 0b00]
@ -321,7 +321,7 @@ pub mod play {
StartFlying, StartFlying,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1d] #[packet_id = 0x1d]
pub struct PlayerAction { pub struct PlayerAction {
pub status: DiggingStatus, pub status: DiggingStatus,
@ -330,7 +330,7 @@ pub mod play {
pub sequence: VarInt, pub sequence: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1e] #[packet_id = 0x1e]
pub struct PlayerCommand { pub struct PlayerCommand {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -338,7 +338,7 @@ pub mod play {
pub jump_boost: VarInt, pub jump_boost: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1f] #[packet_id = 0x1f]
pub struct PlayerInput { pub struct PlayerInput {
pub sideways: f32, pub sideways: f32,
@ -346,13 +346,13 @@ pub mod play {
pub flags: PlayerInputFlags, pub flags: PlayerInputFlags,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x20] #[packet_id = 0x20]
pub struct PongPlay { pub struct PongPlay {
pub id: i32, pub id: i32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x21] #[packet_id = 0x21]
pub struct ChangeRecipeBookSettings { pub struct ChangeRecipeBookSettings {
pub book_id: RecipeBookId, pub book_id: RecipeBookId,
@ -360,19 +360,19 @@ pub mod play {
pub filter_active: bool, pub filter_active: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x22] #[packet_id = 0x22]
pub struct SetSeenRecipe<'a> { pub struct SetSeenRecipe<'a> {
pub recipe_id: Ident<&'a str>, pub recipe_id: Ident<&'a str>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x23] #[packet_id = 0x23]
pub struct RenameItem<'a> { pub struct RenameItem<'a> {
pub item_name: &'a str, pub item_name: &'a str,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x24] #[packet_id = 0x24]
pub enum ResourcePackC2s { pub enum ResourcePackC2s {
SuccessfullyLoaded, SuccessfullyLoaded,
@ -381,33 +381,33 @@ pub mod play {
Accepted, Accepted,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x25] #[packet_id = 0x25]
pub enum SeenAdvancements<'a> { pub enum SeenAdvancements<'a> {
OpenedTab { tab_id: Ident<&'a str> }, OpenedTab { tab_id: Ident<&'a str> },
ClosedScreen, ClosedScreen,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x26] #[packet_id = 0x26]
pub struct SelectTrade { pub struct SelectTrade {
pub selected_slot: VarInt, pub selected_slot: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x27] #[packet_id = 0x27]
pub struct SetBeaconEffect { pub struct SetBeaconEffect {
pub primary_effect: Option<VarInt>, pub primary_effect: Option<VarInt>,
pub secondary_effect: Option<VarInt>, pub secondary_effect: Option<VarInt>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x28] #[packet_id = 0x28]
pub struct SetHeldItemC2s { pub struct SetHeldItemC2s {
pub slot: i16, pub slot: i16,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x29] #[packet_id = 0x29]
pub struct ProgramCommandBlock<'a> { pub struct ProgramCommandBlock<'a> {
pub position: BlockPos, pub position: BlockPos,
@ -416,7 +416,7 @@ pub mod play {
pub flags: CommandBlockFlags, pub flags: CommandBlockFlags,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2a] #[packet_id = 0x2a]
pub struct ProgramCommandBlockMinecart<'a> { pub struct ProgramCommandBlockMinecart<'a> {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -424,14 +424,14 @@ pub mod play {
pub track_output: bool, pub track_output: bool,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2b] #[packet_id = 0x2b]
pub struct SetCreativeModeSlot { pub struct SetCreativeModeSlot {
pub slot: i16, pub slot: i16,
pub clicked_item: Option<ItemStack>, pub clicked_item: Option<ItemStack>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2c] #[packet_id = 0x2c]
pub struct ProgramJigsawBlock<'a> { pub struct ProgramJigsawBlock<'a> {
pub position: BlockPos, pub position: BlockPos,
@ -442,7 +442,7 @@ pub mod play {
pub joint_type: &'a str, pub joint_type: &'a str,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2d] #[packet_id = 0x2d]
pub struct ProgramStructureBlock<'a> { pub struct ProgramStructureBlock<'a> {
pub position: BlockPos, pub position: BlockPos,
@ -459,24 +459,24 @@ pub mod play {
pub flags: StructureBlockFlags, pub flags: StructureBlockFlags,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2e] #[packet_id = 0x2e]
pub struct UpdateSign<'a> { pub struct UpdateSign<'a> {
pub position: BlockPos, pub position: BlockPos,
pub lines: [&'a str; 4], pub lines: [&'a str; 4],
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2f] #[packet_id = 0x2f]
pub struct SwingArm(pub Hand); pub struct SwingArm(pub Hand);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x30] #[packet_id = 0x30]
pub struct TeleportToEntity { pub struct TeleportToEntity {
pub target: Uuid, pub target: Uuid,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x31] #[packet_id = 0x31]
pub struct UseItemOn { pub struct UseItemOn {
pub hand: Hand, pub hand: Hand,
@ -487,7 +487,7 @@ pub mod play {
pub sequence: VarInt, pub sequence: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x32] #[packet_id = 0x32]
pub struct UseItem { pub struct UseItem {
pub hand: Hand, pub hand: Hand,

View file

@ -1,5 +1,5 @@
use uuid::Uuid; use uuid::Uuid;
use valence_derive::{Decode, Encode, Packet}; use valence_derive::{Decode, DecodePacket, Encode, EncodePacket};
use valence_nbt::Compound; use valence_nbt::Compound;
use crate::block_pos::BlockPos; use crate::block_pos::BlockPos;
@ -21,13 +21,13 @@ use crate::LengthPrefixedArray;
pub mod status { pub mod status {
use super::*; use super::*;
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct StatusResponse<'a> { pub struct StatusResponse<'a> {
pub json: &'a str, pub json: &'a str,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x01] #[packet_id = 0x01]
pub struct PingResponse { pub struct PingResponse {
pub payload: u64, pub payload: u64,
@ -45,13 +45,13 @@ pub mod status {
pub mod login { pub mod login {
use super::*; use super::*;
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct DisconnectLogin { pub struct DisconnectLogin {
pub reason: Text, pub reason: Text,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x01] #[packet_id = 0x01]
pub struct EncryptionRequest<'a> { pub struct EncryptionRequest<'a> {
pub server_id: &'a str, pub server_id: &'a str,
@ -59,7 +59,7 @@ pub mod login {
pub verify_token: &'a [u8], pub verify_token: &'a [u8],
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x02] #[packet_id = 0x02]
pub struct LoginSuccess<'a> { pub struct LoginSuccess<'a> {
pub uuid: Uuid, pub uuid: Uuid,
@ -67,13 +67,13 @@ pub mod login {
pub properties: Vec<SignedProperty<'a>>, pub properties: Vec<SignedProperty<'a>>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x03] #[packet_id = 0x03]
pub struct SetCompression { pub struct SetCompression {
pub threshold: VarInt, pub threshold: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x04] #[packet_id = 0x04]
pub struct LoginPluginRequest<'a> { pub struct LoginPluginRequest<'a> {
pub message_id: VarInt, pub message_id: VarInt,
@ -96,7 +96,7 @@ pub mod login {
pub mod play { pub mod play {
use super::*; use super::*;
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x00] #[packet_id = 0x00]
pub struct SpawnEntity { pub struct SpawnEntity {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -111,7 +111,7 @@ pub mod play {
pub velocity: [i16; 3], pub velocity: [i16; 3],
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x01] #[packet_id = 0x01]
pub struct SpawnExperienceOrb { pub struct SpawnExperienceOrb {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -119,7 +119,7 @@ pub mod play {
pub count: i16, pub count: i16,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x02] #[packet_id = 0x02]
pub struct SpawnPlayer { pub struct SpawnPlayer {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -129,20 +129,20 @@ pub mod play {
pub pitch: ByteAngle, pub pitch: ByteAngle,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x03] #[packet_id = 0x03]
pub struct EntityAnimationS2c { pub struct EntityAnimationS2c {
pub entity_id: VarInt, pub entity_id: VarInt,
pub animation: u8, // TODO: use Animation enum. pub animation: u8, // TODO: use Animation enum.
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x05] #[packet_id = 0x05]
pub struct AcknowledgeBlockChange { pub struct AcknowledgeBlockChange {
pub sequence: VarInt, pub sequence: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x06] #[packet_id = 0x06]
pub struct SetBlockDestroyStage { pub struct SetBlockDestroyStage {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -150,7 +150,7 @@ pub mod play {
pub destroy_stage: u8, pub destroy_stage: u8,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x07] #[packet_id = 0x07]
pub struct BlockEntityData { pub struct BlockEntityData {
pub position: BlockPos, pub position: BlockPos,
@ -159,41 +159,41 @@ pub mod play {
pub data: Compound, pub data: Compound,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x09] #[packet_id = 0x09]
pub struct BlockUpdate { pub struct BlockUpdate {
pub position: BlockPos, pub position: BlockPos,
pub block_id: VarInt, pub block_id: VarInt,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0a] #[packet_id = 0x0a]
pub struct BossBar { pub struct BossBar {
pub id: Uuid, pub id: Uuid,
pub action: BossBarAction, pub action: BossBarAction,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0b] #[packet_id = 0x0b]
pub struct SetDifficulty { pub struct SetDifficulty {
pub difficulty: Difficulty, pub difficulty: Difficulty,
pub locked: bool, pub locked: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x0d] #[packet_id = 0x0d]
pub struct ClearTitles { pub struct ClearTitles {
pub reset: bool, pub reset: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x10] #[packet_id = 0x10]
pub struct CloseContainerS2c { pub struct CloseContainerS2c {
/// Ignored by notchian clients. /// Ignored by notchian clients.
pub window_id: u8, pub window_id: u8,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x11] #[packet_id = 0x11]
pub struct SetContainerContent { pub struct SetContainerContent {
pub window_id: u8, pub window_id: u8,
@ -202,7 +202,7 @@ pub mod play {
pub carried_item: Option<ItemStack>, pub carried_item: Option<ItemStack>,
} }
#[derive(Copy, Clone, Debug, Encode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket)]
#[packet_id = 0x11] #[packet_id = 0x11]
pub struct SetContainerContentEncode<'a> { pub struct SetContainerContentEncode<'a> {
pub window_id: u8, pub window_id: u8,
@ -211,7 +211,7 @@ pub mod play {
pub carried_item: &'a Option<ItemStack>, pub carried_item: &'a Option<ItemStack>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x12] #[packet_id = 0x12]
pub struct SetContainerProperty { pub struct SetContainerProperty {
pub window_id: u8, pub window_id: u8,
@ -219,7 +219,7 @@ pub mod play {
pub value: i16, pub value: i16,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x13] #[packet_id = 0x13]
pub struct SetContainerSlot { pub struct SetContainerSlot {
pub window_id: i8, pub window_id: i8,
@ -228,7 +228,7 @@ pub mod play {
pub slot_data: Option<ItemStack>, pub slot_data: Option<ItemStack>,
} }
#[derive(Clone, Debug, Encode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket)]
#[packet_id = 0x13] #[packet_id = 0x13]
pub struct SetContainerSlotEncode<'a> { pub struct SetContainerSlotEncode<'a> {
pub window_id: i8, pub window_id: i8,
@ -237,21 +237,21 @@ pub mod play {
pub slot_data: Option<&'a ItemStack>, pub slot_data: Option<&'a ItemStack>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x14] #[packet_id = 0x14]
pub struct SetCooldown { pub struct SetCooldown {
pub item_id: VarInt, pub item_id: VarInt,
pub cooldown_ticks: VarInt, pub cooldown_ticks: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x16] #[packet_id = 0x16]
pub struct PluginMessageS2c<'a> { pub struct PluginMessageS2c<'a> {
pub channel: Ident<&'a str>, pub channel: Ident<&'a str>,
pub data: RawBytes<'a>, pub data: RawBytes<'a>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x17] #[packet_id = 0x17]
pub struct CustomSoundEffect<'a> { pub struct CustomSoundEffect<'a> {
pub name: Ident<&'a str>, pub name: Ident<&'a str>,
@ -262,34 +262,34 @@ pub mod play {
pub seed: u64, pub seed: u64,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x19] #[packet_id = 0x19]
pub struct DisconnectPlay { pub struct DisconnectPlay {
pub reason: Text, pub reason: Text,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1a] #[packet_id = 0x1a]
pub struct EntityEvent { pub struct EntityEvent {
pub entity_id: i32, pub entity_id: i32,
pub entity_status: u8, pub entity_status: u8,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1c] #[packet_id = 0x1c]
pub struct UnloadChunk { pub struct UnloadChunk {
pub chunk_x: i32, pub chunk_x: i32,
pub chunk_z: i32, pub chunk_z: i32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1d] #[packet_id = 0x1d]
pub struct GameEvent { pub struct GameEvent {
pub reason: GameStateChangeReason, pub reason: GameStateChangeReason,
pub value: f32, pub value: f32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x1f] #[packet_id = 0x1f]
pub struct WorldBorderInitialize { pub struct WorldBorderInitialize {
pub x: f64, pub x: f64,
@ -302,13 +302,13 @@ pub mod play {
pub warning_time: VarInt, pub warning_time: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x20] #[packet_id = 0x20]
pub struct KeepAliveS2c { pub struct KeepAliveS2c {
pub id: u64, pub id: u64,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x21] #[packet_id = 0x21]
pub struct ChunkDataAndUpdateLight<'a> { pub struct ChunkDataAndUpdateLight<'a> {
pub chunk_x: i32, pub chunk_x: i32,
@ -325,7 +325,7 @@ pub mod play {
pub block_light_arrays: Vec<LengthPrefixedArray<u8, 2048>>, pub block_light_arrays: Vec<LengthPrefixedArray<u8, 2048>>,
} }
#[derive(Clone, Debug, Encode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket)]
#[packet_id = 0x21] #[packet_id = 0x21]
pub struct ChunkDataAndUpdateLightEncode<'a> { pub struct ChunkDataAndUpdateLightEncode<'a> {
pub chunk_x: i32, pub chunk_x: i32,
@ -342,7 +342,7 @@ pub mod play {
pub block_light_arrays: &'a [LengthPrefixedArray<u8, 2048>], pub block_light_arrays: &'a [LengthPrefixedArray<u8, 2048>],
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x23] #[packet_id = 0x23]
pub struct ParticleS2c<'a> { pub struct ParticleS2c<'a> {
pub particle_id: VarInt, pub particle_id: VarInt,
@ -354,7 +354,7 @@ pub mod play {
pub data: RawBytes<'a>, pub data: RawBytes<'a>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x25] #[packet_id = 0x25]
pub struct LoginPlay<'a> { pub struct LoginPlay<'a> {
pub entity_id: i32, pub entity_id: i32,
@ -378,7 +378,7 @@ pub mod play {
} }
// TODO: remove this. // TODO: remove this.
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x25] #[packet_id = 0x25]
pub struct LoginPlayOwned { pub struct LoginPlayOwned {
pub entity_id: i32, pub entity_id: i32,
@ -400,7 +400,7 @@ pub mod play {
pub last_death_location: Option<(Ident<String>, BlockPos)>, pub last_death_location: Option<(Ident<String>, BlockPos)>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x28] #[packet_id = 0x28]
pub struct UpdateEntityPosition { pub struct UpdateEntityPosition {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -408,7 +408,7 @@ pub mod play {
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x29] #[packet_id = 0x29]
pub struct UpdateEntityPositionAndRotation { pub struct UpdateEntityPositionAndRotation {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -418,7 +418,7 @@ pub mod play {
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2a] #[packet_id = 0x2a]
pub struct UpdateEntityRotation { pub struct UpdateEntityRotation {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -427,7 +427,7 @@ pub mod play {
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x2d] #[packet_id = 0x2d]
pub struct OpenScreen { pub struct OpenScreen {
pub window_id: VarInt, pub window_id: VarInt,
@ -435,14 +435,14 @@ pub mod play {
pub window_title: Text, pub window_title: Text,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x33] #[packet_id = 0x33]
pub struct PlayerChatMessage<'a> { pub struct PlayerChatMessage<'a> {
// TODO: A _lot_ of fields // TODO: A _lot_ of fields
pub data: RawBytes<'a>, pub data: RawBytes<'a>,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x36] #[packet_id = 0x36]
pub struct CombatDeath { pub struct CombatDeath {
pub player_id: VarInt, pub player_id: VarInt,
@ -451,7 +451,7 @@ pub mod play {
pub message: Text, pub message: Text,
} }
#[derive(Clone, PartialEq, Debug, Encode, Decode, Packet)] #[derive(Clone, PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x37] #[packet_id = 0x37]
pub enum PlayerInfo<'a> { pub enum PlayerInfo<'a> {
AddPlayer(Vec<PlayerInfoAddPlayer<'a>>), AddPlayer(Vec<PlayerInfoAddPlayer<'a>>),
@ -461,7 +461,7 @@ pub mod play {
RemovePlayer(Vec<Uuid>), RemovePlayer(Vec<Uuid>),
} }
#[derive(Copy, Clone, PartialEq, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x39] #[packet_id = 0x39]
pub struct SynchronizePlayerPosition { pub struct SynchronizePlayerPosition {
pub position: [f64; 3], pub position: [f64; 3],
@ -472,19 +472,19 @@ pub mod play {
pub dismount_vehicle: bool, pub dismount_vehicle: bool,
} }
#[derive(Clone, PartialEq, Debug, Encode, Decode, Packet)] #[derive(Clone, PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x3b] #[packet_id = 0x3b]
pub struct RemoveEntities { pub struct RemoveEntities {
pub entity_ids: Vec<VarInt>, pub entity_ids: Vec<VarInt>,
} }
#[derive(Copy, Clone, PartialEq, Debug, Encode, Packet)] #[derive(Copy, Clone, PartialEq, Debug, Encode, EncodePacket)]
#[packet_id = 0x3b] #[packet_id = 0x3b]
pub struct RemoveEntitiesEncode<'a> { pub struct RemoveEntitiesEncode<'a> {
pub entity_ids: &'a [VarInt], pub entity_ids: &'a [VarInt],
} }
#[derive(Clone, PartialEq, Debug, Encode, Decode, Packet)] #[derive(Clone, PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x3d] #[packet_id = 0x3d]
pub struct ResourcePackS2c<'a> { pub struct ResourcePackS2c<'a> {
pub url: &'a str, pub url: &'a str,
@ -493,7 +493,7 @@ pub mod play {
pub prompt_message: Option<Text>, pub prompt_message: Option<Text>,
} }
#[derive(Clone, PartialEq, Debug, Encode, Decode, Packet)] #[derive(Clone, PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x3e] #[packet_id = 0x3e]
pub struct Respawn<'a> { pub struct Respawn<'a> {
pub dimension_type_name: Ident<&'a str>, pub dimension_type_name: Ident<&'a str>,
@ -508,7 +508,7 @@ pub mod play {
} }
// TODO: remove // TODO: remove
#[derive(Clone, PartialEq, Debug, Encode, Decode, Packet)] #[derive(Clone, PartialEq, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x3e] #[packet_id = 0x3e]
pub struct RespawnOwned { pub struct RespawnOwned {
pub dimension_type_name: Ident<String>, pub dimension_type_name: Ident<String>,
@ -522,14 +522,14 @@ pub mod play {
pub last_death_location: Option<(Ident<String>, BlockPos)>, pub last_death_location: Option<(Ident<String>, BlockPos)>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x3f] #[packet_id = 0x3f]
pub struct SetHeadRotation { pub struct SetHeadRotation {
pub entity_id: VarInt, pub entity_id: VarInt,
pub head_yaw: ByteAngle, pub head_yaw: ByteAngle,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x40] #[packet_id = 0x40]
pub struct UpdateSectionBlocks { pub struct UpdateSectionBlocks {
pub chunk_section_position: i64, pub chunk_section_position: i64,
@ -537,7 +537,7 @@ pub mod play {
pub blocks: Vec<VarLong>, pub blocks: Vec<VarLong>,
} }
#[derive(Clone, Debug, Encode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket)]
#[packet_id = 0x40] #[packet_id = 0x40]
pub struct UpdateSectionBlocksEncode<'a> { pub struct UpdateSectionBlocksEncode<'a> {
pub chunk_section_position: i64, pub chunk_section_position: i64,
@ -545,49 +545,49 @@ pub mod play {
pub blocks: &'a [VarLong], pub blocks: &'a [VarLong],
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x43] #[packet_id = 0x43]
pub struct SetActionBarText(pub Text); pub struct SetActionBarText(pub Text);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x4a] #[packet_id = 0x4a]
pub struct SetHeldItemS2c { pub struct SetHeldItemS2c {
pub slot: u8, pub slot: u8,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x4b] #[packet_id = 0x4b]
pub struct SetCenterChunk { pub struct SetCenterChunk {
pub chunk_x: VarInt, pub chunk_x: VarInt,
pub chunk_z: VarInt, pub chunk_z: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x4c] #[packet_id = 0x4c]
pub struct SetRenderDistance(pub VarInt); pub struct SetRenderDistance(pub VarInt);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x4d] #[packet_id = 0x4d]
pub struct SetDefaultSpawnPosition { pub struct SetDefaultSpawnPosition {
pub position: BlockPos, pub position: BlockPos,
pub angle: f32, pub angle: f32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x50] #[packet_id = 0x50]
pub struct SetEntityMetadata<'a> { pub struct SetEntityMetadata<'a> {
pub entity_id: VarInt, pub entity_id: VarInt,
pub metadata: RawBytes<'a>, pub metadata: RawBytes<'a>,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x52] #[packet_id = 0x52]
pub struct SetEntityVelocity { pub struct SetEntityVelocity {
pub entity_id: VarInt, pub entity_id: VarInt,
pub velocity: [i16; 3], pub velocity: [i16; 3],
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x54] #[packet_id = 0x54]
pub struct SetExperience { pub struct SetExperience {
pub bar: f32, pub bar: f32,
@ -595,7 +595,7 @@ pub mod play {
pub total_xp: VarInt, pub total_xp: VarInt,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x55] #[packet_id = 0x55]
pub struct SetHealth { pub struct SetHealth {
pub health: f32, pub health: f32,
@ -603,11 +603,11 @@ pub mod play {
pub food_saturation: f32, pub food_saturation: f32,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x5b] #[packet_id = 0x5b]
pub struct SetSubtitleText(pub Text); pub struct SetSubtitleText(pub Text);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x5c] #[packet_id = 0x5c]
pub struct UpdateTime { pub struct UpdateTime {
/// The age of the world in 1/20ths of a second. /// The age of the world in 1/20ths of a second.
@ -618,11 +618,11 @@ pub mod play {
pub time_of_day: i64, pub time_of_day: i64,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x5d] #[packet_id = 0x5d]
pub struct SetTitleText(pub Text); pub struct SetTitleText(pub Text);
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x5e] #[packet_id = 0x5e]
pub struct SetTitleAnimationTimes { pub struct SetTitleAnimationTimes {
/// Ticks to spend fading in. /// Ticks to spend fading in.
@ -633,7 +633,7 @@ pub mod play {
pub fade_out: i32, pub fade_out: i32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x5f] #[packet_id = 0x5f]
pub struct EntitySoundEffect { pub struct EntitySoundEffect {
pub id: VarInt, pub id: VarInt,
@ -643,7 +643,7 @@ pub mod play {
pub pitch: f32, pub pitch: f32,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x60] #[packet_id = 0x60]
pub struct SoundEffect { pub struct SoundEffect {
pub id: VarInt, pub id: VarInt,
@ -654,7 +654,7 @@ pub mod play {
pub seed: i64, pub seed: i64,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x62] #[packet_id = 0x62]
pub struct SystemChatMessage { pub struct SystemChatMessage {
pub chat: Text, pub chat: Text,
@ -662,14 +662,14 @@ pub mod play {
pub kind: VarInt, pub kind: VarInt,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x63] #[packet_id = 0x63]
pub struct SetTabListHeaderAndFooter { pub struct SetTabListHeaderAndFooter {
pub header: Text, pub header: Text,
pub footer: Text, pub footer: Text,
} }
#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] #[derive(Copy, Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x66] #[packet_id = 0x66]
pub struct TeleportEntity { pub struct TeleportEntity {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -679,7 +679,7 @@ pub mod play {
pub on_ground: bool, pub on_ground: bool,
} }
#[derive(Clone, Debug, Encode, Decode, Packet)] #[derive(Clone, Debug, Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0x68] #[packet_id = 0x68]
pub struct UpdateAttributes<'a> { pub struct UpdateAttributes<'a> {
pub entity_id: VarInt, pub entity_id: VarInt,

View file

@ -3,7 +3,7 @@ use std::io::Write;
use crate::{Decode, Encode, Result}; use crate::{Decode, Encode, Result};
/// While [encoding], the contained slice is written directly to the output /// While [encoding], the contained slice is written directly to the output
/// without any metadata. /// without any length prefix or metadata.
/// ///
/// While [decoding], the remainder of the input is returned as the contained /// While [decoding], the remainder of the input is returned as the contained
/// slice. The input will be at the EOF state after this is finished. /// slice. The input will be at the EOF state after this is finished.
@ -17,10 +17,6 @@ impl Encode for RawBytes<'_> {
fn encode(&self, mut w: impl Write) -> Result<()> { fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_all(self.0)?) Ok(w.write_all(self.0)?)
} }
fn encoded_len(&self) -> usize {
self.0.len()
}
} }
impl<'a> Decode<'a> for RawBytes<'a> { impl<'a> Decode<'a> for RawBytes<'a> {

View file

@ -7,8 +7,7 @@ use std::io::Write;
use serde::de::Visitor; use serde::de::Visitor;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use crate::byte_counter::ByteCounter; use crate::{Decode, Encode, Ident, Result};
use crate::{Decode, Encode, Ident, Result, VarInt};
/// Represents formatted text in Minecraft's JSON text format. /// Represents formatted text in Minecraft's JSON text format.
/// ///
@ -732,18 +731,10 @@ impl fmt::Display for Text {
} }
} }
/// Encode implementation for Text is not very fast. Beware.
impl Encode for Text { impl Encode for Text {
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
serde_json::to_string(self)?.encode(w) serde_json::to_string(self)?.encode(w)
} }
fn encoded_len(&self) -> usize {
let mut counter = ByteCounter::new();
let _ = serde_json::to_writer(&mut counter, self);
VarInt(counter.0.try_into().unwrap_or(i32::MAX)).encoded_len() + counter.0
}
} }
impl Decode<'_> for Text { impl Decode<'_> for Text {

View file

@ -133,10 +133,6 @@ where
fn encode(&self, w: impl Write) -> Result<()> { fn encode(&self, w: impl Write) -> Result<()> {
self.0.encode(w) self.0.encode(w)
} }
fn encoded_len(&self) -> usize {
self.0.encoded_len()
}
} }
impl<'a, S> Decode<'a> for Username<S> impl<'a, S> Decode<'a> for Username<S>

View file

@ -8,6 +8,7 @@ use crate::{Decode, Encode};
/// An `i32` encoded with variable length. /// An `i32` encoded with variable length.
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct VarInt(pub i32); pub struct VarInt(pub i32);
impl VarInt { impl VarInt {
@ -15,6 +16,15 @@ impl VarInt {
/// written to the Minecraft protocol. /// written to the Minecraft protocol.
pub const MAX_SIZE: usize = 5; pub const MAX_SIZE: usize = 5;
/// Returns the exact number of bytes this varint will write when
/// [`Encode::encode`] is called, assuming no error occurs.
pub fn written_size(self) -> usize {
match self.0 {
0 => 1,
n => (31 - n.leading_zeros() as usize) / 7 + 1,
}
}
pub fn decode_partial(mut r: impl Read) -> Result<i32, VarIntDecodeError> { pub fn decode_partial(mut r: impl Read) -> Result<i32, VarIntDecodeError> {
let mut val = 0; let mut val = 0;
for i in 0..Self::MAX_SIZE { for i in 0..Self::MAX_SIZE {
@ -49,14 +59,6 @@ impl Encode for VarInt {
val >>= 7; val >>= 7;
} }
} }
#[inline]
fn encoded_len(&self) -> usize {
match self.0 {
0 => 1,
n => (31 - n.leading_zeros() as usize) / 7 + 1,
}
}
} }
impl Decode<'_> for VarInt { impl Decode<'_> for VarInt {
@ -92,7 +94,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn encoded_len_correct() { fn varint_written_size() {
let mut rng = thread_rng(); let mut rng = thread_rng();
let mut buf = vec![]; let mut buf = vec![];
@ -103,12 +105,12 @@ mod tests {
{ {
buf.clear(); buf.clear();
n.encode(&mut buf).unwrap(); n.encode(&mut buf).unwrap();
assert_eq!(buf.len(), n.encoded_len()); assert_eq!(buf.len(), n.written_size());
} }
} }
#[test] #[test]
fn encode_decode() { fn varint_round_trip() {
let mut rng = thread_rng(); let mut rng = thread_rng();
let mut buf = vec![]; let mut buf = vec![];

View file

@ -7,12 +7,22 @@ use crate::{Decode, Encode, Result};
/// An `i64` encoded with variable length. /// An `i64` encoded with variable length.
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct VarLong(pub i64); pub struct VarLong(pub i64);
impl VarLong { impl VarLong {
/// The maximum number of bytes a `VarLong` can occupy when read from and /// The maximum number of bytes a `VarLong` can occupy when read from and
/// written to the Minecraft protocol. /// written to the Minecraft protocol.
pub const MAX_SIZE: usize = 10; pub const MAX_SIZE: usize = 10;
/// Returns the exact number of bytes this varlong will write when
/// [`Encode::encode`] is called, assuming no error occurs.
pub fn written_size(self) -> usize {
match self.0 {
0 => 1,
n => (63 - n.leading_zeros() as usize) / 7 + 1,
}
}
} }
impl Encode for VarLong { impl Encode for VarLong {
@ -27,13 +37,6 @@ impl Encode for VarLong {
val >>= 7; val >>= 7;
} }
} }
fn encoded_len(&self) -> usize {
match self.0 {
0 => 1,
n => (63 - n.leading_zeros() as usize) / 7 + 1,
}
}
} }
impl Decode<'_> for VarLong { impl Decode<'_> for VarLong {