aboutsummaryrefslogtreecommitdiff
path: root/azalea-chat/src
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-12-05 10:59:05 -0600
committerGitHub <noreply@github.com>2023-12-05 10:59:05 -0600
commit7857a014b92e64361ee237ceae7ef1acc185ac46 (patch)
tree5d70ea6b41943493873810e6a03c3483ff90a235 /azalea-chat/src
parentea3e8600126a58f5666d50fbf70dff8209d8979f (diff)
downloadazalea-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')
-rwxr-xr-xazalea-chat/src/base_component.rs20
-rwxr-xr-xazalea-chat/src/component.rs177
-rwxr-xr-xazalea-chat/src/lib.rs2
-rw-r--r--azalea-chat/src/numbers.rs52
-rwxr-xr-xazalea-chat/src/style.rs209
-rwxr-xr-xazalea-chat/src/text_component.rs22
-rwxr-xr-xazalea-chat/src/translatable_component.rs60
7 files changed, 464 insertions, 78 deletions
diff --git a/azalea-chat/src/base_component.rs b/azalea-chat/src/base_component.rs
index dcc28ecc..8f70ecb7 100755
--- a/azalea-chat/src/base_component.rs
+++ b/azalea-chat/src/base_component.rs
@@ -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()
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)
}
}
diff --git a/azalea-chat/src/lib.rs b/azalea-chat/src/lib.rs
index d6ff7285..9995a183 100755
--- a/azalea-chat/src/lib.rs
+++ b/azalea-chat/src/lib.rs
@@ -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;
diff --git a/azalea-chat/src/numbers.rs b/azalea-chat/src/numbers.rs
new file mode 100644
index 00000000..21c30591
--- /dev/null
+++ b/azalea-chat/src/numbers.rs
@@ -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(())
+ }
+}
diff --git a/azalea-chat/src/style.rs b/azalea-chat/src/style.rs
index ba4d6e72..43b74cbf 100755
--- a/azalea-chat/src/style.rs
+++ b/azalea-chat/src/style.rs
@@ -5,6 +5,8 @@ use azalea_buf::McBuf;
use once_cell::sync::Lazy;
use serde::{ser::SerializeStruct, Serialize, Serializer};
use serde_json::Value;
+#[cfg(feature = "simdnbt")]
+use simdnbt::owned::{NbtCompound, NbtTag};
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TextColor {
@@ -17,11 +19,22 @@ impl Serialize for TextColor {
where
S: Serializer,
{
- if self.name.is_some() {
- serializer.serialize_str(&self.name.as_ref().unwrap().to_ascii_lowercase())
- } else {
- serializer.serialize_str(&self.format())
- }
+ serializer.serialize_str(
+ &self
+ .name
+ .as_ref()
+ .map(|n| n.to_ascii_lowercase())
+ .unwrap_or_else(|| self.format()),
+ )
+ }
+}
+
+#[cfg(feature = "simdnbt")]
+impl simdnbt::ToNbtTag for TextColor {
+ fn to_nbt_tag(self) -> simdnbt::owned::NbtTag {
+ self.name
+ .map(|n| NbtTag::String(n.to_ascii_lowercase().into()))
+ .unwrap_or_else(|| NbtTag::Int(self.value as i32))
}
}
@@ -303,6 +316,36 @@ pub struct Style {
pub reset: bool,
}
+fn serde_serialize_field<S: serde::ser::SerializeStruct>(
+ state: &mut S,
+ name: &'static str,
+ value: &Option<impl serde::Serialize>,
+ default: &(impl serde::Serialize + ?Sized),
+ reset: bool,
+) -> Result<(), S::Error> {
+ if let Some(value) = value {
+ state.serialize_field(name, value)?;
+ } else if reset {
+ state.serialize_field(name, default)?;
+ }
+ Ok(())
+}
+
+#[cfg(feature = "simdnbt")]
+fn simdnbt_serialize_field(
+ compound: &mut simdnbt::owned::NbtCompound,
+ name: &'static str,
+ value: Option<impl simdnbt::ToNbtTag>,
+ default: impl simdnbt::ToNbtTag,
+ reset: bool,
+) {
+ if let Some(value) = value {
+ compound.insert(name, value);
+ } else if reset {
+ compound.insert(name, default);
+ }
+}
+
impl Serialize for Style {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -319,69 +362,97 @@ impl Serialize for Style {
+ usize::from(self.obfuscated.is_some())
};
let mut state = serializer.serialize_struct("Style", len)?;
- if let Some(color) = &self.color {
- state.serialize_field("color", color)?;
- } else if self.reset {
- state.serialize_field("color", "white")?;
- }
- if let Some(bold) = &self.bold {
- state.serialize_field("bold", bold)?;
- } else if self.reset {
- state.serialize_field("bold", &false)?;
- }
- if let Some(italic) = &self.italic {
- state.serialize_field("italic", italic)?;
- } else if self.reset {
- state.serialize_field("italic", &false)?;
- }
- if let Some(underlined) = &self.underlined {
- state.serialize_field("underlined", underlined)?;
- } else if self.reset {
- state.serialize_field("underlined", &false)?;
- }
- if let Some(strikethrough) = &self.strikethrough {
- state.serialize_field("strikethrough", strikethrough)?;
- } else if self.reset {
- state.serialize_field("strikethrough", &false)?;
- }
- if let Some(obfuscated) = &self.obfuscated {
- state.serialize_field("obfuscated", obfuscated)?;
- } else if self.reset {
- state.serialize_field("obfuscated", &false)?;
- }
+
+ serde_serialize_field(&mut state, "color", &self.color, "white", self.reset)?;
+ serde_serialize_field(&mut state, "bold", &self.bold, &false, self.reset)?;
+ serde_serialize_field(&mut state, "italic", &self.italic, &false, self.reset)?;
+ serde_serialize_field(
+ &mut state,
+ "underlined",
+ &self.underlined,
+ &false,
+ self.reset,
+ )?;
+ serde_serialize_field(
+ &mut state,
+ "strikethrough",
+ &self.strikethrough,
+ &false,
+ self.reset,
+ )?;
+ serde_serialize_field(
+ &mut state,
+ "obfuscated",
+ &self.obfuscated,
+ &false,
+ self.reset,
+ )?;
+
state.end()
}
}
+#[cfg(feature = "simdnbt")]
+impl simdnbt::Serialize for Style {
+ fn to_compound(self) -> NbtCompound {
+ let mut compound = NbtCompound::new();
+
+ simdnbt_serialize_field(&mut compound, "color", self.color, "white", self.reset);
+ simdnbt_serialize_field(&mut compound, "bold", self.bold, false, self.reset);
+ simdnbt_serialize_field(&mut compound, "italic", self.italic, false, self.reset);
+ simdnbt_serialize_field(
+ &mut compound,
+ "underlined",
+ self.underlined,
+ false,
+ self.reset,
+ );
+ simdnbt_serialize_field(
+ &mut compound,
+ "strikethrough",
+ self.strikethrough,
+ false,
+ self.reset,
+ );
+ simdnbt_serialize_field(
+ &mut compound,
+ "obfuscated",
+ self.obfuscated,
+ false,
+ self.reset,
+ );
+
+ compound
+ }
+}
+
impl Style {
pub fn empty() -> Self {
Self::default()
}
pub fn deserialize(json: &Value) -> Style {
- return if json.is_object() {
- let json_object = json.as_object().unwrap();
- let bold = json_object.get("bold").and_then(|v| v.as_bool());
- let italic = json_object.get("italic").and_then(|v| v.as_bool());
- let underlined = json_object.get("underlined").and_then(|v| v.as_bool());
- let strikethrough = json_object.get("strikethrough").and_then(|v| v.as_bool());
- let obfuscated = json_object.get("obfuscated").and_then(|v| v.as_bool());
- let color: Option<TextColor> = json_object
- .get("color")
- .and_then(|v| v.as_str())
- .and_then(|v| TextColor::parse(v.to_string()));
- Style {
- color,
- bold,
- italic,
- underlined,
- strikethrough,
- obfuscated,
- ..Style::default()
- }
- } else {
- Style::default()
+ let Some(json_object) = json.as_object() else {
+ return Style::default();
};
+ let bold = json_object.get("bold").and_then(|v| v.as_bool());
+ let italic = json_object.get("italic").and_then(|v| v.as_bool());
+ let underlined = json_object.get("underlined").and_then(|v| v.as_bool());
+ let strikethrough = json_object.get("strikethrough").and_then(|v| v.as_bool());
+ let obfuscated = json_object.get("obfuscated").and_then(|v| v.as_bool());
+ let color: Option<TextColor> = json_object
+ .get("color")
+ .and_then(|v| v.as_str())
+ .and_then(|v| TextColor::parse(v.to_string()));
+ Style {
+ color,
+ bold,
+ italic,
+ underlined,
+ strikethrough,
+ obfuscated,
+ ..Style::default()
+ }
}
/// Check if a style has no attributes set
@@ -507,6 +578,30 @@ impl Style {
}
}
+impl simdnbt::Deserialize for Style {
+ fn from_compound(
+ compound: &simdnbt::borrow::NbtCompound,
+ ) -> Result<Self, simdnbt::DeserializeError> {
+ let bold = compound.byte("bold").map(|v| v != 0);
+ let italic = compound.byte("italic").map(|v| v != 0);
+ let underlined = compound.byte("underlined").map(|v| v != 0);
+ let strikethrough = compound.byte("strikethrough").map(|v| v != 0);
+ let obfuscated = compound.byte("obfuscated").map(|v| v != 0);
+ let color: Option<TextColor> = compound
+ .string("color")
+ .and_then(|v| TextColor::parse(v.to_string()));
+ Ok(Style {
+ color,
+ bold,
+ italic,
+ underlined,
+ strikethrough,
+ obfuscated,
+ ..Style::default()
+ })
+ }
+}
+
#[cfg(test)]
mod tests {
use crate::component::DEFAULT_STYLE;
diff --git a/azalea-chat/src/text_component.rs b/azalea-chat/src/text_component.rs
index fefd2cb8..6f95840d 100755
--- a/azalea-chat/src/text_component.rs
+++ b/azalea-chat/src/text_component.rs
@@ -24,6 +24,28 @@ impl Serialize for TextComponent {
}
}
+#[cfg(feature = "simdnbt")]
+impl simdnbt::Serialize for TextComponent {
+ fn to_compound(self) -> simdnbt::owned::NbtCompound {
+ let mut compound = simdnbt::owned::NbtCompound::new();
+ compound.insert("text", self.text);
+ compound.extend(self.base.style.to_compound());
+ if !self.base.siblings.is_empty() {
+ compound.insert(
+ "extra",
+ simdnbt::owned::NbtList::from(
+ self.base
+ .siblings
+ .into_iter()
+ .map(|component| component.to_compound())
+ .collect::<Vec<_>>(),
+ ),
+ );
+ }
+ compound
+ }
+}
+
const LEGACY_FORMATTING_CODE_SYMBOL: char = 'ยง';
/// Convert a legacy color code string into a FormattedText
diff --git a/azalea-chat/src/translatable_component.rs b/azalea-chat/src/translatable_component.rs
index 56c6507e..912271ae 100755
--- a/azalea-chat/src/translatable_component.rs
+++ b/azalea-chat/src/translatable_component.rs
@@ -4,6 +4,8 @@ use crate::{
base_component::BaseComponent, style::Style, text_component::TextComponent, FormattedText,
};
use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer};
+#[cfg(feature = "simdnbt")]
+use simdnbt::Serialize as _;
#[derive(Clone, Debug, PartialEq, Serialize, Eq, Hash)]
#[serde(untagged)]
@@ -12,6 +14,16 @@ pub enum StringOrComponent {
FormattedText(FormattedText),
}
+#[cfg(feature = "simdnbt")]
+impl simdnbt::ToNbtTag for StringOrComponent {
+ fn to_nbt_tag(self) -> simdnbt::owned::NbtTag {
+ match self {
+ StringOrComponent::String(s) => s.to_nbt_tag(),
+ StringOrComponent::FormattedText(c) => c.to_nbt_tag(),
+ }
+ }
+}
+
/// A message whose content depends on the client's language.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TranslatableComponent {
@@ -33,6 +45,54 @@ impl Serialize for TranslatableComponent {
}
}
+#[cfg(feature = "simdnbt")]
+fn serialize_args_as_nbt(args: &[StringOrComponent]) -> simdnbt::owned::NbtList {
+ // if it's all strings then make it a string list
+ // if it's all components then make it a compound list
+ // if it's a mix then return an error
+
+ let mut string_list = Vec::new();
+ let mut compound_list = Vec::new();
+
+ for arg in args {
+ match arg {
+ StringOrComponent::String(s) => {
+ string_list.push(s.clone());
+ }
+ StringOrComponent::FormattedText(c) => {
+ compound_list.push(c.clone().to_compound());
+ }
+ }
+ }
+
+ if !string_list.is_empty() && !compound_list.is_empty() {
+ // i'm actually not sure what vanilla does here, so i just made it return the
+ // string list
+ tracing::debug!(
+ "Tried to serialize a TranslatableComponent with a mix of strings and components."
+ );
+ return string_list.into();
+ }
+
+ if !string_list.is_empty() {
+ return string_list.into();
+ }
+
+ compound_list.into()
+}
+
+#[cfg(feature = "simdnbt")]
+impl simdnbt::Serialize for TranslatableComponent {
+ fn to_compound(self) -> simdnbt::owned::NbtCompound {
+ let mut compound = simdnbt::owned::NbtCompound::new();
+ compound.insert("translate", self.key);
+ compound.extend(self.base.style.to_compound());
+
+ compound.insert("with", serialize_args_as_nbt(&self.args));
+ compound
+ }
+}
+
impl TranslatableComponent {
pub fn new(key: String, args: Vec<StringOrComponent>) -> Self {
Self {