aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-26 22:15:07 -0500
committermat <github@matdoes.dev>2022-04-26 22:15:07 -0500
commitf859dbbba06278f52517b0096b92ff3a6932ee28 (patch)
tree66f72298eb041f77afd4cff75e39e41caf91a7b0
parent9c69d7d5f2f704b1de37e1a102bf4390cdd879a5 (diff)
downloadazalea-drasl-f859dbbba06278f52517b0096b92ff3a6932ee28.tar.xz
update brigadier
-rwxr-xr-xazalea-client/src/connect.rs3
-rwxr-xr-xazalea-protocol/src/mc_buf/read.rs20
-rwxr-xr-xazalea-protocol/src/mc_buf/write.rs12
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs287
-rw-r--r--azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs9
-rwxr-xr-xazalea-protocol/src/packets/game/mod.rs2
-rw-r--r--bot/src/main.rs2
7 files changed, 328 insertions, 7 deletions
diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs
index b29ead3c..77303930 100755
--- a/azalea-client/src/connect.rs
+++ b/azalea-client/src/connect.rs
@@ -117,6 +117,9 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> {
GamePacket::ClientboundUpdateRecipesPacket(p) => {
println!("Got update recipes packet {:?}", p);
}
+ GamePacket::ClientboundEntityEventPacket(p) => {
+ println!("Got entity event packet {:?}", p);
+ }
},
Err(e) => {
panic!("Error: {:?}", e);
diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-protocol/src/mc_buf/read.rs
index 4c126b7e..d3382e0a 100755
--- a/azalea-protocol/src/mc_buf/read.rs
+++ b/azalea-protocol/src/mc_buf/read.rs
@@ -28,6 +28,7 @@ pub trait Readable {
async fn read_resource_location(&mut self) -> Result<ResourceLocation, String>;
async fn read_short(&mut self) -> Result<i16, String>;
async fn read_float(&mut self) -> Result<f32, String>;
+ async fn read_double(&mut self) -> Result<f64, String>;
}
#[async_trait]
@@ -130,7 +131,6 @@ where
self.read_exact(&mut buffer)
.await
.map_err(|_| "Invalid UTF-8".to_string())?;
-
string.push_str(std::str::from_utf8(&buffer).unwrap());
if string.len() > length as usize {
return Err(format!(
@@ -200,6 +200,13 @@ where
Err(_) => Err("Error reading float".to_string()),
}
}
+
+ async fn read_double(&mut self) -> Result<f64, String> {
+ match AsyncReadExt::read_f64(self).await {
+ Ok(r) => Ok(r),
+ Err(_) => Err("Error reading double".to_string()),
+ }
+ }
}
#[async_trait]
@@ -399,6 +406,17 @@ impl McBufReadable for f32 {
}
}
+// f64
+#[async_trait]
+impl McBufReadable for f64 {
+ async fn read_into<R>(buf: &mut R) -> Result<Self, String>
+ where
+ R: AsyncRead + std::marker::Unpin + std::marker::Send,
+ {
+ buf.read_double().await
+ }
+}
+
// GameType
#[async_trait]
impl McBufReadable for GameType {
diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs
index 2c46157b..b57ad786 100755
--- a/azalea-protocol/src/mc_buf/write.rs
+++ b/azalea-protocol/src/mc_buf/write.rs
@@ -42,6 +42,7 @@ pub trait Writable {
location: &ResourceLocation,
) -> Result<(), std::io::Error>;
fn write_float(&mut self, n: f32) -> Result<(), std::io::Error>;
+ fn write_double(&mut self, n: f64) -> Result<(), std::io::Error>;
}
#[async_trait]
@@ -152,6 +153,10 @@ impl Writable for Vec<u8> {
WriteBytesExt::write_f32::<BigEndian>(self, n)
}
+ fn write_double(&mut self, n: f64) -> Result<(), std::io::Error> {
+ WriteBytesExt::write_f64::<BigEndian>(self, n)
+ }
+
fn write_resource_location(
&mut self,
location: &ResourceLocation,
@@ -291,6 +296,13 @@ impl McBufWritable for f32 {
}
}
+// f64
+impl McBufWritable for f64 {
+ fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
+ buf.write_double(*self)
+ }
+}
+
// GameType
impl McBufWritable for GameType {
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
diff --git a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs b/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
index 2df78ce9..0a16440e 100755
--- a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
@@ -1,8 +1,9 @@
use super::GamePacket;
-use crate::mc_buf::{McBufReadable, Readable};
+use crate::mc_buf::{McBufReadable, McBufWritable, Readable};
use async_trait::async_trait;
+use azalea_core::resource_location::ResourceLocation;
use std::hash::Hash;
-use tokio::io::AsyncRead;
+use tokio::io::{AsyncRead, AsyncReadExt, AsyncWriteExt};
#[derive(Hash, Clone, Debug)]
pub struct ClientboundDeclareCommandsPacket {
@@ -23,6 +24,7 @@ impl ClientboundDeclareCommandsPacket {
buf: &mut T,
) -> Result<GamePacket, String> {
let node_count = buf.read_varint().await?;
+ println!("node_count: {}", node_count);
let mut nodes = Vec::with_capacity(node_count as usize);
for _ in 0..node_count {
let node = BrigadierNodeStub::read_into(buf).await?;
@@ -41,6 +43,268 @@ impl ClientboundDeclareCommandsPacket {
#[derive(Hash, Debug, Clone)]
pub struct BrigadierNodeStub {}
+#[derive(Debug, Clone)]
+pub struct BrigadierNumber<T> {
+ min: Option<T>,
+ max: Option<T>,
+}
+#[async_trait]
+impl<T: McBufReadable + Send> McBufReadable for BrigadierNumber<T> {
+ async fn read_into<R>(buf: &mut R) -> Result<Self, String>
+ where
+ R: AsyncRead + std::marker::Unpin + std::marker::Send,
+ {
+ let flags = buf.read_byte().await?;
+ let min = if flags & 0x01 != 0 {
+ Some(T::read_into(buf).await?)
+ } else {
+ None
+ };
+ let max = if flags & 0x02 != 0 {
+ Some(T::read_into(buf).await?)
+ } else {
+ None
+ };
+ Ok(BrigadierNumber { min, max })
+ }
+}
+impl<T: McBufWritable> McBufWritable for BrigadierNumber<T> {
+ fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
+ let mut flags = 0;
+ if self.min.is_some() {
+ flags |= 0x01;
+ }
+ if self.max.is_some() {
+ flags |= 0x02;
+ }
+ buf.write_i8(flags);
+ if let Some(min) = &self.min {
+ min.write_into(buf)?;
+ }
+ if let Some(max) = &self.max {
+ max.write_into(buf)?;
+ }
+ Ok(())
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum BrigadierString {
+ /// Reads a single word
+ SingleWord = 0,
+ // If it starts with a ", keeps reading until another " (allowing escaping with \). Otherwise behaves the same as SINGLE_WORD
+ QuotablePhrase = 1,
+ // Reads the rest of the content after the cursor. Quotes will not be removed.
+ GreedyPhrase = 2,
+}
+
+#[async_trait]
+impl McBufReadable for BrigadierString {
+ async fn read_into<R>(buf: &mut R) -> Result<Self, String>
+ where
+ R: AsyncRead + std::marker::Unpin + std::marker::Send,
+ {
+ let id = buf.read_byte().await?;
+ Ok(match id {
+ 0 => BrigadierString::SingleWord,
+ 1 => BrigadierString::QuotablePhrase,
+ 2 => BrigadierString::GreedyPhrase,
+ _ => panic!("Unknown BrigadierString id: {}", id),
+ })
+ }
+}
+impl McBufWritable for BrigadierString {
+ fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
+ buf.write_i8(*self as i8);
+ Ok(())
+ }
+}
+
+#[derive(Debug, Clone)]
+pub enum BrigadierParser {
+ Bool,
+ Double(BrigadierNumber<f64>),
+ Float(BrigadierNumber<f32>),
+ Integer(BrigadierNumber<i32>),
+ Long(BrigadierNumber<i64>),
+ String(BrigadierString),
+ Entity { single: bool, players_only: bool },
+ GameProfile,
+ BlockPos,
+ ColumnPos,
+ Vec3,
+ Vec2,
+ BlockState,
+ BlockPredicate,
+ ItemStack,
+ ItemPredicate,
+ Color,
+ Component,
+ Message,
+ Nbt,
+ NbtPath,
+ Objective,
+ ObjectiveCriteira,
+ Operation,
+ Particle,
+ Rotation,
+ Angle,
+ ScoreboardSlot,
+ ScoreHolder { allows_multiple: bool },
+ Swizzle,
+ Team,
+ ItemSlot,
+ ResourceLocation,
+ MobEffect,
+ Function,
+ EntityAnchor,
+ Range { decimals_allowed: bool },
+ IntRange,
+ FloatRange,
+ ItemEnchantment,
+ EntitySummon,
+ Dimension,
+ Uuid,
+ NbtTag,
+ NbtCompoundTag,
+ Time,
+ ResourceOrTag { registry_key: ResourceLocation },
+ Resource { registry_key: ResourceLocation },
+}
+
+#[async_trait]
+impl McBufReadable for BrigadierParser {
+ async fn read_into<R>(buf: &mut R) -> Result<Self, String>
+ where
+ R: AsyncRead + std::marker::Unpin + std::marker::Send,
+ {
+ let parser = buf.read_resource_location().await?;
+
+ if parser == ResourceLocation::new("brigadier:bool")? {
+ Ok(BrigadierParser::Bool)
+ } else if parser == ResourceLocation::new("brigadier:double")? {
+ Ok(BrigadierParser::Double(
+ BrigadierNumber::read_into(buf).await?,
+ ))
+ } else if parser == ResourceLocation::new("brigadier:float")? {
+ Ok(BrigadierParser::Float(
+ BrigadierNumber::read_into(buf).await?,
+ ))
+ } else if parser == ResourceLocation::new("brigadier:integer")? {
+ Ok(BrigadierParser::Integer(
+ BrigadierNumber::read_into(buf).await?,
+ ))
+ } else if parser == ResourceLocation::new("brigadier:long")? {
+ Ok(BrigadierParser::Long(
+ BrigadierNumber::read_into(buf).await?,
+ ))
+ } else if parser == ResourceLocation::new("brigadier:string")? {
+ Ok(BrigadierParser::String(
+ BrigadierString::read_into(buf).await?,
+ ))
+ } else if parser == ResourceLocation::new("minecraft:entity")? {
+ let flags = buf.read_byte().await?;
+ Ok(BrigadierParser::Entity {
+ single: flags & 0x01 != 0,
+ players_only: flags & 0x02 != 0,
+ })
+ } else if parser == ResourceLocation::new("minecraft:game_profile")? {
+ Ok(BrigadierParser::GameProfile)
+ } else if parser == ResourceLocation::new("minecraft:block_pos")? {
+ Ok(BrigadierParser::BlockPos)
+ } else if parser == ResourceLocation::new("minecraft:column_pos")? {
+ Ok(BrigadierParser::ColumnPos)
+ } else if parser == ResourceLocation::new("minecraft:vec3")? {
+ Ok(BrigadierParser::Vec3)
+ } else if parser == ResourceLocation::new("minecraft:vec2")? {
+ Ok(BrigadierParser::Vec2)
+ } else if parser == ResourceLocation::new("minecraft:block_state")? {
+ Ok(BrigadierParser::BlockState)
+ } else if parser == ResourceLocation::new("minecraft:block_predicate")? {
+ Ok(BrigadierParser::BlockPredicate)
+ } else if parser == ResourceLocation::new("minecraft:item_stack")? {
+ Ok(BrigadierParser::ItemStack)
+ } else if parser == ResourceLocation::new("minecraft:item_predicate")? {
+ Ok(BrigadierParser::ItemPredicate)
+ } else if parser == ResourceLocation::new("minecraft:color")? {
+ Ok(BrigadierParser::Color)
+ } else if parser == ResourceLocation::new("minecraft:component")? {
+ Ok(BrigadierParser::Component)
+ } else if parser == ResourceLocation::new("minecraft:message")? {
+ Ok(BrigadierParser::Message)
+ } else if parser == ResourceLocation::new("minecraft:nbt")? {
+ Ok(BrigadierParser::Nbt)
+ } else if parser == ResourceLocation::new("minecraft:nbt_path")? {
+ Ok(BrigadierParser::NbtPath)
+ } else if parser == ResourceLocation::new("minecraft:objective")? {
+ Ok(BrigadierParser::Objective)
+ } else if parser == ResourceLocation::new("minecraft:objective_criteria")? {
+ Ok(BrigadierParser::ObjectiveCriteira)
+ } else if parser == ResourceLocation::new("minecraft:operation")? {
+ Ok(BrigadierParser::Operation)
+ } else if parser == ResourceLocation::new("minecraft:particle")? {
+ Ok(BrigadierParser::Particle)
+ } else if parser == ResourceLocation::new("minecraft:rotation")? {
+ Ok(BrigadierParser::Rotation)
+ } else if parser == ResourceLocation::new("minecraft:angle")? {
+ Ok(BrigadierParser::Angle)
+ } else if parser == ResourceLocation::new("minecraft:scoreboard_slot")? {
+ Ok(BrigadierParser::ScoreboardSlot)
+ } else if parser == ResourceLocation::new("minecraft:score_holder")? {
+ let flags = buf.read_byte().await?;
+ Ok(BrigadierParser::ScoreHolder {
+ allows_multiple: flags & 0x01 != 0,
+ })
+ } else if parser == ResourceLocation::new("minecraft:swizzle")? {
+ Ok(BrigadierParser::Swizzle)
+ } else if parser == ResourceLocation::new("minecraft:team")? {
+ Ok(BrigadierParser::Team)
+ } else if parser == ResourceLocation::new("minecraft:item_slot")? {
+ Ok(BrigadierParser::ItemSlot)
+ } else if parser == ResourceLocation::new("minecraft:resource_location")? {
+ Ok(BrigadierParser::ResourceLocation)
+ } else if parser == ResourceLocation::new("minecraft:mob_effect")? {
+ Ok(BrigadierParser::MobEffect)
+ } else if parser == ResourceLocation::new("minecraft:function")? {
+ Ok(BrigadierParser::Function)
+ } else if parser == ResourceLocation::new("minecraft:entity_anchor")? {
+ Ok(BrigadierParser::EntityAnchor)
+ } else if parser == ResourceLocation::new("minecraft:range")? {
+ Ok(BrigadierParser::Range {
+ decimals_allowed: buf.read_boolean().await?,
+ })
+ } else if parser == ResourceLocation::new("minecraft:int_range")? {
+ Ok(BrigadierParser::IntRange)
+ } else if parser == ResourceLocation::new("minecraft:float_range")? {
+ Ok(BrigadierParser::FloatRange)
+ } else if parser == ResourceLocation::new("minecraft:item_enchantment")? {
+ Ok(BrigadierParser::ItemEnchantment)
+ } else if parser == ResourceLocation::new("minecraft:entity_summon")? {
+ Ok(BrigadierParser::EntitySummon)
+ } else if parser == ResourceLocation::new("minecraft:dimension")? {
+ Ok(BrigadierParser::Dimension)
+ } else if parser == ResourceLocation::new("minecraft:uuid")? {
+ Ok(BrigadierParser::Uuid)
+ } else if parser == ResourceLocation::new("minecraft:nbt_tag")? {
+ Ok(BrigadierParser::NbtTag)
+ } else if parser == ResourceLocation::new("minecraft:nbt_compound_tag")? {
+ Ok(BrigadierParser::NbtCompoundTag)
+ } else if parser == ResourceLocation::new("minecraft:time")? {
+ Ok(BrigadierParser::Time)
+ } else if parser == ResourceLocation::new("minecraft:resource_or_tag")? {
+ Ok(BrigadierParser::ResourceOrTag {
+ registry_key: buf.read_resource_location().await?,
+ })
+ } else if parser == ResourceLocation::new("minecraft:resource")? {
+ Ok(BrigadierParser::Resource {
+ registry_key: buf.read_resource_location().await?,
+ })
+ } else {
+ panic!("Unknown Brigadier parser: {}", parser)
+ }
+ }
+}
+
// azalea_brigadier::tree::CommandNode
#[async_trait]
impl McBufReadable for BrigadierNodeStub {
@@ -49,33 +313,46 @@ impl McBufReadable for BrigadierNodeStub {
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let flags = u8::read_into(buf).await?;
+ if flags > 31 {
+ println!(
+ "Warning: The flags from a Brigadier node are over 31. This is probably a bug."
+ );
+ }
let node_type = flags & 0x03;
let is_executable = flags & 0x04 != 0;
let has_redirect = flags & 0x08 != 0;
let has_suggestions_type = flags & 0x10 != 0;
+ println!("flags: {}, node_type: {}, is_executable: {}, has_redirect: {}, has_suggestions_type: {}", flags, node_type, is_executable, has_redirect, has_suggestions_type);
let children = buf.read_int_id_list().await?;
+ println!("children: {:?}", children);
let redirect_node = if has_redirect {
buf.read_varint().await?
} else {
0
};
+ println!("redirect_node: {}", redirect_node);
+ // argument node
if node_type == 2 {
let name = buf.read_utf().await?;
+ println!("name: {}", name);
+
+ let parser = BrigadierParser::read_into(buf).await?;
- let resource_location = if has_suggestions_type {
+ let suggestions_type = if has_suggestions_type {
Some(buf.read_resource_location().await?)
} else {
None
};
println!(
- "node_type=2, flags={}, name={}, resource_location={:?}",
- flags, name, resource_location
+ "node_type=2, flags={}, name={}, parser={:?}, suggestions_type={:?}",
+ flags, name, parser, suggestions_type
);
return Ok(BrigadierNodeStub {});
}
+ // literal node
if node_type == 1 {
let name = buf.read_utf().await?;
println!("node_type=1, flags={}, name={}", flags, name);
diff --git a/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs
new file mode 100644
index 00000000..82b0072d
--- /dev/null
+++ b/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs
@@ -0,0 +1,9 @@
+use azalea_core::{game_type::GameType, resource_location::ResourceLocation};
+use packet_macros::GamePacket;
+
+// we can't identify the status in azalea-protocol since they vary depending on the entity
+#[derive(Clone, Debug, GamePacket)]
+pub struct ClientboundEntityEventPacket {
+ pub entity_id: i32,
+ pub entity_status: i8,
+}
diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs
index 986a7010..fefeb08b 100755
--- a/azalea-protocol/src/packets/game/mod.rs
+++ b/azalea-protocol/src/packets/game/mod.rs
@@ -2,6 +2,7 @@ pub mod clientbound_change_difficulty_packet;
pub mod clientbound_custom_payload_packet;
pub mod clientbound_declare_commands_packet;
pub mod clientbound_disconnect_packet;
+pub mod clientbound_entity_event_packet;
pub mod clientbound_login_packet;
pub mod clientbound_player_abilities_packet;
pub mod clientbound_set_carried_item_packet;
@@ -18,6 +19,7 @@ declare_state_packets!(
0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
0x12: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket,
0x1a: clientbound_disconnect_packet::ClientboundDisconnectPacket,
+ 0x1b: clientbound_entity_event_packet::ClientboundEntityEventPacket,
0x18: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket,
0x26: clientbound_login_packet::ClientboundLoginPacket,
0x32: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket,
diff --git a/bot/src/main.rs b/bot/src/main.rs
index b13a608b..d7905661 100644
--- a/bot/src/main.rs
+++ b/bot/src/main.rs
@@ -3,7 +3,7 @@ async fn main() {
println!("Hello, world!");
// let address = "95.111.249.143:10000";
- let address = "localhost:57308";
+ let address = "localhost:53810";
// let response = azalea_client::ping::ping_server(&address.try_into().unwrap())
// .await
// .unwrap();