mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +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",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"serde",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -170,6 +171,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azalea-brigadier"
|
name = "azalea-brigadier"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
dependencies = [
|
||||||
|
"azalea-buf",
|
||||||
|
"azalea-chat",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azalea-buf"
|
name = "azalea-buf"
|
||||||
|
@ -274,6 +279,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[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 std::fmt;
|
||||||
|
|
||||||
use crate::{message::Message, string_reader::StringReader};
|
use crate::string_reader::StringReader;
|
||||||
|
|
||||||
use super::command_syntax_exception::CommandSyntaxException;
|
use super::command_syntax_exception::CommandSyntaxException;
|
||||||
|
|
||||||
|
@ -148,12 +148,12 @@ impl fmt::Debug for BuiltInExceptions {
|
||||||
|
|
||||||
impl BuiltInExceptions {
|
impl BuiltInExceptions {
|
||||||
pub fn create(self) -> CommandSyntaxException {
|
pub fn create(self) -> CommandSyntaxException {
|
||||||
let message = Message::from(format!("{self:?}"));
|
let message = format!("{self:?}");
|
||||||
CommandSyntaxException::create(self, message)
|
CommandSyntaxException::create(self, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_with_context(self, reader: &StringReader) -> CommandSyntaxException {
|
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())
|
CommandSyntaxException::new(self, message, reader.string(), reader.cursor())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use super::builtin_exceptions::BuiltInExceptions;
|
use super::builtin_exceptions::BuiltInExceptions;
|
||||||
use crate::message::Message;
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp,
|
cmp,
|
||||||
fmt::{self, Write},
|
fmt::{self, Write},
|
||||||
|
@ -8,7 +7,7 @@ use std::{
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct CommandSyntaxException {
|
pub struct CommandSyntaxException {
|
||||||
pub type_: BuiltInExceptions,
|
pub type_: BuiltInExceptions,
|
||||||
message: Message,
|
message: String,
|
||||||
input: Option<String>,
|
input: Option<String>,
|
||||||
cursor: Option<usize>,
|
cursor: Option<usize>,
|
||||||
}
|
}
|
||||||
|
@ -16,7 +15,7 @@ pub struct CommandSyntaxException {
|
||||||
const CONTEXT_AMOUNT: usize = 10;
|
const CONTEXT_AMOUNT: usize = 10;
|
||||||
|
|
||||||
impl CommandSyntaxException {
|
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 {
|
Self {
|
||||||
type_,
|
type_,
|
||||||
message,
|
message,
|
||||||
|
@ -25,7 +24,7 @@ impl CommandSyntaxException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(type_: BuiltInExceptions, message: Message) -> Self {
|
pub fn create(type_: BuiltInExceptions, message: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
type_,
|
type_,
|
||||||
message,
|
message,
|
||||||
|
@ -35,7 +34,7 @@ impl CommandSyntaxException {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(&self) -> String {
|
pub fn message(&self) -> String {
|
||||||
let mut message = self.message.string();
|
let mut message = self.message.clone();
|
||||||
let context = self.context();
|
let context = self.context();
|
||||||
if let Some(context) = context {
|
if let Some(context) = context {
|
||||||
write!(
|
write!(
|
||||||
|
@ -49,7 +48,7 @@ impl CommandSyntaxException {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_message(&self) -> &Message {
|
pub fn raw_message(&self) -> &String {
|
||||||
&self.message
|
&self.message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ pub mod builder;
|
||||||
pub mod command_dispatcher;
|
pub mod command_dispatcher;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod exceptions;
|
pub mod exceptions;
|
||||||
pub mod message;
|
|
||||||
pub mod modifier;
|
pub mod modifier;
|
||||||
pub mod parse_results;
|
pub mod parse_results;
|
||||||
pub mod string_reader;
|
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;
|
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::*;
|
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)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct Suggestion {
|
pub struct Suggestion<M = String> {
|
||||||
pub range: StringRange,
|
|
||||||
pub text: 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 {
|
pub fn apply(&self, input: &str) -> String {
|
||||||
if self.range.start() == 0 && self.range.end() == input.len() {
|
if self.range.start() == 0 && self.range.end() == input.len() {
|
||||||
return input.to_string();
|
return input.to_string();
|
||||||
|
@ -27,7 +37,7 @@ impl Suggestion {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand(&self, command: &str, range: &StringRange) -> Suggestion {
|
pub fn expand(&self, command: &str, range: &StringRange) -> Suggestion<M> {
|
||||||
if range == &self.range {
|
if range == &self.range {
|
||||||
return self.clone();
|
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 super::Suggestion;
|
||||||
use crate::context::StringRange;
|
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)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Suggestions {
|
pub struct Suggestions<M = String> {
|
||||||
pub range: StringRange,
|
pub range: StringRange,
|
||||||
pub suggestions: Vec<Suggestion>,
|
pub suggestions: Vec<Suggestion<M>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Suggestions {
|
impl<M: Clone + Eq + Hash> Suggestions<M> {
|
||||||
pub fn merge(command: &str, input: &[Suggestions]) -> Self {
|
pub fn merge(command: &str, input: &[Suggestions<M>]) -> Self {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
return Suggestions::default();
|
return Suggestions::default();
|
||||||
} else if input.len() == 1 {
|
} else if input.len() == 1 {
|
||||||
|
@ -24,7 +32,7 @@ impl Suggestions {
|
||||||
Suggestions::create(command, &texts)
|
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() {
|
if suggestions.is_empty() {
|
||||||
return Suggestions::default();
|
return Suggestions::default();
|
||||||
};
|
};
|
||||||
|
@ -39,7 +47,7 @@ impl Suggestions {
|
||||||
for suggestion in suggestions {
|
for suggestion in suggestions {
|
||||||
texts.insert(suggestion.expand(command, &range));
|
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));
|
sorted.sort_by(|a, b| a.text.cmp(&b.text));
|
||||||
Suggestions {
|
Suggestions {
|
||||||
range,
|
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
|
// TODO: have an azalea-inventory or azalea-container crate and put this there
|
||||||
|
|
||||||
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
|
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
|
||||||
|
use azalea_nbt::Tag;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
|
@ -13,29 +14,27 @@ pub enum Slot {
|
||||||
#[derive(Debug, Clone, McBuf)]
|
#[derive(Debug, Clone, McBuf)]
|
||||||
pub struct SlotData {
|
pub struct SlotData {
|
||||||
#[var]
|
#[var]
|
||||||
pub id: i32,
|
pub id: u32,
|
||||||
pub count: u8,
|
pub count: u8,
|
||||||
pub nbt: azalea_nbt::Tag,
|
pub nbt: Tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufReadable for Slot {
|
impl McBufReadable for Slot {
|
||||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||||
let present = bool::read_from(buf)?;
|
let slot = Option::<SlotData>::read_from(buf)?;
|
||||||
if !present {
|
Ok(slot.map_or(Slot::Empty, Slot::Present))
|
||||||
return Ok(Slot::Empty);
|
|
||||||
}
|
|
||||||
let slot = SlotData::read_from(buf)?;
|
|
||||||
Ok(Slot::Present(slot))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufWritable for Slot {
|
impl McBufWritable for Slot {
|
||||||
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 {
|
match self {
|
||||||
Slot::Empty => 0u8.write_into(buf)?,
|
Slot::Empty => false.write_into(buf)?,
|
||||||
Slot::Present(i) => i.write_into(buf)?,
|
Slot::Present(i) => {
|
||||||
}
|
true.write_into(buf)?;
|
||||||
|
i.write_into(buf)?;
|
||||||
|
}
|
||||||
|
};
|
||||||
Ok(())
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ahash = "^0.8.0"
|
ahash = { version = "^0.8.0", features = ["serde"]}
|
||||||
azalea-buf = {path = "../azalea-buf", version = "^0.4.0" }
|
azalea-buf = {path = "../azalea-buf", version = "^0.4.0" }
|
||||||
byteorder = "^1.4.3"
|
byteorder = "^1.4.3"
|
||||||
flate2 = "^1.0.23"
|
flate2 = "^1.0.23"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
num-derive = "^0.3.3"
|
num-derive = "^0.3.3"
|
||||||
num-traits = "^0.2.14"
|
num-traits = "^0.2.14"
|
||||||
|
serde = {version = "^1.0.148", features = ["derive"]}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = {version = "^0.3.5", features = ["html_reports"]}
|
criterion = {version = "^0.3.5", features = ["html_reports"]}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# Azalea NBT
|
# Azalea NBT
|
||||||
|
|
||||||
A fast NBT serializer and deserializer.
|
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)?;
|
write_compound(writer, value, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Tag::End => {
|
||||||
|
0u8.write_into(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => Err(Error::InvalidTag),
|
_ => Err(Error::InvalidTag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
pub enum Tag {
|
pub enum Tag {
|
||||||
End, // 0
|
End, // 0
|
||||||
Byte(i8), // 1
|
Byte(i8), // 1
|
||||||
|
|
|
@ -11,17 +11,17 @@ version = "0.4.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true}
|
async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true}
|
||||||
async-recursion = "1.0.0"
|
async-recursion = "1.0.0"
|
||||||
azalea-auth = {path = "../azalea-auth", 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-block = {path = "../azalea-block", default-features = false, version = "^0.4.0"}
|
||||||
azalea-brigadier = {path = "../azalea-brigadier", 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-buf = {path = "../azalea-buf", version = "^0.4.0"}
|
||||||
azalea-chat = {path = "../azalea-chat", 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-core = {path = "../azalea-core", optional = true, version = "^0.4.0"}
|
||||||
azalea-crypto = {path = "../azalea-crypto", version = "^0.4.0" }
|
azalea-crypto = {path = "../azalea-crypto", version = "^0.4.0"}
|
||||||
azalea-nbt = {path = "../azalea-nbt", 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-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.4.0"}
|
||||||
azalea-registry = {path = "../azalea-registry", version = "^0.4.0" }
|
azalea-registry = {path = "../azalea-registry", version = "^0.4.0"}
|
||||||
azalea-world = {path = "../azalea-world", version = "^0.4.0" }
|
azalea-world = {path = "../azalea-world", version = "^0.4.0"}
|
||||||
byteorder = "^1.4.3"
|
byteorder = "^1.4.3"
|
||||||
bytes = "^1.1.0"
|
bytes = "^1.1.0"
|
||||||
flate2 = "1.0.23"
|
flate2 = "1.0.23"
|
||||||
|
|
|
@ -1,32 +1,36 @@
|
||||||
// use azalea_brigadier::context::StringRange;
|
use azalea_brigadier::suggestion::Suggestions;
|
||||||
use azalea_buf::{
|
use azalea_buf::McBuf;
|
||||||
// BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
|
use azalea_chat::Component;
|
||||||
BufReadError,
|
|
||||||
McBufReadable,
|
|
||||||
McBufWritable,
|
|
||||||
};
|
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use std::io::{Cursor, Write};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, ClientboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||||
pub struct ClientboundCommandSuggestionsPacket {
|
pub struct ClientboundCommandSuggestionsPacket {
|
||||||
#[var]
|
#[var]
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
// pub suggestions: Suggestions,
|
pub suggestions: Suggestions<Component>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl McBufReadable for ClientboundCommandSuggestionsPacket {
|
#[cfg(test)]
|
||||||
fn read_from(_buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
mod tests {
|
||||||
// let id = u32::var_read_from(buf)?;
|
use super::*;
|
||||||
// let start = u32::var_read_from(buf)? as usize;
|
use azalea_brigadier::{context::StringRange, suggestion::Suggestion};
|
||||||
// let length = u32::var_read_from(buf)? as usize;
|
use azalea_buf::{McBufReadable, McBufWritable};
|
||||||
// let stringrange = StringRange::between(start, start + length);
|
use std::io::Cursor;
|
||||||
todo!("Suggestions aren't implemented in azalea-brigadier yet")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McBufWritable for ClientboundCommandSuggestionsPacket {
|
#[test]
|
||||||
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn test_suggestions() {
|
||||||
todo!()
|
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::BufReadError;
|
||||||
use azalea_buf::McBuf;
|
use azalea_buf::McBuf;
|
||||||
use azalea_buf::McBufVarReadable;
|
use azalea_buf::McBufVarReadable;
|
||||||
use azalea_buf::{McBufReadable, McBufWritable};
|
use azalea_buf::{McBufReadable, McBufVarWritable, McBufWritable};
|
||||||
use azalea_core::ResourceLocation;
|
use azalea_core::ResourceLocation;
|
||||||
use azalea_protocol_macros::ClientboundGamePacket;
|
use azalea_protocol_macros::ClientboundGamePacket;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
@ -25,8 +25,13 @@ pub struct BrigadierNodeStub {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BrigadierNumber<T> {
|
pub struct BrigadierNumber<T> {
|
||||||
min: Option<T>,
|
pub min: Option<T>,
|
||||||
max: 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> {
|
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> {
|
||||||
|
@ -119,7 +124,6 @@ pub enum BrigadierParser {
|
||||||
Dimension,
|
Dimension,
|
||||||
Uuid,
|
Uuid,
|
||||||
NbtTag,
|
NbtTag,
|
||||||
NbtCompoundTag,
|
|
||||||
Time,
|
Time,
|
||||||
ResourceOrTag { registry_key: ResourceLocation },
|
ResourceOrTag { registry_key: ResourceLocation },
|
||||||
Resource { registry_key: ResourceLocation },
|
Resource { registry_key: ResourceLocation },
|
||||||
|
@ -157,7 +161,7 @@ impl McBufReadable for BrigadierParser {
|
||||||
16 => Ok(BrigadierParser::Color),
|
16 => Ok(BrigadierParser::Color),
|
||||||
17 => Ok(BrigadierParser::Component),
|
17 => Ok(BrigadierParser::Component),
|
||||||
18 => Ok(BrigadierParser::Message),
|
18 => Ok(BrigadierParser::Message),
|
||||||
19 => Ok(BrigadierParser::NbtCompoundTag),
|
19 => Ok(BrigadierParser::Nbt),
|
||||||
20 => Ok(BrigadierParser::NbtTag),
|
20 => Ok(BrigadierParser::NbtTag),
|
||||||
21 => Ok(BrigadierParser::NbtPath),
|
21 => Ok(BrigadierParser::NbtPath),
|
||||||
22 => Ok(BrigadierParser::Objective),
|
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
|
// 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> {
|
||||||
|
@ -264,8 +443,74 @@ 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> {
|
||||||
todo!()
|
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 {
|
impl McBufWritable for Recipe {
|
||||||
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
todo!()
|
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
Add a link
Reference in a new issue