mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
minecraft-chat compiles
This commit is contained in:
parent
c16d55ccdd
commit
8bc1fd2399
7 changed files with 274 additions and 73 deletions
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
} 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()));
|
||||
}
|
||||
let mut translatable_component = TranslatableComponent::new(translate, with_array);
|
||||
}
|
||||
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);
|
||||
|
||||
Component {}
|
||||
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);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
// 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())?);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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) {}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue