From 1230a082b6ac4bb2f43e8a51037e915f0576a0db Mon Sep 17 00:00:00 2001 From: MoonLake Date: Thu, 15 Jun 2017 20:09:40 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=20=E8=81=8A=E5=A4=A9=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BA=93=E5=9F=BA=E7=A1=80=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 12 + .../moonlake/chat/ChatClickEvent.java | 78 +++++ .../minecraft/moonlake/chat/ChatColor.java | 70 +++++ .../moonlake/chat/ChatComponent.java | 42 +++ .../moonlake/chat/ChatComponentBase.java | 118 ++++++++ .../moonlake/chat/ChatComponentFancy.java | 126 ++++++++ .../moonlake/chat/ChatComponentKeybind.java | 68 +++++ .../moonlake/chat/ChatComponentScore.java | 90 ++++++ .../moonlake/chat/ChatComponentSelector.java | 70 +++++ .../moonlake/chat/ChatComponentText.java | 68 +++++ .../chat/ChatComponentTranslation.java | 84 ++++++ .../moonlake/chat/ChatHoverEvent.java | 77 +++++ .../moonlake/chat/ChatSerializer.java | 281 ++++++++++++++++++ .../minecraft/moonlake/chat/ChatStyle.java | 278 +++++++++++++++++ .../moonlake/chat/test/MoonLakeChatTest.java | 84 ++++++ 15 files changed, 1546 insertions(+) create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatClickEvent.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatColor.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponent.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentBase.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentFancy.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentKeybind.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentScore.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentSelector.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentText.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatComponentTranslation.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatHoverEvent.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatSerializer.java create mode 100644 src/main/java/com/minecraft/moonlake/chat/ChatStyle.java create mode 100644 src/test/java/com/minecraft/moonlake/chat/test/MoonLakeChatTest.java diff --git a/pom.xml b/pom.xml index 696be69..a19e790 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,18 @@ 4.12 test + + com.minecraft.moonlake + Validate + 1.0 + compile + + + com.google.guava + guava + 21.0 + provided + com.google.code.gson Gson diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatClickEvent.java b/src/main/java/com/minecraft/moonlake/chat/ChatClickEvent.java new file mode 100644 index 0000000..805308a --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatClickEvent.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatClickEvent { + + private final Action action; + private final String value; + + public ChatClickEvent(Action action, String value) { + this.action = action; + this.value = value; + } + + public Action getAction() { + return action; + } + + public String getValue() { + return value; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatClickEvent) { + ChatClickEvent other = (ChatClickEvent) obj; + return action == other.action && value != null ? value.equals(other.value) : other.value == null; + } + return false; + } + + @Override + public int hashCode() { + int result = action != null ? action.hashCode() : 0; + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatClickEvent{" + + "action=" + action + + ", value='" + value + '\'' + + '}'; + } + + public enum Action { + + OPEN_URL, + OPEN_FILE, + RUN_COMMAND, + SUGGEST_COMMAND, + CHANGE_PAGE, + ; + + public static Action fromName(String name) { + return Action.valueOf(name.toUpperCase()); + } + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatColor.java b/src/main/java/com/minecraft/moonlake/chat/ChatColor.java new file mode 100644 index 0000000..f4f36fa --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatColor.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public enum ChatColor { + + BLACK('0'), + DARK_BLUE('1'), + DARK_GREEN('2'), + DARK_AQUA('3'), + DARK_RED('4'), + DARK_PURPLE('5'), + GOLD('6'), + GRAY('7'), + DARK_GRAY('8'), + BLUE('9'), + GREEN('a'), + AQUA('b'), + RED('c'), + LIGHT_PURPLE('d'), + YELLOW('e'), + WHITE('f'), + OBFUSCATED('k', true), + BOLD('l', true), + STRIKETHROUGH('m', true), + UNDERLINE('n', true), + ITALIC('o', true), + RESET('r'), + ; + + private final char code; + private final boolean format; + + ChatColor(char code) { + this(code, false); + } + + ChatColor(char code, boolean format) { + this.code = code; + this.format = format; + } + + public char getCode() { + return code; + } + + public boolean isFormat() { + return format; + } + + public static ChatColor fromName(String name) { + return ChatColor.valueOf(name.toUpperCase()); + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponent.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponent.java new file mode 100644 index 0000000..e35e16a --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponent.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +import java.util.List; + +public interface ChatComponent { + + ChatStyle getStyle(); + + ChatComponent setStyle(ChatStyle style); + + List getExtras(); + + int getExtraSize(); + + ChatComponent append(String text); + + ChatComponent append(ChatComponent extra); + + String toJson(); + + String toRaw(); + + String toRaw(boolean color); +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentBase.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentBase.java new file mode 100644 index 0000000..1af9aab --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentBase.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +import com.minecraft.moonlake.validate.Validate; + +import java.util.ArrayList; +import java.util.List; + +public abstract class ChatComponentBase implements ChatComponent { + + private ChatStyle style; + private List extras; + + ChatComponentBase() { + this.extras = new ArrayList<>(); + } + + @Override + public ChatComponent setStyle(ChatStyle style) { + Validate.notNull(style, "The chat style object is null."); + this.style = style; + for(ChatComponent component : extras) + component.getStyle().setParent(getStyle()); + return this; + } + + @Override + public ChatStyle getStyle() { + if(style == null) { + this.style = new ChatStyle(); + for(ChatComponent component : extras) + component.getStyle().setParent(style); + } + return style; + } + + @Override + public final List getExtras() { + return extras; + } + + @Override + public final int getExtraSize() { + return extras.size(); + } + + @Override + public ChatComponent append(String text) { + Validate.notNull(text, "The text object is null."); + return append(new ChatComponentText(text)); + } + + @Override + public ChatComponent append(ChatComponent extra) { + Validate.notNull(extra, "The extra component object is null."); + extra.getStyle().setParent(getStyle()); + extras.add(extra); + return this; + } + + @Override + public String toJson() { + return ChatSerializer.toJson(this); + } + + @Override + public String toRaw() { + return ChatSerializer.toRaw(this); + } + + @Override + public String toRaw(boolean color) { + return ChatSerializer.toRaw(this, color); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatComponentBase) { + ChatComponentBase other = (ChatComponentBase) obj; + return getStyle().equals(other.getStyle()) && extras.equals(other.extras); + } + return false; + } + + @Override + public int hashCode() { + int result = style != null ? style.hashCode() : 0; + result = 31 * result + (extras != null ? extras.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatComponentBase{" + + "style=" + style + + ", extras=" + extras + + '}'; + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentFancy.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentFancy.java new file mode 100644 index 0000000..30f5a38 --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentFancy.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +import com.minecraft.moonlake.validate.Validate; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ChatComponentFancy { + + private List extras; + + public ChatComponentFancy(String text) { + this.extras = new ArrayList<>(); + this.then(text); + } + + public ChatComponentFancy then(String text) { + Validate.notNull(text, "The text object is null."); + return then(new ChatComponentText(text)); + } + + public ChatComponentFancy then(ChatComponent component) { + Validate.notNull(component, "The component object is null."); + extras.add(component); + return this; + } + + public ChatComponentFancy color(ChatColor color) { + Validate.notNull(color, "The chat color object is null."); + getLast().getStyle().setColor(color); + return this; + } + + public ChatComponentFancy file(String path) { + Validate.notNull(path, "The path object is null."); + getLast().getStyle().setClickEvent(new ChatClickEvent(ChatClickEvent.Action.OPEN_FILE, path)); + return this; + } + + public ChatComponentFancy link(String url) { + Validate.notNull(url, "The url object is null."); + getLast().getStyle().setClickEvent(new ChatClickEvent(ChatClickEvent.Action.OPEN_URL, url)); + return this; + } + + public ChatComponentFancy suggest(String command) { + Validate.notNull(command, "The command object is null."); + getLast().getStyle().setClickEvent(new ChatClickEvent(ChatClickEvent.Action.SUGGEST_COMMAND, command)); + return this; + } + + public ChatComponentFancy command(String command) { + Validate.notNull(command, "The command object is null."); + getLast().getStyle().setClickEvent(new ChatClickEvent(ChatClickEvent.Action.RUN_COMMAND, command)); + return this; + } + + public ChatComponentFancy insert(String insertion) { + Validate.notNull(insertion, "The insertion object is null."); + getLast().getStyle().setInsertion(insertion); + return this; + } + + public ChatComponentFancy tooltipText(String text) { + Validate.notNull(text, "The text object is null."); + getLast().getStyle().setHoverEvent(new ChatHoverEvent(ChatHoverEvent.Action.SHOW_TEXT, new ChatComponentText(text))); + return this; + } + + public ChatComponentFancy tooltipTexts(String... texts) { + Validate.notNull(texts, "The texts object is null."); + StringBuilder builder = new StringBuilder(); + for(int i = 0; i < texts.length; i++) { + builder.append(texts[i]); + if(i != texts.length - 1) + builder.append('\n'); + } + return tooltipText(builder.toString()); + } + + public ChatComponentFancy tooltipTexts(Collection collection) { + Validate.notNull(collection, "The collection object is null."); + return tooltipTexts(collection.toArray(new String[collection.size()])); + } + + public ChatComponentFancy tooltipItem(String item) { + Validate.notNull(item, "The item object is null."); + getLast().getStyle().setHoverEvent(new ChatHoverEvent(ChatHoverEvent.Action.SHOW_ITEM, new ChatComponentText(item))); + return this; + } + + public ChatComponentFancy join(ChatComponentFancy componentFancy) { + Validate.notNull(componentFancy, "The component fancy object is null."); + extras.addAll(componentFancy.extras); + return this; + } + + public ChatComponent build() { + ChatComponent component = new ChatComponentText(""); + component.getExtras().addAll(extras); + return component; + } + + protected ChatComponent getLast() { + return extras.get(extras.size() - 1); + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentKeybind.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentKeybind.java new file mode 100644 index 0000000..dcda5d0 --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentKeybind.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatComponentKeybind extends ChatComponentBase { + + private String keybind; + + public ChatComponentKeybind() { + } + + public ChatComponentKeybind(String keybind) { + this.keybind = keybind; + } + + public String getKeybind() { + return keybind; + } + + public ChatComponentKeybind setKeybind(String keyBind) { + this.keybind = keyBind; + return this; + } + + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatComponentKeybind) { + ChatComponentKeybind other = (ChatComponentKeybind) obj; + return super.equals(obj) && keybind != null ? keybind.equals(other.keybind) : other.keybind == null; + } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (keybind != null ? keybind.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatComponentText{" + + "keybind='" + keybind + '\'' + + ", style=" + getStyle() + + ", extras=" + getExtras() + + '}'; + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentScore.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentScore.java new file mode 100644 index 0000000..8fc597a --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentScore.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatComponentScore extends ChatComponentBase { + + private String name; + private String objective; + private String value; + + public ChatComponentScore() { + } + + public ChatComponentScore(String name, String objective) { + this.name = name; + this.objective = objective; + } + + public String getName() { + return name; + } + + public ChatComponentScore setName(String name) { + this.name = name; + return this; + } + + public String getObjective() { + return objective; + } + + public ChatComponentScore setObjective(String objective) { + this.objective = objective; + return this; + } + + public String getValue() { + return value; + } + + public ChatComponentScore setValue(String value) { + this.value = value; + return this; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatComponentScore) { + ChatComponentScore other = (ChatComponentScore) obj; + return super.equals(obj) && name != null ? name.equals(other.name) : other.name == null && objective != null ? objective.equals(other.objective) : other.objective == null; + } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (objective != null ? objective.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatComponentScore{" + + "name='" + name + '\'' + + ", objective='" + objective + '\'' + + ", style=" + getStyle() + + ", extras=" + getExtras() + + '}'; + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentSelector.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentSelector.java new file mode 100644 index 0000000..646d07e --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentSelector.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatComponentSelector extends ChatComponentBase { + + private String selector; + + public ChatComponentSelector() { + } + + public ChatComponentSelector(String selector) { + this.selector = selector; + } + + public String getSelector() { + return selector; + } + + public ChatComponentSelector setSelector(String selector) { + if(selector.startsWith("@")) + this.selector = selector; + else + this.selector = "@" + selector; + return this; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatComponentSelector) { + ChatComponentSelector other = (ChatComponentSelector) obj; + return super.equals(obj) && selector != null ? selector.equals(other.selector) : other.selector == null; + } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (selector != null ? selector.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatComponentScore{" + + "selector='" + selector + '\'' + + ", style=" + getStyle() + + ", extras=" + getExtras() + + '}'; + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentText.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentText.java new file mode 100644 index 0000000..0e5ce3f --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentText.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatComponentText extends ChatComponentBase { + + private String text; + + public ChatComponentText(String text) { + this.text = text; + } + + public ChatComponentText(ChatComponentText text) { + this.text = text.getText(); + } + + public String getText() { + return text; + } + + public ChatComponentText setText(String text) { + this.text = text; + return this; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatComponentText) { + ChatComponentText other = (ChatComponentText) obj; + return super.equals(obj) && text != null ? text.equals(other.text) : other.text == null; + } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (text != null ? text.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatComponentText{" + + "text='" + text + '\'' + + ", style=" + getStyle() + + ", extras=" + getExtras() + + '}'; + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatComponentTranslation.java b/src/main/java/com/minecraft/moonlake/chat/ChatComponentTranslation.java new file mode 100644 index 0000000..383186d --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatComponentTranslation.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ChatComponentTranslation extends ChatComponentBase { + + private String key; + private List withs; + + public ChatComponentTranslation() { + } + + public ChatComponentTranslation(String key) { + this.key = key; + this.withs = new ArrayList<>(); + } + + public ChatComponentTranslation addWiths(Object... with) { + withs.addAll(Arrays.asList(with)); + return this; + } + + public String getKey() { + return key; + } + + public ChatComponentTranslation setKey(String key) { + this.key = key; + return this; + } + + public List getWiths() { + return withs; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatComponentTranslation) { + ChatComponentTranslation other = (ChatComponentTranslation) obj; + return super.equals(obj) && key != null ? key.equals(other.key) : other.key == null && withs.equals(other.withs); + } + return false; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (key != null ? key.hashCode() : 0); + result = 31 * result + (withs != null ? withs.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatComponentTranslation{" + + "key='" + key + '\'' + + ", withs=" + withs + + ", style=" + getStyle() + + ", extras=" + getExtras() + + '}'; + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatHoverEvent.java b/src/main/java/com/minecraft/moonlake/chat/ChatHoverEvent.java new file mode 100644 index 0000000..6345826 --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatHoverEvent.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatHoverEvent { + + private final Action action; + private final ChatComponent value; + + public ChatHoverEvent(Action action, ChatComponent value) { + this.action = action; + this.value = value; + } + + public Action getAction() { + return action; + } + + public ChatComponent getValue() { + return value; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatHoverEvent) { + ChatHoverEvent other = (ChatHoverEvent) obj; + return action == other.action && value != null ? value.equals(other.value) : other.value == null; + } + return false; + } + + @Override + public int hashCode() { + int result = action != null ? action.hashCode() : 0; + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatHoverEvent{" + + "action=" + action + + ", value='" + value + '\'' + + '}'; + } + + public enum Action { + + SHOW_TEXT, + SHOW_ACHIEVEMENT, + SHOW_ITEM, + SHOW_ENTITY, + ; + + public static Action fromName(String name) { + return Action.valueOf(name.toUpperCase()); + } + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatSerializer.java b/src/main/java/com/minecraft/moonlake/chat/ChatSerializer.java new file mode 100644 index 0000000..f1df214 --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatSerializer.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +import com.google.gson.*; +import com.google.gson.stream.JsonReader; +import com.minecraft.moonlake.validate.Validate; + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.util.Map; + +public final class ChatSerializer { + + private final static Gson GSON; + + static { + GSON = new GsonBuilder() + .registerTypeHierarchyAdapter(ChatComponent.class, new ChatComponentSerializer()) + .registerTypeHierarchyAdapter(ChatStyle.class, new ChatStyleSerializer()) + .create(); + } + + private ChatSerializer() { + } + + public static String toRaw(ChatComponent chatComponent) { + return toRaw(chatComponent, true); + } + + public static String toRaw(ChatComponent chatComponent, boolean color) { + StringBuilder builder = new StringBuilder(); + toRaw0(chatComponent, color, builder); + return builder.toString(); + } + + private static void toRaw0(ChatComponent chatComponent, boolean color, StringBuilder builder) { + if(chatComponent instanceof ChatComponentText) { + if(color && chatComponent.getStyle().getColor() != null) + builder.append('\u00A7').append(chatComponent.getStyle().getColor().getCode()); + builder.append(((ChatComponentText) chatComponent).getText()); + } + for(ChatComponent extra : chatComponent.getExtras()) + toRaw0(extra, color, builder); + } + + public static String toJson(ChatComponent chatComponent) { + Validate.notNull(chatComponent, "The chat component object is null."); + return GSON.toJson(chatComponent); + } + + public static ChatComponent fromJson(String json) { + Validate.notNull(json, "The json object is null."); + try { + JsonReader jsonReader = new JsonReader(new StringReader(json)); + jsonReader.setLenient(false); + return GSON.getAdapter(ChatComponent.class).read(jsonReader); + } catch (IOException e) { + throw new JsonParseException(e); + } + } + + public static ChatComponent fromJsonLenient(String json) { + Validate.notNull(json, "The json object is null."); + try { + JsonReader jsonReader = new JsonReader(new StringReader(json)); + jsonReader.setLenient(true); + return GSON.getAdapter(ChatComponent.class).read(jsonReader); + } catch (IOException e) { + throw new JsonParseException(e); + } + } + + private final static class ChatStyleSerializer implements JsonDeserializer, JsonSerializer { + @Override + public ChatStyle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if(json.isJsonObject()) { + JsonObject jsonObject = json.getAsJsonObject(); + if(jsonObject == null) + return null; + ChatStyle style = new ChatStyle(); + if(jsonObject.has("color")) + style.color = ChatColor.fromName(jsonObject.get("color").getAsString()); + if(jsonObject.has("bold")) + style.bold = jsonObject.get("bold").getAsBoolean(); + if(jsonObject.has("italic")) + style.italic = jsonObject.get("italic").getAsBoolean(); + if(jsonObject.has("underlined")) + style.underlined = jsonObject.get("underlined").getAsBoolean(); + if(jsonObject.has("strikethrough")) + style.strikethrough = jsonObject.get("strikethrough").getAsBoolean(); + if(jsonObject.has("obfuscated")) + style.obfuscated = jsonObject.get("obfuscated").getAsBoolean(); + if(jsonObject.has("insertion")) + style.insertion = jsonObject.get("insertion").getAsString(); + if(jsonObject.has("clickEvent")) { + JsonObject jsonObjectClickEvent = jsonObject.getAsJsonObject("clickEvent"); + if(jsonObjectClickEvent != null) { + ChatClickEvent.Action action = ChatClickEvent.Action.fromName(jsonObjectClickEvent.get("action").getAsString()); + String value = jsonObjectClickEvent.get("value").getAsString(); + style.clickEvent = new ChatClickEvent(action, value); + } + } + if(jsonObject.has("hoverEvent")) { + JsonObject jsonObjectHoverEvent = jsonObject.getAsJsonObject("hoverEvent"); + if(jsonObjectHoverEvent != null) { + ChatHoverEvent.Action action = ChatHoverEvent.Action.fromName(jsonObjectHoverEvent.get("action").getAsString()); + ChatComponent value = context.deserialize(jsonObjectHoverEvent.get("value"), ChatComponent.class); + style.hoverEvent = new ChatHoverEvent(action, value); + } + } + return style; + } + return null; + } + + @Override + public JsonElement serialize(ChatStyle src, Type typeOfSrc, JsonSerializationContext context) { + if(src.isEmpty()) + return null; + JsonObject jsonObject = new JsonObject(); + if(src.color != null) + jsonObject.addProperty("color", src.color.toString().toLowerCase()); + if(src.bold != null) + jsonObject.addProperty("bold", src.bold); + if(src.italic != null) + jsonObject.addProperty("italic", src.italic); + if(src.underlined != null) + jsonObject.addProperty("underlined", src.underlined); + if(src.strikethrough != null) + jsonObject.addProperty("strikethrough", src.strikethrough); + if(src.obfuscated != null) + jsonObject.addProperty("bold", src.obfuscated); + if(src.insertion != null) + jsonObject.add("insertion", context.serialize(src.insertion)); + if(src.clickEvent != null) { + JsonObject jsonObjectClickEvent = new JsonObject(); + jsonObjectClickEvent.addProperty("action", src.clickEvent.getAction().toString().toLowerCase()); + jsonObjectClickEvent.addProperty("value", src.clickEvent.getValue()); + jsonObject.add("clickEvent", jsonObjectClickEvent); + } + if(src.hoverEvent != null) { + JsonObject jsonObjectHoverEvent = new JsonObject(); + jsonObjectHoverEvent.addProperty("action", src.hoverEvent.getAction().toString().toLowerCase()); + jsonObjectHoverEvent.add("value", context.serialize(src.hoverEvent.getValue())); + jsonObject.add("hoverEvent", jsonObjectHoverEvent); + } + return jsonObject; + } + } + + private final static class ChatComponentSerializer implements JsonDeserializer, JsonSerializer { + @Override + public ChatComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if(json.isJsonPrimitive()) + return new ChatComponentText(json.getAsString()); + if(!json.isJsonObject() && json.isJsonArray()) { + ChatComponent component = null; + JsonArray array = json.getAsJsonArray(); + for(JsonElement element : array) { + ChatComponent component1 = deserialize(element, element.getClass(), context); + if(component == null) component = component1; + else component.append(component1); + } + return component; + } + ChatComponent component = null; + JsonObject jsonObject = json.getAsJsonObject(); + if(jsonObject.has("text")) { + component = new ChatComponentText(jsonObject.get("text").getAsString()); + } else if(jsonObject.has("translate")) { + String translate = jsonObject.get("translate").getAsString(); + if(jsonObject.has("with")) { + JsonArray jsonArray = jsonObject.getAsJsonArray("with"); + Object[] withs = new Object[jsonArray.size()]; + for(int i = 0; i < withs.length; i++) { + withs[i] = deserialize(jsonArray.get(i), typeOfT, context); + if(withs[i] instanceof ChatComponentText) { + ChatComponentText componentText = (ChatComponentText) withs[i]; + if(componentText.getStyle().isEmpty() && componentText.getExtras().isEmpty()) + withs[i] = componentText.getText(); + } + } + component = new ChatComponentTranslation(translate).addWiths(withs); + } else { + component = new ChatComponentTranslation(translate); + } + } else if(jsonObject.has("score")) { + JsonObject jsonObjectScore = jsonObject.getAsJsonObject("score"); + if(!jsonObjectScore.has("name") || !jsonObjectScore.has("objective")) + throw new JsonParseException("A score component needs a least a name and an objective"); + component = new ChatComponentScore(jsonObjectScore.get("name").getAsString(), jsonObjectScore.get("objective").getAsString()); + if(jsonObjectScore.has("value")) + ((ChatComponentScore) component).setValue(jsonObjectScore.get("value").getAsString()); + } else if(jsonObject.has("selector")) { + component = new ChatComponentSelector(jsonObject.get("selector").getAsString()); + } else if(jsonObject.has("keybind")) { + component = new ChatComponentKeybind(jsonObject.get("keybind").getAsString()); + } else { + throw new JsonParseException("Don't know how to turn " + json + " into a Component."); + } + + if(jsonObject.has("extra")) { + JsonArray jsonArray = jsonObject.getAsJsonArray("extra"); + if(jsonArray.size() <= 0) + throw new JsonParseException("Unexpected empty array of components"); + for(int i = 0; i < jsonArray.size(); ++i) + component.append(deserialize(jsonArray.get(i), typeOfT, context)); + } + component.setStyle(context.deserialize(json, ChatStyle.class)); + return component; + } + + @Override + public JsonElement serialize(ChatComponent src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jsonObject = new JsonObject(); + if(!src.getStyle().isEmpty()) { + JsonElement jsonElement = context.serialize(src.getStyle()); + if(jsonElement.isJsonObject()) { + JsonObject jsonObjectStyle = jsonElement.getAsJsonObject(); + for(Map.Entry entry : jsonObjectStyle.entrySet()) + jsonObject.add(entry.getKey(), entry.getValue()); + } + } + if(!src.getExtras().isEmpty()) { + JsonArray jsonArray = new JsonArray(); + for(ChatComponent component : src.getExtras()) + jsonArray.add(serialize(component, component.getClass(), context)); + jsonObject.add("extra", jsonArray); + } + if(src instanceof ChatComponentText) { + ChatComponentText componentText = (ChatComponentText) src; + jsonObject.addProperty("text", componentText.getText()); + } else if(src instanceof ChatComponentTranslation) { + ChatComponentTranslation componentTranslation = (ChatComponentTranslation) src; + jsonObject.addProperty("translate", componentTranslation.getKey()); + if(!componentTranslation.getWiths().isEmpty()) { + JsonArray jsonArray = new JsonArray(); + for(Object object : componentTranslation.getWiths()) { + if(object instanceof ChatComponent) jsonArray.add(serialize((ChatComponent) object, object.getClass(), context)); + else jsonArray.add(new JsonPrimitive(String.valueOf(object))); + } + jsonObject.add("with", jsonArray); + } + } else if(src instanceof ChatComponentScore) { + JsonObject jsonObjectScore = new JsonObject(); + ChatComponentScore componentScore = (ChatComponentScore) src; + jsonObjectScore.addProperty("name", componentScore.getName()); + jsonObjectScore.addProperty("objective", componentScore.getObjective()); + jsonObjectScore.addProperty("value", componentScore.getValue()); + jsonObject.add("score", jsonObjectScore); + } else if(src instanceof ChatComponentSelector) { + ChatComponentSelector componentSelector = (ChatComponentSelector) src; + jsonObject.addProperty("selector", componentSelector.getSelector()); + } else if(src instanceof ChatComponentKeybind) { + ChatComponentKeybind componentKeybind = (ChatComponentKeybind) src; + jsonObject.addProperty("keybind", componentKeybind.getKeybind()); + } else { + throw new JsonParseException("Don't know how to serialize " + src + " as a Component"); + } + return jsonObject; + } + } +} diff --git a/src/main/java/com/minecraft/moonlake/chat/ChatStyle.java b/src/main/java/com/minecraft/moonlake/chat/ChatStyle.java new file mode 100644 index 0000000..ce29f08 --- /dev/null +++ b/src/main/java/com/minecraft/moonlake/chat/ChatStyle.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat; + +public class ChatStyle { + + private ChatStyle parent; + ChatColor color; + Boolean bold; + Boolean italic; + Boolean underlined; + Boolean strikethrough; + Boolean obfuscated; + ChatClickEvent clickEvent; + ChatHoverEvent hoverEvent; + String insertion; + + private final static ChatStyle ROOT = new ChatStyle() { + @Override + public ChatColor getColor() { + return null; + } + + @Override + public boolean getBold() { + return false; + } + + @Override + public boolean getItalic() { + return false; + } + + @Override + public boolean getStrikethrough() { + return false; + } + + @Override + public boolean getUnderlined() { + return false; + } + + @Override + public boolean getObfuscated() { + return false; + } + + @Override + public ChatClickEvent getClickEvent() { + return null; + } + + @Override + public ChatHoverEvent getHoverEvent() { + return null; + } + + @Override + public String getInsertion() { + return null; + } + + @Override + public ChatStyle setColor(ChatColor color) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setBold(Boolean bold) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setItalic(Boolean italic) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setStrikethrough(Boolean strikethrough) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setUnderlined(Boolean underlined) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setObfuscated(Boolean obfuscated) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setClickEvent(ChatClickEvent clickEvent) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setHoverEvent(ChatHoverEvent hoverEvent) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setInsertion(String insertion) { + throw new UnsupportedOperationException(); + } + + @Override + public ChatStyle setParent(ChatStyle parent) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "ChatStyle.ROOT"; + } + }; + + public ChatColor getColor() { + return color != null ? color : getParent().getColor(); + } + + public boolean getBold() { + return bold != null ? bold : getParent().getBold(); + } + + public boolean getItalic() { + return italic != null ? italic : getParent().getItalic(); + } + + public boolean getStrikethrough() { + return strikethrough != null ? strikethrough : getParent().getStrikethrough(); + } + + public boolean getUnderlined() { + return underlined != null ? underlined : getParent().getUnderlined(); + } + + public boolean getObfuscated() { + return obfuscated != null ? obfuscated : getParent().getObfuscated(); + } + + public ChatClickEvent getClickEvent() { + return clickEvent != null ? clickEvent : getParent().getClickEvent(); + } + + public ChatHoverEvent getHoverEvent() { + return hoverEvent != null ? hoverEvent : getParent().getHoverEvent(); + } + + public String getInsertion() { + return insertion != null ? insertion : getParent().getInsertion(); + } + + public ChatStyle setColor(ChatColor color) { + this.color = color; + return this; + } + + public ChatStyle setBold(Boolean bold) { + this.bold = bold; + return this; + } + + public ChatStyle setItalic(Boolean italic) { + this.italic = italic; + return this; + } + + public ChatStyle setStrikethrough(Boolean strikethrough) { + this.strikethrough = strikethrough; + return this; + } + + public ChatStyle setUnderlined(Boolean underlined) { + this.underlined = underlined; + return this; + } + + public ChatStyle setObfuscated(Boolean obfuscated) { + this.obfuscated = obfuscated; + return this; + } + + public ChatStyle setClickEvent(ChatClickEvent clickEvent) { + this.clickEvent = clickEvent; + return this; + } + + public ChatStyle setHoverEvent(ChatHoverEvent hoverEvent) { + this.hoverEvent = hoverEvent; + return this; + } + + public ChatStyle setInsertion(String insertion) { + this.insertion = insertion; + return this; + } + + public ChatStyle setParent(ChatStyle parent) { + this.parent = parent; + return this; + } + + public boolean isEmpty() { + return color == null && bold == null && italic == null && strikethrough == null && underlined == null && obfuscated == null && clickEvent == null && hoverEvent == null && insertion == null; + } + + private ChatStyle getParent() { + return parent != null ? parent : ROOT; + } + + @Override + public boolean equals(Object obj) { + if(obj == this) + return true; + if(obj instanceof ChatStyle) { + ChatStyle other = (ChatStyle) obj; + return + getColor() == other.getColor() && + getBold() == other.getBold() && + getItalic() == other.getItalic() && + getUnderlined() == other.getUnderlined() && + getStrikethrough() == other.getStrikethrough() && + getObfuscated() == other.getObfuscated() && + getClickEvent() != null ? getClickEvent().equals(other.getClickEvent()) : other.getClickEvent() == null && + getHoverEvent() != null ? getHoverEvent().equals(other.getHoverEvent()) : other.getHoverEvent() == null && + getInsertion() != null ? getInsertion().equals(other.getInsertion()) : other.getInsertion() == null; + } + return false; + } + + @Override + public int hashCode() { + int result = color != null ? color.hashCode() : 0; + result = 31 * result + (bold != null ? bold.hashCode() : 0); + result = 31 * result + (italic != null ? italic.hashCode() : 0); + result = 31 * result + (underlined != null ? underlined.hashCode() : 0); + result = 31 * result + (strikethrough != null ? strikethrough.hashCode() : 0); + result = 31 * result + (obfuscated != null ? obfuscated.hashCode() : 0); + result = 31 * result + (clickEvent != null ? clickEvent.hashCode() : 0); + result = 31 * result + (hoverEvent != null ? hoverEvent.hashCode() : 0); + result = 31 * result + (insertion != null ? insertion.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ChatStyle{" + + "color=" + color + + ", bold=" + bold + + ", italic=" + italic + + ", underlined=" + underlined + + ", strikethrough=" + strikethrough + + ", obfuscated=" + obfuscated + + ", clickEvent=" + clickEvent + + ", hoverEvent=" + hoverEvent + + ", insertion='" + insertion + '\'' + + '}'; + } +} diff --git a/src/test/java/com/minecraft/moonlake/chat/test/MoonLakeChatTest.java b/src/test/java/com/minecraft/moonlake/chat/test/MoonLakeChatTest.java new file mode 100644 index 0000000..d3843ab --- /dev/null +++ b/src/test/java/com/minecraft/moonlake/chat/test/MoonLakeChatTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2017 The MoonLake Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +package com.minecraft.moonlake.chat.test; + +import com.minecraft.moonlake.chat.*; +import org.junit.Assert; +import org.junit.Test; + +public class MoonLakeChatTest { + + public static void main(String[] args) { + } + + @Test + public void testFancy() { + ChatComponent fancy = new ChatComponentFancy("你好啊 ") + .color(ChatColor.AQUA) + .then("Month_Light ") + .color(ChatColor.GREEN) + .then("欢迎来到月色之湖服务器! ") + .color(ChatColor.AQUA) + .join( + new ChatComponentFancy("[") + .color(ChatColor.GREEN) + .then("官方网站") + .color(ChatColor.AQUA) + .link("http://www.mcyszh.net") + .then("]") + .color(ChatColor.GREEN)) + .build(); + + print(fancy); + + Assert.assertEquals("错误: 聊天组件中的内容长度不符合, 应为: 6.", 6, fancy.getExtraSize()); + } + + @Test + public void testRead() { + String json = "{\"text\":\"\",\"extra\":[{\"text\":\"文本内容\",\"color\":\"red\"}]}"; + ChatComponent component = ChatSerializer.fromJson(json); + print(component); + } + + @Test + public void testWrite() { + ChatComponentText root = new ChatComponentText(""); + ChatComponentText text1 = new ChatComponentText("文本内容"); + text1.getStyle().setColor(ChatColor.RED).setBold(true); + root.append(text1); + print(root); + } + + @Test + public void testEquals() { + ChatComponentText text1 = new ChatComponentText("比较"); + text1.getStyle().setColor(ChatColor.RED); + ChatComponentText text2 = new ChatComponentText("比较"); + text2.getStyle().setColor(ChatColor.RED); + + Assert.assertEquals(text1, text2); + } + + public void print(ChatComponent component) { + System.out.println("结果: " + component.toString()); + System.out.println("结果 Json: " + component.toJson()); + System.out.println("结果 Raw: " + component.toRaw()); + } +}