mirror of
https://github.com/italicsjenga/valence.git
synced 2025-02-04 17:46:35 +11:00
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:
parent
1f5ec6f94f
commit
c26bbe7ec2
33 changed files with 683 additions and 994 deletions
|
@ -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"
|
||||
|
|
|
@ -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?;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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()? {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -55,10 +55,6 @@ impl Encode for BlockPos {
|
|||
_ => bail!("out of range: {self:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn encoded_len(&self) -> usize {
|
||||
8
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode<'_> for BlockPos {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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![];
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue