1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

rename Component to FormattedText

also start making the metadata use bevy_ecs but bevy_ecs doesn't let you query on Bundles so it's annoying
This commit is contained in:
mat 2022-12-13 19:08:49 -06:00
parent 129e2adf0a
commit 52772afe85
42 changed files with 11094 additions and 10584 deletions

1
Cargo.lock generated
View file

@ -295,6 +295,7 @@ dependencies = [
"azalea-buf", "azalea-buf",
"azalea-chat", "azalea-chat",
"azalea-nbt", "azalea-nbt",
"bevy_ecs",
"uuid", "uuid",
] ]

View file

@ -4,7 +4,7 @@ use crate::context::StringRange;
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
use azalea_buf::McBufWritable; use azalea_buf::McBufWritable;
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
use azalea_chat::Component; use azalea_chat::FormattedText;
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
use std::io::Write; use std::io::Write;
pub use suggestions::*; pub use suggestions::*;
@ -58,7 +58,7 @@ impl<M: Clone> Suggestion<M> {
} }
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
impl McBufWritable for Suggestion<Component> { impl McBufWritable for Suggestion<FormattedText> {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
self.text.write_into(buf)?; self.text.write_into(buf)?;
self.tooltip.write_into(buf)?; self.tooltip.write_into(buf)?;

View file

@ -5,7 +5,7 @@ use azalea_buf::{
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable, BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
}; };
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
use azalea_chat::Component; use azalea_chat::FormattedText;
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
use std::{collections::HashSet, hash::Hash}; use std::{collections::HashSet, hash::Hash};
@ -68,12 +68,12 @@ impl<M> Default for Suggestions<M> {
} }
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
impl McBufReadable for Suggestions<Component> { impl McBufReadable for Suggestions<FormattedText> {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
#[derive(McBuf)] #[derive(McBuf)]
struct StandaloneSuggestion { struct StandaloneSuggestion {
pub text: String, pub text: String,
pub tooltip: Option<Component>, pub tooltip: Option<FormattedText>,
} }
let start = u32::var_read_from(buf)? as usize; let start = u32::var_read_from(buf)? as usize;
@ -97,7 +97,7 @@ impl McBufReadable for Suggestions<Component> {
} }
#[cfg(feature = "azalea-buf")] #[cfg(feature = "azalea-buf")]
impl McBufWritable for Suggestions<Component> { impl McBufWritable for Suggestions<FormattedText> {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
(self.range.start() as u32).var_write_into(buf)?; (self.range.start() as u32).var_write_into(buf)?;
(self.range.length() as u32).var_write_into(buf)?; (self.range.length() as u32).var_write_into(buf)?;

View file

@ -1,11 +1,11 @@
use crate::{style::Style, Component}; use crate::{style::Style, FormattedText};
use serde::Serialize; use serde::Serialize;
#[derive(Clone, Debug, PartialEq, Serialize)] #[derive(Clone, Debug, PartialEq, Serialize)]
pub struct BaseComponent { pub struct BaseComponent {
// implements mutablecomponent // implements mutablecomponent
#[serde(skip_serializing_if = "Vec::is_empty")] #[serde(skip_serializing_if = "Vec::is_empty")]
pub siblings: Vec<Component>, pub siblings: Vec<FormattedText>,
#[serde(flatten)] #[serde(flatten)]
pub style: Style, pub style: Style,
} }

View file

@ -16,7 +16,7 @@ use std::{
/// A chat component, basically anything you can see in chat. /// A chat component, basically anything you can see in chat.
#[derive(Clone, Debug, PartialEq, Serialize)] #[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Component { pub enum FormattedText {
Text(TextComponent), Text(TextComponent),
Translatable(TranslatableComponent), Translatable(TranslatableComponent),
} }
@ -27,7 +27,7 @@ pub static DEFAULT_STYLE: Lazy<Style> = Lazy::new(|| Style {
}); });
/// A chat component /// A chat component
impl Component { impl FormattedText {
pub fn get_base_mut(&mut self) -> &mut BaseComponent { pub fn get_base_mut(&mut self) -> &mut BaseComponent {
match self { match self {
Self::Text(c) => &mut c.base, Self::Text(c) => &mut c.base,
@ -43,14 +43,16 @@ impl Component {
} }
/// Add a component as a sibling of this one /// Add a component as a sibling of this one
fn append(&mut self, sibling: Component) { fn append(&mut self, sibling: FormattedText) {
self.get_base_mut().siblings.push(sibling); self.get_base_mut().siblings.push(sibling);
} }
/// Get the "separator" component from the json /// Get the "separator" component from the json
fn parse_separator(json: &serde_json::Value) -> Result<Option<Component>, serde_json::Error> { fn parse_separator(
json: &serde_json::Value,
) -> Result<Option<FormattedText>, serde_json::Error> {
if json.get("separator").is_some() { if json.get("separator").is_some() {
return Ok(Some(Component::deserialize( return Ok(Some(FormattedText::deserialize(
json.get("separator").unwrap(), json.get("separator").unwrap(),
)?)); )?));
} }
@ -61,16 +63,17 @@ impl Component {
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code), so you /// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code), so you
/// can print it to your terminal and get styling. /// can print it to your terminal and get styling.
/// ///
/// This is technically a shortcut for [`Component::to_ansi_custom_style`] /// This is technically a shortcut for
/// with a default [`Style`] colored white. /// [`FormattedText::to_ansi_custom_style`] with a default [`Style`]
/// colored white.
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use azalea_chat::Component; /// use azalea_chat::FormattedText;
/// use serde::de::Deserialize; /// use serde::de::Deserialize;
/// ///
/// let component = Component::deserialize(&serde_json::json!({ /// let component = FormattedText::deserialize(&serde_json::json!({
/// "text": "Hello, world!", /// "text": "Hello, world!",
/// "color": "red", /// "color": "red",
/// })).unwrap(); /// })).unwrap();
@ -85,7 +88,7 @@ impl Component {
/// Convert this component into an /// Convert this component into an
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code). /// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code).
/// ///
/// This is the same as [`Component::to_ansi`], but you can specify a /// This is the same as [`FormattedText::to_ansi`], but you can specify a
/// default [`Style`] to use. /// default [`Style`] to use.
pub fn to_ansi_custom_style(&self, default_style: &Style) -> String { pub fn to_ansi_custom_style(&self, default_style: &Style) -> String {
// this contains the final string will all the ansi escape codes // this contains the final string will all the ansi escape codes
@ -116,12 +119,12 @@ impl Component {
} }
} }
impl IntoIterator for Component { impl IntoIterator for FormattedText {
/// Recursively call the function for every component in this component /// Recursively call the function for every component in this component
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
let base = self.get_base(); let base = self.get_base();
let siblings = base.siblings.clone(); let siblings = base.siblings.clone();
let mut v: Vec<Component> = Vec::with_capacity(siblings.len() + 1); let mut v: Vec<FormattedText> = Vec::with_capacity(siblings.len() + 1);
v.push(self); v.push(self);
for sibling in siblings { for sibling in siblings {
v.extend(sibling.into_iter()); v.extend(sibling.into_iter());
@ -130,11 +133,11 @@ impl IntoIterator for Component {
v.into_iter() v.into_iter()
} }
type Item = Component; type Item = FormattedText;
type IntoIter = std::vec::IntoIter<Self::Item>; type IntoIter = std::vec::IntoIter<Self::Item>;
} }
impl<'de> Deserialize<'de> for Component { impl<'de> Deserialize<'de> for FormattedText {
fn deserialize<D>(de: D) -> Result<Self, D::Error> fn deserialize<D>(de: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
@ -142,11 +145,11 @@ impl<'de> Deserialize<'de> for Component {
let json: serde_json::Value = serde::Deserialize::deserialize(de)?; let json: serde_json::Value = serde::Deserialize::deserialize(de)?;
// we create a component that we might add siblings to // we create a component that we might add siblings to
let mut component: Component; let mut component: FormattedText;
// if it's primitive, make it a text component // if it's primitive, make it a text component
if !json.is_array() && !json.is_object() { if !json.is_array() && !json.is_object() {
return Ok(Component::Text(TextComponent::new( return Ok(FormattedText::Text(TextComponent::new(
json.as_str().unwrap_or("").to_string(), json.as_str().unwrap_or("").to_string(),
))); )));
} }
@ -154,7 +157,7 @@ impl<'de> Deserialize<'de> for Component {
else if json.is_object() { else if json.is_object() {
if let Some(text) = json.get("text") { if let Some(text) = json.get("text") {
let text = text.as_str().unwrap_or("").to_string(); let text = text.as_str().unwrap_or("").to_string();
component = Component::Text(TextComponent::new(text)); component = FormattedText::Text(TextComponent::new(text));
} else if let Some(translate) = json.get("translate") { } else if let Some(translate) = json.get("translate") {
let translate = translate let translate = translate
.as_str() .as_str()
@ -169,8 +172,8 @@ impl<'de> Deserialize<'de> for Component {
// if it's a string component with no styling and no siblings, just add a // if it's a string component with no styling and no siblings, just add a
// string to with_array otherwise add the component // string to with_array otherwise add the component
// to the array // to the array
let c = Component::deserialize(item).map_err(de::Error::custom)?; let c = FormattedText::deserialize(item).map_err(de::Error::custom)?;
if let Component::Text(text_component) = c { if let FormattedText::Text(text_component) = c {
if text_component.base.siblings.is_empty() if text_component.base.siblings.is_empty()
&& text_component.base.style.is_empty() && text_component.base.style.is_empty()
{ {
@ -178,16 +181,19 @@ impl<'de> Deserialize<'de> for Component {
continue; continue;
} }
} }
with_array.push(StringOrComponent::Component( with_array.push(StringOrComponent::FormattedText(
Component::deserialize(item).map_err(de::Error::custom)?, FormattedText::deserialize(item).map_err(de::Error::custom)?,
)); ));
} }
component = component = FormattedText::Translatable(TranslatableComponent::new(
Component::Translatable(TranslatableComponent::new(translate, with_array)); translate, with_array,
));
} else { } else {
// if it doesn't have a "with", just have the with_array be empty // if it doesn't have a "with", just have the with_array be empty
component = component = FormattedText::Translatable(TranslatableComponent::new(
Component::Translatable(TranslatableComponent::new(translate, Vec::new())); translate,
Vec::new(),
));
} }
} else if let Some(score) = json.get("score") { } else if let Some(score) = json.get("score") {
// object = GsonHelper.getAsJsonObject(jsonObject, "score"); // object = GsonHelper.getAsJsonObject(jsonObject, "score");
@ -213,10 +219,11 @@ impl<'de> Deserialize<'de> for Component {
nbt nbt
} else { } else {
return Err(de::Error::custom( return Err(de::Error::custom(
format!("Don't know how to turn {json} into a Component").as_str(), format!("Don't know how to turn {json} into a FormattedText").as_str(),
)); ));
}; };
let _separator = Component::parse_separator(&json).map_err(de::Error::custom)?; let _separator =
FormattedText::parse_separator(&json).map_err(de::Error::custom)?;
let _interpret = match json.get("interpret") { let _interpret = match json.get("interpret") {
Some(v) => v.as_bool().ok_or(Some(false)).unwrap(), Some(v) => v.as_bool().ok_or(Some(false)).unwrap(),
@ -237,7 +244,7 @@ impl<'de> Deserialize<'de> for Component {
} }
for extra_component in extra { for extra_component in extra {
let sibling = let sibling =
Component::deserialize(extra_component).map_err(de::Error::custom)?; FormattedText::deserialize(extra_component).map_err(de::Error::custom)?;
component.append(sibling); component.append(sibling);
} }
} }
@ -250,33 +257,35 @@ impl<'de> Deserialize<'de> for Component {
// ok so it's not an object, if it's an array deserialize every item // ok so it's not an object, if it's an array deserialize every item
else if !json.is_array() { else if !json.is_array() {
return Err(de::Error::custom( return Err(de::Error::custom(
format!("Don't know how to turn {json} into a Component").as_str(), format!("Don't know how to turn {json} into a FormattedText").as_str(),
)); ));
} }
let json_array = json.as_array().unwrap(); let json_array = json.as_array().unwrap();
// the first item in the array is the one that we're gonna return, the others // the first item in the array is the one that we're gonna return, the others
// are siblings // are siblings
let mut component = Component::deserialize(&json_array[0]).map_err(de::Error::custom)?; let mut component =
FormattedText::deserialize(&json_array[0]).map_err(de::Error::custom)?;
for i in 1..json_array.len() { for i in 1..json_array.len() {
component.append( component.append(
Component::deserialize(json_array.get(i).unwrap()).map_err(de::Error::custom)?, FormattedText::deserialize(json_array.get(i).unwrap())
.map_err(de::Error::custom)?,
); );
} }
Ok(component) Ok(component)
} }
} }
impl McBufReadable for Component { impl McBufReadable for FormattedText {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let string = String::read_from(buf)?; let string = String::read_from(buf)?;
debug!("Component string: {}", string); debug!("FormattedText string: {}", string);
let json: serde_json::Value = serde_json::from_str(string.as_str())?; let json: serde_json::Value = serde_json::from_str(string.as_str())?;
let component = Component::deserialize(json)?; let component = FormattedText::deserialize(json)?;
Ok(component) Ok(component)
} }
} }
impl McBufWritable for Component { impl McBufWritable for FormattedText {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let json = serde_json::to_string(self).unwrap(); let json = serde_json::to_string(self).unwrap();
json.write_into(buf)?; json.write_into(buf)?;
@ -284,31 +293,31 @@ impl McBufWritable for Component {
} }
} }
impl From<String> for Component { impl From<String> for FormattedText {
fn from(s: String) -> Self { fn from(s: String) -> Self {
Component::Text(TextComponent { FormattedText::Text(TextComponent {
text: s, text: s,
base: BaseComponent::default(), base: BaseComponent::default(),
}) })
} }
} }
impl From<&str> for Component { impl From<&str> for FormattedText {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
Self::from(s.to_string()) Self::from(s.to_string())
} }
} }
impl Display for Component { impl Display for FormattedText {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Component::Text(c) => c.fmt(f), FormattedText::Text(c) => c.fmt(f),
Component::Translatable(c) => c.fmt(f), FormattedText::Translatable(c) => c.fmt(f),
} }
} }
} }
impl Default for Component { impl Default for FormattedText {
fn default() -> Self { fn default() -> Self {
Component::Text(TextComponent::default()) FormattedText::Text(TextComponent::default())
} }
} }

View file

@ -7,4 +7,4 @@ pub mod style;
pub mod text_component; pub mod text_component;
pub mod translatable_component; pub mod translatable_component;
pub use component::Component; pub use component::FormattedText;

View file

@ -1,4 +1,4 @@
use crate::{base_component::BaseComponent, style::ChatFormatting, Component}; use crate::{base_component::BaseComponent, style::ChatFormatting, FormattedText};
use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer}; use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer};
use std::fmt::Display; use std::fmt::Display;
@ -26,7 +26,7 @@ impl Serialize for TextComponent {
const LEGACY_FORMATTING_CODE_SYMBOL: char = '§'; const LEGACY_FORMATTING_CODE_SYMBOL: char = '§';
/// Convert a legacy color code string into a Component /// Convert a legacy color code string into a FormattedText
/// Technically in Minecraft this is done when displaying the text, but AFAIK /// Technically in Minecraft this is done when displaying the text, but AFAIK
/// it's the same as just doing it in TextComponent /// it's the same as just doing it in TextComponent
pub fn legacy_color_code_to_text_component(legacy_color_code: &str) -> TextComponent { pub fn legacy_color_code_to_text_component(legacy_color_code: &str) -> TextComponent {
@ -98,18 +98,18 @@ impl TextComponent {
} }
} }
fn get(self) -> Component { fn get(self) -> FormattedText {
Component::Text(self) FormattedText::Text(self)
} }
} }
impl Display for TextComponent { impl Display for TextComponent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// this contains the final string will all the ansi escape codes // this contains the final string will all the ansi escape codes
for component in Component::Text(self.clone()).into_iter() { for component in FormattedText::Text(self.clone()).into_iter() {
let component_text = match &component { let component_text = match &component {
Component::Text(c) => c.text.to_string(), FormattedText::Text(c) => c.text.to_string(),
Component::Translatable(c) => c.read()?.to_string(), FormattedText::Translatable(c) => c.read()?.to_string(),
}; };
f.write_str(&component_text)?; f.write_str(&component_text)?;

View file

@ -1,7 +1,7 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use crate::{ use crate::{
base_component::BaseComponent, style::Style, text_component::TextComponent, Component, base_component::BaseComponent, style::Style, text_component::TextComponent, FormattedText,
}; };
use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer}; use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSerializer};
@ -9,7 +9,7 @@ use serde::{ser::SerializeMap, Serialize, Serializer, __private::ser::FlatMapSer
#[serde(untagged)] #[serde(untagged)]
pub enum StringOrComponent { pub enum StringOrComponent {
String(String), String(String),
Component(Component), FormattedText(FormattedText),
} }
/// A message whose content depends on the client's language. /// A message whose content depends on the client's language.
@ -42,7 +42,7 @@ impl TranslatableComponent {
} }
} }
/// Convert the key and args to a Component. /// Convert the key and args to a FormattedText.
pub fn read(&self) -> Result<TextComponent, fmt::Error> { pub fn read(&self) -> Result<TextComponent, fmt::Error> {
let template = azalea_language::get(&self.key).unwrap_or(&self.key); let template = azalea_language::get(&self.key).unwrap_or(&self.key);
// decode the % things // decode the % things
@ -122,7 +122,7 @@ impl TranslatableComponent {
Ok(TextComponent { Ok(TextComponent {
base: BaseComponent { base: BaseComponent {
siblings: components.into_iter().map(Component::Text).collect(), siblings: components.into_iter().map(FormattedText::Text).collect(),
style: Style::default(), style: Style::default(),
}, },
text: "".to_string(), text: "".to_string(),
@ -133,10 +133,10 @@ impl TranslatableComponent {
impl Display for TranslatableComponent { impl Display for TranslatableComponent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// this contains the final string will all the ansi escape codes // this contains the final string will all the ansi escape codes
for component in Component::Translatable(self.clone()).into_iter() { for component in FormattedText::Translatable(self.clone()).into_iter() {
let component_text = match &component { let component_text = match &component {
Component::Text(c) => c.text.to_string(), FormattedText::Text(c) => c.text.to_string(),
Component::Translatable(c) => c.read()?.to_string(), FormattedText::Translatable(c) => c.read()?.to_string(),
}; };
f.write_str(&component_text)?; f.write_str(&component_text)?;
@ -150,7 +150,7 @@ impl Display for StringOrComponent {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
match self { match self {
StringOrComponent::String(s) => write!(f, "{s}"), StringOrComponent::String(s) => write!(f, "{s}"),
StringOrComponent::Component(c) => write!(f, "{c}"), StringOrComponent::FormattedText(c) => write!(f, "{c}"),
} }
} }
} }
@ -159,7 +159,7 @@ impl From<StringOrComponent> for TextComponent {
fn from(soc: StringOrComponent) -> Self { fn from(soc: StringOrComponent) -> Self {
match soc { match soc {
StringOrComponent::String(s) => TextComponent::new(s), StringOrComponent::String(s) => TextComponent::new(s),
StringOrComponent::Component(c) => TextComponent::new(c.to_string()), StringOrComponent::FormattedText(c) => TextComponent::new(c.to_string()),
} }
} }
} }

View file

@ -1,6 +1,6 @@
use azalea_chat::{ use azalea_chat::{
style::{Ansi, ChatFormatting, TextColor}, style::{Ansi, ChatFormatting, TextColor},
Component, FormattedText,
}; };
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
@ -15,7 +15,7 @@ fn basic_ansi_test() {
}"#, }"#,
) )
.unwrap(); .unwrap();
let component = Component::deserialize(&j).unwrap(); let component = FormattedText::deserialize(&j).unwrap();
assert_eq!( assert_eq!(
component.to_ansi(), component.to_ansi(),
"\u{1b}[1m\u{1b}[38;2;255;85;85mhello\u{1b}[m" "\u{1b}[1m\u{1b}[38;2;255;85;85mhello\u{1b}[m"
@ -51,7 +51,7 @@ fn complex_ansi_test() {
]"##, ]"##,
) )
.unwrap(); .unwrap();
let component = Component::deserialize(&j).unwrap(); let component = FormattedText::deserialize(&j).unwrap();
assert_eq!( assert_eq!(
component.to_ansi(), component.to_ansi(),
format!( format!(
@ -70,6 +70,6 @@ fn complex_ansi_test() {
#[test] #[test]
fn component_from_string() { fn component_from_string() {
let j: Value = serde_json::from_str("\"foo\"").unwrap(); let j: Value = serde_json::from_str("\"foo\"").unwrap();
let component = Component::deserialize(&j).unwrap(); let component = FormattedText::deserialize(&j).unwrap();
assert_eq!(component.to_ansi(), "foo"); assert_eq!(component.to_ansi(), "foo");
} }

View file

@ -1,7 +1,7 @@
//! Implementations of chat-related features. //! Implementations of chat-related features.
use crate::Client; use crate::Client;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol::packets::game::{ use azalea_protocol::packets::game::{
clientbound_player_chat_packet::ClientboundPlayerChatPacket, clientbound_player_chat_packet::ClientboundPlayerChatPacket,
clientbound_system_chat_packet::ClientboundSystemChatPacket, clientbound_system_chat_packet::ClientboundSystemChatPacket,
@ -29,7 +29,7 @@ macro_rules! regex {
impl ChatPacket { impl ChatPacket {
/// Get the message shown in chat for this packet. /// Get the message shown in chat for this packet.
pub fn message(&self) -> Component { pub fn message(&self) -> FormattedText {
match self { match self {
ChatPacket::System(p) => p.content.clone(), ChatPacket::System(p) => p.content.clone(),
ChatPacket::Player(p) => p.message(), ChatPacket::Player(p) => p.message(),
@ -83,7 +83,7 @@ impl ChatPacket {
/// convenience function for testing. /// convenience function for testing.
pub fn new(message: &str) -> Self { pub fn new(message: &str) -> Self {
ChatPacket::System(Arc::new(ClientboundSystemChatPacket { ChatPacket::System(Arc::new(ClientboundSystemChatPacket {
content: Component::from(message), content: FormattedText::from(message),
overlay: false, overlay: false,
})) }))
} }

View file

@ -1,5 +1,5 @@
use azalea_auth::game_profile::GameProfile; use azalea_auth::game_profile::GameProfile;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_core::GameType; use azalea_core::GameType;
use azalea_world::PartialWorld; use azalea_world::PartialWorld;
use uuid::Uuid; use uuid::Uuid;
@ -13,5 +13,5 @@ pub struct PlayerInfo {
pub gamemode: GameType, pub gamemode: GameType,
pub latency: i32, pub latency: i32,
/// The player's display name in the tab list. /// The player's display name in the tab list.
pub display_name: Option<Component>, pub display_name: Option<FormattedText>,
} }

View file

@ -3,13 +3,17 @@ description = "Miscellaneous things in Azalea."
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
name = "azalea-core" name = "azalea-core"
version = "0.5.0"
repository = "https://github.com/mat-1/azalea/tree/main/azalea-core" repository = "https://github.com/mat-1/azalea/tree/main/azalea-core"
version = "0.5.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.5.0" } azalea-buf = {path = "../azalea-buf", version = "^0.5.0"}
azalea-chat = {path = "../azalea-chat", version = "^0.5.0" } azalea-chat = {path = "../azalea-chat", version = "^0.5.0"}
azalea-nbt = {path = "../azalea-nbt", version = "^0.5.0" } azalea-nbt = {path = "../azalea-nbt", version = "^0.5.0"}
bevy_ecs = {version = "0.9.1", default-features = false, optional = true}
uuid = "^1.1.2" uuid = "^1.1.2"
[features]
bevy_ecs = ["dep:bevy_ecs"]

View file

@ -1,6 +1,7 @@
use crate::{BlockPos, Slot}; use crate::{BlockPos, Slot};
use azalea_buf::McBuf; use azalea_buf::McBuf;
#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
#[derive(Debug, Clone, McBuf, Default)] #[derive(Debug, Clone, McBuf, Default)]
pub struct Particle { pub struct Particle {
#[var] #[var]

View file

@ -1,7 +1,7 @@
use azalea_buf::{ use azalea_buf::{
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable, BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
}; };
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::io::Cursor; use std::io::Cursor;
use std::io::Write; use std::io::Write;
@ -18,7 +18,7 @@ pub enum Operation {
Add(AddOperation), Add(AddOperation),
Remove, Remove,
UpdateProgress(f32), UpdateProgress(f32),
UpdateName(Component), UpdateName(FormattedText),
UpdateStyle(Style), UpdateStyle(Style),
UpdateProperties(Properties), UpdateProperties(Properties),
} }
@ -30,7 +30,7 @@ impl McBufReadable for Operation {
0 => Operation::Add(AddOperation::read_from(buf)?), 0 => Operation::Add(AddOperation::read_from(buf)?),
1 => Operation::Remove, 1 => Operation::Remove,
2 => Operation::UpdateProgress(f32::read_from(buf)?), 2 => Operation::UpdateProgress(f32::read_from(buf)?),
3 => Operation::UpdateName(Component::read_from(buf)?), 3 => Operation::UpdateName(FormattedText::read_from(buf)?),
4 => Operation::UpdateStyle(Style::read_from(buf)?), 4 => Operation::UpdateStyle(Style::read_from(buf)?),
5 => Operation::UpdateProperties(Properties::read_from(buf)?), 5 => Operation::UpdateProperties(Properties::read_from(buf)?),
_ => { _ => {
@ -75,7 +75,7 @@ impl McBufWritable for Operation {
#[derive(Clone, Debug, McBuf)] #[derive(Clone, Debug, McBuf)]
pub struct AddOperation { pub struct AddOperation {
name: Component, name: FormattedText,
progress: f32, progress: f32,
style: Style, style: Style,
properties: Properties, properties: Properties,

View file

@ -1,9 +1,9 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundChatPreviewPacket { pub struct ClientboundChatPreviewPacket {
pub query_id: i32, pub query_id: i32,
pub preview: Option<Component>, pub preview: Option<FormattedText>,
} }

View file

@ -1,13 +1,13 @@
use azalea_brigadier::suggestion::Suggestions; use azalea_brigadier::suggestion::Suggestions;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundCommandSuggestionsPacket { pub struct ClientboundCommandSuggestionsPacket {
#[var] #[var]
pub id: u32, pub id: u32,
pub suggestions: Suggestions<Component>, pub suggestions: Suggestions<FormattedText>,
} }
#[cfg(test)] #[cfg(test)]
@ -24,7 +24,7 @@ mod tests {
suggestions: vec![Suggestion { suggestions: vec![Suggestion {
text: "foo".to_string(), text: "foo".to_string(),
range: StringRange::new(1, 4), range: StringRange::new(1, 4),
tooltip: Some(Component::from("bar".to_string())), tooltip: Some(FormattedText::from("bar".to_string())),
}], }],
}; };
let mut buf = Vec::new(); let mut buf = Vec::new();

View file

@ -99,7 +99,7 @@ pub enum BrigadierParser {
ItemStack, ItemStack,
ItemPredicate, ItemPredicate,
Color, Color,
Component, FormattedText,
Message, Message,
NbtCompoundTag, NbtCompoundTag,
NbtTag, NbtTag,

View file

@ -1,8 +1,8 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundDisconnectPacket { pub struct ClientboundDisconnectPacket {
pub reason: Component, pub reason: FormattedText,
} }

View file

@ -1,10 +1,10 @@
use super::clientbound_player_chat_packet::ChatTypeBound; use super::clientbound_player_chat_packet::ChatTypeBound;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundDisguisedChatPacket { pub struct ClientboundDisguisedChatPacket {
pub message: Component, pub message: FormattedText,
pub chat_type: ChatTypeBound, pub chat_type: ChatTypeBound,
} }

View file

@ -1,6 +1,6 @@
use azalea_buf::{BufReadError, McBuf}; use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable}; use azalea_buf::{McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
@ -76,7 +76,7 @@ pub struct MapDecoration {
/// Minecraft does & 15 on this value, azalea-protocol doesn't. I don't /// Minecraft does & 15 on this value, azalea-protocol doesn't. I don't
/// think it matters. /// think it matters.
pub rot: i8, pub rot: i8,
pub name: Option<Component>, pub name: Option<FormattedText>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -1,5 +1,5 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
@ -7,5 +7,5 @@ pub struct ClientboundOpenScreenPacket {
#[var] #[var]
pub container_id: u32, pub container_id: u32,
pub menu_type: azalea_registry::Menu, pub menu_type: azalea_registry::Menu,
pub title: Component, pub title: FormattedText,
} }

View file

@ -3,7 +3,7 @@ use azalea_buf::{
}; };
use azalea_chat::{ use azalea_chat::{
translatable_component::{StringOrComponent, TranslatableComponent}, translatable_component::{StringOrComponent, TranslatableComponent},
Component, FormattedText,
}; };
use azalea_core::BitSet; use azalea_core::BitSet;
use azalea_crypto::MessageSignature; use azalea_crypto::MessageSignature;
@ -18,7 +18,7 @@ pub struct ClientboundPlayerChatPacket {
pub index: u32, pub index: u32,
pub signature: Option<MessageSignature>, pub signature: Option<MessageSignature>,
pub body: PackedSignedMessageBody, pub body: PackedSignedMessageBody,
pub unsigned_content: Option<Component>, pub unsigned_content: Option<FormattedText>,
pub filter_mask: FilterMask, pub filter_mask: FilterMask,
pub chat_type: ChatTypeBound, pub chat_type: ChatTypeBound,
} }
@ -66,8 +66,8 @@ pub enum ChatType {
#[derive(Clone, Debug, McBuf, PartialEq)] #[derive(Clone, Debug, McBuf, PartialEq)]
pub struct ChatTypeBound { pub struct ChatTypeBound {
pub chat_type: ChatType, pub chat_type: ChatType,
pub name: Component, pub name: FormattedText,
pub target_name: Option<Component>, pub target_name: Option<FormattedText>,
} }
// must be in Client // must be in Client
@ -87,17 +87,17 @@ pub struct MessageSignatureCache {
// {} } // {} }
impl ClientboundPlayerChatPacket { impl ClientboundPlayerChatPacket {
/// Returns the content of the message. If you want to get the Component /// Returns the content of the message. If you want to get the FormattedText
/// for the whole message including the sender part, use /// for the whole message including the sender part, use
/// [`ClientboundPlayerChatPacket::message`]. /// [`ClientboundPlayerChatPacket::message`].
pub fn content(&self) -> Component { pub fn content(&self) -> FormattedText {
self.unsigned_content self.unsigned_content
.clone() .clone()
.unwrap_or_else(|| Component::from(self.body.content.clone())) .unwrap_or_else(|| FormattedText::from(self.body.content.clone()))
} }
/// Get the full message, including the sender part. /// Get the full message, including the sender part.
pub fn message(&self) -> Component { pub fn message(&self) -> FormattedText {
let sender = self.chat_type.name.clone(); let sender = self.chat_type.name.clone();
let content = self.content(); let content = self.content();
let target = self.chat_type.target_name.clone(); let target = self.chat_type.target_name.clone();
@ -105,16 +105,16 @@ impl ClientboundPlayerChatPacket {
let translation_key = self.chat_type.chat_type.chat_translation_key(); let translation_key = self.chat_type.chat_type.chat_translation_key();
let mut args = vec![ let mut args = vec![
StringOrComponent::Component(sender), StringOrComponent::FormattedText(sender),
StringOrComponent::Component(content), StringOrComponent::FormattedText(content),
]; ];
if let Some(target) = target { if let Some(target) = target {
args.push(StringOrComponent::Component(target)); args.push(StringOrComponent::FormattedText(target));
} }
let component = TranslatableComponent::new(translation_key.to_string(), args); let component = TranslatableComponent::new(translation_key.to_string(), args);
Component::Translatable(component) FormattedText::Translatable(component)
} }
} }

View file

@ -1,5 +1,5 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
/// Used to send a respawn screen. /// Used to send a respawn screen.
@ -8,5 +8,5 @@ pub struct ClientboundPlayerCombatKillPacket {
#[var] #[var]
pub player_id: u32, pub player_id: u32,
pub killer_id: u32, pub killer_id: u32,
pub message: Component, pub message: FormattedText,
} }

View file

@ -2,7 +2,7 @@ use azalea_auth::game_profile::{GameProfile, ProfilePropertyValue};
use azalea_buf::{ use azalea_buf::{
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable, BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
}; };
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_core::{BitSet, GameType}; use azalea_core::{BitSet, GameType};
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::{ use std::{
@ -25,7 +25,7 @@ pub struct PlayerInfoEntry {
pub listed: bool, pub listed: bool,
pub latency: i32, pub latency: i32,
pub game_mode: GameType, pub game_mode: GameType,
pub display_name: Option<Component>, pub display_name: Option<FormattedText>,
pub chat_session: Option<RemoteChatSessionData>, pub chat_session: Option<RemoteChatSessionData>,
} }
@ -53,7 +53,7 @@ pub struct UpdateLatencyAction {
} }
#[derive(Clone, Debug, McBuf)] #[derive(Clone, Debug, McBuf)]
pub struct UpdateDisplayNameAction { pub struct UpdateDisplayNameAction {
pub display_name: Option<Component>, pub display_name: Option<FormattedText>,
} }
impl McBufReadable for ClientboundPlayerInfoUpdatePacket { impl McBufReadable for ClientboundPlayerInfoUpdatePacket {

View file

@ -1,5 +1,5 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
@ -7,5 +7,5 @@ pub struct ClientboundResourcePackPacket {
pub url: String, pub url: String,
pub hash: String, pub hash: String,
pub required: bool, pub required: bool,
pub prompt: Option<Component>, pub prompt: Option<FormattedText>,
} }

View file

@ -1,10 +1,10 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundServerDataPacket { pub struct ClientboundServerDataPacket {
pub motd: Option<Component>, pub motd: Option<FormattedText>,
pub icon_base64: Option<String>, pub icon_base64: Option<String>,
pub enforces_secure_chat: bool, pub enforces_secure_chat: bool,
} }

View file

@ -1,8 +1,8 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundSetActionBarTextPacket { pub struct ClientboundSetActionBarTextPacket {
pub text: Component, pub text: FormattedText,
} }

View file

@ -1,5 +1,5 @@
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
@ -48,7 +48,7 @@ impl McBufWritable for Method {
#[derive(McBuf, Clone, Debug)] #[derive(McBuf, Clone, Debug)]
pub struct DisplayInfo { pub struct DisplayInfo {
pub display_name: Component, pub display_name: FormattedText,
pub render_type: RenderType, pub render_type: RenderType,
} }

View file

@ -1,5 +1,5 @@
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
use azalea_chat::{style::ChatFormatting, Component}; use azalea_chat::{style::ChatFormatting, FormattedText};
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
@ -61,13 +61,13 @@ impl McBufWritable for Method {
#[derive(McBuf, Clone, Debug)] #[derive(McBuf, Clone, Debug)]
pub struct Parameters { pub struct Parameters {
pub display_name: Component, pub display_name: FormattedText,
pub options: u8, pub options: u8,
pub nametag_visibility: String, pub nametag_visibility: String,
pub collision_rule: String, pub collision_rule: String,
pub color: ChatFormatting, pub color: ChatFormatting,
pub player_prefix: Component, pub player_prefix: FormattedText,
pub player_suffix: Component, pub player_suffix: FormattedText,
} }
type PlayerList = Vec<String>; type PlayerList = Vec<String>;

View file

@ -1,8 +1,8 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundSetSubtitleTextPacket { pub struct ClientboundSetSubtitleTextPacket {
pub text: Component, pub text: FormattedText,
} }

View file

@ -1,8 +1,8 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundSetTitleTextPacket { pub struct ClientboundSetTitleTextPacket {
pub text: Component, pub text: FormattedText,
} }

View file

@ -1,9 +1,9 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket, PartialEq)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket, PartialEq)]
pub struct ClientboundSystemChatPacket { pub struct ClientboundSystemChatPacket {
pub content: Component, pub content: FormattedText,
pub overlay: bool, pub overlay: bool,
} }

View file

@ -1,9 +1,9 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundTabListPacket { pub struct ClientboundTabListPacket {
pub header: Component, pub header: FormattedText,
pub footer: Component, pub footer: FormattedText,
} }

View file

@ -1,5 +1,5 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_core::{ResourceLocation, Slot}; use azalea_core::{ResourceLocation, Slot};
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::collections::HashMap; use std::collections::HashMap;
@ -25,8 +25,8 @@ pub struct Advancement {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DisplayInfo { pub struct DisplayInfo {
pub title: Component, pub title: FormattedText,
pub description: Component, pub description: FormattedText,
pub icon: Slot, pub icon: Slot,
pub frame: FrameType, pub frame: FrameType,
pub show_toast: bool, pub show_toast: bool,
@ -132,9 +132,9 @@ pub struct CriterionProgress {
// Advancement { // Advancement {
// parent_id: None, // parent_id: None,
// display: Some(DisplayInfo { // display: Some(DisplayInfo {
// title: Component::from("title".to_string()), // title: FormattedText::from("title".to_string()),
// description: // description:
// Component::from("description".to_string()), icon: // FormattedText::from("description".to_string()), icon:
// Slot::Empty, frame: FrameType::Task, // Slot::Empty, frame: FrameType::Task,
// show_toast: true, // show_toast: true,
// hidden: false, // hidden: false,

View file

@ -1,8 +1,8 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundLoginPacket; use azalea_protocol_macros::ClientboundLoginPacket;
#[derive(Clone, Debug, McBuf, ClientboundLoginPacket)] #[derive(Clone, Debug, McBuf, ClientboundLoginPacket)]
pub struct ClientboundLoginDisconnectPacket { pub struct ClientboundLoginDisconnectPacket {
pub reason: Component, pub reason: FormattedText,
} }

View file

@ -1,5 +1,5 @@
use azalea_buf::{BufReadError, McBufReadable, McBufWritable}; use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundStatusPacket; use azalea_protocol_macros::ClientboundStatusPacket;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{value::Serializer, Value}; use serde_json::{value::Serializer, Value};
@ -28,7 +28,7 @@ pub struct Players {
// the entire packet is just json, which is why it has deserialize // the entire packet is just json, which is why it has deserialize
#[derive(Clone, Debug, Serialize, Deserialize, ClientboundStatusPacket)] #[derive(Clone, Debug, Serialize, Deserialize, ClientboundStatusPacket)]
pub struct ClientboundStatusResponsePacket { pub struct ClientboundStatusResponsePacket {
pub description: Component, pub description: FormattedText,
#[serde(default)] #[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub favicon: Option<String>, pub favicon: Option<String>,

View file

@ -1205,7 +1205,7 @@ registry!(CommandArgumentKind, {
ItemStack => "minecraft:item_stack", ItemStack => "minecraft:item_stack",
ItemPredicate => "minecraft:item_predicate", ItemPredicate => "minecraft:item_predicate",
Color => "minecraft:color", Color => "minecraft:color",
Component => "minecraft:component", FormattedText => "minecraft:component",
Message => "minecraft:message", Message => "minecraft:message",
NbtCompoundTag => "minecraft:nbt_compound_tag", NbtCompoundTag => "minecraft:nbt_compound_tag",
NbtTag => "minecraft:nbt_tag", NbtTag => "minecraft:nbt_tag",

View file

@ -9,13 +9,13 @@ version = "0.5.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-block = { path = "../azalea-block", default-features = false, version = "^0.5.0" } azalea-block = {path = "../azalea-block", default-features = false, version = "^0.5.0"}
azalea-buf = { path = "../azalea-buf", version = "^0.5.0" } azalea-buf = {path = "../azalea-buf", version = "^0.5.0"}
azalea-chat = { path = "../azalea-chat", version = "^0.5.0" } azalea-chat = {path = "../azalea-chat", version = "^0.5.0"}
azalea-core = { path = "../azalea-core", version = "^0.5.0" } azalea-core = {path = "../azalea-core", version = "^0.5.0", features = ["bevy_ecs"]}
azalea-nbt = { path = "../azalea-nbt", version = "^0.5.0" } azalea-nbt = {path = "../azalea-nbt", version = "^0.5.0"}
azalea-registry = { path = "../azalea-registry", version = "^0.5.0" } azalea-registry = {path = "../azalea-registry", version = "^0.5.0"}
bevy_ecs = { version = "0.9.1", default-features = false } bevy_ecs = {version = "0.9.1", default-features = false}
enum-as-inner = "0.5.1" enum-as-inner = "0.5.1"
log = "0.4.17" log = "0.4.17"
nohash-hasher = "0.2.0" nohash-hasher = "0.2.0"

View file

@ -1,8 +1,9 @@
use azalea_block::BlockState; use azalea_block::BlockState;
use azalea_buf::{BufReadError, McBufVarReadable, McBufVarWritable}; use azalea_buf::{BufReadError, McBufVarReadable, McBufVarWritable};
use azalea_buf::{McBuf, McBufReadable, McBufWritable}; use azalea_buf::{McBuf, McBufReadable, McBufWritable};
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_core::{BlockPos, Direction, GlobalPos, Particle, Slot}; use azalea_core::{BlockPos, Direction, GlobalPos, Particle, Slot};
use bevy_ecs::component::Component;
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
use nohash_hasher::IntSet; use nohash_hasher::IntSet;
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
@ -52,8 +53,8 @@ pub enum EntityDataValue {
Long(i64), Long(i64),
Float(f32), Float(f32),
String(String), String(String),
Component(Component), FormattedText(FormattedText),
OptionalComponent(Option<Component>), OptionalComponent(Option<FormattedText>),
ItemStack(Slot), ItemStack(Slot),
Boolean(bool), Boolean(bool),
Rotations(Rotations), Rotations(Rotations),
@ -105,7 +106,7 @@ pub struct Rotations {
pub z: f32, pub z: f32,
} }
#[derive(Clone, Debug, Copy, McBuf, Default)] #[derive(Clone, Debug, Copy, McBuf, Default, Component)]
pub enum Pose { pub enum Pose {
#[default] #[default]
Standing = 0, Standing = 0,

File diff suppressed because it is too large Load diff

View file

@ -15,8 +15,8 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
{'name': 'Long', 'type': 'i64'}, {'name': 'Long', 'type': 'i64'},
{'name': 'Float', 'type': 'f32'}, {'name': 'Float', 'type': 'f32'},
{'name': 'String', 'type': 'String'}, {'name': 'String', 'type': 'String'},
{'name': 'Component', 'type': 'Component'}, {'name': 'Component', 'type': 'FormattedText'},
{'name': 'OptionalComponent', 'type': 'Option<Component>'}, {'name': 'OptionalComponent', 'type': 'Option<FormattedText>'},
{'name': 'ItemStack', 'type': 'Slot'}, {'name': 'ItemStack', 'type': 'Slot'},
{'name': 'Boolean', 'type': 'bool'}, {'name': 'Boolean', 'type': 'bool'},
{'name': 'Rotations', 'type': 'Rotations'}, {'name': 'Rotations', 'type': 'Rotations'},
@ -45,9 +45,9 @@ use super::{
EntityDataValue, EntityMetadataItems, OptionalUnsignedInt, Pose, Rotations, VillagerData, EntityDataValue, EntityMetadataItems, OptionalUnsignedInt, Pose, Rotations, VillagerData,
}; };
use azalea_block::BlockState; use azalea_block::BlockState;
use azalea_chat::Component; use azalea_chat::FormattedText;
use azalea_core::{BlockPos, Direction, Particle, Slot}; use azalea_core::{BlockPos, Direction, Particle, Slot};
use hecs::{Query, EntityBuilder, BuiltEntity}; use bevy_ecs::{bundle::Bundle, component::Component};
use thiserror::Error; use thiserror::Error;
use uuid::Uuid; use uuid::Uuid;
@ -160,33 +160,124 @@ impl From<EntityDataValue> for UpdateMetadataError {
metadata_type_data = metadata_types[type_id] metadata_type_data = metadata_types[type_id]
rust_type = metadata_type_data['type'] rust_type = metadata_type_data['type']
code.append(f'#[derive(Component)]')
code.append(f'pub struct {struct_name}(pub {rust_type});') code.append(f'pub struct {struct_name}(pub {rust_type});')
else: else:
# if it's a bitfield just make a struct for each bit # if it's a bitfield just make a struct for each bit
for mask, name in name_or_bitfield.items(): for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index) name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name)) struct_name = upper_first_letter(to_camel_case(name))
code.append(f'#[derive(Component)]')
code.append(f'pub struct {struct_name}(pub bool);') code.append(f'pub struct {struct_name}(pub bool);')
# add the entity struct and Query struct # add the entity struct and Query struct
is_actually_entity = not entity_id.startswith('~') is_actually_entity = not entity_id.startswith('~')
if is_actually_entity: if is_actually_entity:
struct_name: str = upper_first_letter(to_camel_case(entity_id)) struct_name: str = upper_first_letter(to_camel_case(entity_id))
code.append(f'#[derive(Component)]')
code.append(f'pub struct {struct_name};') code.append(f'pub struct {struct_name};')
# impl Allay { # #[derive(Bundle)]
# pub fn default(builder: &mut EntityBuilder) { # struct AllayBundle {
# builder # health: Health,
# .add(OnFire(false)) # ...
# .add(ShiftKeyDown(false)) # dancing: Dancing,
# .add(Sprinting(false)) # can_duplicate: CanDuplicate,
# .add(Swimming(false)); # }
bundle_struct_name = f'{struct_name}Bundle'
code.append(f'')
code.append(f'#[derive(Bundle)]')
code.append(f'struct {bundle_struct_name} {{')
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
if isinstance(name_or_bitfield, str):
name_or_bitfield = maybe_rename_field(
name_or_bitfield, index)
struct_name = upper_first_letter(
to_camel_case(name_or_bitfield))
code.append(
f' {name_or_bitfield}: {struct_name},')
else:
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
code.append(f' {name}: {struct_name},')
code.append('}')
# impl AllayBundle {
# pub fn update_metadata(
# &mut self,
# ecs: bevy_ecs::world::World,
# entity: bevy_ecs::world::EntityMut,
# data: EntityMetadataItems,
# ) -> Result<(), UpdateMetadataError> {
# for d in data.0 {
# match d.index {
# 0 => self.health = Health(d.value.into_float()?),
# 1 => self.dancing = Dancing(d.value.into_boolean()?),
# 2 => self.can_duplicate = CanDuplicate(d.value.into_boolean()?),
# }
# }
# Ok(())
# } # }
# } # }
code.append(f'impl {struct_name} {{') code.append(f'impl {bundle_struct_name} {{')
code.append( code.append(
' pub fn default(builder: &mut EntityBuilder) -> BuiltEntity {') f' pub fn update_metadata(&mut self, ecs: bevy_ecs::world::World, entity: bevy_ecs::world::EntityMut, data: EntityMetadataItems) -> Result<(), UpdateMetadataError> {{')
code.append(' builder') code.append(f' for d in data.0 {{')
code.append(f' match d.index {{')
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
if isinstance(name_or_bitfield, str):
name_or_bitfield = maybe_rename_field(
name_or_bitfield, index)
struct_name = upper_first_letter(
to_camel_case(name_or_bitfield))
if name_or_bitfield in single_use_imported_types:
struct_name = ''
type_id = next(filter(lambda i: i['index'] == index, entity_metadatas))[
'type_id']
metadata_type_data = metadata_types[type_id]
rust_type = metadata_type_data['type']
type_name = metadata_type_data['name']
type_name_field = to_snake_case(type_name)
read_field_code = f'{struct_name}(d.value.into_{type_name_field}()?)' if struct_name else f'd.value.into_{type_name_field}()?'
code.append(
f' {index} => self.{name_or_bitfield} = {read_field_code},')
else:
code.append(f' {index} => {{')
code.append(
f'let bitfield = d.value.into_byte()?;')
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
code.append(
f'self.{name} = {struct_name}(bitfield & {mask} != 0);')
code.append(' },')
code.append(' }')
code.append(' }')
code.append(' Ok(())')
code.append(' }')
code.append('}')
code.append('')
# impl Default for AllayBundle {
# fn default() -> Self {
# Self {
# on_fire: OnFire(false),
# shift_key_down: ShiftKeyDown(false),
# sprinting: Sprinting(false),
# swimming: Swimming(false)
# }
# }
# }
code.append(f'impl Default for {bundle_struct_name} {{')
code.append(
' fn default() -> Self {')
code.append(' Self {')
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields): for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
default = next(filter(lambda i: i['index'] == index, entity_metadatas)).get( default = next(filter(lambda i: i['index'] == index, entity_metadatas)).get(
'default', 'Default::default()') 'default', 'Default::default()')
@ -212,7 +303,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
elif type_name == 'FrogVariant': elif type_name == 'FrogVariant':
default = 'azalea_registry::FrogVariant::Temperate' default = 'azalea_registry::FrogVariant::Temperate'
elif type_name == 'VillagerData': elif type_name == 'VillagerData':
default = 'VillagerData { kind: azalea_registry::VillagerType::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }' default = 'VillagerData { kind: azalea_registry::VillagerKind::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }'
else: else:
default = f'{type_name}::default()' if name in single_use_imported_types else 'Default::default()' default = f'{type_name}::default()' if name in single_use_imported_types else 'Default::default()'
else: else:
@ -238,10 +329,10 @@ impl From<EntityDataValue> for UpdateMetadataError {
elif type_name == 'CompoundTag': elif type_name == 'CompoundTag':
default = f'azalea_nbt::Tag::Compound({default})' if default != 'Empty' else 'azalea_nbt::Tag::Compound(Default::default())' default = f'azalea_nbt::Tag::Compound({default})' if default != 'Empty' else 'azalea_nbt::Tag::Compound(Default::default())'
if name in single_use_imported_types: if name in single_use_imported_types:
code.append(f' .add({default})') code.append(f' {name}: {default},')
else: else:
code.append( code.append(
f' .add({upper_first_letter(to_camel_case(name))}({default}))') f' {name}: {upper_first_letter(to_camel_case(name))}({default}),')
else: else:
# if it's a bitfield, we'll have to extract the default for # if it's a bitfield, we'll have to extract the default for
# each bool from each bit in the default # each bool from each bit in the default
@ -251,94 +342,8 @@ impl From<EntityDataValue> for UpdateMetadataError {
bit_default = 'true' if ( bit_default = 'true' if (
default & mask != 0) else 'false' default & mask != 0) else 'false'
code.append( code.append(
f' .add({upper_first_letter(to_camel_case(name))}({bit_default}))') f' {name}: {upper_first_letter(to_camel_case(name))}({bit_default}),')
code.append(f' .build()')
code.append(' }')
code.append('}')
# #[derive(Query)]
# struct AllayQuery<'a> {
# health: &'a mut Health,
# ...
# dancing: &'a mut Dancing,
# can_duplicate: &'a mut CanDuplicate,
# }
query_struct_name = f'{struct_name}Query'
code.append(f'')
code.append(f'#[derive(Query)]')
code.append(f'struct {query_struct_name}<\'a> {{')
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
if isinstance(name_or_bitfield, str):
name_or_bitfield = maybe_rename_field(
name_or_bitfield, index)
struct_name = upper_first_letter(
to_camel_case(name_or_bitfield))
code.append(
f' {name_or_bitfield}: &\'a mut {struct_name},')
else:
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
code.append(f' {name}: &\'a mut {struct_name},')
code.append('}')
# impl AllayQuery<'_> {
# pub fn update_metadata(
# &mut self,
# world: hecs::World,
# entity: hecs::Entity,
# data: EntityMetadataItems,
# ) -> Result<(), UpdateMetadataError> {
# for d in data.0 {
# match d.index {
# 0 => *self.health = Health(d.value.into_float()?),
# 1 => *self.dancing = Dancing(d.value.into_boolean()?),
# 2 => *self.can_duplicate = CanDuplicate(d.value.into_boolean()?),
# }
# }
# Ok(())
# }
# }
code.append(f'impl {query_struct_name}<\'_> {{')
code.append(
f' pub fn update_metadata(&mut self, world: hecs::World, entity: hecs::Entity, data: EntityMetadataItems) -> Result<(), UpdateMetadataError> {{')
code.append(f' for d in data.0 {{')
code.append(f' match d.index {{')
for index, name_or_bitfield in enumerate(all_field_names_or_bitfields):
if isinstance(name_or_bitfield, str):
name_or_bitfield = maybe_rename_field(
name_or_bitfield, index)
struct_name = upper_first_letter(
to_camel_case(name_or_bitfield))
if name_or_bitfield in single_use_imported_types:
struct_name = ''
type_id = next(filter(lambda i: i['index'] == index, entity_metadatas))[
'type_id']
metadata_type_data = metadata_types[type_id]
rust_type = metadata_type_data['type']
type_name = metadata_type_data['name']
type_name_field = to_snake_case(type_name)
read_field_code = f'{struct_name}(d.value.into_{type_name_field}()?)' if struct_name else f'd.value.into_{type_name_field}()?'
code.append(
f' {index} => *self.{name_or_bitfield} = {read_field_code},')
else:
code.append(f' {index} => {{')
code.append(
f'let bitfield = d.value.into_byte()?;')
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
code.append(
f'*self.{name} = {struct_name}(bitfield & {mask} != 0);')
code.append(' },')
code.append(' }')
code.append(' }') code.append(' }')
code.append(' Ok(())')
code.append(' }') code.append(' }')
code.append('}') code.append('}')
code.append('') code.append('')
@ -349,29 +354,29 @@ impl From<EntityDataValue> for UpdateMetadataError {
# and now make the main update_metadata # and now make the main update_metadata
# fn update_metadata( # fn update_metadata(
# world: hecs::World, # ecs: bevy_ecs::world::World,
# entity: hecs::Entity, # entity: bevy_ecs::world::EntityMut,
# data: EntityMetadataItems, # data: EntityMetadataItems,
# ) -> Result<(), UpdateMetadataError> { # ) -> Result<(), UpdateMetadataError> {
# if let Ok(e) = world.query_one_mut::<AllayQuery>(entity) { # if let Ok(e) = world.query_one_mut::<AllayBundle>(entity) {
# e.update_metadata(world, entity, data)?; # e.update_metadata(ecs, entity, data)?;
# return Ok(()); # return Ok(());
# } # }
# Ok(()) # Ok(())
# } # }
code.append( code.append(
f'fn update_metadata(world: hecs::World, entity: hecs::Entity, data: EntityMetadataItems) -> Result<(), UpdateMetadataError> {{') f'fn update_metadata(ecs: bevy_ecs::world::World, entity: bevy_ecs::world::EntityMut, data: EntityMetadataItems) -> Result<(), UpdateMetadataError> {{')
for entity_id in burger_entity_data: for entity_id in burger_entity_data:
if entity_id.startswith('~'): if entity_id.startswith('~'):
# not actually an entiry # not actually an entiry
continue continue
struct_name: str = upper_first_letter(to_camel_case(entity_id)) struct_name: str = upper_first_letter(to_camel_case(entity_id))
query_struct_name = f'{struct_name}Query' bundle_struct_name = f'{struct_name}Bundle'
code.append( code.append(
f' if let Ok(e) = world.query_one_mut::<{query_struct_name}>(entity) {{') f' if let Ok(e) = ecs.query_one_mut::<{bundle_struct_name}>(entity) {{')
code.append( code.append(
f' e.update_metadata(world, entity, data)?;') f' e.update_metadata(ecs, entity, data)?;')
code.append(f' return Ok(());') code.append(f' return Ok(());')
code.append(' }') code.append(' }')
code.append(' Ok(())') code.append(' Ok(())')

View file

@ -44,8 +44,8 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst
field_type_rs = 'String' field_type_rs = 'String'
elif burger_type == 'chatcomponent': elif burger_type == 'chatcomponent':
field_type_rs = 'Component' field_type_rs = 'FormattedText'
uses.add('azalea_chat::Component') uses.add('azalea_chat::FormattedText')
elif burger_type == 'identifier': elif burger_type == 'identifier':
field_type_rs = 'ResourceLocation' field_type_rs = 'ResourceLocation'
uses.add('azalea_core::ResourceLocation') uses.add('azalea_core::ResourceLocation')