aboutsummaryrefslogtreecommitdiff
path: root/minecraft-chat/src
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2021-12-08 22:09:24 +0000
committermat <github@matdoes.dev>2021-12-08 22:09:24 +0000
commit8bc1fd23991539eb8b01fc940b1219786ae5f32b (patch)
treed544a4a5dca863c56ece143f201f07445e7cbf4a /minecraft-chat/src
parentc16d55ccddd741057bf532bd946b2854dc208c65 (diff)
downloadazalea-drasl-8bc1fd23991539eb8b01fc940b1219786ae5f32b.tar.xz
minecraft-chat compiles
Diffstat (limited to 'minecraft-chat/src')
-rw-r--r--minecraft-chat/src/base_component.rs19
-rw-r--r--minecraft-chat/src/component.rs171
-rw-r--r--minecraft-chat/src/lib.rs3
-rw-r--r--minecraft-chat/src/mutable_component.rs7
-rw-r--r--minecraft-chat/src/style.rs107
-rw-r--r--minecraft-chat/src/text_component.rs13
-rw-r--r--minecraft-chat/src/translatable_component.rs21
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,
+ }
}
}