mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
293 lines
8.9 KiB
Rust
Executable file
293 lines
8.9 KiB
Rust
Executable file
use azalea_buf::BufReadError;
|
|
use azalea_buf::McBuf;
|
|
use azalea_buf::McBufVarReadable;
|
|
use azalea_buf::{McBufReadable, McBufWritable};
|
|
use azalea_core::ResourceLocation;
|
|
use azalea_protocol_macros::ClientboundGamePacket;
|
|
use log::warn;
|
|
use std::io::Cursor;
|
|
use std::io::Write;
|
|
|
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
|
pub struct ClientboundCommandsPacket {
|
|
pub entries: Vec<BrigadierNodeStub>,
|
|
#[var]
|
|
pub root_index: u32,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct BrigadierNodeStub {
|
|
pub is_executable: bool,
|
|
pub children: Vec<u32>,
|
|
pub redirect_node: Option<u32>,
|
|
pub node_type: NodeType,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct BrigadierNumber<T> {
|
|
min: Option<T>,
|
|
max: Option<T>,
|
|
}
|
|
impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
|
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
|
let flags = u8::read_from(buf)?;
|
|
let min = if flags & 0x01 != 0 {
|
|
Some(T::read_from(buf)?)
|
|
} else {
|
|
None
|
|
};
|
|
let max = if flags & 0x02 != 0 {
|
|
Some(T::read_from(buf)?)
|
|
} else {
|
|
None
|
|
};
|
|
Ok(BrigadierNumber { min, max })
|
|
}
|
|
}
|
|
impl<T: McBufWritable> McBufWritable for BrigadierNumber<T> {
|
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
|
let mut flags: u8 = 0;
|
|
if self.min.is_some() {
|
|
flags |= 0x01;
|
|
}
|
|
if self.max.is_some() {
|
|
flags |= 0x02;
|
|
}
|
|
flags.write_into(buf)?;
|
|
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, McBuf)]
|
|
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,
|
|
}
|
|
|
|
#[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,
|
|
IntRange,
|
|
FloatRange,
|
|
ItemEnchantment,
|
|
EntitySummon,
|
|
Dimension,
|
|
Uuid,
|
|
NbtTag,
|
|
NbtCompoundTag,
|
|
Time,
|
|
ResourceOrTag { registry_key: ResourceLocation },
|
|
Resource { registry_key: ResourceLocation },
|
|
TemplateMirror,
|
|
TemplateRotation,
|
|
}
|
|
|
|
impl McBufReadable for BrigadierParser {
|
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
|
let parser_type = u32::var_read_from(buf)?;
|
|
|
|
match parser_type {
|
|
0 => Ok(BrigadierParser::Bool),
|
|
1 => Ok(BrigadierParser::Float(BrigadierNumber::read_from(buf)?)),
|
|
2 => Ok(BrigadierParser::Double(BrigadierNumber::read_from(buf)?)),
|
|
3 => Ok(BrigadierParser::Integer(BrigadierNumber::read_from(buf)?)),
|
|
4 => Ok(BrigadierParser::Long(BrigadierNumber::read_from(buf)?)),
|
|
5 => Ok(BrigadierParser::String(BrigadierString::read_from(buf)?)),
|
|
6 => {
|
|
let flags = u8::read_from(buf)?;
|
|
Ok(BrigadierParser::Entity {
|
|
single: flags & 0x01 != 0,
|
|
players_only: flags & 0x02 != 0,
|
|
})
|
|
}
|
|
7 => Ok(BrigadierParser::GameProfile),
|
|
8 => Ok(BrigadierParser::BlockPos),
|
|
9 => Ok(BrigadierParser::ColumnPos),
|
|
10 => Ok(BrigadierParser::Vec3),
|
|
11 => Ok(BrigadierParser::Vec2),
|
|
12 => Ok(BrigadierParser::BlockState),
|
|
13 => Ok(BrigadierParser::BlockPredicate),
|
|
14 => Ok(BrigadierParser::ItemStack),
|
|
15 => Ok(BrigadierParser::ItemPredicate),
|
|
16 => Ok(BrigadierParser::Color),
|
|
17 => Ok(BrigadierParser::Component),
|
|
18 => Ok(BrigadierParser::Message),
|
|
19 => Ok(BrigadierParser::NbtCompoundTag),
|
|
20 => Ok(BrigadierParser::NbtTag),
|
|
21 => Ok(BrigadierParser::NbtPath),
|
|
22 => Ok(BrigadierParser::Objective),
|
|
23 => Ok(BrigadierParser::ObjectiveCriteira),
|
|
24 => Ok(BrigadierParser::Operation),
|
|
25 => Ok(BrigadierParser::Particle),
|
|
26 => Ok(BrigadierParser::Angle),
|
|
27 => Ok(BrigadierParser::Rotation),
|
|
28 => Ok(BrigadierParser::ScoreboardSlot),
|
|
29 => {
|
|
let flags = u8::read_from(buf)?;
|
|
Ok(BrigadierParser::ScoreHolder {
|
|
allows_multiple: flags & 0x01 != 0,
|
|
})
|
|
}
|
|
30 => Ok(BrigadierParser::Swizzle),
|
|
31 => Ok(BrigadierParser::Team),
|
|
32 => Ok(BrigadierParser::ItemSlot),
|
|
33 => Ok(BrigadierParser::ResourceLocation),
|
|
34 => Ok(BrigadierParser::MobEffect),
|
|
35 => Ok(BrigadierParser::Function),
|
|
36 => Ok(BrigadierParser::EntityAnchor),
|
|
37 => Ok(BrigadierParser::IntRange),
|
|
38 => Ok(BrigadierParser::FloatRange),
|
|
39 => Ok(BrigadierParser::ItemEnchantment),
|
|
40 => Ok(BrigadierParser::EntitySummon),
|
|
41 => Ok(BrigadierParser::Dimension),
|
|
42 => Ok(BrigadierParser::Time),
|
|
43 => Ok(BrigadierParser::ResourceOrTag {
|
|
registry_key: ResourceLocation::read_from(buf)?,
|
|
}),
|
|
44 => Ok(BrigadierParser::Resource {
|
|
registry_key: ResourceLocation::read_from(buf)?,
|
|
}),
|
|
45 => Ok(BrigadierParser::TemplateMirror),
|
|
46 => Ok(BrigadierParser::TemplateRotation),
|
|
47 => Ok(BrigadierParser::Uuid),
|
|
_ => Err(BufReadError::UnexpectedEnumVariant {
|
|
id: parser_type as i32,
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: BrigadierNodeStub should have more stuff
|
|
impl McBufReadable for BrigadierNodeStub {
|
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
|
let flags = u8::read_from(buf)?;
|
|
if flags > 31 {
|
|
warn!(
|
|
"Warning: The flags from a Brigadier node are over 31 ({flags}; {flags:#b}). 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;
|
|
|
|
let children = Vec::<u32>::var_read_from(buf)?;
|
|
let redirect_node = if has_redirect {
|
|
Some(u32::var_read_from(buf)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// argument node
|
|
if node_type == 2 {
|
|
let name = String::read_from(buf)?;
|
|
let parser = BrigadierParser::read_from(buf)?;
|
|
let suggestions_type = if has_suggestions_type {
|
|
Some(ResourceLocation::read_from(buf)?)
|
|
} else {
|
|
None
|
|
};
|
|
return Ok(BrigadierNodeStub {
|
|
is_executable,
|
|
children,
|
|
redirect_node,
|
|
node_type: NodeType::Argument {
|
|
name,
|
|
parser,
|
|
suggestions_type,
|
|
},
|
|
});
|
|
}
|
|
// literal node
|
|
if node_type == 1 {
|
|
let name = String::read_from(buf)?;
|
|
return Ok(BrigadierNodeStub {
|
|
is_executable,
|
|
children,
|
|
redirect_node,
|
|
node_type: NodeType::Literal { name },
|
|
});
|
|
}
|
|
Ok(BrigadierNodeStub {
|
|
is_executable,
|
|
children,
|
|
redirect_node,
|
|
node_type: NodeType::Root,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl McBufWritable for BrigadierNodeStub {
|
|
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum NodeType {
|
|
Root,
|
|
Literal {
|
|
name: String,
|
|
},
|
|
Argument {
|
|
name: String,
|
|
parser: BrigadierParser,
|
|
suggestions_type: Option<ResourceLocation>,
|
|
},
|
|
}
|
|
|
|
impl BrigadierNodeStub {
|
|
pub fn name(&self) -> Option<&str> {
|
|
match &self.node_type {
|
|
NodeType::Root => None,
|
|
NodeType::Literal { name } => Some(name),
|
|
NodeType::Argument { name, .. } => Some(name),
|
|
}
|
|
}
|
|
}
|