diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2023-12-05 10:59:05 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-05 10:59:05 -0600 |
| commit | 7857a014b92e64361ee237ceae7ef1acc185ac46 (patch) | |
| tree | 5d70ea6b41943493873810e6a03c3483ff90a235 /azalea-chat/src/component.rs | |
| parent | ea3e8600126a58f5666d50fbf70dff8209d8979f (diff) | |
| download | azalea-drasl-7857a014b92e64361ee237ceae7ef1acc185ac46.tar.xz | |
1.20.3 (#110)
* 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
Diffstat (limited to 'azalea-chat/src/component.rs')
| -rwxr-xr-x | azalea-chat/src/component.rs | 177 |
1 files changed, 156 insertions, 21 deletions
diff --git a/azalea-chat/src/component.rs b/azalea-chat/src/component.rs index e80e7e4b..ded77d01 100755 --- a/azalea-chat/src/component.rs +++ b/azalea-chat/src/component.rs @@ -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)] @@ -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. @@ -83,7 +88,7 @@ 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 @@ -91,7 +96,7 @@ impl FormattedText { /// /// 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 @@ -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()), + )?; + 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) } } |
