mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
More packet fixes, tests, handle error (#61)
* Fix packet, fix tests, fixedbitsets * Clippy: Nightmare Mode * Fix mistake * simplify impl Display and make thing pub --------- Co-authored-by: mat <github@matdoes.dev>
This commit is contained in:
parent
2539f948c7
commit
6e818852d8
28 changed files with 499 additions and 333 deletions
|
@ -24,6 +24,8 @@ pub enum ClientSessionServerError {
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
#[error("Forbidden operation (expired session?)")]
|
#[error("Forbidden operation (expired session?)")]
|
||||||
ForbiddenOperation,
|
ForbiddenOperation,
|
||||||
|
#[error("RateLimiter disallowed request")]
|
||||||
|
RateLimited,
|
||||||
#[error("Unexpected response from sessionserver (status code {status_code}): {body}")]
|
#[error("Unexpected response from sessionserver (status code {status_code}): {body}")]
|
||||||
UnexpectedResponse { status_code: u16, body: String },
|
UnexpectedResponse { status_code: u16, body: String },
|
||||||
}
|
}
|
||||||
|
@ -95,6 +97,7 @@ pub async fn join(
|
||||||
_ => Err(ClientSessionServerError::Unknown(forbidden.error)),
|
_ => Err(ClientSessionServerError::Unknown(forbidden.error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
StatusCode::TOO_MANY_REQUESTS => Err(ClientSessionServerError::RateLimited),
|
||||||
status_code => {
|
status_code => {
|
||||||
// log the headers
|
// log the headers
|
||||||
debug!("Error headers: {:#?}", res.headers());
|
debug!("Error headers: {:#?}", res.headers());
|
||||||
|
|
|
@ -150,7 +150,7 @@ async fn handle_connection(stream: TcpStream) -> anyhow::Result<()> {
|
||||||
if let Some(id) = hello.profile_id {
|
if let Some(id) = hello.profile_id {
|
||||||
id.to_string()
|
id.to_string()
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
String::new()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split the reader and writer into two objects. This doesn't allocate.
|
/// Split the reader and writer into two objects. This doesn't allocate.
|
||||||
|
#[must_use]
|
||||||
pub fn into_split(self) -> (ReadConnection<R>, WriteConnection<W>) {
|
pub fn into_split(self) -> (ReadConnection<R>, WriteConnection<W>) {
|
||||||
(self.reader, self.writer)
|
(self.reader, self.writer)
|
||||||
}
|
}
|
||||||
|
@ -229,12 +230,14 @@ impl Connection<ClientboundHandshakePacket, ServerboundHandshakePacket> {
|
||||||
|
|
||||||
/// Change our state from handshake to login. This is the state that is used
|
/// Change our state from handshake to login. This is the state that is used
|
||||||
/// for logging in.
|
/// for logging in.
|
||||||
|
#[must_use]
|
||||||
pub fn login(self) -> Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
pub fn login(self) -> Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change our state from handshake to status. This is the state that is
|
/// Change our state from handshake to status. This is the state that is
|
||||||
/// used for pinging the server.
|
/// used for pinging the server.
|
||||||
|
#[must_use]
|
||||||
pub fn status(self) -> Connection<ClientboundStatusPacket, ServerboundStatusPacket> {
|
pub fn status(self) -> Connection<ClientboundStatusPacket, ServerboundStatusPacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
@ -265,6 +268,7 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
||||||
|
|
||||||
/// Change our state from login to game. This is the state that's used when
|
/// Change our state from login to game. This is the state that's used when
|
||||||
/// you're actually in the game.
|
/// you're actually in the game.
|
||||||
|
#[must_use]
|
||||||
pub fn game(self) -> Connection<ClientboundGamePacket, ServerboundGamePacket> {
|
pub fn game(self) -> Connection<ClientboundGamePacket, ServerboundGamePacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
@ -343,12 +347,14 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
||||||
impl Connection<ServerboundHandshakePacket, ClientboundHandshakePacket> {
|
impl Connection<ServerboundHandshakePacket, ClientboundHandshakePacket> {
|
||||||
/// Change our state from handshake to login. This is the state that is used
|
/// Change our state from handshake to login. This is the state that is used
|
||||||
/// for logging in.
|
/// for logging in.
|
||||||
|
#[must_use]
|
||||||
pub fn login(self) -> Connection<ServerboundLoginPacket, ClientboundLoginPacket> {
|
pub fn login(self) -> Connection<ServerboundLoginPacket, ClientboundLoginPacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change our state from handshake to status. This is the state that is
|
/// Change our state from handshake to status. This is the state that is
|
||||||
/// used for pinging the server.
|
/// used for pinging the server.
|
||||||
|
#[must_use]
|
||||||
pub fn status(self) -> Connection<ServerboundStatusPacket, ClientboundStatusPacket> {
|
pub fn status(self) -> Connection<ServerboundStatusPacket, ClientboundStatusPacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
@ -379,6 +385,7 @@ impl Connection<ServerboundLoginPacket, ClientboundLoginPacket> {
|
||||||
|
|
||||||
/// Change our state from login to game. This is the state that's used when
|
/// Change our state from login to game. This is the state that's used when
|
||||||
/// the client is actually in the game.
|
/// the client is actually in the game.
|
||||||
|
#[must_use]
|
||||||
pub fn game(self) -> Connection<ServerboundGamePacket, ClientboundGamePacket> {
|
pub fn game(self) -> Connection<ServerboundGamePacket, ClientboundGamePacket> {
|
||||||
Connection::from(self)
|
Connection::from(self)
|
||||||
}
|
}
|
||||||
|
@ -406,6 +413,7 @@ where
|
||||||
{
|
{
|
||||||
/// Creates a `Connection` of a type from a `Connection` of another type.
|
/// Creates a `Connection` of a type from a `Connection` of another type.
|
||||||
/// Useful for servers or custom packets.
|
/// Useful for servers or custom packets.
|
||||||
|
#[must_use]
|
||||||
pub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
|
pub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
|
||||||
where
|
where
|
||||||
R2: ProtocolPacket + Debug,
|
R2: ProtocolPacket + Debug,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! A low-level crate to send and receive Minecraft packets.
|
//! A low-level crate to send and receive Minecraft packets.
|
||||||
//!
|
//!
|
||||||
//! You should probably use [`azalea`] or [`azalea_client`] instead, as
|
//! You should probably use [`azalea`] or [`azalea_client`] instead, as
|
||||||
//! azalea_protocol delegates much of the work, such as auth, to the user of
|
//! `azalea_protocol` delegates much of the work, such as auth, to the user of
|
||||||
//! the crate.
|
//! the crate.
|
||||||
//!
|
//!
|
||||||
//! [`azalea`]: https://crates.io/crates/azalea
|
//! [`azalea`]: https://crates.io/crates/azalea
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
#![feature(error_generic_member_access)]
|
#![feature(error_generic_member_access)]
|
||||||
#![feature(provide_any)]
|
#![feature(provide_any)]
|
||||||
|
|
||||||
use std::{net::SocketAddr, str::FromStr};
|
use std::{fmt::Display, net::SocketAddr, str::FromStr};
|
||||||
|
|
||||||
#[cfg(feature = "connecting")]
|
#[cfg(feature = "connecting")]
|
||||||
pub mod connect;
|
pub mod connect;
|
||||||
|
@ -27,7 +27,7 @@ pub mod write;
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ServerAddress implements TryFrom<&str>, so you can use it like this:
|
/// `ServerAddress` implements TryFrom<&str>, so you can use it like this:
|
||||||
/// ```
|
/// ```
|
||||||
/// use azalea_protocol::ServerAddress;
|
/// use azalea_protocol::ServerAddress;
|
||||||
///
|
///
|
||||||
|
@ -45,7 +45,7 @@ impl<'a> TryFrom<&'a str> for ServerAddress {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
/// Convert a Minecraft server address (host:port, the port is optional) to
|
/// Convert a Minecraft server address (host:port, the port is optional) to
|
||||||
/// a ServerAddress
|
/// a `ServerAddress`
|
||||||
fn try_from(string: &str) -> Result<Self, Self::Error> {
|
fn try_from(string: &str) -> Result<Self, Self::Error> {
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
return Err("Empty string".to_string());
|
return Err("Empty string".to_string());
|
||||||
|
@ -60,9 +60,9 @@ impl<'a> TryFrom<&'a str> for ServerAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SocketAddr> for ServerAddress {
|
impl From<SocketAddr> for ServerAddress {
|
||||||
/// Convert an existing SocketAddr into a ServerAddress. This just converts
|
/// Convert an existing `SocketAddr` into a `ServerAddress`. This just
|
||||||
/// the ip to a string and passes along the port. The resolver will realize
|
/// converts the ip to a string and passes along the port. The resolver
|
||||||
/// it's already an IP address and not do any DNS requests.
|
/// will realize it's already an IP address and not do any DNS requests.
|
||||||
fn from(addr: SocketAddr) -> Self {
|
fn from(addr: SocketAddr) -> Self {
|
||||||
ServerAddress {
|
ServerAddress {
|
||||||
host: addr.ip().to_string(),
|
host: addr.ip().to_string(),
|
||||||
|
@ -71,6 +71,12 @@ impl From<SocketAddr> for ServerAddress {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ServerAddress {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}:{}", self.host, self.port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use azalea_buf::{
|
||||||
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
|
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
|
||||||
};
|
};
|
||||||
use azalea_chat::Component;
|
use azalea_chat::Component;
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
@ -116,28 +117,28 @@ pub struct Properties {
|
||||||
|
|
||||||
impl McBufReadable for Properties {
|
impl McBufReadable for Properties {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<3>::read_from(buf)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
darken_screen: byte & 1 != 0,
|
darken_screen: set.index(0),
|
||||||
play_music: byte & 2 != 0,
|
play_music: set.index(1),
|
||||||
create_world_fog: byte & 4 != 0,
|
create_world_fog: set.index(2),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufWritable for Properties {
|
impl McBufWritable for Properties {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut byte = 0;
|
let mut set = FixedBitSet::<3>::new();
|
||||||
if self.darken_screen {
|
if self.darken_screen {
|
||||||
byte |= 1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.play_music {
|
if self.play_music {
|
||||||
byte |= 2;
|
set.set(1);
|
||||||
}
|
}
|
||||||
if self.create_world_fog {
|
if self.create_world_fog {
|
||||||
byte |= 4;
|
set.set(2);
|
||||||
}
|
}
|
||||||
u8::write_into(&byte, buf)?;
|
set.write_into(buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use azalea_buf::BufReadError;
|
||||||
use azalea_buf::McBuf;
|
use azalea_buf::McBuf;
|
||||||
use azalea_buf::McBufVarReadable;
|
use azalea_buf::McBufVarReadable;
|
||||||
use azalea_buf::{McBufReadable, McBufVarWritable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufVarWritable, McBufWritable};
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_core::ResourceLocation;
|
use azalea_core::ResourceLocation;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
@ -15,7 +16,7 @@ pub struct ClientboundCommandsPacket {
|
||||||
pub root_index: u32,
|
pub root_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct BrigadierNodeStub {
|
pub struct BrigadierNodeStub {
|
||||||
pub is_executable: bool,
|
pub is_executable: bool,
|
||||||
pub children: Vec<u32>,
|
pub children: Vec<u32>,
|
||||||
|
@ -23,7 +24,7 @@ pub struct BrigadierNodeStub {
|
||||||
pub node_type: NodeType,
|
pub node_type: NodeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct BrigadierNumber<T> {
|
pub struct BrigadierNumber<T> {
|
||||||
pub min: Option<T>,
|
pub min: Option<T>,
|
||||||
pub max: Option<T>,
|
pub max: Option<T>,
|
||||||
|
@ -33,15 +34,29 @@ impl<T> BrigadierNumber<T> {
|
||||||
BrigadierNumber { min, max }
|
BrigadierNumber { min, max }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<T: PartialEq> PartialEq for BrigadierNumber<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (&self.min, &self.max, &other.min, &other.max) {
|
||||||
|
(Some(f_min), None, Some(s_min), None) => f_min == s_min,
|
||||||
|
(None, Some(f_max), None, Some(s_max)) => f_max == s_max,
|
||||||
|
(Some(f_min), Some(f_max), Some(s_min), Some(s_max)) => {
|
||||||
|
f_min == s_min && f_max == s_max
|
||||||
|
}
|
||||||
|
(None, None, None, None) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
|
impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let flags = u8::read_from(buf)?;
|
let flags = FixedBitSet::<2>::read_from(buf)?;
|
||||||
let min = if flags & 0x01 != 0 {
|
let min = if flags.index(0) {
|
||||||
Some(T::read_from(buf)?)
|
Some(T::read_from(buf)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let max = if flags & 0x02 != 0 {
|
let max = if flags.index(1) {
|
||||||
Some(T::read_from(buf)?)
|
Some(T::read_from(buf)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -51,12 +66,12 @@ impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
|
||||||
}
|
}
|
||||||
impl<T: McBufWritable> McBufWritable for BrigadierNumber<T> {
|
impl<T: McBufWritable> McBufWritable for BrigadierNumber<T> {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut flags: u8 = 0;
|
let mut flags = FixedBitSet::<2>::new();
|
||||||
if self.min.is_some() {
|
if self.min.is_some() {
|
||||||
flags |= 0x01;
|
flags.set(0);
|
||||||
}
|
}
|
||||||
if self.max.is_some() {
|
if self.max.is_some() {
|
||||||
flags |= 0x02;
|
flags.set(1);
|
||||||
}
|
}
|
||||||
flags.write_into(buf)?;
|
flags.write_into(buf)?;
|
||||||
if let Some(min) = &self.min {
|
if let Some(min) = &self.min {
|
||||||
|
@ -69,7 +84,7 @@ impl<T: McBufWritable> McBufWritable for BrigadierNumber<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, McBuf)]
|
#[derive(Debug, Clone, Copy, McBuf, PartialEq, Eq)]
|
||||||
pub enum BrigadierString {
|
pub enum BrigadierString {
|
||||||
/// Reads a single word
|
/// Reads a single word
|
||||||
SingleWord = 0,
|
SingleWord = 0,
|
||||||
|
@ -80,7 +95,7 @@ pub enum BrigadierString {
|
||||||
GreedyPhrase = 2,
|
GreedyPhrase = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, McBuf)]
|
#[derive(Debug, Clone, McBuf, PartialEq)]
|
||||||
pub enum BrigadierParser {
|
pub enum BrigadierParser {
|
||||||
Bool,
|
Bool,
|
||||||
Float(BrigadierNumber<f32>),
|
Float(BrigadierNumber<f32>),
|
||||||
|
@ -132,28 +147,28 @@ pub enum BrigadierParser {
|
||||||
Uuid,
|
Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct EntityParser {
|
pub struct EntityParser {
|
||||||
pub single: bool,
|
pub single: bool,
|
||||||
pub players_only: bool,
|
pub players_only: bool,
|
||||||
}
|
}
|
||||||
impl McBufReadable for EntityParser {
|
impl McBufReadable for EntityParser {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let flags = u8::read_from(buf)?;
|
let flags = FixedBitSet::<2>::read_from(buf)?;
|
||||||
Ok(EntityParser {
|
Ok(EntityParser {
|
||||||
single: flags & 0x01 != 0,
|
single: flags.index(0),
|
||||||
players_only: flags & 0x02 != 0,
|
players_only: flags.index(1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl McBufWritable for EntityParser {
|
impl McBufWritable for EntityParser {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut flags: u8 = 0;
|
let mut flags = FixedBitSet::<2>::new();
|
||||||
if self.single {
|
if self.single {
|
||||||
flags |= 0x01;
|
flags.set(0);
|
||||||
}
|
}
|
||||||
if self.players_only {
|
if self.players_only {
|
||||||
flags |= 0x02;
|
flags.set(1);
|
||||||
}
|
}
|
||||||
flags.write_into(buf)?;
|
flags.write_into(buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -163,17 +178,15 @@ impl McBufWritable for EntityParser {
|
||||||
// TODO: BrigadierNodeStub should have more stuff
|
// TODO: BrigadierNodeStub should have more stuff
|
||||||
impl McBufReadable for BrigadierNodeStub {
|
impl McBufReadable for BrigadierNodeStub {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let flags = u8::read_from(buf)?;
|
let flags = FixedBitSet::<8>::read_from(buf)?;
|
||||||
if flags > 31 {
|
if flags.index(5) || flags.index(6) || flags.index(7) {
|
||||||
warn!(
|
warn!("Warning: The flags from a Brigadier node are over 31. This is probably a bug.",);
|
||||||
"Warning: The flags from a Brigadier node are over 31 ({flags}; {flags:#b}). This is probably a bug.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let node_type = flags & 0x03;
|
let node_type = u8::from(flags.index(0)) + (u8::from(flags.index(1)) * 2);
|
||||||
let is_executable = flags & 0x04 != 0;
|
let is_executable = flags.index(2);
|
||||||
let has_redirect = flags & 0x08 != 0;
|
let has_redirect = flags.index(3);
|
||||||
let has_suggestions_type = flags & 0x10 != 0;
|
let has_suggestions_type = flags.index(4);
|
||||||
|
|
||||||
let children = Vec::<u32>::var_read_from(buf)?;
|
let children = Vec::<u32>::var_read_from(buf)?;
|
||||||
let redirect_node = if has_redirect {
|
let redirect_node = if has_redirect {
|
||||||
|
@ -224,16 +237,17 @@ impl McBufReadable for BrigadierNodeStub {
|
||||||
|
|
||||||
impl McBufWritable for BrigadierNodeStub {
|
impl McBufWritable for BrigadierNodeStub {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
match &self.node_type {
|
let mut flags = FixedBitSet::<4>::new();
|
||||||
NodeType::Root => {
|
|
||||||
let mut flags = 0x00;
|
|
||||||
if self.is_executable {
|
if self.is_executable {
|
||||||
flags |= 0x04;
|
flags.set(2);
|
||||||
}
|
}
|
||||||
if self.redirect_node.is_some() {
|
if self.redirect_node.is_some() {
|
||||||
flags |= 0x08;
|
flags.set(3);
|
||||||
}
|
}
|
||||||
flags.var_write_into(buf)?;
|
|
||||||
|
match &self.node_type {
|
||||||
|
NodeType::Root => {
|
||||||
|
flags.write_into(buf)?;
|
||||||
|
|
||||||
self.children.var_write_into(buf)?;
|
self.children.var_write_into(buf)?;
|
||||||
|
|
||||||
|
@ -242,14 +256,8 @@ impl McBufWritable for BrigadierNodeStub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeType::Literal { name } => {
|
NodeType::Literal { name } => {
|
||||||
let mut flags = 0x01;
|
flags.set(0);
|
||||||
if self.is_executable {
|
flags.write_into(buf)?;
|
||||||
flags |= 0x04;
|
|
||||||
}
|
|
||||||
if self.redirect_node.is_some() {
|
|
||||||
flags |= 0x08;
|
|
||||||
}
|
|
||||||
flags.var_write_into(buf)?;
|
|
||||||
|
|
||||||
self.children.var_write_into(buf)?;
|
self.children.var_write_into(buf)?;
|
||||||
|
|
||||||
|
@ -264,17 +272,11 @@ impl McBufWritable for BrigadierNodeStub {
|
||||||
parser,
|
parser,
|
||||||
suggestions_type,
|
suggestions_type,
|
||||||
} => {
|
} => {
|
||||||
let mut flags = 0x02;
|
flags.set(1);
|
||||||
if self.is_executable {
|
|
||||||
flags |= 0x04;
|
|
||||||
}
|
|
||||||
if self.redirect_node.is_some() {
|
|
||||||
flags |= 0x08;
|
|
||||||
}
|
|
||||||
if suggestions_type.is_some() {
|
if suggestions_type.is_some() {
|
||||||
flags |= 0x10;
|
flags.set(4);
|
||||||
}
|
}
|
||||||
flags.var_write_into(buf)?;
|
flags.write_into(buf)?;
|
||||||
|
|
||||||
self.children.var_write_into(buf)?;
|
self.children.var_write_into(buf)?;
|
||||||
|
|
||||||
|
@ -294,7 +296,7 @@ impl McBufWritable for BrigadierNodeStub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum NodeType {
|
pub enum NodeType {
|
||||||
Root,
|
Root,
|
||||||
Literal {
|
Literal {
|
||||||
|
@ -308,11 +310,67 @@ pub enum NodeType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BrigadierNodeStub {
|
impl BrigadierNodeStub {
|
||||||
|
#[must_use]
|
||||||
pub fn name(&self) -> Option<&str> {
|
pub fn name(&self) -> Option<&str> {
|
||||||
match &self.node_type {
|
match &self.node_type {
|
||||||
NodeType::Root => None,
|
NodeType::Root => None,
|
||||||
NodeType::Literal { name } => Some(name),
|
NodeType::Literal { name } | NodeType::Argument { name, .. } => Some(name),
|
||||||
NodeType::Argument { name, .. } => Some(name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_brigadier_node_stub_root() {
|
||||||
|
let data = BrigadierNodeStub {
|
||||||
|
is_executable: false,
|
||||||
|
children: vec![1, 2],
|
||||||
|
redirect_node: None,
|
||||||
|
node_type: NodeType::Root,
|
||||||
|
};
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
data.write_into(&mut buf).unwrap();
|
||||||
|
let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
|
||||||
|
let read_data = BrigadierNodeStub::read_from(&mut data_cursor).unwrap();
|
||||||
|
assert_eq!(data, read_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_brigadier_node_stub_literal() {
|
||||||
|
let data = BrigadierNodeStub {
|
||||||
|
is_executable: true,
|
||||||
|
children: vec![],
|
||||||
|
redirect_node: None,
|
||||||
|
node_type: NodeType::Literal {
|
||||||
|
name: "String".to_string(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
data.write_into(&mut buf).unwrap();
|
||||||
|
let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
|
||||||
|
let read_data = BrigadierNodeStub::read_from(&mut data_cursor).unwrap();
|
||||||
|
assert_eq!(data, read_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_brigadier_node_stub_argument() {
|
||||||
|
let data = BrigadierNodeStub {
|
||||||
|
is_executable: false,
|
||||||
|
children: vec![6, 9],
|
||||||
|
redirect_node: Some(5),
|
||||||
|
node_type: NodeType::Argument {
|
||||||
|
name: "position".to_string(),
|
||||||
|
parser: BrigadierParser::Vec3,
|
||||||
|
suggestions_type: Some(ResourceLocation::new("minecraft:test_suggestion").unwrap()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
data.write_into(&mut buf).unwrap();
|
||||||
|
let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
|
||||||
|
let read_data = BrigadierNodeStub::read_from(&mut data_cursor).unwrap();
|
||||||
|
assert_eq!(data, read_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,9 +31,9 @@ impl McBufReadable for ClientboundExplodePacket {
|
||||||
let mut to_blow = Vec::with_capacity(to_blow_len as usize);
|
let mut to_blow = Vec::with_capacity(to_blow_len as usize);
|
||||||
for _ in 0..to_blow_len {
|
for _ in 0..to_blow_len {
|
||||||
// the bytes are offsets from the main x y z
|
// the bytes are offsets from the main x y z
|
||||||
let x = x_floor + i8::read_from(buf)? as i32;
|
let x = x_floor + i32::from(i8::read_from(buf)?);
|
||||||
let y = y_floor + i8::read_from(buf)? as i32;
|
let y = y_floor + i32::from(i8::read_from(buf)?);
|
||||||
let z = z_floor + i8::read_from(buf)? as i32;
|
let z = z_floor + i32::from(i8::read_from(buf)?);
|
||||||
to_blow.push(BlockPos { x, y, z });
|
to_blow.push(BlockPos { x, y, z });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,71 +1,15 @@
|
||||||
use azalea_buf::{BufReadError, McBuf};
|
use azalea_buf::{McBuf, McBufReadable, McBufWritable};
|
||||||
use azalea_buf::{McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
|
|
||||||
use azalea_chat::Component;
|
use azalea_chat::Component;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use std::io::{Cursor, Write};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, ClientboundGamePacket)]
|
#[derive(Clone, Debug, ClientboundGamePacket, McBuf)]
|
||||||
pub struct ClientboundMapItemDataPacket {
|
pub struct ClientboundMapItemDataPacket {
|
||||||
// #[var]
|
#[var]
|
||||||
pub map_id: u32,
|
pub map_id: u32,
|
||||||
pub scale: u8,
|
pub scale: u8,
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
pub decorations: Vec<MapDecoration>,
|
pub decorations: Option<Vec<MapDecoration>>,
|
||||||
pub color_patch: Option<MapPatch>,
|
pub color_patch: OptionalMapPatch,
|
||||||
}
|
|
||||||
|
|
||||||
impl McBufReadable for ClientboundMapItemDataPacket {
|
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
|
||||||
let map_id = u32::var_read_from(buf)?;
|
|
||||||
let scale = u8::read_from(buf)?;
|
|
||||||
let locked = bool::read_from(buf)?;
|
|
||||||
let decorations = Option::<Vec<MapDecoration>>::read_from(buf)?.unwrap_or_default();
|
|
||||||
|
|
||||||
let width = u8::read_from(buf)?;
|
|
||||||
let color_patch = if width == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let height = u8::read_from(buf)?;
|
|
||||||
let start_x = u8::read_from(buf)?;
|
|
||||||
let start_y = u8::read_from(buf)?;
|
|
||||||
let map_colors = Vec::<u8>::read_from(buf)?;
|
|
||||||
Some(MapPatch {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
start_x,
|
|
||||||
start_y,
|
|
||||||
map_colors,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
map_id,
|
|
||||||
scale,
|
|
||||||
locked,
|
|
||||||
decorations,
|
|
||||||
color_patch,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McBufWritable for ClientboundMapItemDataPacket {
|
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
|
||||||
self.map_id.var_write_into(buf)?;
|
|
||||||
self.scale.write_into(buf)?;
|
|
||||||
self.locked.write_into(buf)?;
|
|
||||||
(!self.decorations.is_empty()).write_into(buf)?;
|
|
||||||
self.decorations.write_into(buf)?;
|
|
||||||
if let Some(color_patch) = &self.color_patch {
|
|
||||||
color_patch.width.write_into(buf)?;
|
|
||||||
color_patch.height.write_into(buf)?;
|
|
||||||
color_patch.start_x.write_into(buf)?;
|
|
||||||
color_patch.start_y.write_into(buf)?;
|
|
||||||
color_patch.map_colors.write_into(buf)?;
|
|
||||||
} else {
|
|
||||||
0u8.write_into(buf)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, McBuf)]
|
#[derive(Clone, Debug, McBuf)]
|
||||||
|
@ -80,11 +24,35 @@ pub struct MapDecoration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OptionalMapPatch(pub Option<MapPatch>);
|
||||||
|
|
||||||
|
impl McBufReadable for OptionalMapPatch {
|
||||||
|
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
|
||||||
|
let pos = buf.position();
|
||||||
|
Ok(Self(if u8::read_from(buf)? == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
buf.set_position(pos);
|
||||||
|
Some(MapPatch::read_from(buf)?)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl McBufWritable for OptionalMapPatch {
|
||||||
|
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
||||||
|
match &self.0 {
|
||||||
|
None => 0u8.write_into(buf),
|
||||||
|
Some(m) => m.write_into(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, McBuf)]
|
||||||
pub struct MapPatch {
|
pub struct MapPatch {
|
||||||
pub start_x: u8,
|
|
||||||
pub start_y: u8,
|
|
||||||
pub width: u8,
|
pub width: u8,
|
||||||
pub height: u8,
|
pub height: u8,
|
||||||
|
pub start_x: u8,
|
||||||
|
pub start_y: u8,
|
||||||
pub map_colors: Vec<u8>,
|
pub map_colors: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use azalea_buf::{BufReadError, McBuf};
|
use azalea_buf::{BufReadError, McBuf};
|
||||||
use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
|
@ -21,31 +22,31 @@ pub struct PlayerAbilitiesFlags {
|
||||||
|
|
||||||
impl McBufReadable for PlayerAbilitiesFlags {
|
impl McBufReadable for PlayerAbilitiesFlags {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<4>::read_from(buf)?;
|
||||||
Ok(PlayerAbilitiesFlags {
|
Ok(PlayerAbilitiesFlags {
|
||||||
invulnerable: byte & 1 != 0,
|
invulnerable: set.index(0),
|
||||||
flying: byte & 2 != 0,
|
flying: set.index(1),
|
||||||
can_fly: byte & 4 != 0,
|
can_fly: set.index(2),
|
||||||
instant_break: byte & 8 != 0,
|
instant_break: set.index(3),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufWritable for PlayerAbilitiesFlags {
|
impl McBufWritable for PlayerAbilitiesFlags {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut byte = 0;
|
let mut set = FixedBitSet::<4>::new();
|
||||||
if self.invulnerable {
|
if self.invulnerable {
|
||||||
byte |= 0b1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.flying {
|
if self.flying {
|
||||||
byte |= 0b10;
|
set.set(1);
|
||||||
}
|
}
|
||||||
if self.can_fly {
|
if self.can_fly {
|
||||||
byte |= 0b100;
|
set.set(2);
|
||||||
}
|
}
|
||||||
if self.instant_break {
|
if self.instant_break {
|
||||||
byte |= 0b1000;
|
set.set(3);
|
||||||
}
|
}
|
||||||
u8::write_into(&byte, buf)
|
set.write_into(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@ impl ClientboundPlayerChatPacket {
|
||||||
/// Returns the content of the message. If you want to get the Component
|
/// Returns the content of the message. If you want to get the Component
|
||||||
/// for the whole message including the sender part, use
|
/// for the whole message including the sender part, use
|
||||||
/// [`ClientboundPlayerChatPacket::message`].
|
/// [`ClientboundPlayerChatPacket::message`].
|
||||||
|
#[must_use]
|
||||||
pub fn content(&self) -> Component {
|
pub fn content(&self) -> Component {
|
||||||
self.unsigned_content
|
self.unsigned_content
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -97,6 +98,7 @@ impl ClientboundPlayerChatPacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the full message, including the sender part.
|
/// Get the full message, including the sender part.
|
||||||
|
#[must_use]
|
||||||
pub fn message(&self) -> Component {
|
pub fn message(&self) -> Component {
|
||||||
let sender = self.chat_type.name.clone();
|
let sender = self.chat_type.name.clone();
|
||||||
let content = self.content();
|
let content = self.content();
|
||||||
|
@ -119,6 +121,7 @@ impl ClientboundPlayerChatPacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatType {
|
impl ChatType {
|
||||||
|
#[must_use]
|
||||||
pub fn chat_translation_key(&self) -> &'static str {
|
pub fn chat_translation_key(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
ChatType::Chat => "chat.type.text",
|
ChatType::Chat => "chat.type.text",
|
||||||
|
@ -131,15 +134,11 @@ impl ChatType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn narrator_translation_key(&self) -> &'static str {
|
pub fn narrator_translation_key(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
ChatType::Chat => "chat.type.text.narrate",
|
|
||||||
ChatType::SayCommand => "chat.type.text.narrate",
|
|
||||||
ChatType::MsgCommandIncoming => "chat.type.text.narrate",
|
|
||||||
ChatType::MsgCommandOutgoing => "chat.type.text.narrate",
|
|
||||||
ChatType::TeamMsgCommandIncoming => "chat.type.text.narrate",
|
|
||||||
ChatType::TeamMsgCommandOutgoing => "chat.type.text.narrate",
|
|
||||||
ChatType::EmoteCommand => "chat.type.emote",
|
ChatType::EmoteCommand => "chat.type.emote",
|
||||||
|
_ => "chat.type.text.narrate",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use azalea_buf::{BufReadError, McBuf};
|
use azalea_buf::{BufReadError, McBuf};
|
||||||
use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
|
@ -29,35 +30,35 @@ pub struct RelativeArguments {
|
||||||
|
|
||||||
impl McBufReadable for RelativeArguments {
|
impl McBufReadable for RelativeArguments {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<5>::read_from(buf)?;
|
||||||
Ok(RelativeArguments {
|
Ok(RelativeArguments {
|
||||||
x: byte & 0b1 != 0,
|
x: set.index(0),
|
||||||
y: byte & 0b10 != 0,
|
y: set.index(1),
|
||||||
z: byte & 0b100 != 0,
|
z: set.index(2),
|
||||||
y_rot: byte & 0b1000 != 0,
|
y_rot: set.index(3),
|
||||||
x_rot: byte & 0b10000 != 0,
|
x_rot: set.index(4),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufWritable for RelativeArguments {
|
impl McBufWritable for RelativeArguments {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut byte = 0;
|
let mut set = FixedBitSet::<5>::new();
|
||||||
if self.x {
|
if self.x {
|
||||||
byte |= 0b1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.y {
|
if self.y {
|
||||||
byte |= 0b10;
|
set.set(1);
|
||||||
}
|
}
|
||||||
if self.z {
|
if self.z {
|
||||||
byte |= 0b100;
|
set.set(2);
|
||||||
}
|
}
|
||||||
if self.y_rot {
|
if self.y_rot {
|
||||||
byte |= 0b1000;
|
set.set(3);
|
||||||
}
|
}
|
||||||
if self.x_rot {
|
if self.x_rot {
|
||||||
byte |= 0b10000;
|
set.set(4);
|
||||||
}
|
}
|
||||||
u8::write_into(&byte, buf)
|
set.write_into(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl McBufReadable for BlockStateWithPosition {
|
||||||
impl McBufWritable for BlockStateWithPosition {
|
impl McBufWritable for BlockStateWithPosition {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let data = (self.state as u64) << 12
|
let data = (self.state as u64) << 12
|
||||||
| ((self.pos.x as u64) << 8 | (self.pos.z as u64) << 4 | (self.pos.y as u64));
|
| (u64::from(self.pos.x) << 8 | u64::from(self.pos.z) << 4 | u64::from(self.pos.y));
|
||||||
u64::var_write_into(&data, buf)?;
|
u64::var_write_into(&data, buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ pub enum EquipmentSlot {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EquipmentSlot {
|
impl EquipmentSlot {
|
||||||
|
#[must_use]
|
||||||
pub fn from_byte(byte: u8) -> Option<Self> {
|
pub fn from_byte(byte: u8) -> Option<Self> {
|
||||||
match byte {
|
match byte {
|
||||||
0 => Some(EquipmentSlot::MainHand),
|
0 => Some(EquipmentSlot::MainHand),
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl McBufReadable for Method {
|
||||||
0 => Method::Add(DisplayInfo::read_from(buf)?),
|
0 => Method::Add(DisplayInfo::read_from(buf)?),
|
||||||
1 => Method::Remove,
|
1 => Method::Remove,
|
||||||
2 => Method::Change(DisplayInfo::read_from(buf)?),
|
2 => Method::Change(DisplayInfo::read_from(buf)?),
|
||||||
id => return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 }),
|
id => return Err(BufReadError::UnexpectedEnumVariant { id: i32::from(id) }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl McBufReadable for Method {
|
||||||
2 => Method::Change(Parameters::read_from(buf)?),
|
2 => Method::Change(Parameters::read_from(buf)?),
|
||||||
3 => Method::Join(PlayerList::read_from(buf)?),
|
3 => Method::Join(PlayerList::read_from(buf)?),
|
||||||
4 => Method::Leave(PlayerList::read_from(buf)?),
|
4 => Method::Leave(PlayerList::read_from(buf)?),
|
||||||
id => return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 }),
|
id => return Err(BufReadError::UnexpectedEnumVariant { id: i32::from(id) }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl McBufWritable for ClientboundSetScorePacket {
|
||||||
// convert None to an empty string
|
// convert None to an empty string
|
||||||
self.objective_name
|
self.objective_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(&"".to_string())
|
.unwrap_or(&String::new())
|
||||||
.write_into(buf)?;
|
.write_into(buf)?;
|
||||||
if let Method::Change { score } = self.method {
|
if let Method::Change { score } = self.method {
|
||||||
score.var_write_into(buf)?;
|
score.var_write_into(buf)?;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
|
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
|
||||||
use azalea_core::ResourceLocation;
|
use azalea_core::{FixedBitSet, ResourceLocation};
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
|
@ -13,13 +13,13 @@ pub struct ClientboundStopSoundPacket {
|
||||||
|
|
||||||
impl McBufReadable for ClientboundStopSoundPacket {
|
impl McBufReadable for ClientboundStopSoundPacket {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<2>::read_from(buf)?;
|
||||||
let source = if byte & 1 != 0 {
|
let source = if set.index(0) {
|
||||||
Some(SoundSource::read_from(buf)?)
|
Some(SoundSource::read_from(buf)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let name = if byte & 2 != 0 {
|
let name = if set.index(1) {
|
||||||
Some(ResourceLocation::read_from(buf)?)
|
Some(ResourceLocation::read_from(buf)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -31,14 +31,14 @@ impl McBufReadable for ClientboundStopSoundPacket {
|
||||||
|
|
||||||
impl McBufWritable for ClientboundStopSoundPacket {
|
impl McBufWritable for ClientboundStopSoundPacket {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut byte = 0u8;
|
let mut set = FixedBitSet::<2>::new();
|
||||||
if self.source.is_some() {
|
if self.source.is_some() {
|
||||||
byte |= 1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.name.is_some() {
|
if self.name.is_some() {
|
||||||
byte |= 2;
|
set.set(1);
|
||||||
}
|
}
|
||||||
byte.write_into(buf)?;
|
set.write_into(buf)?;
|
||||||
if let Some(source) = &self.source {
|
if let Some(source) = &self.source {
|
||||||
source.write_into(buf)?;
|
source.write_into(buf)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,8 @@ pub struct ClientboundUpdateAdvancementsPacket {
|
||||||
pub struct Advancement {
|
pub struct Advancement {
|
||||||
parent_id: Option<ResourceLocation>,
|
parent_id: Option<ResourceLocation>,
|
||||||
display: Option<DisplayInfo>,
|
display: Option<DisplayInfo>,
|
||||||
// rewards: AdvancementRewards.EMPTY,
|
|
||||||
criteria: HashMap<ResourceLocation, Criterion>,
|
criteria: HashMap<ResourceLocation, Criterion>,
|
||||||
requirements: Vec<Vec<String>>,
|
requirements: Vec<Vec<String>>,
|
||||||
// requirements_strategy: RequirementsStrategy.AND
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -87,11 +85,11 @@ impl azalea_buf::McBufReadable for DisplayInfo {
|
||||||
description,
|
description,
|
||||||
icon,
|
icon,
|
||||||
frame,
|
frame,
|
||||||
|
show_toast,
|
||||||
|
hidden,
|
||||||
background,
|
background,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
hidden,
|
|
||||||
show_toast,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,57 +112,77 @@ pub struct CriterionProgress {
|
||||||
date: Option<u64>,
|
date: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(test)]
|
#[cfg(test)]
|
||||||
// mod tests {
|
mod tests {
|
||||||
// use super::*;
|
use super::*;
|
||||||
// use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
// use azalea_core::ResourceLocation;
|
use azalea_core::ResourceLocation;
|
||||||
// use azalea_protocol_macros::ClientboundGamePacket;
|
use std::io::Cursor;
|
||||||
// use std::io::Cursor;
|
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test() {
|
fn test() {
|
||||||
// let mut buf = Cursor::new(Vec::new());
|
let packet = ClientboundUpdateAdvancementsPacket {
|
||||||
// let packet = ClientboundUpdateAdvancementsPacket {
|
reset: true,
|
||||||
// reset: true,
|
added: [(
|
||||||
// added: [(
|
ResourceLocation::new("minecraft:test").unwrap(),
|
||||||
// ResourceLocation::new("minecraft:test").unwrap(),
|
Advancement {
|
||||||
// Advancement {
|
parent_id: None,
|
||||||
// parent_id: None,
|
display: Some(DisplayInfo {
|
||||||
// display: Some(DisplayInfo {
|
title: Component::from("title".to_string()),
|
||||||
// title: Component::from("title".to_string()),
|
description: Component::from("description".to_string()),
|
||||||
// description:
|
icon: Slot::Empty,
|
||||||
// Component::from("description".to_string()), icon:
|
frame: FrameType::Task,
|
||||||
// Slot::Empty, frame: FrameType::Task,
|
show_toast: true,
|
||||||
// show_toast: true,
|
hidden: false,
|
||||||
// hidden: false,
|
background: None,
|
||||||
// background: None,
|
x: 0.0,
|
||||||
// x: 0.0,
|
y: 0.0,
|
||||||
// y: 0.0,
|
}),
|
||||||
// }),
|
criteria: HashMap::new(),
|
||||||
// criteria: HashMap::new(),
|
requirements: Vec::new(),
|
||||||
// requirements: Vec::new(),
|
},
|
||||||
// },
|
)]
|
||||||
// )]
|
.into_iter()
|
||||||
// .into_iter()
|
.collect(),
|
||||||
// .collect(),
|
removed: vec![ResourceLocation::new("minecraft:test2").unwrap()],
|
||||||
// removed: vec![ResourceLocation::new("minecraft:test2").unwrap()],
|
progress: [(
|
||||||
// progress: [(
|
ResourceLocation::new("minecraft:test3").unwrap(),
|
||||||
// ResourceLocation::new("minecraft:test3").unwrap(),
|
[(
|
||||||
// [(
|
ResourceLocation::new("minecraft:test4").unwrap(),
|
||||||
// ResourceLocation::new("minecraft:test4").unwrap(),
|
CriterionProgress {
|
||||||
// CriterionProgress {
|
date: Some(123456789),
|
||||||
// date: Some(123456789),
|
},
|
||||||
// },
|
)]
|
||||||
// )]
|
.into_iter()
|
||||||
// .into_iter()
|
.collect(),
|
||||||
// .collect(),
|
)]
|
||||||
// )]
|
.into_iter()
|
||||||
// .into_iter()
|
.collect(),
|
||||||
// .collect(),
|
};
|
||||||
// };
|
|
||||||
// packet.write_into(&mut buf).unwrap();
|
let mut data = Vec::new();
|
||||||
// let packet = ClientboundUpdateAdvancementsPacket::read_from(&mut
|
packet.write_into(&mut data).unwrap();
|
||||||
// buf).unwrap(); assert_eq!(packet.reset, true);
|
let mut buf: Cursor<&[u8]> = Cursor::new(&data);
|
||||||
// }
|
|
||||||
// }
|
let read_packet = ClientboundUpdateAdvancementsPacket::read_from(&mut buf).unwrap();
|
||||||
|
assert_eq!(packet.reset, read_packet.reset);
|
||||||
|
assert_eq!(packet.removed, read_packet.removed);
|
||||||
|
|
||||||
|
let advancement = packet
|
||||||
|
.added
|
||||||
|
.get(&ResourceLocation::new("minecraft:test").unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
let read_advancement = read_packet
|
||||||
|
.added
|
||||||
|
.get(&ResourceLocation::new("minecraft:test").unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
assert_eq!(advancement.parent_id, read_advancement.parent_id);
|
||||||
|
|
||||||
|
let display = advancement.display.unwrap();
|
||||||
|
let read_display = read_advancement.display.unwrap();
|
||||||
|
assert_eq!(display.title, read_display.title);
|
||||||
|
assert_eq!(display.description, read_display.description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use azalea_buf::McBuf;
|
use azalea_buf::{McBuf, McBufReadable, McBufWritable};
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_protocol_macros::ServerboundGamePacket;
|
use azalea_protocol_macros::ServerboundGamePacket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ServerboundGamePacket, PartialEq, Eq)]
|
||||||
pub struct ServerboundClientInformationPacket {
|
pub struct ServerboundClientInformationPacket {
|
||||||
/// The locale of the client.
|
/// The locale of the client.
|
||||||
pub language: String,
|
pub language: String,
|
||||||
|
@ -14,7 +15,7 @@ pub struct ServerboundClientInformationPacket {
|
||||||
/// Whether the messages sent from the server should have colors. Note that
|
/// Whether the messages sent from the server should have colors. Note that
|
||||||
/// many servers ignore this and always send colored messages.
|
/// many servers ignore this and always send colored messages.
|
||||||
pub chat_colors: bool,
|
pub chat_colors: bool,
|
||||||
pub model_customisation: u8,
|
pub model_customisation: ModelCustomization,
|
||||||
pub main_hand: HumanoidArm,
|
pub main_hand: HumanoidArm,
|
||||||
pub text_filtering_enabled: bool,
|
pub text_filtering_enabled: bool,
|
||||||
/// Whether the client should show up as "Anonymous Player" in the server
|
/// Whether the client should show up as "Anonymous Player" in the server
|
||||||
|
@ -27,9 +28,9 @@ impl Default for ServerboundClientInformationPacket {
|
||||||
Self {
|
Self {
|
||||||
language: "en_us".to_string(),
|
language: "en_us".to_string(),
|
||||||
view_distance: 8,
|
view_distance: 8,
|
||||||
chat_visibility: ChatVisibility::Full,
|
chat_visibility: ChatVisibility::default(),
|
||||||
chat_colors: true,
|
chat_colors: true,
|
||||||
model_customisation: 0,
|
model_customisation: ModelCustomization::default(),
|
||||||
main_hand: HumanoidArm::Right,
|
main_hand: HumanoidArm::Right,
|
||||||
text_filtering_enabled: false,
|
text_filtering_enabled: false,
|
||||||
allows_listing: false,
|
allows_listing: false,
|
||||||
|
@ -37,9 +38,10 @@ impl Default for ServerboundClientInformationPacket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(McBuf, Clone, Copy, Debug)]
|
#[derive(McBuf, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||||
pub enum ChatVisibility {
|
pub enum ChatVisibility {
|
||||||
/// All chat messages should be sent to the client.
|
/// All chat messages should be sent to the client.
|
||||||
|
#[default]
|
||||||
Full = 0,
|
Full = 0,
|
||||||
/// Chat messages from other players should be not sent to the client, only
|
/// Chat messages from other players should be not sent to the client, only
|
||||||
/// messages from the server like "Player joined the game" should be sent.
|
/// messages from the server like "Player joined the game" should be sent.
|
||||||
|
@ -48,8 +50,125 @@ pub enum ChatVisibility {
|
||||||
Hidden = 2,
|
Hidden = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(McBuf, Clone, Copy, Debug)]
|
#[derive(McBuf, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||||
pub enum HumanoidArm {
|
pub enum HumanoidArm {
|
||||||
Left = 0,
|
Left = 0,
|
||||||
|
#[default]
|
||||||
Right = 1,
|
Right = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct ModelCustomization {
|
||||||
|
pub cape: bool,
|
||||||
|
pub jacket: bool,
|
||||||
|
pub left_sleeve: bool,
|
||||||
|
pub right_sleeve: bool,
|
||||||
|
pub left_pants: bool,
|
||||||
|
pub right_pants: bool,
|
||||||
|
pub hat: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ModelCustomization {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
cape: true,
|
||||||
|
jacket: true,
|
||||||
|
left_sleeve: true,
|
||||||
|
right_sleeve: true,
|
||||||
|
left_pants: true,
|
||||||
|
right_pants: true,
|
||||||
|
hat: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl McBufReadable for ModelCustomization {
|
||||||
|
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
|
||||||
|
let set = FixedBitSet::<7>::read_from(buf)?;
|
||||||
|
Ok(Self {
|
||||||
|
cape: set.index(0),
|
||||||
|
jacket: set.index(1),
|
||||||
|
left_sleeve: set.index(2),
|
||||||
|
right_sleeve: set.index(3),
|
||||||
|
left_pants: set.index(4),
|
||||||
|
right_pants: set.index(5),
|
||||||
|
hat: set.index(6),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl McBufWritable for ModelCustomization {
|
||||||
|
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
||||||
|
let mut set = FixedBitSet::<7>::new();
|
||||||
|
if self.cape {
|
||||||
|
set.set(0);
|
||||||
|
}
|
||||||
|
if self.jacket {
|
||||||
|
set.set(1);
|
||||||
|
}
|
||||||
|
if self.left_sleeve {
|
||||||
|
set.set(2);
|
||||||
|
}
|
||||||
|
if self.right_sleeve {
|
||||||
|
set.set(3);
|
||||||
|
}
|
||||||
|
if self.left_pants {
|
||||||
|
set.set(4);
|
||||||
|
}
|
||||||
|
if self.right_pants {
|
||||||
|
set.set(5);
|
||||||
|
}
|
||||||
|
if self.hat {
|
||||||
|
set.set(6);
|
||||||
|
}
|
||||||
|
set.write_into(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_client_information_packet() {
|
||||||
|
{
|
||||||
|
let data = ServerboundClientInformationPacket::default();
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
data.write_into(&mut buf).unwrap();
|
||||||
|
let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
|
||||||
|
|
||||||
|
let read_data =
|
||||||
|
ServerboundClientInformationPacket::read_from(&mut data_cursor).unwrap();
|
||||||
|
assert_eq!(read_data, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let data = ServerboundClientInformationPacket {
|
||||||
|
language: "en_gb".to_string(),
|
||||||
|
view_distance: 24,
|
||||||
|
chat_visibility: ChatVisibility::Hidden,
|
||||||
|
chat_colors: false,
|
||||||
|
model_customisation: ModelCustomization {
|
||||||
|
cape: false,
|
||||||
|
jacket: false,
|
||||||
|
left_sleeve: true,
|
||||||
|
right_sleeve: false,
|
||||||
|
left_pants: true,
|
||||||
|
right_pants: false,
|
||||||
|
hat: true,
|
||||||
|
},
|
||||||
|
main_hand: HumanoidArm::Left,
|
||||||
|
text_filtering_enabled: true,
|
||||||
|
allows_listing: true,
|
||||||
|
};
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
data.write_into(&mut buf).unwrap();
|
||||||
|
let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
|
||||||
|
|
||||||
|
let read_data =
|
||||||
|
ServerboundClientInformationPacket::read_from(&mut data_cursor).unwrap();
|
||||||
|
assert_eq!(read_data, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -63,9 +63,9 @@ impl McBufReadable for ActionType {
|
||||||
let hand = InteractionHand::read_from(buf)?;
|
let hand = InteractionHand::read_from(buf)?;
|
||||||
Ok(ActionType::InteractAt {
|
Ok(ActionType::InteractAt {
|
||||||
location: Vec3 {
|
location: Vec3 {
|
||||||
x: x as f64,
|
x: f64::from(x),
|
||||||
y: y as f64,
|
y: f64::from(y),
|
||||||
z: z as f64,
|
z: f64::from(z),
|
||||||
},
|
},
|
||||||
hand,
|
hand,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
use crate::packets::BufReadError;
|
use crate::packets::BufReadError;
|
||||||
use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_protocol_macros::ServerboundGamePacket;
|
use azalea_protocol_macros::ServerboundGamePacket;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
#[derive(Clone, Debug, ServerboundGamePacket)]
|
#[derive(Clone, Debug, ServerboundGamePacket)]
|
||||||
pub struct ServerboundPlayerAbilitiesPacket {
|
pub struct ServerboundPlayerAbilitiesPacket {
|
||||||
is_flying: bool,
|
pub is_flying: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufReadable for ServerboundPlayerAbilitiesPacket {
|
impl McBufReadable for ServerboundPlayerAbilitiesPacket {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<2>::read_from(buf)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
is_flying: byte & 2 != 0,
|
is_flying: set.index(1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufWritable for ServerboundPlayerAbilitiesPacket {
|
impl McBufWritable for ServerboundPlayerAbilitiesPacket {
|
||||||
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
||||||
let mut byte = 0;
|
let mut set = FixedBitSet::<2>::new();
|
||||||
if self.is_flying {
|
if self.is_flying {
|
||||||
byte |= 2;
|
set.set(1);
|
||||||
}
|
}
|
||||||
u8::write_into(&byte, buf)?;
|
set.write_into(buf)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::io::Cursor;
|
||||||
|
|
||||||
use azalea_buf::BufReadError;
|
use azalea_buf::BufReadError;
|
||||||
use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
|
use azalea_core::FixedBitSet;
|
||||||
use azalea_protocol_macros::ServerboundGamePacket;
|
use azalea_protocol_macros::ServerboundGamePacket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, ServerboundGamePacket)]
|
#[derive(Clone, Debug, ServerboundGamePacket)]
|
||||||
|
@ -16,14 +17,12 @@ impl McBufReadable for ServerboundPlayerInputPacket {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let xxa = f32::read_from(buf)?;
|
let xxa = f32::read_from(buf)?;
|
||||||
let zza = f32::read_from(buf)?;
|
let zza = f32::read_from(buf)?;
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<2>::read_from(buf)?;
|
||||||
let is_jumping = byte & 1 != 0;
|
|
||||||
let is_shift_key_down = byte & 2 != 0;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
xxa,
|
xxa,
|
||||||
zza,
|
zza,
|
||||||
is_jumping,
|
is_jumping: set.index(0),
|
||||||
is_shift_key_down,
|
is_shift_key_down: set.index(1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,14 +31,13 @@ impl McBufWritable for ServerboundPlayerInputPacket {
|
||||||
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
|
||||||
self.xxa.write_into(buf)?;
|
self.xxa.write_into(buf)?;
|
||||||
self.zza.write_into(buf)?;
|
self.zza.write_into(buf)?;
|
||||||
let mut byte = 0u8;
|
let mut set = FixedBitSet::<2>::new();
|
||||||
if self.is_jumping {
|
if self.is_jumping {
|
||||||
byte |= 1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.is_shift_key_down {
|
if self.is_shift_key_down {
|
||||||
byte |= 2;
|
set.set(1);
|
||||||
}
|
}
|
||||||
byte.write_into(buf)?;
|
set.write_into(buf)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::packets::McBufWritable;
|
use crate::packets::McBufWritable;
|
||||||
use azalea_buf::{BufReadError, McBuf, McBufReadable};
|
use azalea_buf::{BufReadError, McBuf, McBufReadable};
|
||||||
use azalea_core::BlockPos;
|
use azalea_core::{BlockPos, FixedBitSet};
|
||||||
use azalea_protocol_macros::ServerboundGamePacket;
|
use azalea_protocol_macros::ServerboundGamePacket;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
@ -28,17 +28,14 @@ impl McBufReadable for ServerboundSetCommandBlockPacket {
|
||||||
let command = String::read_from(buf)?;
|
let command = String::read_from(buf)?;
|
||||||
let mode = Mode::read_from(buf)?;
|
let mode = Mode::read_from(buf)?;
|
||||||
|
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<3>::read_from(buf)?;
|
||||||
let track_output = byte & 1 != 0;
|
|
||||||
let conditional = byte & 2 != 0;
|
|
||||||
let automatic = byte & 4 != 0;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
pos,
|
pos,
|
||||||
command,
|
command,
|
||||||
mode,
|
mode,
|
||||||
track_output,
|
track_output: set.index(0),
|
||||||
conditional,
|
conditional: set.index(1),
|
||||||
automatic,
|
automatic: set.index(2),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,17 +46,16 @@ impl McBufWritable for ServerboundSetCommandBlockPacket {
|
||||||
self.command.write_into(buf)?;
|
self.command.write_into(buf)?;
|
||||||
self.mode.write_into(buf)?;
|
self.mode.write_into(buf)?;
|
||||||
|
|
||||||
let mut byte: u8 = 0;
|
let mut set = FixedBitSet::<3>::new();
|
||||||
if self.track_output {
|
if self.track_output {
|
||||||
byte |= 1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.conditional {
|
if self.conditional {
|
||||||
byte |= 2;
|
set.set(1);
|
||||||
}
|
}
|
||||||
if self.automatic {
|
if self.automatic {
|
||||||
byte |= 4;
|
set.set(2);
|
||||||
}
|
}
|
||||||
byte.write_into(buf)?;
|
set.write_into(buf)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::packets::BufReadError;
|
use crate::packets::BufReadError;
|
||||||
use azalea_buf::McBuf;
|
use azalea_buf::McBuf;
|
||||||
use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
use azalea_core::BlockPos;
|
use azalea_core::{BlockPos, FixedBitSet};
|
||||||
use azalea_protocol_macros::ServerboundGamePacket;
|
use azalea_protocol_macros::ServerboundGamePacket;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
|
@ -69,28 +69,28 @@ pub struct Flags {
|
||||||
|
|
||||||
impl McBufReadable for Flags {
|
impl McBufReadable for Flags {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let byte = u8::read_from(buf)?;
|
let set = FixedBitSet::<3>::read_from(buf)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ignore_entities: byte & 1 != 0,
|
ignore_entities: set.index(0),
|
||||||
show_air: byte & 2 != 0,
|
show_air: set.index(1),
|
||||||
show_bounding_box: byte & 4 != 0,
|
show_bounding_box: set.index(2),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufWritable for Flags {
|
impl McBufWritable for Flags {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let mut byte = 0;
|
let mut set = FixedBitSet::<3>::new();
|
||||||
if self.ignore_entities {
|
if self.ignore_entities {
|
||||||
byte |= 1;
|
set.set(0);
|
||||||
}
|
}
|
||||||
if self.show_air {
|
if self.show_air {
|
||||||
byte |= 2;
|
set.set(1);
|
||||||
}
|
}
|
||||||
if self.show_bounding_box {
|
if self.show_bounding_box {
|
||||||
byte |= 4;
|
set.set(2);
|
||||||
}
|
}
|
||||||
u8::write_into(&byte, buf)?;
|
set.write_into(buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,9 @@ impl McBufWritable for BlockHitResult {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
self.block_pos.write_into(buf)?;
|
self.block_pos.write_into(buf)?;
|
||||||
self.direction.write_into(buf)?;
|
self.direction.write_into(buf)?;
|
||||||
f32::write_into(&((self.location.x - (self.block_pos.x as f64)) as f32), buf)?;
|
f32::write_into(&((self.location.x - f64::from(self.block_pos.x)) as f32), buf)?;
|
||||||
f32::write_into(&((self.location.y - (self.block_pos.y as f64)) as f32), buf)?;
|
f32::write_into(&((self.location.y - f64::from(self.block_pos.y)) as f32), buf)?;
|
||||||
f32::write_into(&((self.location.z - (self.block_pos.z as f64)) as f32), buf)?;
|
f32::write_into(&((self.location.z - f64::from(self.block_pos.z)) as f32), buf)?;
|
||||||
self.inside.write_into(buf)?;
|
self.inside.write_into(buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -44,9 +44,9 @@ impl McBufReadable for BlockHitResult {
|
||||||
block_pos,
|
block_pos,
|
||||||
direction,
|
direction,
|
||||||
location: Vec3 {
|
location: Vec3 {
|
||||||
x: block_pos.x as f64 + cursor_x as f64,
|
x: f64::from(block_pos.x) + f64::from(cursor_x),
|
||||||
y: block_pos.y as f64 + cursor_y as f64,
|
y: f64::from(block_pos.y) + f64::from(cursor_y),
|
||||||
z: block_pos.z as f64 + cursor_z as f64,
|
z: f64::from(block_pos.z) + f64::from(cursor_z),
|
||||||
},
|
},
|
||||||
inside,
|
inside,
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub enum ConnectionProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectionProtocol {
|
impl ConnectionProtocol {
|
||||||
|
#[must_use]
|
||||||
pub fn from_i32(i: i32) -> Option<Self> {
|
pub fn from_i32(i: i32) -> Option<Self> {
|
||||||
match i {
|
match i {
|
||||||
-1 => Some(ConnectionProtocol::Handshake),
|
-1 => Some(ConnectionProtocol::Handshake),
|
||||||
|
@ -39,7 +40,7 @@ where
|
||||||
{
|
{
|
||||||
fn id(&self) -> u32;
|
fn id(&self) -> u32;
|
||||||
|
|
||||||
/// Read a packet by its id, ConnectionProtocol, and flow
|
/// Read a packet by its id, `ConnectionProtocol`, and flow
|
||||||
fn read(id: u32, buf: &mut Cursor<&[u8]>) -> Result<Self, Box<ReadPacketError>>;
|
fn read(id: u32, buf: &mut Cursor<&[u8]>) -> Result<Self, Box<ReadPacketError>>;
|
||||||
|
|
||||||
fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error>;
|
fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error>;
|
||||||
|
|
|
@ -76,8 +76,8 @@ pub enum FrameSplitterError {
|
||||||
ConnectionClosed,
|
ConnectionClosed,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a length, then read that amount of bytes from BytesMut. If there's not
|
/// Read a length, then read that amount of bytes from `BytesMut`. If there's
|
||||||
/// enough data, return None
|
/// not enough data, return None
|
||||||
fn parse_frame(buffer: &mut BytesMut) -> Result<BytesMut, FrameSplitterError> {
|
fn parse_frame(buffer: &mut BytesMut) -> Result<BytesMut, FrameSplitterError> {
|
||||||
// copy the buffer first and read from the copy, then once we make sure
|
// copy the buffer first and read from the copy, then once we make sure
|
||||||
// the packet is all good we read it fully
|
// the packet is all good we read it fully
|
||||||
|
@ -258,41 +258,28 @@ where
|
||||||
Ok(packet)
|
Ok(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(test)]
|
#[cfg(test)]
|
||||||
// mod tests {
|
mod tests {
|
||||||
// use super::*;
|
use super::*;
|
||||||
// use crate::packets::game::{clientbound_player_chat_packet::ChatType,
|
use crate::packets::game::ClientboundGamePacket;
|
||||||
// ClientboundGamePacket}; use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
// #[tokio::test]
|
#[tokio::test]
|
||||||
// async fn test_read_packet() {
|
async fn test_read_packet() {
|
||||||
// let mut buf: Cursor<&[u8]> = Cursor::new(&[
|
let mut buf: Cursor<&[u8]> = Cursor::new(&[
|
||||||
// 51, 0, 12, 177, 250, 155, 132, 106, 60, 218, 161, 217, 90, 157,
|
56, 64, 85, 58, 141, 138, 71, 146, 193, 64, 88, 0, 0, 0, 0, 0, 0, 64, 60, 224, 105, 34,
|
||||||
// 105, 57, 206, 20, 0, 5, 104, 101, 108, 108, 111, 0, 0, 0, 0, 0,
|
119, 8, 228, 67, 50, 51, 68, 194, 177, 230, 101, 0, 17, 0,
|
||||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 116, 123, 34, 101, 120,
|
]);
|
||||||
// 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114, 34, 58,
|
let packet = packet_decoder::<ClientboundGamePacket>(&mut buf).unwrap();
|
||||||
// 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58,
|
match &packet {
|
||||||
// 34, 91, 77, 69, 77, 66, 69, 82, 93, 32, 112, 108, 97, 121, 101,
|
ClientboundGamePacket::PlayerPosition(p) => {
|
||||||
// 114, 49, 34, 125, 44, 123, 34, 116, 101, 120, 116, 34, 58, 34,
|
assert_eq!(p.id, 17);
|
||||||
// 32, 34, 125, 44, 123, 34, 99, 111, 108, 111, 114, 34, 58, 34, 103,
|
assert_eq!(p.x, 84.91488892545296);
|
||||||
// 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 92,
|
assert_eq!(p.y, 96.0);
|
||||||
// 117, 48, 48, 51, 101, 32, 104, 101, 108, 108, 111, 34, 125, 93,
|
assert_eq!(p.z, 28.876604227124417);
|
||||||
// 44, 34, 116, 101, 120, 116, 34, 58, 34, 34, 125, 0, 7, 64, 123,
|
assert_eq!(p.dismount_vehicle, false);
|
||||||
// 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114,
|
}
|
||||||
// 34, 58, 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116,
|
_ => panic!("Wrong packet type"),
|
||||||
// 34, 58, 34, 91, 77, 69, 77, 66, 69, 82, 93, 32, 112, 108, 97,
|
}
|
||||||
// 121, 101, 114, 49, 34, 125, 93, 44, 34, 116, 101, 120, 116, 34,
|
}
|
||||||
// 58, 34, 34, 125, 0, ]);
|
}
|
||||||
// let packet = packet_decoder::<ClientboundGamePacket>(&mut
|
|
||||||
// buf).unwrap(); match &packet {
|
|
||||||
// ClientboundGamePacket::PlayerChat(m) => {
|
|
||||||
// assert_eq!(
|
|
||||||
// m.chat_type.chat_type,
|
|
||||||
// ChatType::Chat,
|
|
||||||
// "Enums should default if they're invalid"
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// _ => panic!("Wrong packet type"),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub enum ResolverError {
|
||||||
|
|
||||||
/// Resolve a Minecraft server address into an IP address and port.
|
/// Resolve a Minecraft server address into an IP address and port.
|
||||||
/// If it's already an IP address, it's returned as-is.
|
/// If it's already an IP address, it's returned as-is.
|
||||||
|
#[must_use]
|
||||||
#[async_recursion]
|
#[async_recursion]
|
||||||
pub async fn resolve_address(address: &ServerAddress) -> Result<SocketAddr, ResolverError> {
|
pub async fn resolve_address(address: &ServerAddress) -> Result<SocketAddr, ResolverError> {
|
||||||
// If the address.host is already in the format of an ip address, return it.
|
// If the address.host is already in the format of an ip address, return it.
|
||||||
|
|
Loading…
Add table
Reference in a new issue