Skip to content

Commit

Permalink
1.20.3 (#110)
Browse files Browse the repository at this point in the history
* 23w40a

* 23w41a

* 23w42a

* 23w43a

* 23w44a

* serialize FormattedText as nbt in network

* use azalea-nbt/serde in azalea-chat

* 23w45a

* fix 23w45a to compile

* handle Object in codegen

* 1.20.3-pre2

* remove unused clientbound_resource_pack_packet.rs

* merge main and make azalea-chat use simdnbt

* 1.20.3-rc1

* fix tests

* use simdnbt 0.3

* fix ServerboundSetJigsawBlockPacket

* 1.20.3
  • Loading branch information
mat-1 authored Dec 5, 2023
1 parent ea3e860 commit 7857a01
Show file tree
Hide file tree
Showing 59 changed files with 4,430 additions and 1,826 deletions.
430 changes: 262 additions & 168 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A collection of Rust crates for making Minecraft bots, clients, and tools.
</p>

<!-- The line below is automatically read and updated by the migrate script, so don't change it manually. -->
*Currently supported Minecraft version: `1.20.2`.*
*Currently supported Minecraft version: `1.20.3`.*

> [!WARNING]
> Azalea is still very unfinished, though most crates are in a somewhat useable state
Expand Down
273 changes: 260 additions & 13 deletions azalea-block/src/generated.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion azalea-buf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ tracing = "0.1.40"
serde_json = { version = "^1.0", optional = true }
thiserror = "1.0.50"
uuid = "^1.5.0"
simdnbt = { version = "0.2.1" }
simdnbt = "0.3"

[features]
serde_json = ["dep:serde_json"]
5 changes: 5 additions & 0 deletions azalea-chat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ version = "0.8.0"

[features]
default = ["azalea-buf"]
azalea-buf = ["dep:azalea-buf", "simdnbt"]
numbers = ["dep:azalea-registry", "dep:simdnbt"]
simdnbt = ["dep:simdnbt"]

[dependencies]
azalea-buf = { path = "../azalea-buf", features = [
"serde_json",
], version = "^0.8.0", optional = true }
azalea-language = { path = "../azalea-language", version = "0.8.0" }
simdnbt = { version = "0.3", optional = true }
tracing = "0.1.40"
once_cell = "1.18.0"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0.108"
azalea-registry = { path = "../azalea-registry", version = "0.8.0", optional = true }
20 changes: 20 additions & 0 deletions azalea-chat/src/base_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@ impl BaseComponent {
}
}

#[cfg(feature = "simdnbt")]
impl simdnbt::Serialize for BaseComponent {
fn to_compound(self) -> simdnbt::owned::NbtCompound {
let mut compound = simdnbt::owned::NbtCompound::new();
if !self.siblings.is_empty() {
compound.insert(
"extra",
simdnbt::owned::NbtList::from(
self.siblings
.into_iter()
.map(|component| component.to_compound())
.collect::<Vec<_>>(),
),
);
}
compound.extend(self.style.to_compound());
compound
}
}

impl Default for BaseComponent {
fn default() -> Self {
Self::new()
Expand Down
177 changes: 156 additions & 21 deletions azalea-chat/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ use crate::{
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use once_cell::sync::Lazy;
use serde::{de, Deserialize, Deserializer, Serialize};
use std::{
fmt::Display,
io::{Cursor, Write},
};
use tracing::debug;
#[cfg(feature = "simdnbt")]
use simdnbt::{Deserialize as _, FromNbtTag as _, Serialize as _};
use std::fmt::Display;

/// A chat component, basically anything you can see in chat.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Hash)]
Expand Down Expand Up @@ -52,14 +50,21 @@ impl FormattedText {
fn parse_separator(
json: &serde_json::Value,
) -> Result<Option<FormattedText>, serde_json::Error> {
if json.get("separator").is_some() {
return Ok(Some(FormattedText::deserialize(
json.get("separator").unwrap(),
)?));
if let Some(separator) = json.get("separator") {
return Ok(Some(FormattedText::deserialize(separator)?));
}
Ok(None)
}

#[cfg(feature = "simdnbt")]
fn parse_separator_nbt(nbt: &simdnbt::borrow::NbtCompound) -> Option<FormattedText> {
if let Some(separator) = nbt.get("separator") {
FormattedText::from_nbt_tag(separator)
} else {
None
}
}

/// Convert this component into an
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code), so you
/// can print it to your terminal and get styling.
Expand All @@ -83,15 +88,15 @@ impl FormattedText {
/// ```
pub fn to_ansi(&self) -> String {
// default the default_style to white if it's not set
self.to_ansi_custom_style(&DEFAULT_STYLE)
self.to_ansi_with_custom_style(&DEFAULT_STYLE)
}

/// Convert this component into an
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code).
///
/// This is the same as [`FormattedText::to_ansi`], but you can specify a
/// default [`Style`] to use.
pub fn to_ansi_custom_style(&self, default_style: &Style) -> String {
pub fn to_ansi_with_custom_style(&self, default_style: &Style) -> String {
// this contains the final string will all the ansi escape codes
let mut built_string = String::new();
// this style will update as we visit components
Expand Down Expand Up @@ -273,23 +278,153 @@ impl<'de> Deserialize<'de> for FormattedText {
}
}

#[cfg(feature = "simdnbt")]
impl simdnbt::Serialize for FormattedText {
fn to_compound(self) -> simdnbt::owned::NbtCompound {
match self {
FormattedText::Text(c) => c.to_compound(),
FormattedText::Translatable(c) => c.to_compound(),
}
}
}

#[cfg(feature = "simdnbt")]
impl simdnbt::FromNbtTag for FormattedText {
fn from_nbt_tag(tag: &simdnbt::borrow::NbtTag) -> Option<Self> {
// we create a component that we might add siblings to
let mut component: FormattedText;

match tag {
// if it's a string, return a text component with that string
simdnbt::borrow::NbtTag::String(string) => {
Some(FormattedText::Text(TextComponent::new(string.to_string())))
}
// if it's a compound, make it do things with { text } and stuff
simdnbt::borrow::NbtTag::Compound(compound) => {
if let Some(text) = compound.get("text") {
let text = text.string().unwrap_or_default().to_string();
component = FormattedText::Text(TextComponent::new(text));
} else if let Some(translate) = compound.get("translate") {
let translate = translate.string()?.into();
if let Some(with) = compound.get("with") {
let with = with.list()?.compounds()?;
let mut with_array = Vec::with_capacity(with.len());
for item in with {
// if it's a string component with no styling and no siblings, just add
// a string to with_array otherwise add the
// component to the array
let c = FormattedText::from_nbt_tag(
&simdnbt::borrow::NbtTag::Compound(item.clone()),
)?;
if let FormattedText::Text(text_component) = c {
if text_component.base.siblings.is_empty()
&& text_component.base.style.is_empty()
{
with_array.push(StringOrComponent::String(text_component.text));
continue;
}
}
with_array.push(StringOrComponent::FormattedText(
FormattedText::from_nbt_tag(&simdnbt::borrow::NbtTag::Compound(
item.clone(),
))?,
));
}
component = FormattedText::Translatable(TranslatableComponent::new(
translate, with_array,
));
} else {
// if it doesn't have a "with", just have the with_array be empty
component = FormattedText::Translatable(TranslatableComponent::new(
translate,
Vec::new(),
));
}
} else if let Some(score) = compound.compound("score") {
// object = GsonHelper.getAsJsonObject(jsonObject, "score");
if score.get("name").is_none() || score.get("objective").is_none() {
// A score component needs at least a name and an objective
tracing::trace!("A score component needs at least a name and an objective");
return None;
}
// TODO, score text components aren't yet supported
return None;
} else if compound.get("selector").is_some() {
// selector text components aren't yet supported
tracing::trace!("selector text components aren't yet supported");
return None;
} else if compound.get("keybind").is_some() {
// keybind text components aren't yet supported
tracing::trace!("keybind text components aren't yet supported");
return None;
} else {
let Some(_nbt) = compound.get("nbt") else {
// Don't know how to turn 'nbt' into a FormattedText
return None;
};
let _separator = FormattedText::parse_separator_nbt(compound)?;

let _interpret = match compound.get("interpret") {
Some(v) => v.byte().unwrap_or_default() != 0,
None => false,
};
if let Some(_block) = compound.get("block") {}
// nbt text components aren't yet supported
return None;
}
if let Some(extra) = compound.get("extra") {
let extra = extra.list()?.compounds()?;
if extra.is_empty() {
// Unexpected empty array of components
return None;
}
for extra_component in extra {
let sibling = FormattedText::from_nbt_tag(
&simdnbt::borrow::NbtTag::Compound(extra_component.clone()),
)?;
component.append(sibling);
}
}

let style = Style::from_compound(compound).ok()?;
component.get_base_mut().style = style;

Some(component)
}
// ok so it's not a compound, if it's a list deserialize every item
simdnbt::borrow::NbtTag::List(list) => {
let list = list.compounds()?;
let mut component = FormattedText::from_nbt_tag(
&simdnbt::borrow::NbtTag::Compound(list.get(0)?.clone()),

Check warning on line 398 in azalea-chat/src/component.rs

View workflow job for this annotation

GitHub Actions / clippy

accessing first element with `list.get(0)`

warning: accessing first element with `list.get(0)` --> azalea-chat/src/component.rs:398:56 | 398 | &simdnbt::borrow::NbtTag::Compound(list.get(0)?.clone()), | ^^^^^^^^^^^ help: try: `list.first()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#get_first = note: `#[warn(clippy::get_first)]` on by default
)?;
for i in 1..list.len() {
component.append(FormattedText::from_nbt_tag(
&simdnbt::borrow::NbtTag::Compound(list.get(i)?.clone()),
)?);
}
Some(component)
}
_ => Some(FormattedText::Text(TextComponent::new("".to_owned()))),
}
}
}

#[cfg(feature = "azalea-buf")]
impl McBufReadable for FormattedText {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let string = String::read_from(buf)?;
debug!("FormattedText string: {}", string);
let json: serde_json::Value = serde_json::from_str(string.as_str())?;
let component = FormattedText::deserialize(json)?;
Ok(component)
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, BufReadError> {
let nbt = simdnbt::borrow::NbtTag::read(buf)?;
FormattedText::from_nbt_tag(&nbt)
.ok_or(BufReadError::Custom("couldn't read nbt".to_owned()))
}
}

#[cfg(feature = "azalea-buf")]
#[cfg(feature = "simdnbt")]
impl McBufWritable for FormattedText {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let json = serde_json::to_string(self).unwrap();
json.write_into(buf)?;
Ok(())
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
let mut out = Vec::new();
simdnbt::owned::BaseNbt::write_unnamed(&(self.clone().to_compound().into()), &mut out);
buf.write_all(&out)
}
}

Expand Down
2 changes: 2 additions & 0 deletions azalea-chat/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

pub mod base_component;
mod component;
#[cfg(feature = "numbers")]
pub mod numbers;
pub mod style;
pub mod text_component;
pub mod translatable_component;
Expand Down
52 changes: 52 additions & 0 deletions azalea-chat/src/numbers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//! Contains a few ways to style numbers. At the time of writing, Minecraft only
//! uses this for rendering scoreboard objectives.
use std::io::{Cursor, Write};

#[cfg(feature = "azalea-buf")]
use azalea_buf::{McBufReadable, McBufWritable};
use azalea_registry::NumberFormatKind;
use simdnbt::owned::Nbt;

use crate::FormattedText;

#[derive(Clone, Debug)]
pub enum NumberFormat {
Blank,
Styled { style: Nbt },
Fixed { value: FormattedText },
}

#[cfg(feature = "azalea-buf")]
impl McBufReadable for NumberFormat {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
let kind = NumberFormatKind::read_from(buf)?;
match kind {
NumberFormatKind::Blank => Ok(NumberFormat::Blank),
NumberFormatKind::Styled => Ok(NumberFormat::Styled {
style: Nbt::read(buf)?,
}),
NumberFormatKind::Fixed => Ok(NumberFormat::Fixed {
value: FormattedText::read_from(buf)?,
}),
}
}
}

#[cfg(feature = "azalea-buf")]
impl McBufWritable for NumberFormat {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match self {
NumberFormat::Blank => NumberFormatKind::Blank.write_into(buf)?,
NumberFormat::Styled { style } => {
NumberFormatKind::Styled.write_into(buf)?;
style.write_into(buf)?;
}
NumberFormat::Fixed { value } => {
NumberFormatKind::Fixed.write_into(buf)?;
value.write_into(buf)?;
}
}
Ok(())
}
}
Loading

0 comments on commit 7857a01

Please sign in to comment.