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]
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"] }
anyhow = "1"
chrono = "0.4.19"
regex = "1.6.0"

View file

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

View file

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

View file

@ -1,11 +1,11 @@
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 {
fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()>
where
P: Encode + Packet + ?Sized;
P: EncodePacket + ?Sized;
fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()>;
}
@ -13,7 +13,7 @@ pub trait WritePacket {
impl<W: WritePacket> WritePacket for &mut W {
fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()>
where
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
(*self).write_packet(packet)
}
@ -23,35 +23,35 @@ impl<W: WritePacket> WritePacket for &mut W {
}
}
pub struct PacketWriter<'a, W> {
writer: W,
pub struct PacketWriter<'a> {
buf: &'a mut Vec<u8>,
threshold: Option<u32>,
scratch: &'a mut Vec<u8>,
}
impl<'a, W: Write> PacketWriter<'a, W> {
pub fn new(writer: W, threshold: Option<u32>, scratch: &'a mut Vec<u8>) -> PacketWriter<W> {
impl<'a> PacketWriter<'a> {
pub fn new(buf: &'a mut Vec<u8>, threshold: Option<u32>, scratch: &'a mut Vec<u8>) -> Self {
Self {
writer,
buf,
threshold,
scratch,
}
}
}
impl<W: Write> WritePacket for PacketWriter<'_, W> {
fn write_packet<P>(&mut self, packet: &P) -> anyhow::Result<()>
impl WritePacket for PacketWriter<'_> {
fn write_packet<P>(&mut self, pkt: &P) -> anyhow::Result<()>
where
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
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 {
write_packet(&mut self.writer, packet)
encode_packet(self.buf, pkt)
}
}
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::time::timeout;
use tracing::debug;
use valence_protocol::{Decode, Encode, Packet, PacketDecoder, PacketEncoder};
use valence_protocol::{DecodePacket, EncodePacket, PacketDecoder, PacketEncoder};
use crate::packet::WritePacket;
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<()>
where
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
self.enc.append_packet(pkt)?;
let bytes = self.enc.take();
@ -60,7 +60,7 @@ where
pub async fn recv_packet<'a, P>(&'a mut self) -> Result<P>
where
P: Decode<'a> + Packet,
P: DecodePacket<'a>,
{
timeout(self.timeout, async {
while !self.dec.has_next_packet()? {
@ -196,7 +196,7 @@ pub struct PlayPacketSender {
impl PlayPacketSender {
pub fn append_packet<P>(&mut self, pkt: &P) -> Result<()>
where
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
self.enc.append_packet(pkt)
}
@ -207,7 +207,7 @@ impl PlayPacketSender {
pub fn prepend_packet<P>(&mut self, pkt: &P) -> Result<()>
where
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
self.enc.prepend_packet(pkt)
}
@ -222,7 +222,7 @@ impl PlayPacketSender {
impl WritePacket for PlayPacketSender {
fn write_packet<P>(&mut self, packet: &P) -> Result<()>
where
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
self.append_packet(packet)
}
@ -259,7 +259,7 @@ pub struct PlayPacketReceiver {
impl PlayPacketReceiver {
pub fn try_next_packet<'a, P>(&'a mut self) -> Result<Option<P>>
where
P: Decode<'a> + Packet,
P: DecodePacket<'a>,
{
self.dec.try_next_packet()
}

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use quote::quote;
use syn::spanned::Spanned;
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 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 {
return Err(Error::new(
@ -79,36 +73,15 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
Ok(quote! {
#[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
{
fn decode(_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);
)*
use ::valence_protocol::__private::{Decode, Context, ensure};
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_) => {
@ -170,16 +143,11 @@ pub fn derive_decode(item: TokenStream) -> Result<TokenStream> {
Ok(quote! {
#[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
{
fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result<Self> {
use ::valence_protocol::__private::{Decode, Context, VarInt, bail, ensure};
#(
let id = VarInt::decode(_r).context("failed to decode packet ID")?.0;
ensure!(id == #packet_id, "unexpected packet ID {} (expected {})", id, #packet_id);
)*
use ::valence_protocol::__private::{Decode, Context, VarInt, bail};
let disc = VarInt::decode(_r).context("failed to decode enum discriminant")?.0;
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(
@ -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 quote::{quote, ToTokens};
use quote::quote;
use syn::spanned::Spanned;
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 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<_>>();
add_trait_bounds(
&mut input.generics,
quote!(::valence_protocol::__private::Encode),
);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
match input.data {
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 {
Fields::Named(fields) => fields
.named
@ -49,87 +43,22 @@ pub fn derive_encode(item: TokenStream) -> Result<TokenStream> {
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! {
#[allow(unused_imports)]
impl #impl_generics ::valence_protocol::__private::Encode for #name #ty_generics
#where_clause
{
fn encode(&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")?;
)*
use ::valence_protocol::__private::{Encode, Context};
#encode_fields
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_) => {
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 encode_arms = variants
@ -211,45 +140,6 @@ pub fn derive_encode(item: TokenStream) -> Result<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! {
#[allow(unused_imports, unreachable_code)]
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<()> {
use ::valence_protocol::__private::{Encode, VarInt, Context};
#(
VarInt(#packet_id)
.encode(&mut _w)
.context("failed to encode packet ID")?;
)*
match self {
#encode_arms
_ => 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(
@ -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.
use proc_macro::TokenStream as StdTokenStream;
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{
parse2, parse_quote, Attribute, DeriveInput, Error, GenericParam, Generics, Lifetime,
LifetimeDef, Lit, LitInt, Meta, Result, Variant,
parse_quote, Attribute, Error, GenericParam, Generics, Lifetime, LifetimeDef, Lit, LitInt,
Meta, Result, Variant,
};
mod decode;
mod encode;
#[proc_macro_derive(Encode, attributes(packet_id, tag))]
#[proc_macro_derive(Encode, attributes(tag))]
pub fn derive_encode(item: StdTokenStream) -> StdTokenStream {
match encode::derive_encode(item.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 {
match decode::derive_decode(item.into()) {
Ok(tokens) => tokens.into(),
@ -30,41 +38,14 @@ pub fn derive_decode(item: StdTokenStream) -> StdTokenStream {
}
}
#[proc_macro_derive(Packet)]
pub fn derive_packet(item: StdTokenStream) -> StdTokenStream {
match derive_packet_inner(item.into()) {
#[proc_macro_derive(DecodePacket, attributes(packet_id))]
pub fn derive_decode_packet(item: StdTokenStream) -> StdTokenStream {
match decode::derive_decode_packet(item.into()) {
Ok(tokens) => tokens.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>> {
for attr in attrs {
if let Meta::NameValue(nv) = attr.parse_meta()? {

View file

@ -4,7 +4,7 @@ use std::hash::Hash;
use std::iter::FusedIterator;
use std::ops::{Index, IndexMut};
use crate::to_binary_writer::encoded_len;
use crate::to_binary_writer::written_size;
use crate::Value;
/// 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>;
impl Compound {
/// Returns the number of bytes that will be written with
/// [`to_binary_writer`] when called with this compound and root name.
/// Returns the number of bytes that will be written when
/// [`to_binary_writer`] is called with this compound and root name.
///
/// If [`to_binary_writer`] results in `Ok`, the exact number of bytes
/// 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 number of bytes that have actually 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
/// number of bytes that have actually been written.
///
/// [`to_binary_writer`]: crate::to_binary_writer()
pub fn binary_encoded_len(&self, root_name: &str) -> usize {
encoded_len(self, root_name)
pub fn written_size(&self, root_name: &str) -> usize {
written_size(self, root_name)
}
}

View file

@ -94,7 +94,7 @@ fn correct_length() {
let mut buf = vec![];
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")]

View file

@ -22,7 +22,7 @@ pub fn to_binary_writer<W: Write>(writer: W, compound: &Compound, root_name: &st
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 {
match val {
Value::Byte(_) => 1,

View file

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

View file

@ -5,12 +5,11 @@ use rand::Rng;
use valence_nbt::{compound, List};
use valence_protocol::block::{BlockKind, BlockState, PropName, PropValue};
use valence_protocol::packets::s2c::play::{
ChunkDataAndUpdateLight, ChunkDataAndUpdateLightEncode, SetTabListHeaderAndFooter,
TeleportEntity,
ChunkDataAndUpdateLight, ChunkDataAndUpdateLightEncode, SetTabListHeaderAndFooter, SpawnEntity,
};
use valence_protocol::text::Color;
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,
};
@ -18,7 +17,7 @@ criterion_group! {
name = benches;
config = Criterion::default()
.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);
@ -139,12 +138,16 @@ fn packets(c: &mut Criterion) {
threshold.",
};
let teleport_entity_packet = TeleportEntity {
entity_id: VarInt(123456),
let spawn_entity_packet = SpawnEntity {
entity_id: VarInt(1234),
object_uuid: Default::default(),
kind: VarInt(5),
position: [123.0, 456.0, 789.0],
yaw: ByteAngle(42),
pitch: ByteAngle(69),
on_ground: true,
pitch: ByteAngle(200),
yaw: ByteAngle(100),
head_yaw: ByteAngle(50),
data: VarInt(i32::MIN),
velocity: [12, 34, 56],
};
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(|| {
let encoder = black_box(&mut encoder);
encoder.clear();
encoder.append_packet(&teleport_entity_packet).unwrap();
encoder.append_packet(&spawn_entity_packet).unwrap();
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(|| {
let encoder = black_box(&mut encoder);
encoder.clear();
encoder.append_packet(&teleport_entity_packet).unwrap();
encoder.append_packet(&spawn_entity_packet).unwrap();
black_box(encoder);
});
@ -222,7 +225,7 @@ fn packets(c: &mut Criterion) {
let mut decoder = PacketDecoder::new();
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| {
b.iter(|| {
@ -238,7 +241,7 @@ fn packets(c: &mut Criterion) {
});
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| {
b.iter(|| {
@ -254,14 +257,14 @@ fn packets(c: &mut Criterion) {
});
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(|| {
let decoder = black_box(&mut decoder);
decoder.queue_slice(&packet_buf);
decoder.try_next_packet::<TeleportEntity>().unwrap();
decoder.try_next_packet::<SpawnEntity>().unwrap();
black_box(decoder);
});
@ -272,7 +275,7 @@ fn packets(c: &mut Criterion) {
let mut scratch = vec![];
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| {
b.iter(|| {
@ -288,11 +291,11 @@ fn packets(c: &mut Criterion) {
});
packet_buf.clear();
write_packet_compressed(
encode_packet_compressed(
&mut packet_buf,
&tab_list_header_footer_packet,
256,
&mut scratch,
&tab_list_header_footer_packet,
)
.unwrap();
@ -310,14 +313,14 @@ fn packets(c: &mut Criterion) {
});
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(|| {
let decoder = black_box(&mut decoder);
decoder.queue_slice(&packet_buf);
decoder.try_next_packet::<TeleportEntity>().unwrap();
decoder.try_next_packet::<SpawnEntity>().unwrap();
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)?;
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> {

View file

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

View file

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

View file

@ -29,10 +29,6 @@ where
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>
@ -82,10 +78,6 @@ where
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>

View file

@ -29,10 +29,6 @@ impl Encode for ByteAngle {
fn encode(&self, w: impl Write) -> Result<()> {
self.0.encode(w)
}
fn encoded_len(&self) -> usize {
self.0.encoded_len()
}
}
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")]
use aes::cipher::{AsyncStreamCipher, NewCipher};
use anyhow::{bail, ensure};
use bytes::{Buf, BufMut, BytesMut};
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
/// operation.
@ -29,108 +27,93 @@ impl PacketEncoder {
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]) {
self.buf.extend_from_slice(bytes)
}
pub fn prepend_packet<P>(&mut self, pkt: &P) -> Result<()>
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>(
&mut self,
pkt: &(impl Encode + Packet + ?Sized),
) -> Result<()> {
let data_len = pkt.encoded_len();
pub fn append_packet<P>(&mut self, pkt: &P) -> Result<()>
where
P: EncodePacket + ?Sized,
{
let start_len = self.buf.len();
#[cfg(debug_assertions)]
{
use crate::byte_counter::ByteCounter;
pkt.encode_packet((&mut self.buf).writer())?;
let mut counter = ByteCounter::new();
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()
);
}
let data_len = self.buf.len() - start_len;
#[cfg(feature = "compression")]
if let Some(threshold) = self.compression_threshold {
use flate2::write::ZlibEncoder;
use std::io::Read;
use flate2::bufread::ZlibEncoder;
use flate2::Compression;
if data_len >= threshold as usize {
let mut z = ZlibEncoder::new(&mut self.compress_buf, 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);
}
if data_len > threshold as usize {
let mut z = ZlibEncoder::new(&self.buf[start_len..], Compression::new(4));
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!(
packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);
drop(z);
self.buf.truncate(start_len);
let mut writer = (&mut self.buf).writer();
if APPEND {
VarInt(packet_len as i32).encode(&mut writer)?;
VarInt(0).encode(&mut writer)?; // 0 for no compression on this packet.
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 writer)?;
VarInt(data_len as i32).encode(&mut writer)?;
self.buf.extend_from_slice(&self.compress_buf);
} else {
let data_len_size = 1;
let packet_len = data_len_size + data_len;
VarInt(packet_len as i32).encode(&mut slice)?;
VarInt(0).encode(&mut slice)?;
pkt.encode(&mut slice)?;
}
ensure!(
packet_len <= MAX_PACKET_SIZE as usize,
"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(());
@ -143,27 +126,14 @@ impl PacketEncoder {
"packet exceeds maximum length"
);
if APPEND {
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,
);
let packet_len_size = VarInt(packet_len as i32).written_size();
VarInt(packet_len as i32).encode(&mut slice)?;
pkt.encode(&mut slice)?;
self.buf.put_bytes(0, packet_len_size);
self.buf
.copy_within(start_len..start_len + data_len, start_len + packet_len_size);
debug_assert!(
slice.is_empty(),
"actual size of {} packet differs from reported size (actual = {}, reported = {})",
pkt.packet_name(),
data_len - slice.len(),
data_len,
);
}
let front = &mut self.buf[start_len..];
VarInt(packet_len as i32).encode(front)?;
Ok(())
}
@ -199,75 +169,98 @@ impl PacketEncoder {
}
}
/// Move the bytes in `bytes` forward by `count` bytes and return a
/// 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<()>
pub fn encode_packet<P>(buf: &mut Vec<u8>, pkt: &P) -> Result<()>
where
W: Write,
P: Encode + Packet + ?Sized,
P: EncodePacket + ?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!(
packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);
VarInt(packet_len as i32).encode(&mut writer)?;
packet.encode(&mut writer)
let packet_len_size = VarInt(packet_len as i32).written_size();
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")]
pub fn write_packet_compressed<W, P>(
mut writer: W,
pub fn encode_packet_compressed<P>(
buf: &mut Vec<u8>,
pkt: &P,
threshold: u32,
scratch: &mut Vec<u8>,
packet: &P,
) -> Result<()>
where
W: Write,
P: Encode + Packet + ?Sized,
P: EncodePacket + ?Sized,
{
use flate2::write::ZlibEncoder;
use std::io::Read;
use flate2::bufread::ZlibEncoder;
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 {
let mut z = ZlibEncoder::new(&buf[start_len..], Compression::new(4));
scratch.clear();
let mut z = ZlibEncoder::new(&mut *scratch, Compression::new(4));
packet.encode(&mut z)?;
let data_len_size = VarInt(data_len as i32).written_size();
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);
let packet_len = VarInt(data_len as i32).encoded_len() + scratch.len();
buf.truncate(start_len);
ensure!(
packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);
VarInt(packet_len as i32).encode(&mut writer)?;
VarInt(data_len as i32).encode(&mut writer)?;
writer.write_all(scratch)?;
VarInt(packet_len as i32).encode(&mut *buf)?;
VarInt(data_len as i32).encode(&mut *buf)?;
buf.extend_from_slice(scratch);
} else {
let packet_len = VarInt(0).encoded_len() + data_len;
let data_len_size = 1;
let packet_len = data_len_size + data_len;
ensure!(
packet_len <= MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);
VarInt(packet_len as i32).encode(&mut writer)?;
VarInt(0).encode(&mut writer)?; // 0 for no compression on this packet.
packet.encode(&mut writer)?;
let packet_len_size = VarInt(packet_len as i32).written_size();
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(())
@ -292,7 +285,7 @@ impl PacketDecoder {
pub fn try_next_packet<'a, P>(&'a mut self) -> Result<Option<P>>
where
P: Decode<'a> + Packet,
P: DecodePacket<'a>,
{
self.buf.advance(self.cursor);
self.cursor = 0;
@ -318,6 +311,13 @@ impl PacketDecoder {
#[cfg(feature = "compression")]
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;
ensure!(
@ -326,11 +326,6 @@ impl PacketDecoder {
);
if data_len != 0 {
use std::io::Read;
use anyhow::Context;
use flate2::bufread::ZlibDecoder;
self.decompress_buf.clear();
self.decompress_buf.reserve_exact(data_len as usize);
let mut z = ZlibDecoder::new(r).take(data_len as u64);
@ -339,16 +334,16 @@ impl PacketDecoder {
.context("decompressing packet")?;
r = &self.decompress_buf;
P::decode(&mut r)?
P::decode_packet(&mut r)?
} else {
P::decode(&mut r)?
P::decode_packet(&mut r)?
}
} else {
P::decode(&mut r)?
P::decode_packet(&mut r)?
};
#[cfg(not(feature = "compression"))]
let packet = P::decode(&mut r)?;
let packet = P::decode_packet(&mut r)?;
ensure!(
r.is_empty(),
@ -356,7 +351,7 @@ impl PacketDecoder {
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;
Ok(Some(packet))
@ -440,11 +435,12 @@ mod tests {
use crate::text::{Text, TextFormat};
use crate::username::Username;
use crate::var_long::VarLong;
use crate::Decode;
#[cfg(feature = "encryption")]
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]
struct TestPacket<'a> {
a: bool,
@ -507,6 +503,7 @@ mod tests {
enc.enable_encryption(&CRYPT_KEY);
enc.append_packet(&TestPacket::new("third")).unwrap();
enc.prepend_packet(&TestPacket::new("fourth")).unwrap();
buf.unsplit(enc.take());
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<()> {
self.string.encode(w)
}
fn encoded_len(&self) -> usize {
self.string.encoded_len()
}
}
impl<'a, S> Decode<'a> for Ident<S>

View file

@ -1,11 +1,11 @@
use std::borrow::Cow;
use std::io::Write;
use std::mem;
use std::mem::MaybeUninit;
use std::rc::Rc;
use std::sync::Arc;
use std::{io, mem};
use anyhow::ensure;
use arrayvec::ArrayVec;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use uuid::Uuid;
use valence_nbt::Compound;
@ -19,9 +19,12 @@ impl Encode for bool {
Ok(w.write_u8(*self as u8)?)
}
fn encoded_len(&self) -> usize {
1
fn write_slice(slice: &[bool], mut w: impl Write) -> io::Result<()> {
let bytes: &[u8] = unsafe { mem::transmute(slice) };
w.write_all(bytes)
}
const HAS_WRITE_SLICE: bool = true;
}
impl Decode<'_> for bool {
@ -37,9 +40,11 @@ impl Encode for u8 {
Ok(w.write_u8(*self)?)
}
fn encoded_len(&self) -> usize {
1
fn write_slice(slice: &[u8], mut w: impl Write) -> io::Result<()> {
w.write_all(slice)
}
const HAS_WRITE_SLICE: bool = true;
}
impl Decode<'_> for u8 {
@ -53,9 +58,15 @@ impl Encode for i8 {
Ok(w.write_i8(*self)?)
}
fn encoded_len(&self) -> usize {
1
fn write_slice(slice: &[i8], mut w: impl Write) -> io::Result<()>
where
Self: Sized,
{
let bytes: &[u8] = unsafe { mem::transmute(slice) };
w.write_all(bytes)
}
const HAS_WRITE_SLICE: bool = true;
}
impl Decode<'_> for i8 {
@ -68,10 +79,6 @@ impl Encode for u16 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u16::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
2
}
}
impl Decode<'_> for u16 {
@ -84,10 +91,6 @@ impl Encode for i16 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i16::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
2
}
}
impl Decode<'_> for i16 {
@ -100,10 +103,6 @@ impl Encode for u32 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u32::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
4
}
}
impl Decode<'_> for u32 {
@ -116,10 +115,6 @@ impl Encode for i32 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i32::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
4
}
}
impl Decode<'_> for i32 {
@ -132,10 +127,6 @@ impl Encode for u64 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u64::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
8
}
}
impl Decode<'_> for u64 {
@ -154,10 +145,6 @@ impl Encode for u128 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_u128::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
16
}
}
impl Decode<'_> for u128 {
@ -170,10 +157,6 @@ impl Encode for i128 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i128::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
16
}
}
impl Decode<'_> for i128 {
@ -186,10 +169,6 @@ impl Encode for i64 {
fn encode(&self, mut w: impl Write) -> Result<()> {
Ok(w.write_i64::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
8
}
}
impl Encode for f32 {
@ -201,10 +180,6 @@ impl Encode for f32 {
);
Ok(w.write_f32::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
4
}
}
impl Decode<'_> for f32 {
@ -224,10 +199,6 @@ impl Encode for f64 {
);
Ok(w.write_f64::<BigEndian>(*self)?)
}
fn encoded_len(&self) -> usize {
8
}
}
impl Decode<'_> for f64 {
@ -244,30 +215,18 @@ impl<T: Encode + ?Sized> Encode for &T {
fn encode(&self, w: impl Write) -> Result<()> {
(**self).encode(w)
}
fn encoded_len(&self) -> usize {
(**self).encoded_len()
}
}
impl<T: Encode + ?Sized> Encode for &mut T {
fn encode(&self, w: impl Write) -> Result<()> {
(**self).encode(w)
}
fn encoded_len(&self) -> usize {
(**self).encoded_len()
}
}
impl<T: Encode + ?Sized> Encode for Box<T> {
fn encode(&self, w: impl Write) -> Result<()> {
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> {
@ -280,10 +239,6 @@ impl<T: Encode + ?Sized> Encode for Rc<T> {
fn encode(&self, w: impl Write) -> Result<()> {
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> {
@ -296,10 +251,6 @@ impl<T: Encode + ?Sized> Encode for Arc<T> {
fn encode(&self, w: impl Write) -> Result<()> {
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> {
@ -321,11 +272,6 @@ macro_rules! impl_tuple {
)*
Ok(())
}
fn encoded_len(&self) -> usize {
let ($($ty,)*) = self;
0 $(+ $ty.encoded_len())*
}
}
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.
impl<const N: usize, T: Encode> Encode for [T; N] {
fn encode(&self, mut w: impl Write) -> Result<()> {
if T::HAS_WRITE_SLICE {
return Ok(T::write_slice(self, w)?);
}
for t in self {
t.encode(&mut w)?;
}
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] {
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();
for _ in 0..N {
elems.push(T::decode(r)?);
let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
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)?;
if T::HAS_WRITE_SLICE {
return Ok(T::write_slice(self, w)?);
}
for t in self {
t.encode(&mut w)?;
}
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] {
@ -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> {
fn encode(&self, w: impl Write) -> Result<()> {
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> {
@ -478,10 +442,6 @@ impl Encode for str {
VarInt(self.len() as i32).encode(&mut w)?;
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 {
@ -502,10 +462,6 @@ impl Encode for String {
fn encode(&self, w: impl Write) -> Result<()> {
self.as_str().encode(w)
}
fn encoded_len(&self) -> usize {
self.as_str().encoded_len()
}
}
impl Decode<'_> for String {
@ -532,10 +488,6 @@ impl<T: Encode> Encode for Option<T> {
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> {
@ -554,10 +506,6 @@ where
fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w)
}
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
}
impl<'a, B> Decode<'a> for Cow<'a, B>
@ -574,10 +522,6 @@ impl Encode for Uuid {
fn encode(&self, w: impl Write) -> Result<()> {
self.as_u128().encode(w)
}
fn encoded_len(&self) -> usize {
16
}
}
impl<'a> Decode<'a> for Uuid {
@ -590,10 +534,6 @@ impl Encode for Compound {
fn encode(&self, w: impl Write) -> Result<()> {
Ok(valence_nbt::to_binary_writer(w, self, "")?)
}
fn encoded_len(&self) -> usize {
self.binary_encoded_len("")
}
}
impl Decode<'_> for Compound {

View file

@ -42,10 +42,6 @@ impl Encode for Option<ItemStack> {
fn encode(&self, w: impl Write) -> Result<()> {
self.as_ref().encode(w)
}
fn encoded_len(&self) -> usize {
self.as_ref().encoded_len()
}
}
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> {
@ -106,10 +91,6 @@ impl Encode for ItemKind {
fn encode(&self, w: impl Write) -> Result<()> {
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 {

View file

@ -44,7 +44,6 @@
//!
//! TODO
#![forbid(unsafe_code)]
#![deny(
rustdoc::broken_intra_doc_links,
rustdoc::private_intra_doc_links,
@ -69,6 +68,7 @@
// Allows us to use our own proc macros internally.
extern crate self as valence_protocol;
use std::io;
use std::io::Write;
pub use anyhow::{Error, Result};
@ -84,13 +84,11 @@ pub use raw_bytes::RawBytes;
pub use text::{Text, TextFormat};
pub use username::Username;
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_long::VarLong;
pub use {uuid, valence_nbt as nbt};
use crate::byte_counter::ByteCounter;
/// The Minecraft protocol version this library currently targets.
pub const PROTOCOL_VERSION: i32 = 760;
@ -103,7 +101,6 @@ pub mod block;
mod block_pos;
mod bounded;
mod byte_angle;
mod byte_counter;
mod codec;
pub mod enchant;
pub mod entity_meta;
@ -117,7 +114,7 @@ pub mod text;
pub mod translation_key;
pub mod types;
pub mod username;
mod var_int;
pub mod var_int;
mod var_long;
/// Used only by proc macros. Not public API.
@ -125,7 +122,7 @@ mod var_long;
pub mod __private {
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.
@ -141,22 +138,15 @@ pub const MAX_PACKET_SIZE: i32 = 2097152;
/// implement `Encode`. Components are encoded in the order they appear in the
/// 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`]
/// discriminant (tag). The discriminant value can be changed using the `#[tag =
/// ...]` attribute on the variant in question. Discriminant values are assigned
/// to variants using rules similar to regular enum discriminants.
///
/// [`VarInt`]: var_int::VarInt
///
/// ```
/// use valence_protocol::Encode;
///
/// #[derive(Encode)]
/// #[packet_id = 42]
/// struct MyStruct<'a> {
/// first: i32,
/// second: &'a str,
@ -193,32 +183,22 @@ pub trait Encode {
/// the data that was written to the writer. The exact number of bytes
/// 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
fn encode(&self, w: impl Write) -> Result<()>;
/// Returns the number of bytes that will be written when [`Self::encode`]
/// is called.
///
/// If [`Self::encode`] returns `Ok`, then the exact number of bytes
/// reported by this function must be written to the writer argument.
///
/// If the result is `Err`, then the number of written bytes must be less
/// than or equal to the count returned by this function.
///
/// # 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)]
fn write_slice(slice: &[Self], w: impl Write) -> io::Result<()>
where
Self: Sized,
{
let _ = (slice, w);
unimplemented!("for internal use in valence_protocol only")
}
/// 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
@ -234,10 +214,6 @@ pub trait Encode {
/// implement `Decode`. Components are decoded in the order they appear in the
/// 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`]
/// discriminant (tag). The discriminant value can be changed using the `#[tag =
/// ...]` attribute on the variant in question. Discriminant values are assigned
@ -247,7 +223,6 @@ pub trait Encode {
/// use valence_protocol::Decode;
///
/// #[derive(PartialEq, Debug, Decode)]
/// #[packet_id = 5]
/// struct MyStruct {
/// first: i32,
/// second: MyEnum,
@ -262,7 +237,7 @@ pub trait Encode {
/// 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 expected = MyStruct {
@ -283,60 +258,80 @@ pub trait Decode<'a>: Sized {
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`]
/// and [`Decode`] implementations on `Self`, if present, are expected to handle
/// this leading `VarInt`.
pub trait Packet {
/// The name of this packet.
///
/// This is usually the name of the type representing the packet without any
/// generic parameters or other decorations.
fn packet_name(&self) -> &'static str;
/// # Deriving
///
/// This trait can be implemented automatically by using the
/// [`EncodePacket`][macro] derive macro. The trait is implemented by writing
/// the packet ID provided in the `#[packet_id = ...]` helper attribute followed
/// by a call to [`Encode::encode`].
///
/// ```
/// 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]
/// derive macro with the `#[packet_id = ...]` attribute.
/// Like [`Decode`], but implementations must read a leading [`VarInt`] packet
/// ID before any other data.
///
/// Along with [`DerivedPacketDecode`], 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.
/// # Deriving
///
/// [macro]: valence_derive::Encode
#[doc(hidden)]
pub trait DerivedPacketEncode: Encode {
/// The ID of this packet specified with `#[packet_id = ...]`.
const ID: i32;
/// The name of the type implementing this trait.
const NAME: &'static str;
/// This trait can be implemented automatically by using the
/// [`DecodePacket`][macro] derive macro. The trait is implemented by reading
/// the packet ID provided in the `#[packet_id = ...]` helper attribute followed
/// by a call to [`Decode::decode`].
///
/// ```
/// 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
/// ID.
fn encode_without_id(&self, w: impl Write) -> Result<()>;
/// 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>;
/// Like [`Decode::decode`], but a leading [`VarInt`] packet ID must be read
/// first.
fn decode_packet(r: &mut &'a [u8]) -> Result<Self>;
}
#[allow(dead_code)]
@ -344,7 +339,7 @@ pub trait DerivedPacketDecode<'a>: Decode<'a> {
mod derive_tests {
use super::*;
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 1]
struct RegularStruct {
foo: i32,
@ -352,30 +347,30 @@ mod derive_tests {
baz: f64,
}
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 2]
struct UnitStruct;
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 3]
struct EmptyStruct {}
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 4]
struct TupleStruct(i32, bool, f64);
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 5]
struct StructWithGenerics<'z, T = ()> {
foo: &'z str,
bar: T,
}
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 6]
struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T);
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 7]
enum RegularEnum {
Empty,
@ -383,11 +378,11 @@ mod derive_tests {
Fields { foo: i32, bar: bool, baz: f64 },
}
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 8]
enum EmptyEnum {}
#[derive(Encode, Decode, Packet)]
#[derive(Encode, EncodePacket, Decode, DecodePacket)]
#[packet_id = 0xbeef]
enum EnumWithGenericsAndTags<'z, T = ()> {
#[tag = 5]
@ -404,7 +399,7 @@ mod derive_tests {
#[allow(unconditional_recursion)]
fn has_impls<'a, T>()
where
T: Encode + Decode<'a> + DerivedPacketEncode + DerivedPacketDecode<'a> + Packet,
T: Encode + EncodePacket + Decode<'a> + DecodePacket<'a>,
{
has_impls::<RegularStruct>();
has_impls::<UnitStruct>();

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ use std::io::Write;
use crate::{Decode, Encode, Result};
/// 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
/// 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<()> {
Ok(w.write_all(self.0)?)
}
fn encoded_len(&self) -> usize {
self.0.len()
}
}
impl<'a> Decode<'a> for RawBytes<'a> {

View file

@ -7,8 +7,7 @@ use std::io::Write;
use serde::de::Visitor;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use crate::byte_counter::ByteCounter;
use crate::{Decode, Encode, Ident, Result, VarInt};
use crate::{Decode, Encode, Ident, Result};
/// 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 {
fn encode(&self, w: impl Write) -> Result<()> {
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 {

View file

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

View file

@ -8,6 +8,7 @@ use crate::{Decode, Encode};
/// An `i32` encoded with variable length.
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct VarInt(pub i32);
impl VarInt {
@ -15,6 +16,15 @@ impl VarInt {
/// written to the Minecraft protocol.
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> {
let mut val = 0;
for i in 0..Self::MAX_SIZE {
@ -49,14 +59,6 @@ impl Encode for VarInt {
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 {
@ -92,7 +94,7 @@ mod tests {
use super::*;
#[test]
fn encoded_len_correct() {
fn varint_written_size() {
let mut rng = thread_rng();
let mut buf = vec![];
@ -103,12 +105,12 @@ mod tests {
{
buf.clear();
n.encode(&mut buf).unwrap();
assert_eq!(buf.len(), n.encoded_len());
assert_eq!(buf.len(), n.written_size());
}
}
#[test]
fn encode_decode() {
fn varint_round_trip() {
let mut rng = thread_rng();
let mut buf = vec![];

View file

@ -7,12 +7,22 @@ use crate::{Decode, Encode, Result};
/// An `i64` encoded with variable length.
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct VarLong(pub i64);
impl VarLong {
/// The maximum number of bytes a `VarLong` can occupy when read from and
/// written to the Minecraft protocol.
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 {
@ -27,13 +37,6 @@ impl Encode for VarLong {
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 {