0

add Text component

реализация скопирована из mc-core
(mc-server, g1/master)
This commit is contained in:
2020-05-12 11:34:40 +03:00
parent 49a932baea
commit ce76e5d5c7
5 changed files with 552 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
package mc.protocol.text;
import com.google.common.collect.ImmutableList;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import java.util.*;
@Getter
public class Text {
private static final Text EMPTY = new Text();
private static final Text NEW_LINE = new Text("\n", null, null, null);
private final String content;
private final TextColor color;
private final TextStyle style;
private final ImmutableList<Text> children;
private Text() {
content = "";
color = null;
style = null;
children = null;
}
private Text(String content, TextColor color, TextStyle style, ImmutableList<Text> children) {
this.content = content;
this.color = color;
this.style = style;
this.children = children;
}
public boolean isEmpty() {
boolean result = (content == null || content.isEmpty());
if (children != null && !children.isEmpty()) {
for (Text child : children) {
result = result && child.isEmpty();
}
}
return result;
}
public String toPlain() {
if (children != null && !children.isEmpty()) {
final StringJoiner sj = new StringJoiner("");
children.forEach(child -> sj.add(child.toPlain()));
return sj.toString();
} else {
return content;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Text text = (Text) o;
return Objects.equals(toPlain(), text.toPlain());
}
@Override
public int hashCode() {
return Objects.hash(toPlain());
}
public static class Builder {
@Getter
private String content;
@Getter
private TextColor color;
@Getter
private TextStyle style;
private List<Text> children;
public Builder() {
this("");
}
public Builder(String content) {
this.content = content;
this.color = null;
this.style = null;
this.children = new ArrayList<>();
}
public Builder(Object... objects) {
this.children = new ArrayList<>();
for(Object obj : objects) {
if (obj instanceof String) {
if (this.content == null) {
this.content = (String) obj;
} else {
this.content = this.content.concat((String) obj);
}
} else if (obj instanceof TextStyle) {
if (this.style == null) {
this.style = TextStyle.none();
} else {
this.style.merge((TextStyle) obj);
}
} else if (obj instanceof TextColor) {
this.color = (TextColor) obj;
} else if (obj instanceof Text) {
children.add((Text) obj);
}
}
}
public List<Text> getChildren() {
return Collections.unmodifiableList(children);
}
public Builder color(TextColor color) {
this.color = color;
return this;
}
public Builder style(TextStyle style) {
if (this.style == null) {
this.style = TextStyle.none();
} else {
this.style.merge(style);
}
return this;
}
public Builder style(TextStyle... styles) {
if (this.style == null) {
this.style = TextStyle.none();
}
for(TextStyle style : styles) {
this.style.merge(style);
}
return this;
}
public Builder append(String string) {
return append(Text.of(string));
}
public Builder append(Text child) {
this.children.add(child);
return this;
}
public Builder append(Text... children) {
Collections.addAll(this.children, children);
return this;
}
public Text build() {
if ((children.isEmpty() || (children.size() == 1 && children.get(0) == null))
&& (content == null || content.isEmpty())) {
return Text.EMPTY;
}
if (children.size() == 1 && children.get(0) != null) {
return children.get(0);
} else {
return new Text(
content,
color,
style,
ImmutableList.copyOf(children)
);
}
}
}
public static Builder builder() {
return new Builder();
}
public static Builder builder(String content) {
return new Builder(content);
}
public static Builder builder(Object... objects) {
return new Builder(objects);
}
public static Text of() {
return EMPTY;
}
public static Text of(String string) {
if (string == null || string.isEmpty()) {
return EMPTY;
} else if (string.equals("\n")) {
return NEW_LINE;
} else {
return new Text(string, null, null, null);
}
}
public static Text of(Object... objects) {
TextColor color = null;
TextStyle style = null;
String content = null;
for(Object obj : objects) {
if (obj instanceof String) {
if (content == null) {
content = (String) obj;
} else {
content = content.concat((String) obj);
}
} else if (obj instanceof TextStyle) {
if (style == null) {
style = (TextStyle) obj;
} else {
style.merge((TextStyle) obj);
}
} else if (obj instanceof TextColor) {
color = (TextColor) obj;
} else if (obj != null){
if (content == null) {
content = obj.toString();
} else {
content = content.concat(obj.toString());
}
}
}
if (content == null || content.isEmpty()) {
return EMPTY;
} else {
return new Text(content, color, style, null);
}
}
}

View File

@@ -0,0 +1,28 @@
package mc.protocol.text;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum TextColor {
BLACK ("black", '0'),
DARK_BLUE ("dark_blue", '1'),
DARK_GREEN ("dark_green", '2'),
DARK_AQUA ("dark_aqua", '3'),
DARK_RED ("dark_red", '4'),
DARK_PUEPLE("dark_purple", '5'),
GOLD ("gold", '6'),
GRAY ("gray", '7'),
DARK_GRAY ("dark_gray", '8'),
BLUE ("blue", '9'),
GREEN ("green", 'a'),
AQUA ("aqua", 'b'),
RED ("red", 'c'),
PUEPLE ("light_purple",'d'),
YELLOW ("yellow", 'e'),
WHITE ("white", 'f');
private final String name;
private final char code;
}

View File

@@ -0,0 +1,66 @@
package mc.protocol.text;
import lombok.Getter;
import lombok.Setter;
import javax.annotation.Nullable;
import java.util.Optional;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Getter
@Setter
public class TextStyle {
public static final TextStyle BOLD = new TextStyle(true, null, null, null, null);
public static final TextStyle ITALIC = new TextStyle(null, true, null, null, null);
public static final TextStyle UNDERLINE = new TextStyle(null, null, true, null, null);
public static final TextStyle STRIKETHOUGH = new TextStyle(null, null, null, true, null);
public static final TextStyle OBFUSCATED = new TextStyle(null, null, null, null, true);
public static final TextStyle RESET = new TextStyle(false, false, false, false, false);
private static class OptionalBoolean {
private static final Optional<Boolean> TRUE = Optional.of(true);
private static final Optional<Boolean> FALSE = Optional.of(false);
private static final Optional<Boolean> NONE = Optional.empty();
static Optional<Boolean> of(boolean bool) {
return bool ? TRUE : FALSE;
}
static Optional<Boolean> of(@Nullable Boolean bool) {
if (bool != null) {
return of(bool.booleanValue());
}
return NONE;
}
}
private Optional<Boolean> bold;
private Optional<Boolean> italic;
private Optional<Boolean> underline;
private Optional<Boolean> strikethrough;
private Optional<Boolean> obfuscated;
public TextStyle(@Nullable Boolean bold,
@Nullable Boolean italic,
@Nullable Boolean underline,
@Nullable Boolean strikethrough,
@Nullable Boolean obfuscated) {
this.bold = OptionalBoolean.of(bold);
this.italic = OptionalBoolean.of(italic);
this.underline = OptionalBoolean.of(underline);
this.strikethrough = OptionalBoolean.of(strikethrough);
this.obfuscated = OptionalBoolean.of(obfuscated);
}
public void merge(TextStyle style) {
if (style.bold.isPresent()) this.bold = style.bold;
if (style.italic.isPresent()) this.italic = style.italic;
if (style.underline.isPresent()) this.underline = style.underline;
if (style.strikethrough.isPresent()) this.strikethrough = style.strikethrough;
if (style.obfuscated.isPresent()) this.obfuscated = style.obfuscated;
}
public static TextStyle none() {
return new TextStyle(null,null,null,null, null);
}
}

View File

@@ -0,0 +1,146 @@
package mc.protocol.text;
import com.google.common.collect.ImmutableList;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import java.util.*;
public class TextTemplate {
private final ImmutableList<Object> elements;
private TextTemplate(ImmutableList<Object> elements) {
this.elements = elements;
}
public Text apply(Object... objects) {
Map<String, Object> variableMap = new HashMap<>((objects.length % 2) == 1 ? (objects.length / 2) + 1 : (objects.length / 2));
boolean skipValue = false;
String key = null;
for (Object obj : objects) {
if (skipValue) {
skipValue = false;
continue;
}
if (key == null) {
if (obj == null || obj.toString().trim().isEmpty()) {
skipValue = true;
continue;
}
key = obj.toString().trim();
} else {
variableMap.put(key, obj);
key = null;
}
}
if (key != null) {
variableMap.put(key, "");
}
return apply(variableMap);
}
public Text apply(Map<String, Object> variables) {
Text.Builder textBuilder = Text.builder();
for(Object obj : elements) {
if (obj instanceof Text) {
textBuilder.append((Text) obj);
} else if (obj instanceof Arg) {
Arg arg = (Arg) obj;
if (variables.containsKey(arg.getKey())) {
Object valueObj = variables.get(arg.getKey());
if (valueObj instanceof Text) {
textBuilder.append((Text) valueObj);
} else {
textBuilder.append(Text.of(valueObj, arg.getColor(), arg.getStyle()));
}
} else {
textBuilder.append(Text.of(arg.getDefaultValue(), arg.getColor(), arg.getStyle()));
}
}
}
return textBuilder.build();
}
@RequiredArgsConstructor
@Getter
public static class Arg {
private final String key;
private final String defaultValue;
@Setter
private TextColor color;
@Setter
private TextStyle style;
}
public static class Builder {
private List<Object> elements = new ArrayList<>();
public Builder append(Text element) {
this.elements.add(element);
return this;
}
public Builder append(Text... elements) {
Collections.addAll(this.elements, elements);
return this;
}
public Builder arg(String name) {
this.elements.add(new Arg(name, null));
return this;
}
public Builder arg(String name, String defaultValue) {
this.elements.add(new Arg(name, defaultValue));
return this;
}
public Builder arg(Object... objects) {
String key = null,
defaultValue = null;
TextColor color = null;
TextStyle style = null;
for(Object obj : objects) {
if (obj instanceof String) {
if (key == null) {
key = (String) obj;
} else {
defaultValue = (String) obj;
}
} else if (obj instanceof TextColor) {
color = (TextColor) obj;
} else if (obj instanceof TextStyle) {
if (style == null) {
style = TextStyle.none();
}
style.merge((TextStyle) obj);
}
}
Arg arg = new Arg(key, defaultValue);
arg.setColor(color);
arg.setStyle(style);
this.elements.add(arg);
return this;
}
public TextTemplate build() {
return new TextTemplate(ImmutableList.copyOf(elements));
}
}
public static Builder builder() {
return new Builder();
}
}

View File

@@ -0,0 +1,75 @@
package mc.protocol.text;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class TextTest {
@Test
void testToPlain() {
final String m1 = "mes";
final String m2 = "sage";
final String message = m1 + m2;
assertEquals(message, Text.of(message).toPlain());
assertEquals(message, Text.builder(message).build().toPlain());
assertEquals(message, Text.builder(Text.of(message)).build().toPlain());
assertEquals(message, Text.builder().append(message).build().toPlain());
assertEquals(message, Text.builder().append(Text.of(message)).build().toPlain());
assertEquals(message, Text.builder(m1, m2).build().toPlain());
assertEquals(message, Text.builder(Text.of(m1), Text.of(m2)).build().toPlain());
assertEquals(message, Text.builder().append(Text.of(m1), Text.of(m2)).build().toPlain());
assertEquals(message, Text.builder().append(Text.of(m1)).append(Text.of(m2)).build().toPlain());
}
@Test
void testEquals() {
assertEquals(Text.of(), Text.of(""));
assertEquals(Text.of(), Text.builder().build());
assertEquals(Text.of(), Text.builder("").build());
assertEquals(Text.of(), Text.builder().append().build());
assertEquals(Text.of(), Text.builder().append("").build());
assertNotEquals(Text.of(), Text.of("??"));
assertNotEquals(Text.of(), Text.builder("??").build());
assertNotEquals(Text.of(), Text.builder().append("??").build());
assertEquals(Text.of("message"), Text.builder("message").build());
assertEquals(Text.of("message"), Text.builder(Text.of("message")).build());
assertEquals(Text.of("message"), Text.builder().append("message").build());
assertEquals(Text.of("message"), Text.builder().append(Text.of("message")).build());
}
@Test
void testEmpty() {
assertTrue(Text.of().isEmpty());
assertTrue(Text.of((String) null).isEmpty());
assertTrue(Text.of((Text) null).isEmpty());
assertTrue(Text.of("").isEmpty());
assertTrue(Text.of("", "").isEmpty());
assertTrue(Text.builder().build().isEmpty());
assertTrue(Text.builder((String) null).build().isEmpty());
assertTrue(Text.builder((Text) null).build().isEmpty());
assertTrue(Text.builder("").build().isEmpty());
assertTrue(Text.builder("", "").build().isEmpty());
assertTrue(Text.builder(Text.of()).build().isEmpty());
assertTrue(Text.builder(Text.of(), Text.of()).build().isEmpty());
assertTrue(Text.builder().append().build().isEmpty());
assertTrue(Text.builder().append((String) null).build().isEmpty());
assertTrue(Text.builder().append((Text) null).build().isEmpty());
assertTrue(Text.builder().append("").build().isEmpty());
assertTrue(Text.builder().append(Text.of()).build().isEmpty());
assertTrue(Text.builder().append(Text.of(), Text.of()).build().isEmpty());
assertTrue(Text.builder().append(Text.of()).append(Text.of()).build().isEmpty());
assertFalse(Text.of("??").isEmpty());
assertFalse(Text.builder("??").build().isEmpty());
assertFalse(Text.builder(Text.of("??")).build().isEmpty());
assertFalse(Text.builder().append("??").build().isEmpty());
assertFalse(Text.builder().append(Text.of("??")).build().isEmpty());
}
}