mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
Complete ClientboundCommand{Suggestion}sPacket, Serde support for NBT Tags (#49)
* Serializing ClientboundStatusResponsePacket Enable serialization of ClientboundStatusResponsePacket * Update clientbound_status_response_packet.rs Add options previewsChat and enforcesSecureChat * Serialize Style and TextColor * Serialize BaseComponent * Serialize TextComponent * Fix Style * Serialize Component * Fix multiple formats per message, fix reset tag * Fix Style, again * Use FlatMapSerializer * Forgot italics * Count struct fields, reorganize logic * Serialize TranslatableComponent * Rewrite TextComponent Serializer * Fix using TextColor::Parse * Code Cleanup * Add default attribute, just in case * Clippy * use serde derive feature + preferred formatting choices * McBufWritable for BrigadierNodeStub * Thanks Clippy... * Implement suggestions in azalea-brigadier * Serde support for NBT Tags * Serde options * Forgot Options * Oops, that's McBufWritable for BrigadierParser * Fix McBufWritable for SlotData * Complete ClientboundUpdateRecipesPacket * fix some issues * better impl McBufReadable for Suggestions Co-authored-by: BuildTools <unconfigured@null.spigotmc.org> Co-authored-by: mat <github@matdoes.dev>
This commit is contained in:
parent
e99a822995
commit
9f5e5c092b
17 changed files with 563 additions and 96 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -37,6 +37,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -170,6 +171,10 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "azalea-brigadier"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"azalea-buf",
|
||||
"azalea-chat",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azalea-buf"
|
||||
|
@ -274,6 +279,7 @@ dependencies = [
|
|||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -9,3 +9,8 @@ version = "0.4.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
azalea-buf = {path = "../azalea-buf", version = "^0.4.0", optional = true}
|
||||
azalea-chat = {path = "../azalea-chat", version = "^0.4.0", optional = true}
|
||||
|
||||
[features]
|
||||
azalea-buf = ["dep:azalea-buf", "dep:azalea-chat"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::{message::Message, string_reader::StringReader};
|
||||
use crate::string_reader::StringReader;
|
||||
|
||||
use super::command_syntax_exception::CommandSyntaxException;
|
||||
|
||||
|
@ -148,12 +148,12 @@ impl fmt::Debug for BuiltInExceptions {
|
|||
|
||||
impl BuiltInExceptions {
|
||||
pub fn create(self) -> CommandSyntaxException {
|
||||
let message = Message::from(format!("{self:?}"));
|
||||
let message = format!("{self:?}");
|
||||
CommandSyntaxException::create(self, message)
|
||||
}
|
||||
|
||||
pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxException {
|
||||
let message = Message::from(format!("{self:?}"));
|
||||
let message = format!("{self:?}");
|
||||
CommandSyntaxException::new(self, message, reader.string(), reader.cursor())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use super::builtin_exceptions::BuiltInExceptions;
|
||||
use crate::message::Message;
|
||||
use std::{
|
||||
cmp,
|
||||
fmt::{self, Write},
|
||||
|
@ -8,7 +7,7 @@ use std::{
|
|||
#[derive(Clone, PartialEq)]
|
||||
pub struct CommandSyntaxException {
|
||||
pub type_: BuiltInExceptions,
|
||||
message: Message,
|
||||
message: String,
|
||||
input: Option<String>,
|
||||
cursor: Option<usize>,
|
||||
}
|
||||
|
@ -16,7 +15,7 @@ pub struct CommandSyntaxException {
|
|||
const CONTEXT_AMOUNT: usize = 10;
|
||||
|
||||
impl CommandSyntaxException {
|
||||
pub fn new(type_: BuiltInExceptions, message: Message, input: &str, cursor: usize) -> Self {
|
||||
pub fn new(type_: BuiltInExceptions, message: String, input: &str, cursor: usize) -> Self {
|
||||
Self {
|
||||
type_,
|
||||
message,
|
||||
|
@ -25,7 +24,7 @@ impl CommandSyntaxException {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create(type_: BuiltInExceptions, message: Message) -> Self {
|
||||
pub fn create(type_: BuiltInExceptions, message: String) -> Self {
|
||||
Self {
|
||||
type_,
|
||||
message,
|
||||
|
@ -35,7 +34,7 @@ impl CommandSyntaxException {
|
|||
}
|
||||
|
||||
pub fn message(&self) -> String {
|
||||
let mut message = self.message.string();
|
||||
let mut message = self.message.clone();
|
||||
let context = self.context();
|
||||
if let Some(context) = context {
|
||||
write!(
|
||||
|
@ -49,7 +48,7 @@ impl CommandSyntaxException {
|
|||
message
|
||||
}
|
||||
|
||||
pub fn raw_message(&self) -> &Message {
|
||||
pub fn raw_message(&self) -> &String {
|
||||
&self.message
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ pub mod builder;
|
|||
pub mod command_dispatcher;
|
||||
pub mod context;
|
||||
pub mod exceptions;
|
||||
pub mod message;
|
||||
pub mod modifier;
|
||||
pub mod parse_results;
|
||||
pub mod string_reader;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Message(String);
|
||||
|
||||
impl Message {
|
||||
pub fn string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Message {
|
||||
fn from(s: String) -> Self {
|
||||
Self(s)
|
||||
}
|
||||
}
|
|
@ -1,16 +1,26 @@
|
|||
mod suggestions;
|
||||
|
||||
use crate::{context::StringRange, message::Message};
|
||||
use crate::context::StringRange;
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
use azalea_buf::McBufWritable;
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
use azalea_chat::Component;
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
use std::io::Write;
|
||||
pub use suggestions::*;
|
||||
|
||||
/// A suggestion given to the user for what they might want to type next.
|
||||
///
|
||||
/// The `M` generic is the type of the tooltip, so for example a `String` or
|
||||
/// just `()` if you don't care about it.
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct Suggestion {
|
||||
pub range: StringRange,
|
||||
pub struct Suggestion<M = String> {
|
||||
pub text: String,
|
||||
pub tooltip: Option<Message>,
|
||||
pub range: StringRange,
|
||||
pub tooltip: Option<M>,
|
||||
}
|
||||
|
||||
impl Suggestion {
|
||||
impl<M: Clone> Suggestion<M> {
|
||||
pub fn apply(&self, input: &str) -> String {
|
||||
if self.range.start() == 0 && self.range.end() == input.len() {
|
||||
return input.to_string();
|
||||
|
@ -27,7 +37,7 @@ impl Suggestion {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn expand(&self, command: &str, range: &StringRange) -> Suggestion {
|
||||
pub fn expand(&self, command: &str, range: &StringRange) -> Suggestion<M> {
|
||||
if range == &self.range {
|
||||
return self.clone();
|
||||
}
|
||||
|
@ -46,3 +56,12 @@ impl Suggestion {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
impl McBufWritable for Suggestion<Component> {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
self.text.write_into(buf)?;
|
||||
self.tooltip.write_into(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
use super::Suggestion;
|
||||
use crate::context::StringRange;
|
||||
use std::collections::HashSet;
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
use azalea_buf::{
|
||||
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
|
||||
};
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
use azalea_chat::Component;
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
use std::io::{Cursor, Write};
|
||||
use std::{collections::HashSet, hash::Hash};
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||
pub struct Suggestions {
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Suggestions<M = String> {
|
||||
pub range: StringRange,
|
||||
pub suggestions: Vec<Suggestion>,
|
||||
pub suggestions: Vec<Suggestion<M>>,
|
||||
}
|
||||
|
||||
impl Suggestions {
|
||||
pub fn merge(command: &str, input: &[Suggestions]) -> Self {
|
||||
impl<M: Clone + Eq + Hash> Suggestions<M> {
|
||||
pub fn merge(command: &str, input: &[Suggestions<M>]) -> Self {
|
||||
if input.is_empty() {
|
||||
return Suggestions::default();
|
||||
} else if input.len() == 1 {
|
||||
|
@ -24,7 +32,7 @@ impl Suggestions {
|
|||
Suggestions::create(command, &texts)
|
||||
}
|
||||
|
||||
pub fn create(command: &str, suggestions: &HashSet<Suggestion>) -> Self {
|
||||
pub fn create(command: &str, suggestions: &HashSet<Suggestion<M>>) -> Self {
|
||||
if suggestions.is_empty() {
|
||||
return Suggestions::default();
|
||||
};
|
||||
|
@ -39,7 +47,7 @@ impl Suggestions {
|
|||
for suggestion in suggestions {
|
||||
texts.insert(suggestion.expand(command, &range));
|
||||
}
|
||||
let mut sorted: Vec<Suggestion> = texts.into_iter().collect();
|
||||
let mut sorted = texts.into_iter().collect::<Vec<_>>();
|
||||
sorted.sort_by(|a, b| a.text.cmp(&b.text));
|
||||
Suggestions {
|
||||
range,
|
||||
|
@ -47,3 +55,53 @@ impl Suggestions {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this can't be derived because that'd require the generic to have `Default`
|
||||
// too even if it's not actually necessary
|
||||
impl<M> Default for Suggestions<M> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
range: StringRange::default(),
|
||||
suggestions: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
impl McBufReadable for Suggestions<Component> {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
#[derive(McBuf)]
|
||||
struct StandaloneSuggestion {
|
||||
pub text: String,
|
||||
pub tooltip: Option<Component>,
|
||||
}
|
||||
|
||||
let start = u32::var_read_from(buf)? as usize;
|
||||
let length = u32::var_read_from(buf)? as usize;
|
||||
let range = StringRange::between(start, start + length);
|
||||
|
||||
// the range of a Suggestion depends on the Suggestions containing it,
|
||||
// so we can't just `impl McBufReadable for Suggestion`
|
||||
let mut suggestions = Vec::<StandaloneSuggestion>::read_from(buf)?
|
||||
.into_iter()
|
||||
.map(|s| Suggestion {
|
||||
text: s.text,
|
||||
tooltip: s.tooltip,
|
||||
range: range.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
suggestions.sort_by(|a, b| a.text.cmp(&b.text));
|
||||
|
||||
Ok(Suggestions { range, suggestions })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "azalea-buf")]
|
||||
impl McBufWritable for Suggestions<Component> {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
(self.range.start() as u32).var_write_into(buf)?;
|
||||
(self.range.length() as u32).var_write_into(buf)?;
|
||||
self.suggestions.write_into(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// TODO: have an azalea-inventory or azalea-container crate and put this there
|
||||
|
||||
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
|
||||
use azalea_nbt::Tag;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
@ -13,29 +14,27 @@ pub enum Slot {
|
|||
#[derive(Debug, Clone, McBuf)]
|
||||
pub struct SlotData {
|
||||
#[var]
|
||||
pub id: i32,
|
||||
pub id: u32,
|
||||
pub count: u8,
|
||||
pub nbt: azalea_nbt::Tag,
|
||||
pub nbt: Tag,
|
||||
}
|
||||
|
||||
impl McBufReadable for Slot {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
let present = bool::read_from(buf)?;
|
||||
if !present {
|
||||
return Ok(Slot::Empty);
|
||||
}
|
||||
let slot = SlotData::read_from(buf)?;
|
||||
Ok(Slot::Present(slot))
|
||||
let slot = Option::<SlotData>::read_from(buf)?;
|
||||
Ok(slot.map_or(Slot::Empty, Slot::Present))
|
||||
}
|
||||
}
|
||||
|
||||
impl McBufWritable for Slot {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match self {
|
||||
Slot::Empty => 0u8.write_into(buf)?,
|
||||
Slot::Present(i) => i.write_into(buf)?,
|
||||
}
|
||||
|
||||
Slot::Empty => false.write_into(buf)?,
|
||||
Slot::Present(i) => {
|
||||
true.write_into(buf)?;
|
||||
i.write_into(buf)?;
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,14 @@ repository = "https://github.com/mat-1/azalea/tree/main/azalea-nbt"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ahash = "^0.8.0"
|
||||
ahash = { version = "^0.8.0", features = ["serde"]}
|
||||
azalea-buf = {path = "../azalea-buf", version = "^0.4.0" }
|
||||
byteorder = "^1.4.3"
|
||||
flate2 = "^1.0.23"
|
||||
log = "0.4.17"
|
||||
num-derive = "^0.3.3"
|
||||
num-traits = "^0.2.14"
|
||||
serde = {version = "^1.0.148", features = ["derive"]}
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = {version = "^0.3.5", features = ["html_reports"]}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# Azalea NBT
|
||||
|
||||
A fast NBT serializer and deserializer.
|
||||
|
||||
TODO: serde support for fast registry_holder parsing in azalea-client
|
||||
|
|
|
@ -193,6 +193,10 @@ impl Tag {
|
|||
write_compound(writer, value, false)?;
|
||||
Ok(())
|
||||
}
|
||||
Tag::End => {
|
||||
0u8.write_into(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(Error::InvalidTag),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use ahash::AHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Tag {
|
||||
End, // 0
|
||||
Byte(i8), // 1
|
||||
|
|
|
@ -11,17 +11,17 @@ version = "0.4.0"
|
|||
[dependencies]
|
||||
async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true}
|
||||
async-recursion = "1.0.0"
|
||||
azalea-auth = {path = "../azalea-auth", version = "^0.4.0" }
|
||||
azalea-block = {path = "../azalea-block", default-features = false, version = "^0.4.0" }
|
||||
azalea-brigadier = {path = "../azalea-brigadier", version = "^0.4.0" }
|
||||
azalea-buf = {path = "../azalea-buf", version = "^0.4.0" }
|
||||
azalea-chat = {path = "../azalea-chat", version = "^0.4.0" }
|
||||
azalea-core = {path = "../azalea-core", optional = true, version = "^0.4.0" }
|
||||
azalea-crypto = {path = "../azalea-crypto", version = "^0.4.0" }
|
||||
azalea-nbt = {path = "../azalea-nbt", version = "^0.4.0" }
|
||||
azalea-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.4.0" }
|
||||
azalea-registry = {path = "../azalea-registry", version = "^0.4.0" }
|
||||
azalea-world = {path = "../azalea-world", version = "^0.4.0" }
|
||||
azalea-auth = {path = "../azalea-auth", version = "^0.4.0"}
|
||||
azalea-block = {path = "../azalea-block", default-features = false, version = "^0.4.0"}
|
||||
azalea-brigadier = {path = "../azalea-brigadier", version = "^0.4.0", features = ["azalea-buf"]}
|
||||
azalea-buf = {path = "../azalea-buf", version = "^0.4.0"}
|
||||
azalea-chat = {path = "../azalea-chat", version = "^0.4.0"}
|
||||
azalea-core = {path = "../azalea-core", optional = true, version = "^0.4.0"}
|
||||
azalea-crypto = {path = "../azalea-crypto", version = "^0.4.0"}
|
||||
azalea-nbt = {path = "../azalea-nbt", version = "^0.4.0"}
|
||||
azalea-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.4.0"}
|
||||
azalea-registry = {path = "../azalea-registry", version = "^0.4.0"}
|
||||
azalea-world = {path = "../azalea-world", version = "^0.4.0"}
|
||||
byteorder = "^1.4.3"
|
||||
bytes = "^1.1.0"
|
||||
flate2 = "1.0.23"
|
||||
|
|
|
@ -1,32 +1,36 @@
|
|||
// use azalea_brigadier::context::StringRange;
|
||||
use azalea_buf::{
|
||||
// BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
|
||||
BufReadError,
|
||||
McBufReadable,
|
||||
McBufWritable,
|
||||
};
|
||||
use azalea_brigadier::suggestion::Suggestions;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_chat::Component;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
#[derive(Clone, Debug, ClientboundGamePacket)]
|
||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||
pub struct ClientboundCommandSuggestionsPacket {
|
||||
#[var]
|
||||
pub id: u32,
|
||||
// pub suggestions: Suggestions,
|
||||
pub suggestions: Suggestions<Component>,
|
||||
}
|
||||
|
||||
impl McBufReadable for ClientboundCommandSuggestionsPacket {
|
||||
fn read_from(_buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
// let id = u32::var_read_from(buf)?;
|
||||
// let start = u32::var_read_from(buf)? as usize;
|
||||
// let length = u32::var_read_from(buf)? as usize;
|
||||
// let stringrange = StringRange::between(start, start + length);
|
||||
todo!("Suggestions aren't implemented in azalea-brigadier yet")
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use azalea_brigadier::{context::StringRange, suggestion::Suggestion};
|
||||
use azalea_buf::{McBufReadable, McBufWritable};
|
||||
use std::io::Cursor;
|
||||
|
||||
impl McBufWritable for ClientboundCommandSuggestionsPacket {
|
||||
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
todo!()
|
||||
#[test]
|
||||
fn test_suggestions() {
|
||||
let suggestions = Suggestions {
|
||||
range: StringRange::new(0, 5),
|
||||
suggestions: vec![Suggestion {
|
||||
text: "foo".to_string(),
|
||||
range: StringRange::new(1, 4),
|
||||
tooltip: Some(Component::from("bar".to_string())),
|
||||
}],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
suggestions.write_into(&mut buf).unwrap();
|
||||
let mut cursor = Cursor::new(&buf[..]);
|
||||
let suggestions = Suggestions::read_from(&mut cursor).unwrap();
|
||||
assert_eq!(suggestions, suggestions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use azalea_buf::BufReadError;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_buf::McBufVarReadable;
|
||||
use azalea_buf::{McBufReadable, McBufWritable};
|
||||
use azalea_buf::{McBufReadable, McBufVarWritable, McBufWritable};
|
||||
use azalea_core::ResourceLocation;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
use log::warn;
|
||||
|
@ -25,8 +25,13 @@ pub struct BrigadierNodeStub {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BrigadierNumber<T> {
|
||||
min: Option<T>,
|
||||
max: Option<T>,
|
||||
pub min: Option<T>,
|
||||
pub max: Option<T>,
|
||||
}
|
||||
impl<T> BrigadierNumber<T> {
|
||||
pub fn new(min: Option<T>, max: Option<T>) -> BrigadierNumber<T> {
|
||||
BrigadierNumber { min, max }
|
||||
}
|
||||
}
|
||||
impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
|
@ -119,7 +124,6 @@ pub enum BrigadierParser {
|
|||
Dimension,
|
||||
Uuid,
|
||||
NbtTag,
|
||||
NbtCompoundTag,
|
||||
Time,
|
||||
ResourceOrTag { registry_key: ResourceLocation },
|
||||
Resource { registry_key: ResourceLocation },
|
||||
|
@ -157,7 +161,7 @@ impl McBufReadable for BrigadierParser {
|
|||
16 => Ok(BrigadierParser::Color),
|
||||
17 => Ok(BrigadierParser::Component),
|
||||
18 => Ok(BrigadierParser::Message),
|
||||
19 => Ok(BrigadierParser::NbtCompoundTag),
|
||||
19 => Ok(BrigadierParser::Nbt),
|
||||
20 => Ok(BrigadierParser::NbtTag),
|
||||
21 => Ok(BrigadierParser::NbtPath),
|
||||
22 => Ok(BrigadierParser::Objective),
|
||||
|
@ -202,6 +206,181 @@ impl McBufReadable for BrigadierParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl McBufWritable for BrigadierParser {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match &self {
|
||||
BrigadierParser::Bool => {
|
||||
u32::var_write_into(&0, buf)?;
|
||||
}
|
||||
BrigadierParser::Float(f) => {
|
||||
u32::var_write_into(&1, buf)?;
|
||||
f.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::Double(d) => {
|
||||
u32::var_write_into(&2, buf)?;
|
||||
d.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::Integer(i) => {
|
||||
u32::var_write_into(&3, buf)?;
|
||||
i.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::Long(l) => {
|
||||
u32::var_write_into(&4, buf)?;
|
||||
l.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::String(s) => {
|
||||
u32::var_write_into(&5, buf)?;
|
||||
s.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::Entity {
|
||||
single,
|
||||
players_only,
|
||||
} => {
|
||||
u32::var_write_into(&6, buf)?;
|
||||
let mut bitmask: u8 = 0x00;
|
||||
if *single {
|
||||
bitmask |= 0x01;
|
||||
}
|
||||
if *players_only {
|
||||
bitmask |= 0x02;
|
||||
}
|
||||
bitmask.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::GameProfile => {
|
||||
u32::var_write_into(&7, buf)?;
|
||||
}
|
||||
BrigadierParser::BlockPos => {
|
||||
u32::var_write_into(&8, buf)?;
|
||||
}
|
||||
BrigadierParser::ColumnPos => {
|
||||
u32::var_write_into(&9, buf)?;
|
||||
}
|
||||
BrigadierParser::Vec3 => {
|
||||
u32::var_write_into(&10, buf)?;
|
||||
}
|
||||
BrigadierParser::Vec2 => {
|
||||
u32::var_write_into(&11, buf)?;
|
||||
}
|
||||
BrigadierParser::BlockState => {
|
||||
u32::var_write_into(&12, buf)?;
|
||||
}
|
||||
BrigadierParser::BlockPredicate => {
|
||||
u32::var_write_into(&13, buf)?;
|
||||
}
|
||||
BrigadierParser::ItemStack => {
|
||||
u32::var_write_into(&14, buf)?;
|
||||
}
|
||||
BrigadierParser::ItemPredicate => {
|
||||
u32::var_write_into(&15, buf)?;
|
||||
}
|
||||
BrigadierParser::Color => {
|
||||
u32::var_write_into(&16, buf)?;
|
||||
}
|
||||
BrigadierParser::Component => {
|
||||
u32::var_write_into(&17, buf)?;
|
||||
}
|
||||
BrigadierParser::Message => {
|
||||
u32::var_write_into(&18, buf)?;
|
||||
}
|
||||
BrigadierParser::Nbt => {
|
||||
u32::var_write_into(&19, buf)?;
|
||||
}
|
||||
BrigadierParser::NbtTag => {
|
||||
u32::var_write_into(&20, buf)?;
|
||||
}
|
||||
BrigadierParser::NbtPath => {
|
||||
u32::var_write_into(&21, buf)?;
|
||||
}
|
||||
BrigadierParser::Objective => {
|
||||
u32::var_write_into(&22, buf)?;
|
||||
}
|
||||
BrigadierParser::ObjectiveCriteira => {
|
||||
u32::var_write_into(&23, buf)?;
|
||||
}
|
||||
BrigadierParser::Operation => {
|
||||
u32::var_write_into(&24, buf)?;
|
||||
}
|
||||
BrigadierParser::Particle => {
|
||||
u32::var_write_into(&25, buf)?;
|
||||
}
|
||||
BrigadierParser::Angle => {
|
||||
u32::var_write_into(&26, buf)?;
|
||||
}
|
||||
BrigadierParser::Rotation => {
|
||||
u32::var_write_into(&27, buf)?;
|
||||
}
|
||||
BrigadierParser::ScoreboardSlot => {
|
||||
u32::var_write_into(&28, buf)?;
|
||||
}
|
||||
BrigadierParser::ScoreHolder { allows_multiple } => {
|
||||
u32::var_write_into(&29, buf)?;
|
||||
if *allows_multiple {
|
||||
buf.write_all(&[0x01])?;
|
||||
} else {
|
||||
buf.write_all(&[0x00])?;
|
||||
}
|
||||
}
|
||||
BrigadierParser::Swizzle => {
|
||||
u32::var_write_into(&30, buf)?;
|
||||
}
|
||||
BrigadierParser::Team => {
|
||||
u32::var_write_into(&31, buf)?;
|
||||
}
|
||||
BrigadierParser::ItemSlot => {
|
||||
u32::var_write_into(&32, buf)?;
|
||||
}
|
||||
BrigadierParser::ResourceLocation => {
|
||||
u32::var_write_into(&33, buf)?;
|
||||
}
|
||||
BrigadierParser::MobEffect => {
|
||||
u32::var_write_into(&34, buf)?;
|
||||
}
|
||||
BrigadierParser::Function => {
|
||||
u32::var_write_into(&35, buf)?;
|
||||
}
|
||||
BrigadierParser::EntityAnchor => {
|
||||
u32::var_write_into(&36, buf)?;
|
||||
}
|
||||
BrigadierParser::IntRange => {
|
||||
u32::var_write_into(&37, buf)?;
|
||||
}
|
||||
BrigadierParser::FloatRange => {
|
||||
u32::var_write_into(&38, buf)?;
|
||||
}
|
||||
BrigadierParser::ItemEnchantment => {
|
||||
u32::var_write_into(&39, buf)?;
|
||||
}
|
||||
BrigadierParser::EntitySummon => {
|
||||
u32::var_write_into(&40, buf)?;
|
||||
}
|
||||
BrigadierParser::Dimension => {
|
||||
u32::var_write_into(&41, buf)?;
|
||||
}
|
||||
BrigadierParser::Time => {
|
||||
u32::var_write_into(&42, buf)?;
|
||||
}
|
||||
BrigadierParser::ResourceOrTag { registry_key } => {
|
||||
u32::var_write_into(&43, buf)?;
|
||||
registry_key.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::Resource { registry_key } => {
|
||||
u32::var_write_into(&44, buf)?;
|
||||
registry_key.write_into(buf)?;
|
||||
}
|
||||
BrigadierParser::TemplateMirror => {
|
||||
u32::var_write_into(&45, buf)?;
|
||||
}
|
||||
BrigadierParser::TemplateRotation => {
|
||||
u32::var_write_into(&46, buf)?;
|
||||
}
|
||||
BrigadierParser::Uuid => {
|
||||
u32::var_write_into(&47, buf)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: BrigadierNodeStub should have more stuff
|
||||
impl McBufReadable for BrigadierNodeStub {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
|
@ -264,8 +443,74 @@ impl McBufReadable for BrigadierNodeStub {
|
|||
}
|
||||
|
||||
impl McBufWritable for BrigadierNodeStub {
|
||||
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
todo!()
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match &self.node_type {
|
||||
NodeType::Root => {
|
||||
let mut flags = 0x00;
|
||||
if self.is_executable {
|
||||
flags |= 0x04;
|
||||
}
|
||||
if self.redirect_node.is_some() {
|
||||
flags |= 0x08;
|
||||
}
|
||||
flags.var_write_into(buf)?;
|
||||
|
||||
self.children.var_write_into(buf)?;
|
||||
|
||||
if let Some(redirect) = self.redirect_node {
|
||||
redirect.var_write_into(buf)?;
|
||||
}
|
||||
}
|
||||
NodeType::Literal { name } => {
|
||||
let mut flags = 0x01;
|
||||
if self.is_executable {
|
||||
flags |= 0x04;
|
||||
}
|
||||
if self.redirect_node.is_some() {
|
||||
flags |= 0x08;
|
||||
}
|
||||
flags.var_write_into(buf)?;
|
||||
|
||||
self.children.var_write_into(buf)?;
|
||||
|
||||
if let Some(redirect) = self.redirect_node {
|
||||
redirect.var_write_into(buf)?;
|
||||
}
|
||||
|
||||
name.write_into(buf)?;
|
||||
}
|
||||
NodeType::Argument {
|
||||
name,
|
||||
parser,
|
||||
suggestions_type,
|
||||
} => {
|
||||
let mut flags = 0x02;
|
||||
if self.is_executable {
|
||||
flags |= 0x04;
|
||||
}
|
||||
if self.redirect_node.is_some() {
|
||||
flags |= 0x08;
|
||||
}
|
||||
if suggestions_type.is_some() {
|
||||
flags |= 0x10;
|
||||
}
|
||||
flags.var_write_into(buf)?;
|
||||
|
||||
self.children.var_write_into(buf)?;
|
||||
|
||||
if let Some(redirect) = self.redirect_node {
|
||||
redirect.var_write_into(buf)?;
|
||||
}
|
||||
|
||||
name.write_into(buf)?;
|
||||
parser.write_into(buf)?;
|
||||
|
||||
if let Some(suggestion) = suggestions_type {
|
||||
suggestion.write_into(buf)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,8 +121,150 @@ pub struct Ingredient {
|
|||
}
|
||||
|
||||
impl McBufWritable for Recipe {
|
||||
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
todo!()
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match &self.data {
|
||||
RecipeData::CraftingShapeless(recipe) => {
|
||||
ResourceLocation::new("minecraft:crafting_shapeless")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingShaped(recipe) => {
|
||||
ResourceLocation::new("minecraft:crafting_shaped")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialArmorDye => {
|
||||
ResourceLocation::new("minecraft:crafting_special_armordye")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialBookCloning => {
|
||||
ResourceLocation::new("minecraft:crafting_special_bookcloning")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialMapCloning => {
|
||||
ResourceLocation::new("minecraft:crafting_special_mapcloning")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialMapExtending => {
|
||||
ResourceLocation::new("minecraft:crafting_special_mapextending")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialFireworkRocket => {
|
||||
ResourceLocation::new("minecraft:crafting_special_firework_rocket")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialFireworkStar => {
|
||||
ResourceLocation::new("minecraft:crafting_special_firework_star")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialFireworkStarFade => {
|
||||
ResourceLocation::new("minecraft:crafting_special_firework_star_fade")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialRepairItem => {
|
||||
ResourceLocation::new("minecraft:crafting_special_repairitem")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialTippedArrow => {
|
||||
ResourceLocation::new("minecraft:crafting_special_tippedarrow")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialBannerDuplicate => {
|
||||
ResourceLocation::new("minecraft:crafting_special_bannerduplicate")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialBannerAddPattern => {
|
||||
ResourceLocation::new("minecraft:crafting_special_banneraddpattern")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialShieldDecoration => {
|
||||
ResourceLocation::new("minecraft:crafting_special_shielddecoration")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialShulkerBoxColoring => {
|
||||
ResourceLocation::new("minecraft:crafting_special_shulkerboxcoloring")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CraftingSpecialSuspiciousStew => {
|
||||
ResourceLocation::new("minecraft:crafting_special_suspiciousstew")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
}
|
||||
RecipeData::Smelting(recipe) => {
|
||||
ResourceLocation::new("minecraft:smelting")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::Blasting(recipe) => {
|
||||
ResourceLocation::new("minecraft:blasting")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::Smoking(recipe) => {
|
||||
ResourceLocation::new("minecraft:smoking")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::CampfireCooking(recipe) => {
|
||||
ResourceLocation::new("minecraft:campfire_cooking")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::Stonecutting(recipe) => {
|
||||
ResourceLocation::new("minecraft:stonecutting")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
RecipeData::Smithing(recipe) => {
|
||||
ResourceLocation::new("minecraft:smithing")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue