diff options
| author | mat <github@matdoes.dev> | 2021-12-08 22:09:24 +0000 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2021-12-08 22:09:24 +0000 |
| commit | 8bc1fd23991539eb8b01fc940b1219786ae5f32b (patch) | |
| tree | d544a4a5dca863c56ece143f201f07445e7cbf4a /minecraft-chat/src | |
| parent | c16d55ccddd741057bf532bd946b2854dc208c65 (diff) | |
| download | azalea-drasl-8bc1fd23991539eb8b01fc940b1219786ae5f32b.tar.xz | |
minecraft-chat compiles
Diffstat (limited to 'minecraft-chat/src')
| -rw-r--r-- | minecraft-chat/src/base_component.rs | 19 | ||||
| -rw-r--r-- | minecraft-chat/src/component.rs | 171 | ||||
| -rw-r--r-- | minecraft-chat/src/lib.rs | 3 | ||||
| -rw-r--r-- | minecraft-chat/src/mutable_component.rs | 7 | ||||
| -rw-r--r-- | minecraft-chat/src/style.rs | 107 | ||||
| -rw-r--r-- | minecraft-chat/src/text_component.rs | 13 | ||||
| -rw-r--r-- | minecraft-chat/src/translatable_component.rs | 21 |
7 files changed, 271 insertions, 70 deletions
diff --git a/minecraft-chat/src/base_component.rs b/minecraft-chat/src/base_component.rs index 2ed5646d..30e66173 100644 --- a/minecraft-chat/src/base_component.rs +++ b/minecraft-chat/src/base_component.rs @@ -1,6 +1,17 @@ -use crate::component::Component; +use crate::{component::Component, style::Style}; -pub trait BaseComponent { - const siblings: Vec<Component>; - // style: +#[derive(Clone)] +pub struct BaseComponent { + // implements mutablecomponent + pub siblings: Vec<Component>, + pub style: Style, +} + +impl BaseComponent { + pub fn new() -> Self { + Self { + siblings: Vec::new(), + style: Style::new(), + } + } } diff --git a/minecraft-chat/src/component.rs b/minecraft-chat/src/component.rs index 7955eeda..aa2c598e 100644 --- a/minecraft-chat/src/component.rs +++ b/minecraft-chat/src/component.rs @@ -1,38 +1,169 @@ use serde_json; use crate::{ - base_component::BaseComponent, text_component::TextComponent, - translatable_component::TranslatableComponent, + base_component::BaseComponent, + text_component::TextComponent, + translatable_component::{StringOrComponent, TranslatableComponent}, }; -pub struct Component {} +// pub struct Component { +// base: BaseComponent, +// } + +#[derive(Clone)] +pub enum Component { + TextComponent(TextComponent), + TranslatableComponent(TranslatableComponent), +} + +/// A chat component +impl Component { + pub fn new(json: &serde_json::Value) -> Result<Component, String> { + // we create a component that we might add siblings to + let mut component: Component; -// public static class Serializer -pub impl Component { - pub fn new(json: serde_json::Value) -> Self { - let component: BaseComponent; // if it's primitive, make it a text component if !json.is_array() && !json.is_object() { - return TextComponent::new(json.as_str().unwrap()); + component = Component::TextComponent(TextComponent::new(json.to_string())); } - // if it's an object, do things with { text } and stuff - if json.is_object() { - // if it has text, + else if json.is_object() { if json.get("text").is_some() { let text = json.get("text").unwrap().to_string(); + component = Component::TextComponent(TextComponent::new(text)); + } else if json.get("translate").is_some() { + let translate = json.get("translate").unwrap().to_string(); + if json.get("with").is_some() { + let with = json.get("with").unwrap().as_array().unwrap(); + let mut with_array = Vec::with_capacity(with.len()); + for i in 0..with.len() { + // 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 = Component::new(&with[i])?; + if let Component::TextComponent(textComponent) = c { + if textComponent.base.siblings.len() == 0 + && textComponent.base.style.is_empty() + { + with_array.push(StringOrComponent::String(textComponent.text)); + break; + } + } + with_array.push(StringOrComponent::Component(Component::new(&with[i])?)); + } + component = Component::TranslatableComponent(TranslatableComponent::new( + translate, with_array, + )); + } else { + // if it doesn't have a "with", just have the with_array be empty + component = Component::TranslatableComponent(TranslatableComponent::new( + translate, + Vec::new(), + )); + } + } else if json.get("score").is_some() { + // object = GsonHelper.getAsJsonObject(jsonObject, "score"); + let score_json = json.get("score").unwrap(); + // if (!object.has("name") || !object.has("objective")) throw new JsonParseException("A score component needs a least a name and an objective"); + // ScoreComponent scoreComponent = new ScoreComponent(GsonHelper.getAsString((JsonObject)object, "name"), GsonHelper.getAsString((JsonObject)object, "objective")); + if score_json.get("name").is_none() || score_json.get("objective").is_none() { + return Err( + "A score component needs at least a name and an objective".to_string() + ); + } + // TODO + return Err("score text components aren't yet supported".to_string()); + // component = ScoreComponent + } else if json.get("selector").is_some() { + // } else if (jsonObject.has("selector")) { + // object = this.parseSeparator(type, jsonDeserializationContext, jsonObject); + // SelectorComponent selectorComponent = new SelectorComponent(GsonHelper.getAsString(jsonObject, "selector"), (Optional<Component>)object); + + return Err("selector text components aren't yet supported".to_string()); + // } else if (jsonObject.has("keybind")) { + // KeybindComponent keybindComponent = new KeybindComponent(GsonHelper.getAsString(jsonObject, "keybind")); + } else if json.get("keybind").is_some() { + return Err("keybind text components aren't yet supported".to_string()); + } else { + // } else { + // if (!jsonObject.has("nbt")) throw new JsonParseException("Don't know how to turn " + jsonElement + " into a Component"); + if json.get("nbt").is_none() { + return Err(format!("Don't know how to turn {} into a Component", json)); + } + // object = GsonHelper.getAsString(jsonObject, "nbt"); + let nbt = json.get("nbt").unwrap().to_string(); + // Optional<Component> optional = this.parseSeparator(type, jsonDeserializationContext, jsonObject); + let separator = Component::parse_separator(json)?; + + let interpret = match json.get("interpret") { + Some(v) => v.as_bool().ok_or(Some(false)).unwrap(), + None => false, + }; + // boolean bl = GsonHelper.getAsBoolean(jsonObject, "interpret", false); + // if (jsonObject.has("block")) { + if json.get("block").is_some() {} + return Err("nbt text components aren't yet supported".to_string()); + // NbtComponent.BlockNbtComponent blockNbtComponent = new NbtComponent.BlockNbtComponent((String)object, bl, GsonHelper.getAsString(jsonObject, "block"), optional); + // } else if (jsonObject.has("entity")) { + // NbtComponent.EntityNbtComponent entityNbtComponent = new NbtComponent.EntityNbtComponent((String)object, bl, GsonHelper.getAsString(jsonObject, "entity"), optional); + // } else { + // if (!jsonObject.has("storage")) throw new JsonParseException("Don't know how to turn " + jsonElement + " into a Component"); + // NbtComponent.StorageNbtComponent storageNbtComponent = new NbtComponent.StorageNbtComponent((String)object, bl, new ResourceLocation(GsonHelper.getAsString(jsonObject, "storage")), optional); + // } + // } } - } else if json.get("translate").is_some() { - let translate = json.get("translate").unwrap().to_string(); - } else if json.get("with").is_some() { - let with = json.get("with").unwrap().as_array().unwrap(); - let mut with_array = Vec::with_capacity(with.len()); - for i in 0..with.len() { - with_array.push(Component::new(with[i].clone()).deserialize(with[i].clone())); + // if (jsonObject.has("extra")) { + // object = GsonHelper.getAsJsonArray(jsonObject, "extra"); + // if (object.size() <= 0) throw new JsonParseException("Unexpected empty array of components"); + // for (int i = 0; i < object.size(); ++i) { + // var5_17.append(this.deserialize(object.get(i), type, jsonDeserializationContext)); + // } + // } + // var5_17.setStyle((Style)jsonDeserializationContext.deserialize(jsonElement, Style.class)); + // return var5_17; + // } + if json.get("extra").is_some() { + let extra = match json.get("extra").unwrap().as_array() { + Some(r) => r, + None => return Err("Extra isn't an array".to_string()), + }; + if extra.len() == 0 { + return Err("Unexpected empty array of components".to_string()); + } + for i in 0..extra.len() { + component.append(Component::new(extra.get(i).unwrap())?); + } } - let mut translatable_component = TranslatableComponent::new(translate, with_array); + + return Ok(component); + } + // ok so it's not an object, if it's an array deserialize every item + if !json.is_array() { + return Err(format!("Don't know how to turn {} into a Component", json)); } + let json_array = json.as_array().unwrap(); + // the first item in the array is the one that we're gonna return, the others are siblings + let mut component = Component::new(&json_array[0])?; + for i in 1..json_array.len() { + component.append(Component::new(json_array.get(i).unwrap())?); + } + Ok(component) + } - Component {} + /// Add a component as a sibling of this one + fn append(&mut self, sibling: Component) { + match self { + Self::TextComponent(c) => c.base.siblings.push(sibling), + Self::TranslatableComponent(c) => c.base.siblings.push(sibling), + } } + + /// Get the "separator" component from the json + fn parse_separator(json: &serde_json::Value) -> Result<Option<Component>, String> { + if json.get("separator").is_some() { + return Ok(Some(Component::new(json.get("separator").unwrap())?)); + } + Ok(None) + } + + fn to_ansi(&self) {} } diff --git a/minecraft-chat/src/lib.rs b/minecraft-chat/src/lib.rs index cc887f66..73485a3e 100644 --- a/minecraft-chat/src/lib.rs +++ b/minecraft-chat/src/lib.rs @@ -1,8 +1,9 @@ -//! Things for working with Minecraft chat messages. +//! Things for working with Minecraft chat messages, inspired by the Minecraft source code and prismarine-chat. pub mod base_component; pub mod component; pub mod mutable_component; +pub mod style; pub mod text_component; pub mod translatable_component; diff --git a/minecraft-chat/src/mutable_component.rs b/minecraft-chat/src/mutable_component.rs index 4fd3124d..d294e3b3 100644 --- a/minecraft-chat/src/mutable_component.rs +++ b/minecraft-chat/src/mutable_component.rs @@ -1 +1,6 @@ -pub struct MutableComponent {} +use crate::{base_component::BaseComponent, component::Component}; + +pub trait MutableComponent { + /// Add a component as a sibling of this one + fn append(&self, component: Component); +} diff --git a/minecraft-chat/src/style.rs b/minecraft-chat/src/style.rs index 63422305..3e72ac82 100644 --- a/minecraft-chat/src/style.rs +++ b/minecraft-chat/src/style.rs @@ -1,3 +1,4 @@ +#[derive(Clone)] struct TextColor { value: u32, name: Option<String>, @@ -5,18 +6,24 @@ struct TextColor { const PREFIX_CODE: char = '\u{00a7}'; -struct ChatFormatting { - name: String, +struct ChatFormatting<'a> { + name: &'a str, code: char, is_format: bool, id: i32, color: Option<u32>, } -impl ChatFormatting { - fn new(name: &str, code: char, is_format: bool, id: i32, color: Option<u32>) -> ChatFormatting { +impl<'a> ChatFormatting<'a> { + const fn new( + name: &str, + code: char, + is_format: bool, + id: i32, + color: Option<u32>, + ) -> ChatFormatting { ChatFormatting { - name: name.to_string(), + name: name, code, is_format, id, @@ -25,30 +32,32 @@ impl ChatFormatting { } } -enum ChatFormatting { - BLACK = ChatFormatting::new("BLACK", '0', false, 0, Some(0)), - DARK_BLUE = ChatFormatting::new("DARK_BLUE", '1', false, 1, Some(170)), - DARK_GREEN = ChatFormatting::new("DARK_GREEN", '2', false, 2, Some(43520)), - DARK_AQUA = ChatFormatting::new("DARK_AQUA", '3', false, 3, Some(43690)), - DARK_RED = ChatFormatting::new("DARK_RED", '4', false, 4, Some(1114112)), - DARK_PURPLE = ChatFormatting::new("DARK_PURPLE", '5', false, 5, Some(11141290)), - GOLD = ChatFormatting::new("GOLD", '6', false, 6, Some(16755200)), - GRAY = ChatFormatting::new("GRAY", '7', false, 7, Some(11184810)), - DARK_GRAY = ChatFormatting::new("DARK_GRAY", '8', false, 8, Some(5592405)), - BLUE = ChatFormatting::new("BLUE", '9', false, 9, Some(5592575)), - GREEN = ChatFormatting::new("GREEN", 'a', false, 10, Some(5635925)), - AQUA = ChatFormatting::new("AQUA", 'b', false, 11, Some(5636095)), - RED = ChatFormatting::new("RED", 'c', false, 12, Some(16733525)), - LIGHT_PURPLE = ChatFormatting::new("LIGHT_PURPLE", 'd', false, 13, Some(16733695)), - YELLOW = ChatFormatting::new("YELLOW", 'e', false, 14, Some(16777045)), - WHITE = ChatFormatting::new("WHITE", 'f', false, 15, Some(16777215)), - OBFUSCATED = ChatFormatting::new("OBFUSCATED", 'k', true, -1, None), - BOLD = ChatFormatting::new("BOLD", 'l', true, -1, None), - STRIKETHROUGH = ChatFormatting::new("STRIKETHROUGH", 'm', true, -1, None), - UNDERLINE = ChatFormatting::new("UNDERLINE", 'n', true, -1, None), - ITALIC = ChatFormatting::new("ITALIC", 'o', true, -1, None), - RESET = ChatFormatting::new("RESET", 'r', -1, -1, None), -} +// pub const BLACK: ChatFormatting = ChatFormatting::new("BLACK", '0', false, 0, Some(0)); +// pub const DARK_BLUE: ChatFormatting = ChatFormatting::new("DARK_BLUE", '1', false, 1, Some(170)); +// pub const DARK_GREEN: ChatFormatting = +// ChatFormatting::new("DARK_GREEN", '2', false, 2, Some(43520)); +// pub const DARK_AQUA: ChatFormatting = ChatFormatting::new("DARK_AQUA", '3', false, 3, Some(43690)); +// pub const DARK_RED: ChatFormatting = ChatFormatting::new("DARK_RED", '4', false, 4, Some(1114112)); +// pub const DARK_PURPLE: ChatFormatting = +// ChatFormatting::new("DARK_PURPLE", '5', false, 5, Some(11141290)); +// pub const GOLD: ChatFormatting = ChatFormatting::new("GOLD", '6', false, 6, Some(16755200)); +// pub const GRAY: ChatFormatting = ChatFormatting::new("GRAY", '7', false, 7, Some(11184810)); +// pub const DARK_GRAY: ChatFormatting = +// ChatFormatting::new("DARK_GRAY", '8', false, 8, Some(5592405)); +// pub const BLUE: ChatFormatting = ChatFormatting::new("BLUE", '9', false, 9, Some(5592575)); +// pub const GREEN: ChatFormatting = ChatFormatting::new("GREEN", 'a', false, 10, Some(5635925)); +// pub const AQUA: ChatFormatting = ChatFormatting::new("AQUA", 'b', false, 11, Some(5636095)); +// pub const RED: ChatFormatting = ChatFormatting::new("RED", 'c', false, 12, Some(16733525)); +// pub const LIGHT_PURPLE: ChatFormatting = +// ChatFormatting::new("LIGHT_PURPLE", 'd', false, 13, Some(16733695)); +// pub const YELLOW: ChatFormatting = ChatFormatting::new("YELLOW", 'e', false, 14, Some(16777045)); +// pub const WHITE: ChatFormatting = ChatFormatting::new("WHITE", 'f', false, 15, Some(16777215)); +// pub const OBFUSCATED: ChatFormatting = ChatFormatting::new("OBFUSCATED", 'k', true, -1, None); +// pub const STRIKETHROUGH: ChatFormatting = ChatFormatting::new("STRIKETHROUGH", 'm', true, -1, None); +// pub const BOLD: ChatFormatting = ChatFormatting::new("BOLD", 'l', true, -1, None); +// pub const UNDERLINE: ChatFormatting = ChatFormatting::new("UNDERLINE", 'n', true, -1, None); +// pub const ITALIC: ChatFormatting = ChatFormatting::new("ITALIC", 'o', true, -1, None); +// pub const RESET: ChatFormatting = ChatFormatting::new("RESET", 'r', true, -1, None); impl TextColor { fn new(value: u32, name: Option<String>) -> Self { @@ -68,7 +77,8 @@ impl TextColor { } } -struct Style { +#[derive(Clone)] +pub struct Style { // @Nullable // final TextColor color; // @Nullable @@ -89,10 +99,35 @@ struct Style { // final String insertion; // @Nullable // final ResourceLocation font; - color: TextColor, - bold: bool, - italic: bool, - underlined: bool, - strikethrough: bool, - obfuscated: bool, + + // these are options instead of just bools because None is different than false in this case + color: Option<TextColor>, + bold: Option<bool>, + italic: Option<bool>, + underlined: Option<bool>, + strikethrough: Option<bool>, + obfuscated: Option<bool>, +} + +impl Style { + pub fn new() -> Style { + Style { + color: None, + bold: Some(false), + italic: Some(false), + underlined: Some(false), + strikethrough: Some(false), + obfuscated: Some(false), + } + } + + /// Check if a style has no attributes set + pub fn is_empty(&self) -> bool { + self.color.is_none() + && self.bold.is_none() + && self.italic.is_none() + && self.underlined.is_none() + && self.strikethrough.is_none() + && self.obfuscated.is_none() + } } diff --git a/minecraft-chat/src/text_component.rs b/minecraft-chat/src/text_component.rs index 381befbb..a89264b2 100644 --- a/minecraft-chat/src/text_component.rs +++ b/minecraft-chat/src/text_component.rs @@ -1,13 +1,16 @@ -use crate::base_component::BaseComponent; +use crate::{base_component::BaseComponent, mutable_component::MutableComponent}; +#[derive(Clone)] pub struct TextComponent { + pub base: BaseComponent, pub text: String, } -impl TextComponent { - pub fn new(text: &str) -> TextComponent { - TextComponent { - text: text.to_string(), +impl<'a> TextComponent { + pub fn new(text: String) -> Self { + Self { + text: text, + base: BaseComponent::new(), } } diff --git a/minecraft-chat/src/translatable_component.rs b/minecraft-chat/src/translatable_component.rs index e9099e55..1aecb7a7 100644 --- a/minecraft-chat/src/translatable_component.rs +++ b/minecraft-chat/src/translatable_component.rs @@ -1,10 +1,25 @@ +use crate::{base_component::BaseComponent, component::Component}; + +#[derive(Clone)] +pub enum StringOrComponent { + String(String), + Component(Component), +} + +// extends BaseComponent implements ContextAwareComponent +#[derive(Clone)] pub struct TranslatableComponent { + pub base: BaseComponent, pub key: String, - pub args: Vec<String>, + pub args: Vec<StringOrComponent>, } impl TranslatableComponent { - pub fn new(key: String, args: Vec<String>) -> Self { - Self { key, args } + pub fn new(key: String, args: Vec<StringOrComponent>) -> Self { + Self { + base: BaseComponent::new(), + key, + args, + } } } |
