更新
This commit is contained in:
@@ -14,10 +14,11 @@ public class ExampleMain extends JavaPlugin {
|
||||
public void onEnable() {
|
||||
update.addListener(((oldVal, newVal) -> {
|
||||
Bukkit.getLogger().info("配置项 enableUpdate 的值由 " + oldVal + " 变为了 " + newVal);
|
||||
if (newVal)
|
||||
if (newVal) {
|
||||
Updater.start();
|
||||
else
|
||||
} else {
|
||||
Updater.stop();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@ public class Property<T> {
|
||||
|
||||
public void set(T value) {
|
||||
if (value != this.value) {
|
||||
if (consumers != null)
|
||||
if (consumers != null) {
|
||||
for (BiConsumer<T, T> consumer : consumers) {
|
||||
consumer.accept(this.value, value);
|
||||
}
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -29,8 +30,9 @@ public class Property<T> {
|
||||
}
|
||||
|
||||
public void addListener(BiConsumer<T, T> consumer) {
|
||||
if (consumers == null)
|
||||
if (consumers == null) {
|
||||
consumers = new ArrayList<>();
|
||||
}
|
||||
consumers.add(consumer);
|
||||
}
|
||||
|
||||
|
||||
180
src/main/java/com/ilummc/tlib/bungee/api/ChatColor.java
Normal file
180
src/main/java/com/ilummc/tlib/bungee/api/ChatColor.java
Normal file
@@ -0,0 +1,180 @@
|
||||
package com.ilummc.tlib.bungee.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Simplistic enumeration of all supported color values for chat.
|
||||
* @author md_5
|
||||
*/
|
||||
public enum ChatColor {
|
||||
|
||||
/**
|
||||
* Represents black.
|
||||
*/
|
||||
BLACK('0', "black"),
|
||||
/**
|
||||
* Represents dark blue.
|
||||
*/
|
||||
DARK_BLUE('1', "dark_blue"),
|
||||
/**
|
||||
* Represents dark green.
|
||||
*/
|
||||
DARK_GREEN('2', "dark_green"),
|
||||
/**
|
||||
* Represents dark blue (aqua).
|
||||
*/
|
||||
DARK_AQUA('3', "dark_aqua"),
|
||||
/**
|
||||
* Represents dark red.
|
||||
*/
|
||||
DARK_RED('4', "dark_red"),
|
||||
/**
|
||||
* Represents dark purple.
|
||||
*/
|
||||
DARK_PURPLE('5', "dark_purple"),
|
||||
/**
|
||||
* Represents gold.
|
||||
*/
|
||||
GOLD('6', "gold"),
|
||||
/**
|
||||
* Represents gray.
|
||||
*/
|
||||
GRAY('7', "gray"),
|
||||
/**
|
||||
* Represents dark gray.
|
||||
*/
|
||||
DARK_GRAY('8', "dark_gray"),
|
||||
/**
|
||||
* Represents blue.
|
||||
*/
|
||||
BLUE('9', "blue"),
|
||||
/**
|
||||
* Represents green.
|
||||
*/
|
||||
GREEN('a', "green"),
|
||||
/**
|
||||
* Represents aqua.
|
||||
*/
|
||||
AQUA('b', "aqua"),
|
||||
/**
|
||||
* Represents red.
|
||||
*/
|
||||
RED('c', "red"),
|
||||
/**
|
||||
* Represents light purple.
|
||||
*/
|
||||
LIGHT_PURPLE('d', "light_purple"),
|
||||
/**
|
||||
* Represents yellow.
|
||||
*/
|
||||
YELLOW('e', "yellow"),
|
||||
/**
|
||||
* Represents white.
|
||||
*/
|
||||
WHITE('f', "white"),
|
||||
/**
|
||||
* Represents magical characters that change around randomly.
|
||||
*/
|
||||
MAGIC('k', "obfuscated"),
|
||||
/**
|
||||
* Makes the text bold.
|
||||
*/
|
||||
BOLD('l', "bold"),
|
||||
/**
|
||||
* Makes a line appear through the text.
|
||||
*/
|
||||
STRIKETHROUGH('m', "strikethrough"),
|
||||
/**
|
||||
* Makes the text appear underlined.
|
||||
*/
|
||||
UNDERLINE('n', "underline"),
|
||||
/**
|
||||
* Makes the text italic.
|
||||
*/
|
||||
ITALIC('o', "italic"),
|
||||
/**
|
||||
* Resets all previous chat colors or formats.
|
||||
*/
|
||||
RESET('r', "reset");
|
||||
/**
|
||||
* The special character which prefixes all chat colour codes. Use this if
|
||||
* you need to dynamically convert colour codes from your custom format.
|
||||
*/
|
||||
public static final char COLOR_CHAR = '\u00A7';
|
||||
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
|
||||
/**
|
||||
* Pattern to remove all colour codes.
|
||||
*/
|
||||
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
|
||||
/**
|
||||
* Colour instances keyed by their active character.
|
||||
*/
|
||||
private static final Map<Character, ChatColor> BY_CHAR = new HashMap<Character, ChatColor>();
|
||||
/**
|
||||
* The code appended to {@link #COLOR_CHAR} to make usable colour.
|
||||
*/
|
||||
private final char code;
|
||||
/**
|
||||
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
|
||||
*/
|
||||
private final String toString;
|
||||
|
||||
private final String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
static {
|
||||
for (ChatColor colour : values()) {
|
||||
BY_CHAR.put(colour.code, colour);
|
||||
}
|
||||
}
|
||||
|
||||
ChatColor(char code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.toString = new String(new char[]{COLOR_CHAR, code});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the given message of all color codes
|
||||
*
|
||||
* @param input String to strip of color
|
||||
* @return A copy of the input string, without any coloring
|
||||
*/
|
||||
public static String stripColor(final String input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
|
||||
}
|
||||
|
||||
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
|
||||
char[] b = textToTranslate.toCharArray();
|
||||
for (int i = 0; i < b.length - 1; i++) {
|
||||
if (b[i] == altColorChar && ALL_CODES.indexOf(b[i + 1]) > -1) {
|
||||
b[i] = ChatColor.COLOR_CHAR;
|
||||
b[i + 1] = Character.toLowerCase(b[i + 1]);
|
||||
}
|
||||
}
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour represented by the specified code.
|
||||
*
|
||||
* @param code the code to search for
|
||||
* @return the mapped colour, or null if non exists
|
||||
*/
|
||||
public static ChatColor getByChar(char code) {
|
||||
return BY_CHAR.get(code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.ilummc.tlib.bungee.api;
|
||||
|
||||
/**
|
||||
* Represents the position on the screen where a message will appear.
|
||||
* @author md_5
|
||||
*/
|
||||
public enum ChatMessageType {
|
||||
|
||||
CHAT,
|
||||
SYSTEM,
|
||||
ACTION_BAR
|
||||
}
|
||||
493
src/main/java/com/ilummc/tlib/bungee/api/chat/BaseComponent.java
Normal file
493
src/main/java/com/ilummc/tlib/bungee/api/chat/BaseComponent.java
Normal file
@@ -0,0 +1,493 @@
|
||||
package com.ilummc.tlib.bungee.api.chat;
|
||||
|
||||
import com.ilummc.tlib.bungee.api.ChatColor;
|
||||
import com.ilummc.tlib.bungee.api.chat.ComponentBuilder.FormatRetention;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public abstract class BaseComponent {
|
||||
|
||||
BaseComponent parent;
|
||||
|
||||
/**
|
||||
* The color of this component and any child components (unless overridden)
|
||||
*/
|
||||
private ChatColor color;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* bold
|
||||
*/
|
||||
private Boolean bold;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* italic
|
||||
*/
|
||||
private Boolean italic;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* underlined
|
||||
*/
|
||||
private Boolean underlined;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* strikethrough
|
||||
*/
|
||||
private Boolean strikethrough;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* obfuscated
|
||||
*/
|
||||
private Boolean obfuscated;
|
||||
/**
|
||||
* The text to insert into the chat when this component (and child
|
||||
* components) are clicked while pressing the shift key
|
||||
*/
|
||||
private String insertion;
|
||||
|
||||
/**
|
||||
* Appended components that inherit this component's formatting and events
|
||||
*/
|
||||
private List<BaseComponent> extra;
|
||||
|
||||
/**
|
||||
* The action to perform when this component (and child components) are
|
||||
* clicked
|
||||
*/
|
||||
private ClickEvent clickEvent;
|
||||
/**
|
||||
* The action to perform when this component (and child components) are
|
||||
* hovered over
|
||||
*/
|
||||
private HoverEvent hoverEvent;
|
||||
|
||||
public String getInsertion() {
|
||||
return insertion;
|
||||
}
|
||||
|
||||
public List<BaseComponent> getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public ClickEvent getClickEvent() {
|
||||
return clickEvent;
|
||||
}
|
||||
|
||||
public HoverEvent getHoverEvent() {
|
||||
return hoverEvent;
|
||||
}
|
||||
|
||||
public void setParent(BaseComponent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setColor(ChatColor color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public void setBold(Boolean bold) {
|
||||
this.bold = bold;
|
||||
}
|
||||
|
||||
public void setItalic(Boolean italic) {
|
||||
this.italic = italic;
|
||||
}
|
||||
|
||||
public void setUnderlined(Boolean underlined) {
|
||||
this.underlined = underlined;
|
||||
}
|
||||
|
||||
public void setStrikethrough(Boolean strikethrough) {
|
||||
this.strikethrough = strikethrough;
|
||||
}
|
||||
|
||||
public void setObfuscated(Boolean obfuscated) {
|
||||
this.obfuscated = obfuscated;
|
||||
}
|
||||
|
||||
public void setInsertion(String insertion) {
|
||||
this.insertion = insertion;
|
||||
}
|
||||
|
||||
public void setClickEvent(ClickEvent clickEvent) {
|
||||
this.clickEvent = clickEvent;
|
||||
}
|
||||
|
||||
public void setHoverEvent(HoverEvent hoverEvent) {
|
||||
this.hoverEvent = hoverEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "parent=" + "BaseComponent{" + parent + ", color=" + color + ", bold=" + bold + ", italic=" + italic + ", underlined=" + underlined + ", strikethrough=" + strikethrough + ", obfuscated=" + obfuscated + ", insertion='" + insertion + '\'' + ", extra=" + extra + ", clickEvent=" + clickEvent + ", hoverEvent=" + hoverEvent + '}';
|
||||
}
|
||||
|
||||
BaseComponent() {
|
||||
}
|
||||
|
||||
BaseComponent(BaseComponent old) {
|
||||
copyFormatting(old, FormatRetention.ALL, true);
|
||||
|
||||
if (old.getExtra() != null) {
|
||||
for (BaseComponent extra : old.getExtra()) {
|
||||
addExtra(extra.duplicate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the events and formatting of a BaseComponent. Already set
|
||||
* formatting will be replaced.
|
||||
*
|
||||
* @param component the component to copy from
|
||||
*/
|
||||
public void copyFormatting(BaseComponent component) {
|
||||
copyFormatting(component, FormatRetention.ALL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the events and formatting of a BaseComponent.
|
||||
*
|
||||
* @param component the component to copy from
|
||||
* @param replace if already set formatting should be replaced by the new
|
||||
* component
|
||||
*/
|
||||
public void copyFormatting(BaseComponent component, boolean replace) {
|
||||
copyFormatting(component, FormatRetention.ALL, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the specified formatting of a BaseComponent.
|
||||
*
|
||||
* @param component the component to copy from
|
||||
* @param retention the formatting to copy
|
||||
* @param replace if already set formatting should be replaced by the new
|
||||
* component
|
||||
*/
|
||||
public void copyFormatting(BaseComponent component, FormatRetention retention, boolean replace) {
|
||||
if (retention == FormatRetention.EVENTS || retention == FormatRetention.ALL) {
|
||||
if (replace || clickEvent == null) {
|
||||
setClickEvent(component.getClickEvent());
|
||||
}
|
||||
if (replace || hoverEvent == null) {
|
||||
setHoverEvent(component.getHoverEvent());
|
||||
}
|
||||
}
|
||||
if (retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL) {
|
||||
if (replace || color == null) {
|
||||
setColor(component.getColorRaw());
|
||||
}
|
||||
if (replace || bold == null) {
|
||||
setBold(component.isBoldRaw());
|
||||
}
|
||||
if (replace || italic == null) {
|
||||
setItalic(component.isItalicRaw());
|
||||
}
|
||||
if (replace || underlined == null) {
|
||||
setUnderlined(component.isUnderlinedRaw());
|
||||
}
|
||||
if (replace || strikethrough == null) {
|
||||
setStrikethrough(component.isStrikethroughRaw());
|
||||
}
|
||||
if (replace || obfuscated == null) {
|
||||
setObfuscated(component.isObfuscatedRaw());
|
||||
}
|
||||
if (replace || insertion == null) {
|
||||
setInsertion(component.getInsertion());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only the specified formatting.
|
||||
*
|
||||
* @param retention the formatting to retain
|
||||
*/
|
||||
public void retain(FormatRetention retention) {
|
||||
if (retention == FormatRetention.FORMATTING || retention == FormatRetention.NONE) {
|
||||
setClickEvent(null);
|
||||
setHoverEvent(null);
|
||||
}
|
||||
if (retention == FormatRetention.EVENTS || retention == FormatRetention.NONE) {
|
||||
setColor(null);
|
||||
setBold(null);
|
||||
setItalic(null);
|
||||
setUnderlined(null);
|
||||
setStrikethrough(null);
|
||||
setObfuscated(null);
|
||||
setInsertion(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the BaseComponent and returns the clone.
|
||||
*
|
||||
* @return The duplicate of this BaseComponent
|
||||
*/
|
||||
public abstract BaseComponent duplicate();
|
||||
|
||||
/**
|
||||
* Clones the BaseComponent without formatting and returns the clone.
|
||||
*
|
||||
* @return The duplicate of this BaseComponent
|
||||
* @deprecated API use discouraged, use traditional duplicate
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseComponent duplicateWithoutFormatting() {
|
||||
BaseComponent component = duplicate();
|
||||
component.retain(FormatRetention.NONE);
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the components to a string that uses the old formatting codes
|
||||
* ({@link ChatColor#COLOR_CHAR}
|
||||
*
|
||||
* @param components the components to convert
|
||||
* @return the string in the old format
|
||||
*/
|
||||
public static String toLegacyText(BaseComponent... components) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (BaseComponent msg : components) {
|
||||
builder.append(msg.toLegacyText());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the components into a string without any formatting
|
||||
*
|
||||
* @param components the components to convert
|
||||
* @return the string as plain text
|
||||
*/
|
||||
public static String toPlainText(BaseComponent... components) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (BaseComponent msg : components) {
|
||||
builder.append(msg.toPlainText());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color of this component. This uses the parent's color if this
|
||||
* component doesn't have one. {@link ChatColor#WHITE}
|
||||
* is returned if no color is found.
|
||||
*
|
||||
* @return the color of this component
|
||||
*/
|
||||
public ChatColor getColor() {
|
||||
if (color == null) {
|
||||
if (parent == null) {
|
||||
return ChatColor.WHITE;
|
||||
}
|
||||
return parent.getColor();
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color of this component without checking the parents color.
|
||||
* May return null
|
||||
*
|
||||
* @return the color of this component
|
||||
*/
|
||||
public ChatColor getColorRaw() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is bold. This uses the parent's setting if
|
||||
* this component hasn't been set. false is returned if none of the parent
|
||||
* chain has been set.
|
||||
*
|
||||
* @return whether the component is bold
|
||||
*/
|
||||
public boolean isBold() {
|
||||
if (bold == null) {
|
||||
return parent != null && parent.isBold();
|
||||
}
|
||||
return bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is bold without checking the parents
|
||||
* setting. May return null
|
||||
*
|
||||
* @return whether the component is bold
|
||||
*/
|
||||
public Boolean isBoldRaw() {
|
||||
return bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is italic. This uses the parent's setting
|
||||
* if this component hasn't been set. false is returned if none of the
|
||||
* parent chain has been set.
|
||||
*
|
||||
* @return whether the component is italic
|
||||
*/
|
||||
public boolean isItalic() {
|
||||
if (italic == null) {
|
||||
return parent != null && parent.isItalic();
|
||||
}
|
||||
return italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is italic without checking the parents
|
||||
* setting. May return null
|
||||
*
|
||||
* @return whether the component is italic
|
||||
*/
|
||||
public Boolean isItalicRaw() {
|
||||
return italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is underlined. This uses the parent's
|
||||
* setting if this component hasn't been set. false is returned if none of
|
||||
* the parent chain has been set.
|
||||
*
|
||||
* @return whether the component is underlined
|
||||
*/
|
||||
public boolean isUnderlined() {
|
||||
if (underlined == null) {
|
||||
return parent != null && parent.isUnderlined();
|
||||
}
|
||||
return underlined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is underlined without checking the parents
|
||||
* setting. May return null
|
||||
*
|
||||
* @return whether the component is underlined
|
||||
*/
|
||||
public Boolean isUnderlinedRaw() {
|
||||
return underlined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is strikethrough. This uses the parent's
|
||||
* setting if this component hasn't been set. false is returned if none of
|
||||
* the parent chain has been set.
|
||||
*
|
||||
* @return whether the component is strikethrough
|
||||
*/
|
||||
public boolean isStrikethrough() {
|
||||
if (strikethrough == null) {
|
||||
return parent != null && parent.isStrikethrough();
|
||||
}
|
||||
return strikethrough;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is strikethrough without checking the
|
||||
* parents setting. May return null
|
||||
*
|
||||
* @return whether the component is strikethrough
|
||||
*/
|
||||
public Boolean isStrikethroughRaw() {
|
||||
return strikethrough;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is obfuscated. This uses the parent's
|
||||
* setting if this component hasn't been set. false is returned if none of
|
||||
* the parent chain has been set.
|
||||
*
|
||||
* @return whether the component is obfuscated
|
||||
*/
|
||||
public boolean isObfuscated() {
|
||||
if (obfuscated == null) {
|
||||
return parent != null && parent.isObfuscated();
|
||||
}
|
||||
return obfuscated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is obfuscated without checking the parents
|
||||
* setting. May return null
|
||||
*
|
||||
* @return whether the component is obfuscated
|
||||
*/
|
||||
public Boolean isObfuscatedRaw() {
|
||||
return obfuscated;
|
||||
}
|
||||
|
||||
public void setExtra(List<BaseComponent> components) {
|
||||
components.forEach(component -> component.parent = this);
|
||||
extra = components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a text element to the component. The text will inherit this
|
||||
* component's formatting
|
||||
*
|
||||
* @param text the text to append
|
||||
*/
|
||||
public void addExtra(String text) {
|
||||
addExtra(new TextComponent(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component to the component. The text will inherit this
|
||||
* component's formatting
|
||||
*
|
||||
* @param component the component to append
|
||||
*/
|
||||
public void addExtra(BaseComponent component) {
|
||||
if (extra == null) {
|
||||
extra = new ArrayList<>();
|
||||
}
|
||||
component.parent = this;
|
||||
extra.add(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the component has any formatting or events applied to it
|
||||
*
|
||||
* @return Whether any formatting or events are applied
|
||||
*/
|
||||
public boolean hasFormatting() {
|
||||
return color != null || italic != null || bold != null || underlined != null || strikethrough != null || obfuscated != null || insertion != null || hoverEvent != null || clickEvent != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the component into a string without any formatting
|
||||
*
|
||||
* @return the string as plain text
|
||||
*/
|
||||
public String toPlainText() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
toPlainText(builder);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
void toPlainText(StringBuilder builder) {
|
||||
if (extra != null) {
|
||||
extra.forEach(e -> e.toPlainText(builder));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the component to a string that uses the old formatting codes
|
||||
* ({@link ChatColor#COLOR_CHAR}
|
||||
*
|
||||
* @return the string in the old format
|
||||
*/
|
||||
public String toLegacyText() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
toLegacyText(builder);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
void toLegacyText(StringBuilder builder) {
|
||||
if (extra != null) {
|
||||
extra.forEach(e -> e.toLegacyText(builder));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.ilummc.tlib.bungee.api.chat;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public final class ClickEvent {
|
||||
|
||||
/**
|
||||
* The type of action to perform on click
|
||||
*/
|
||||
private final Action action;
|
||||
/**
|
||||
* Depends on action
|
||||
*
|
||||
* @see Action
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
public ClickEvent(Action action, String value) {
|
||||
this.action = action;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
|
||||
/**
|
||||
* Open a url at the path given by
|
||||
* {@link ClickEvent#value}
|
||||
*/
|
||||
OPEN_URL,
|
||||
/**
|
||||
* Open a file at the path given by
|
||||
* {@link ClickEvent#value}
|
||||
*/
|
||||
OPEN_FILE,
|
||||
/**
|
||||
* Run the command given by
|
||||
* {@link ClickEvent#value}
|
||||
*/
|
||||
RUN_COMMAND,
|
||||
/**
|
||||
* Inserts the string given by
|
||||
* {@link ClickEvent#value} into the players
|
||||
* text box
|
||||
*/
|
||||
SUGGEST_COMMAND,
|
||||
/**
|
||||
* Change to the page number given by
|
||||
* {@link ClickEvent#value} in a book
|
||||
*/
|
||||
CHANGE_PAGE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
package com.ilummc.tlib.bungee.api.chat;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.ilummc.tlib.bungee.api.ChatColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ComponentBuilder simplifies creating basic messages by allowing the use of a
|
||||
* chainable builder.
|
||||
* </p>
|
||||
* <pre>
|
||||
* new ComponentBuilder("Hello ").color(ChatColor.RED).
|
||||
* append("World").color(ChatColor.BLUE). append("!").bold(true).create();
|
||||
* </pre>
|
||||
* <p>
|
||||
* All methods (excluding {@link #append(String)} and {@link #create()} work on
|
||||
* the last part appended to the builder, so in the example above "Hello " would
|
||||
* be {@link ChatColor#RED} and "World" would be
|
||||
* {@link ChatColor#BLUE} but "!" would be bold and
|
||||
* {@link ChatColor#BLUE} because append copies the previous
|
||||
* part's formatting
|
||||
* </p>
|
||||
*
|
||||
* @author md_5
|
||||
*/
|
||||
public final class ComponentBuilder {
|
||||
|
||||
private BaseComponent current;
|
||||
private final List<BaseComponent> parts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a ComponentBuilder from the other given ComponentBuilder to clone
|
||||
* it.
|
||||
*
|
||||
* @param original the original for the new ComponentBuilder.
|
||||
*/
|
||||
public ComponentBuilder(ComponentBuilder original) {
|
||||
current = original.current.duplicate();
|
||||
original.parts.stream().map(BaseComponent::duplicate).forEach(parts::add);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ComponentBuilder with the given text as the first part.
|
||||
*
|
||||
* @param text the first text element
|
||||
*/
|
||||
public ComponentBuilder(String text) {
|
||||
current = new TextComponent(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ComponentBuilder with the given component as the first part.
|
||||
*
|
||||
* @param component the first component element
|
||||
*/
|
||||
public ComponentBuilder(BaseComponent component) {
|
||||
current = component.duplicate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component to the builder and makes it the current target for
|
||||
* formatting. The component will have all the formatting from previous
|
||||
* part.
|
||||
*
|
||||
* @param component the component to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent component) {
|
||||
return append(component, FormatRetention.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component to the builder and makes it the current target for
|
||||
* formatting. You can specify the amount of formatting retained from
|
||||
* previous part.
|
||||
*
|
||||
* @param component the component to append
|
||||
* @param retention the formatting to retain
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent component, FormatRetention retention) {
|
||||
parts.add(current);
|
||||
|
||||
BaseComponent previous = current;
|
||||
current = component.duplicate();
|
||||
current.copyFormatting(previous, retention, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the components to the builder and makes the last element the
|
||||
* current target for formatting. The components will have all the
|
||||
* formatting from previous part.
|
||||
*
|
||||
* @param components the components to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent[] components) {
|
||||
return append(components, FormatRetention.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the components to the builder and makes the last element the
|
||||
* current target for formatting. You can specify the amount of formatting
|
||||
* retained from previous part.
|
||||
*
|
||||
* @param components the components to append
|
||||
* @param retention the formatting to retain
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent[] components, FormatRetention retention) {
|
||||
Preconditions.checkArgument(components.length != 0, "No components to append");
|
||||
|
||||
BaseComponent previous = current;
|
||||
for (BaseComponent component : components) {
|
||||
parts.add(current);
|
||||
|
||||
current = component.duplicate();
|
||||
current.copyFormatting(previous, retention, false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text to the builder and makes it the current target for
|
||||
* formatting. The text will have all the formatting from previous part.
|
||||
*
|
||||
* @param text the text to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(String text) {
|
||||
return append(text, FormatRetention.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text to the builder and makes it the current target for
|
||||
* formatting. You can specify the amount of formatting retained from
|
||||
* previous part.
|
||||
*
|
||||
* @param text the text to append
|
||||
* @param retention the formatting to retain
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(String text, FormatRetention retention) {
|
||||
parts.add(current);
|
||||
|
||||
BaseComponent old = current;
|
||||
current = new TextComponent(text);
|
||||
current.copyFormatting(old, retention, false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the current part.
|
||||
*
|
||||
* @param color the new color
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder color(ChatColor color) {
|
||||
current.setColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the current part is bold.
|
||||
*
|
||||
* @param bold whether this part is bold
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder bold(boolean bold) {
|
||||
current.setBold(bold);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the current part is italic.
|
||||
*
|
||||
* @param italic whether this part is italic
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder italic(boolean italic) {
|
||||
current.setItalic(italic);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the current part is underlined.
|
||||
*
|
||||
* @param underlined whether this part is underlined
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder underlined(boolean underlined) {
|
||||
current.setUnderlined(underlined);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the current part is strikethrough.
|
||||
*
|
||||
* @param strikethrough whether this part is strikethrough
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder strikethrough(boolean strikethrough) {
|
||||
current.setStrikethrough(strikethrough);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the current part is obfuscated.
|
||||
*
|
||||
* @param obfuscated whether this part is obfuscated
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder obfuscated(boolean obfuscated) {
|
||||
current.setObfuscated(obfuscated);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the insertion text for the current part.
|
||||
*
|
||||
* @param insertion the insertion text
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder insertion(String insertion) {
|
||||
current.setInsertion(insertion);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the click event for the current part.
|
||||
*
|
||||
* @param clickEvent the click event
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder event(ClickEvent clickEvent) {
|
||||
current.setClickEvent(clickEvent);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hover event for the current part.
|
||||
*
|
||||
* @param hoverEvent the hover event
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder event(HoverEvent hoverEvent) {
|
||||
current.setHoverEvent(hoverEvent);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current part back to normal settings. Only text is kept.
|
||||
*
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder reset() {
|
||||
return retain(FormatRetention.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only the specified formatting. Text is not modified.
|
||||
*
|
||||
* @param retention the formatting to retain
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder retain(FormatRetention retention) {
|
||||
current.retain(retention);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the components needed to display the message created by this
|
||||
* builder.
|
||||
*
|
||||
* @return the created components
|
||||
*/
|
||||
public BaseComponent[] create() {
|
||||
BaseComponent[] result = parts.toArray(new BaseComponent[parts.size() + 1]);
|
||||
result[parts.size()] = current;
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum FormatRetention {
|
||||
|
||||
/**
|
||||
* Specify that we do not want to retain anything from the previous
|
||||
* component.
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* Specify that we want the formatting retained from the previous
|
||||
* component.
|
||||
*/
|
||||
FORMATTING,
|
||||
/**
|
||||
* Specify that we want the events retained from the previous component.
|
||||
*/
|
||||
EVENTS,
|
||||
/**
|
||||
* Specify that we want to retain everything from the previous
|
||||
* component.
|
||||
*/
|
||||
ALL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ilummc.tlib.bungee.api.chat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public final class HoverEvent {
|
||||
|
||||
private final Action action;
|
||||
private final BaseComponent[] value;
|
||||
|
||||
public HoverEvent(Action action, BaseComponent[] value) {
|
||||
this.action = action;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public BaseComponent[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "action=" + "HoverEvent{" + action + ", value=" + Arrays.toString(value) + '}';
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
|
||||
SHOW_TEXT,
|
||||
SHOW_ACHIEVEMENT,
|
||||
SHOW_ITEM,
|
||||
SHOW_ENTITY
|
||||
}
|
||||
}
|
||||
184
src/main/java/com/ilummc/tlib/bungee/api/chat/TextComponent.java
Normal file
184
src/main/java/com/ilummc/tlib/bungee/api/chat/TextComponent.java
Normal file
@@ -0,0 +1,184 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
package com.ilummc.tlib.bungee.api.chat;
|
||||
|
||||
import com.ilummc.tlib.bungee.api.*;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public class TextComponent extends BaseComponent {
|
||||
|
||||
private static final Pattern url = Pattern.compile("^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$");
|
||||
private String text;
|
||||
|
||||
public static BaseComponent[] fromLegacyText(String message) {
|
||||
ArrayList<BaseComponent> components = new ArrayList();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
TextComponent component = new TextComponent();
|
||||
Matcher matcher = url.matcher(message);
|
||||
|
||||
for(int i = 0; i < message.length(); ++i) {
|
||||
char c = message.charAt(i);
|
||||
TextComponent old;
|
||||
if (c == 167) {
|
||||
++i;
|
||||
c = message.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c = (char)(c + 32);
|
||||
}
|
||||
|
||||
ChatColor format = ChatColor.getByChar(c);
|
||||
if (format != null) {
|
||||
if (builder.length() > 0) {
|
||||
old = component;
|
||||
component = new TextComponent(component);
|
||||
old.setText(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
components.add(old);
|
||||
}
|
||||
|
||||
switch(format) {
|
||||
case BOLD:
|
||||
component.setBold(true);
|
||||
break;
|
||||
case ITALIC:
|
||||
component.setItalic(true);
|
||||
break;
|
||||
case UNDERLINE:
|
||||
component.setUnderlined(true);
|
||||
break;
|
||||
case STRIKETHROUGH:
|
||||
component.setStrikethrough(true);
|
||||
break;
|
||||
case MAGIC:
|
||||
component.setObfuscated(true);
|
||||
break;
|
||||
case RESET:
|
||||
format = ChatColor.WHITE;
|
||||
default:
|
||||
component = new TextComponent();
|
||||
component.setColor(format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int pos = message.indexOf(32, i);
|
||||
if (pos == -1) {
|
||||
pos = message.length();
|
||||
}
|
||||
|
||||
if (matcher.region(i, pos).find()) {
|
||||
if (builder.length() > 0) {
|
||||
old = component;
|
||||
component = new TextComponent(component);
|
||||
old.setText(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
components.add(old);
|
||||
}
|
||||
|
||||
old = component;
|
||||
component = new TextComponent(component);
|
||||
String urlString = message.substring(i, pos);
|
||||
component.setText(urlString);
|
||||
component.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, urlString.startsWith("http") ? urlString : "http://" + urlString));
|
||||
components.add(component);
|
||||
i += pos - i - 1;
|
||||
component = old;
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.length() > 0) {
|
||||
component.setText(builder.toString());
|
||||
components.add(component);
|
||||
}
|
||||
|
||||
if (components.isEmpty()) {
|
||||
components.add(new TextComponent(""));
|
||||
}
|
||||
|
||||
return components.toArray(new BaseComponent[0]);
|
||||
}
|
||||
|
||||
public TextComponent() {
|
||||
this.text = "";
|
||||
}
|
||||
|
||||
public TextComponent(TextComponent textComponent) {
|
||||
super(textComponent);
|
||||
this.setText(textComponent.getText());
|
||||
}
|
||||
|
||||
public TextComponent(BaseComponent... extras) {
|
||||
this.setText("");
|
||||
this.setExtra(new ArrayList(Arrays.asList(extras)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent duplicate() {
|
||||
return new TextComponent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder) {
|
||||
builder.append(this.text);
|
||||
super.toPlainText(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder) {
|
||||
builder.append(this.getColor());
|
||||
if (this.isBold()) {
|
||||
builder.append(ChatColor.BOLD);
|
||||
}
|
||||
|
||||
if (this.isItalic()) {
|
||||
builder.append(ChatColor.ITALIC);
|
||||
}
|
||||
|
||||
if (this.isUnderlined()) {
|
||||
builder.append(ChatColor.UNDERLINE);
|
||||
}
|
||||
|
||||
if (this.isStrikethrough()) {
|
||||
builder.append(ChatColor.STRIKETHROUGH);
|
||||
}
|
||||
|
||||
if (this.isObfuscated()) {
|
||||
builder.append(ChatColor.MAGIC);
|
||||
}
|
||||
|
||||
builder.append(this.text);
|
||||
super.toLegacyText(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("TextComponent{text=%s, %s}", this.text, super.toString());
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@ConstructorProperties({"text"})
|
||||
public TextComponent(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.ilummc.tlib.bungee.api.chat;
|
||||
|
||||
import com.ilummc.tlib.bungee.api.ChatColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public final class TranslatableComponent extends BaseComponent {
|
||||
|
||||
private final ResourceBundle locales = ResourceBundle.getBundle("mojang-translations/en_US");
|
||||
private final Pattern format = Pattern.compile("%(?:(\\d+)\\$)?([A-Za-z%]|$)");
|
||||
|
||||
/**
|
||||
* The key into the Minecraft locale files to use for the translation. The
|
||||
* text depends on the client's locale setting. The console is always en_US
|
||||
*/
|
||||
private String translate;
|
||||
/**
|
||||
* The components to substitute into the translation
|
||||
*/
|
||||
private List<BaseComponent> with;
|
||||
|
||||
public ResourceBundle getLocales() {
|
||||
return locales;
|
||||
}
|
||||
|
||||
public Pattern getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public String getTranslate() {
|
||||
return translate;
|
||||
}
|
||||
|
||||
public void setTranslate(String translate) {
|
||||
this.translate = translate;
|
||||
}
|
||||
|
||||
public List<BaseComponent> getWith() {
|
||||
return with;
|
||||
}
|
||||
|
||||
public TranslatableComponent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a translatable component from the original to clone it.
|
||||
*
|
||||
* @param original the original for the new translatable component.
|
||||
*/
|
||||
public TranslatableComponent(TranslatableComponent original) {
|
||||
super(original);
|
||||
setTranslate(original.getTranslate());
|
||||
|
||||
if (original.getWith() != null) {
|
||||
setWith(original.getWith().stream().map(BaseComponent::duplicate).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a translatable component with the passed substitutions
|
||||
*
|
||||
* @param translate the translation key
|
||||
* @param with the {@link java.lang.String}s and
|
||||
* {@link BaseComponent}s to use into the
|
||||
* translation
|
||||
* @see #translate
|
||||
* @see #setWith(java.util.List)
|
||||
*/
|
||||
public TranslatableComponent(String translate, Object... with) {
|
||||
setTranslate(translate);
|
||||
if (with != null && with.length != 0) {
|
||||
List<BaseComponent> temp = new ArrayList<>();
|
||||
for (Object w : with) {
|
||||
if (w instanceof String) {
|
||||
temp.add(new TextComponent((String) w));
|
||||
} else {
|
||||
temp.add((BaseComponent) w);
|
||||
}
|
||||
}
|
||||
setWith(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a duplicate of this TranslatableComponent.
|
||||
*
|
||||
* @return the duplicate of this TranslatableComponent.
|
||||
*/
|
||||
@Override
|
||||
public BaseComponent duplicate() {
|
||||
return new TranslatableComponent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "locales=" + "TranslatableComponent{" + locales + ", format=" + format + ", translate='" + translate + '\'' + ", with=" + with + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the translation substitutions to be used in this component. Removes
|
||||
* any previously set substitutions
|
||||
*
|
||||
* @param components the components to substitute
|
||||
*/
|
||||
public void setWith(List<BaseComponent> components) {
|
||||
components.forEach(component -> component.parent = this);
|
||||
with = components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a text substitution to the component. The text will inherit this
|
||||
* component's formatting
|
||||
*
|
||||
* @param text the text to substitute
|
||||
*/
|
||||
public void addWith(String text) {
|
||||
addWith(new TextComponent(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a component substitution to the component. The text will inherit
|
||||
* this component's formatting
|
||||
*
|
||||
* @param component the component to substitute
|
||||
*/
|
||||
public void addWith(BaseComponent component) {
|
||||
if (with == null) {
|
||||
with = new ArrayList<>();
|
||||
}
|
||||
component.parent = this;
|
||||
with.add(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder) {
|
||||
String trans;
|
||||
try {
|
||||
trans = locales.getString(translate);
|
||||
} catch (MissingResourceException ex) {
|
||||
trans = translate;
|
||||
}
|
||||
|
||||
Matcher matcher = format.matcher(trans);
|
||||
int position = 0;
|
||||
int i = 0;
|
||||
while (matcher.find(position)) {
|
||||
int pos = matcher.start();
|
||||
if (pos != position) {
|
||||
builder.append(trans, position, pos);
|
||||
}
|
||||
position = matcher.end();
|
||||
|
||||
String formatCode = matcher.group(2);
|
||||
switch (formatCode.charAt(0)) {
|
||||
case 's':
|
||||
case 'd':
|
||||
String withIndex = matcher.group(1);
|
||||
with.get(withIndex != null ? Integer.parseInt(withIndex) - 1 : i++).toPlainText(builder);
|
||||
break;
|
||||
case '%':
|
||||
builder.append('%');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trans.length() != position) {
|
||||
builder.append(trans, position, trans.length());
|
||||
}
|
||||
super.toPlainText(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder) {
|
||||
String trans;
|
||||
try {
|
||||
trans = locales.getString(translate);
|
||||
} catch (MissingResourceException e) {
|
||||
trans = translate;
|
||||
}
|
||||
|
||||
Matcher matcher = format.matcher(trans);
|
||||
int position = 0;
|
||||
int i = 0;
|
||||
while (matcher.find(position)) {
|
||||
int pos = matcher.start();
|
||||
if (pos != position) {
|
||||
addFormat(builder);
|
||||
builder.append(trans, position, pos);
|
||||
}
|
||||
position = matcher.end();
|
||||
|
||||
String formatCode = matcher.group(2);
|
||||
switch (formatCode.charAt(0)) {
|
||||
case 's':
|
||||
case 'd':
|
||||
String withIndex = matcher.group(1);
|
||||
with.get(withIndex != null ? Integer.parseInt(withIndex) - 1 : i++).toLegacyText(builder);
|
||||
break;
|
||||
case '%':
|
||||
addFormat(builder);
|
||||
builder.append('%');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trans.length() != position) {
|
||||
addFormat(builder);
|
||||
builder.append(trans, position, trans.length());
|
||||
}
|
||||
super.toLegacyText(builder);
|
||||
}
|
||||
|
||||
private void addFormat(StringBuilder builder) {
|
||||
builder.append(getColor());
|
||||
if (isBold()) {
|
||||
builder.append(ChatColor.BOLD);
|
||||
}
|
||||
if (isItalic()) {
|
||||
builder.append(ChatColor.ITALIC);
|
||||
}
|
||||
if (isUnderlined()) {
|
||||
builder.append(ChatColor.UNDERLINE);
|
||||
}
|
||||
if (isStrikethrough()) {
|
||||
builder.append(ChatColor.STRIKETHROUGH);
|
||||
}
|
||||
if (isObfuscated()) {
|
||||
builder.append(ChatColor.MAGIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.ilummc.tlib.bungee.chat;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.ilummc.tlib.bungee.api.ChatColor;
|
||||
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
|
||||
import com.ilummc.tlib.bungee.api.chat.ClickEvent;
|
||||
import com.ilummc.tlib.bungee.api.chat.HoverEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public class BaseComponentSerializer {
|
||||
|
||||
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context) {
|
||||
if (object.has("color")) {
|
||||
component.setColor(ChatColor.valueOf(object.get("color").getAsString().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
if (object.has("bold")) {
|
||||
component.setBold(object.get("bold").getAsBoolean());
|
||||
}
|
||||
if (object.has("italic")) {
|
||||
component.setItalic(object.get("italic").getAsBoolean());
|
||||
}
|
||||
if (object.has("underlined")) {
|
||||
component.setUnderlined(object.get("underlined").getAsBoolean());
|
||||
}
|
||||
if (object.has("strikethrough")) {
|
||||
component.setStrikethrough(object.get("strikethrough").getAsBoolean());
|
||||
}
|
||||
if (object.has("obfuscated")) {
|
||||
component.setObfuscated(object.get("obfuscated").getAsBoolean());
|
||||
}
|
||||
if (object.has("insertion")) {
|
||||
component.setInsertion(object.get("insertion").getAsString());
|
||||
}
|
||||
if (object.has("extra")) {
|
||||
component.setExtra(Arrays.asList(context.<BaseComponent[]>deserialize(object.get("extra"), BaseComponent[].class)));
|
||||
}
|
||||
|
||||
//Events
|
||||
if (object.has("clickEvent")) {
|
||||
JsonObject event = object.getAsJsonObject("clickEvent");
|
||||
component.setClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.valueOf(event.get("action").getAsString().toUpperCase(Locale.ROOT)),
|
||||
event.get("value").getAsString()));
|
||||
}
|
||||
if (object.has("hoverEvent")) {
|
||||
JsonObject event = object.getAsJsonObject("hoverEvent");
|
||||
BaseComponent[] res;
|
||||
if (event.get("value").isJsonArray()) {
|
||||
res = context.deserialize(event.get("value"), BaseComponent[].class);
|
||||
} else {
|
||||
res = new BaseComponent[]{context.deserialize(event.get("value"), BaseComponent.class)};
|
||||
}
|
||||
component.setHoverEvent(new HoverEvent(HoverEvent.Action.valueOf(event.get("action").getAsString().toUpperCase(Locale.ROOT)), res));
|
||||
}
|
||||
}
|
||||
|
||||
protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context) {
|
||||
boolean first = false;
|
||||
if (ComponentSerializer.serializedComponents.get() == null) {
|
||||
first = true;
|
||||
ComponentSerializer.serializedComponents.set(new HashSet<>());
|
||||
}
|
||||
try {
|
||||
Preconditions.checkArgument(!ComponentSerializer.serializedComponents.get().contains(component), "Component loop");
|
||||
ComponentSerializer.serializedComponents.get().add(component);
|
||||
if (component.getColorRaw() != null) {
|
||||
object.addProperty("color", component.getColorRaw().getName());
|
||||
}
|
||||
if (component.isBoldRaw() != null) {
|
||||
object.addProperty("bold", component.isBoldRaw());
|
||||
}
|
||||
if (component.isItalicRaw() != null) {
|
||||
object.addProperty("italic", component.isItalicRaw());
|
||||
}
|
||||
if (component.isUnderlinedRaw() != null) {
|
||||
object.addProperty("underlined", component.isUnderlinedRaw());
|
||||
}
|
||||
if (component.isStrikethroughRaw() != null) {
|
||||
object.addProperty("strikethrough", component.isStrikethroughRaw());
|
||||
}
|
||||
if (component.isObfuscatedRaw() != null) {
|
||||
object.addProperty("obfuscated", component.isObfuscatedRaw());
|
||||
}
|
||||
if (component.getInsertion() != null) {
|
||||
object.addProperty("insertion", component.getInsertion());
|
||||
}
|
||||
|
||||
if (component.getExtra() != null) {
|
||||
object.add("extra", context.serialize(component.getExtra()));
|
||||
}
|
||||
|
||||
//Events
|
||||
if (component.getClickEvent() != null) {
|
||||
JsonObject clickEvent = new JsonObject();
|
||||
clickEvent.addProperty("action", component.getClickEvent().getAction().toString().toLowerCase(Locale.ROOT));
|
||||
clickEvent.addProperty("value", component.getClickEvent().getValue());
|
||||
object.add("clickEvent", clickEvent);
|
||||
}
|
||||
if (component.getHoverEvent() != null) {
|
||||
JsonObject hoverEvent = new JsonObject();
|
||||
hoverEvent.addProperty("action", component.getHoverEvent().getAction().toString().toLowerCase(Locale.ROOT));
|
||||
hoverEvent.add("value", context.serialize(component.getHoverEvent().getValue()));
|
||||
object.add("hoverEvent", hoverEvent);
|
||||
}
|
||||
} finally {
|
||||
ComponentSerializer.serializedComponents.get().remove(component);
|
||||
if (first) {
|
||||
ComponentSerializer.serializedComponents.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.ilummc.tlib.bungee.chat;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
|
||||
import com.ilummc.tlib.bungee.api.chat.TextComponent;
|
||||
import com.ilummc.tlib.bungee.api.chat.TranslatableComponent;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public class ComponentSerializer implements JsonDeserializer<BaseComponent> {
|
||||
|
||||
private final static JsonParser JSON_PARSER = new JsonParser();
|
||||
private final static Gson gson = new GsonBuilder().
|
||||
registerTypeAdapter(BaseComponent.class, new ComponentSerializer()).
|
||||
registerTypeAdapter(TextComponent.class, new TextComponentSerializer()).
|
||||
registerTypeAdapter(TranslatableComponent.class, new TranslatableComponentSerializer()).
|
||||
create();
|
||||
|
||||
public final static ThreadLocal<HashSet<BaseComponent>> serializedComponents = new ThreadLocal<>();
|
||||
|
||||
public static BaseComponent[] parse(String json) {
|
||||
JsonElement jsonElement = JSON_PARSER.parse(json);
|
||||
|
||||
if (jsonElement.isJsonArray()) {
|
||||
return gson.fromJson(jsonElement, BaseComponent[].class);
|
||||
} else {
|
||||
return new BaseComponent[]{gson.fromJson(jsonElement, BaseComponent.class)};
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent component) {
|
||||
return gson.toJson(component);
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent... components) {
|
||||
if (components.length == 1) {
|
||||
return gson.toJson(components[0]);
|
||||
} else {
|
||||
return gson.toJson(new TextComponent(components));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (json.isJsonPrimitive()) {
|
||||
return new TextComponent(json.getAsString());
|
||||
}
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
if (object.has("translate")) {
|
||||
return context.deserialize(json, TranslatableComponent.class);
|
||||
}
|
||||
return context.deserialize(json, TextComponent.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
package com.ilummc.tlib.bungee.chat;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.ilummc.tlib.bungee.api.chat.*;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public class TextComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TextComponent>, JsonDeserializer<TextComponent> {
|
||||
|
||||
public TextComponentSerializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
TextComponent component = new TextComponent();
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
this.deserialize(object, component, context);
|
||||
component.setText(object.get("text").getAsString());
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(TextComponent src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
List<BaseComponent> extra = src.getExtra();
|
||||
JsonObject object = new JsonObject();
|
||||
if (src.hasFormatting() || extra != null && !extra.isEmpty()) {
|
||||
this.serialize(object, src, context);
|
||||
}
|
||||
object.addProperty("text", src.getText());
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
package com.ilummc.tlib.bungee.chat;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
|
||||
import com.ilummc.tlib.bungee.api.chat.TranslatableComponent;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author md_5
|
||||
*/
|
||||
public class TranslatableComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TranslatableComponent>, JsonDeserializer<TranslatableComponent> {
|
||||
|
||||
public TranslatableComponentSerializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslatableComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
TranslatableComponent component = new TranslatableComponent();
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
this.deserialize(object, component, context);
|
||||
component.setTranslate(object.get("translate").getAsString());
|
||||
if (object.has("with")) {
|
||||
component.setWith(Arrays.asList((BaseComponent[]) context.deserialize(object.get("with"), BaseComponent[].class)));
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(TranslatableComponent src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject object = new JsonObject();
|
||||
this.serialize(object, src, context);
|
||||
object.addProperty("translate", src.getTranslate());
|
||||
if (src.getWith() != null) {
|
||||
object.add("with", context.serialize(src.getWith()));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,11 @@ public abstract class PlaceholderHook {
|
||||
private static PlaceholderHook impl;
|
||||
|
||||
public static void init() {
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null)
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
impl = new PlaceholderImpl();
|
||||
else impl = new AbstractImpl();
|
||||
} else {
|
||||
impl = new AbstractImpl();
|
||||
}
|
||||
}
|
||||
|
||||
public static String replace(CommandSender sender, String text) {
|
||||
|
||||
@@ -55,7 +55,9 @@ public final class Pool extends ThreadPoolExecutor {
|
||||
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
if (t != null) Base.close();
|
||||
if (t != null) {
|
||||
Base.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.ilummc.tlib.filter;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Filter;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* @author Bkm016
|
||||
* @since 2018-04-22
|
||||
@@ -27,6 +27,9 @@ public class TLoggerFilter implements Filter {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (e.getMessage().contains("Enabled plugin with unregistered PluginClassLoader")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,10 +55,17 @@ public class TConfigInjector {
|
||||
TConfig config = clazz.getAnnotation(TConfig.class);
|
||||
Validate.notNull(config);
|
||||
File file = new File(plugin.getDataFolder(), config.name());
|
||||
if (!file.exists()) if (config.fromJar()) plugin.saveResource(config.name(), true);
|
||||
else saveConfig(plugin, clazz.newInstance());
|
||||
if (!file.exists()) {
|
||||
if (config.fromJar()) {
|
||||
plugin.saveResource(config.name(), true);
|
||||
} else {
|
||||
saveConfig(plugin, clazz.newInstance());
|
||||
}
|
||||
}
|
||||
Object obj = unserialize(plugin, clazz);
|
||||
if (config.readOnly()) saveConfig(plugin, obj);
|
||||
if (config.readOnly()) {
|
||||
saveConfig(plugin, obj);
|
||||
}
|
||||
return obj;
|
||||
} catch (NullPointerException e) {
|
||||
TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), clazz.getSimpleName());
|
||||
@@ -75,7 +82,9 @@ public class TConfigInjector {
|
||||
File file = new File(plugin.getDataFolder(), config.name());
|
||||
Map<String, Object> map = ConfigUtils.confToMap(ConfigUtils.loadYaml(plugin, file));
|
||||
Object obj = ConfigUtils.mapToObj(map, object);
|
||||
if (config.readOnly()) saveConfig(plugin, obj);
|
||||
if (config.readOnly()) {
|
||||
saveConfig(plugin, obj);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), object.getClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
@@ -124,7 +133,9 @@ public class TConfigInjector {
|
||||
Map map = gson.fromJson(gson.toJson(object), HashMap.class);
|
||||
YamlConfiguration configuration = (YamlConfiguration) ConfigUtils.mapToConf(map);
|
||||
File target = new File(plugin.getDataFolder(), config.name());
|
||||
if (!target.exists()) target.createNewFile();
|
||||
if (!target.exists()) {
|
||||
target.createNewFile();
|
||||
}
|
||||
byte[] arr = configuration.saveToString().getBytes(config.charset());
|
||||
Files.write(arr, target);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ilummc.tlib.inject;
|
||||
|
||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
|
||||
import java.io.File;
|
||||
@@ -10,12 +11,16 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author lzzelAliz
|
||||
*/
|
||||
public class TConfigWatcher {
|
||||
|
||||
private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
|
||||
private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("tconfig-watcher-schedule-pool-%d").daemon(true).build());
|
||||
|
||||
private final Map<WatchService, Triple<File, Object, Consumer<Object>>> map = new HashMap<>();
|
||||
|
||||
@@ -24,8 +29,9 @@ public class TConfigWatcher {
|
||||
WatchKey key;
|
||||
while ((key = service.poll()) != null) {
|
||||
for (WatchEvent<?> watchEvent : key.pollEvents()) {
|
||||
if (triple.getLeft().getName().equals(Objects.toString(watchEvent.context())))
|
||||
if (triple.getLeft().getName().equals(Objects.toString(watchEvent.context()))) {
|
||||
triple.getRight().accept(triple.getMiddle());
|
||||
}
|
||||
}
|
||||
key.reset();
|
||||
}
|
||||
|
||||
@@ -96,8 +96,9 @@ public class TDependencyInjector {
|
||||
if ((logger = field.getAnnotation(Logger.class)) != null) {
|
||||
field.getType().asSubclass(com.ilummc.tlib.logger.TLogger.class);
|
||||
com.ilummc.tlib.logger.TLogger tLogger = new com.ilummc.tlib.logger.TLogger(logger.value(), plugin, logger.level());
|
||||
if (!field.isAccessible())
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
field.set(o, tLogger);
|
||||
TLoggerManager.setDefaultLogger(plugin, tLogger);
|
||||
}
|
||||
@@ -111,8 +112,9 @@ public class TDependencyInjector {
|
||||
try {
|
||||
PluginInstance instance;
|
||||
if ((instance = field.getAnnotation(PluginInstance.class)) != null) {
|
||||
if (!field.isAccessible())
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
field.getType().asSubclass(JavaPlugin.class);
|
||||
Plugin pl;
|
||||
if ((pl = Bukkit.getPluginManager().getPlugin(instance.value())) == null) {
|
||||
@@ -123,8 +125,9 @@ public class TDependencyInjector {
|
||||
pl = Bukkit.getPluginManager().getPlugin(instance.value());
|
||||
}
|
||||
}
|
||||
if (pl != null)
|
||||
if (pl != null) {
|
||||
field.set(o, pl);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
@@ -104,7 +104,9 @@ public class TPluginManager implements PluginManager {
|
||||
@Override
|
||||
public void disablePlugins() {
|
||||
for (Plugin plugin : getPlugins()) {
|
||||
if (plugin != main) disablePlugin(plugin);
|
||||
if (plugin != main) {
|
||||
disablePlugin(plugin);
|
||||
}
|
||||
}
|
||||
disablePlugin(main);
|
||||
}
|
||||
|
||||
@@ -42,38 +42,45 @@ public class TLogger {
|
||||
}
|
||||
|
||||
public void verbose(String msg) {
|
||||
if (level <= VERBOSE)
|
||||
if (level <= VERBOSE) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§f全部", ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public void finest(String msg) {
|
||||
if (level <= FINEST)
|
||||
if (level <= FINEST) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§e良好", ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public void fine(String msg) {
|
||||
if (level <= FINE)
|
||||
if (level <= FINE) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§a正常", ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public void info(String msg) {
|
||||
if (level <= INFO)
|
||||
if (level <= INFO) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§b信息", ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public void warn(String msg) {
|
||||
if (level <= WARN)
|
||||
if (level <= WARN) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§6警告", "§6" + ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public void error(String msg) {
|
||||
if (level <= ERROR)
|
||||
if (level <= ERROR) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§c错误", "§c" + ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public void fatal(String msg) {
|
||||
if (level <= FATAL)
|
||||
if (level <= FATAL) {
|
||||
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§4致命错误", "§4" + ChatColor.translateAlternateColorCodes('&', msg)));
|
||||
}
|
||||
}
|
||||
|
||||
public static TLogger getUnformatted(Plugin plugin) {
|
||||
|
||||
@@ -47,8 +47,8 @@ public class TLocale {
|
||||
try {
|
||||
return asString(path, Ref.getCallerClassNotOptional(3), args);
|
||||
} catch (Exception e) {
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("FETCH-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage()));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("FETCH-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage()));
|
||||
return "§4<" + path + "§4>";
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,8 @@ public class TLocale {
|
||||
try {
|
||||
return asStringList(path, Ref.getCallerClassNotOptional(3), args);
|
||||
} catch (Exception e) {
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("FETCH-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage()));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("FETCH-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage()));
|
||||
return Collections.singletonList("§4<" + path + "§4>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ class TLocaleInstance {
|
||||
}
|
||||
});
|
||||
} catch (Exception | Error e) {
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("SEND-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.toString()));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("SEND-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.toString()));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,10 +37,12 @@ public class TLocaleLoader {
|
||||
}
|
||||
|
||||
public static void sendTo(Plugin plugin, String path, CommandSender sender, String... args) {
|
||||
if (Bukkit.isPrimaryThread())
|
||||
Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args));
|
||||
else synchronized (TLocaleLoader.class) {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args));
|
||||
} else {
|
||||
synchronized (TLocaleLoader.class) {
|
||||
Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,9 @@ public class TLocaleActionBar implements TLocaleSendable, ConfigurationSerializa
|
||||
|
||||
@Override
|
||||
public void sendTo(CommandSender sender, String... args) {
|
||||
if (sender instanceof Player)
|
||||
if (sender instanceof Player) {
|
||||
ActionBar.sendActionBar(((Player) sender), replace(sender, text, args));
|
||||
}
|
||||
}
|
||||
|
||||
private String replace(CommandSender sender, String text, String[] args) {
|
||||
|
||||
@@ -4,13 +4,13 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.ilummc.tlib.TLib;
|
||||
import com.ilummc.tlib.bungee.api.chat.*;
|
||||
import com.ilummc.tlib.bungee.chat.ComponentSerializer;
|
||||
import com.ilummc.tlib.compat.PlaceholderHook;
|
||||
import com.ilummc.tlib.resources.TLocaleSendable;
|
||||
import com.ilummc.tlib.util.Strings;
|
||||
import me.skymc.taboolib.Main;
|
||||
import me.skymc.taboolib.jsonformatter.JSONFormatter;
|
||||
import net.md_5.bungee.api.chat.*;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
@@ -52,7 +52,9 @@ public class TLocaleJson implements TLocaleSendable, ConfigurationSerializable {
|
||||
List<BaseComponent> builder = template.length > index ? new ArrayList<>(Arrays.asList(TextComponent.fromLegacyText(template[index++]))) : new ArrayList<>();
|
||||
while (matcher.find()) {
|
||||
String replace = matcher.group();
|
||||
if (replace.length() <= 2) continue;
|
||||
if (replace.length() <= 2) {
|
||||
continue;
|
||||
}
|
||||
replace = replace.substring(1, replace.length() - 1);
|
||||
String[] split = replace.split("@");
|
||||
String text = split.length > 1 ? split[0] : "";
|
||||
@@ -73,7 +75,7 @@ public class TLocaleJson implements TLocaleSendable, ConfigurationSerializable {
|
||||
builder.addAll(Arrays.asList(component));
|
||||
} else {
|
||||
builder.addAll(Arrays.asList(TextComponent.fromLegacyText(text)));
|
||||
TLib.getTLib().getLogger().warn(Strings.replaceWithOrder(TLib.getTLib().getInternalLanguage().getString("MISSING-ARGUMENT"), node));
|
||||
TLib.getTLib().getLogger().warn(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("MISSING-ARGUMENT"), node));
|
||||
}
|
||||
if (index < template.length) {
|
||||
builder.addAll(Arrays.asList(TextComponent.fromLegacyText(template[index++])));
|
||||
|
||||
@@ -37,11 +37,14 @@ public class Ref {
|
||||
try {
|
||||
|
||||
// 特殊判断
|
||||
if (clazz == TLib.class)
|
||||
if (clazz == TLib.class) {
|
||||
return Arrays.asList(clazz.getDeclaredFields());
|
||||
}
|
||||
|
||||
List<Field> fields;
|
||||
if ((fields = cachedFields.get(clazz.getName())) != null) return fields;
|
||||
if ((fields = cachedFields.get(clazz.getName())) != null) {
|
||||
return fields;
|
||||
}
|
||||
ClassReader classReader = new ClassReader(clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class"));
|
||||
AsmAnalyser analyser = new AsmAnalyser(new ClassWriter(ClassWriter.COMPUTE_MAXS), excludeModifiers);
|
||||
classReader.accept(analyser, ClassReader.SKIP_DEBUG);
|
||||
@@ -52,7 +55,9 @@ public class Ref {
|
||||
return null;
|
||||
}
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (cache) cachedFields.putIfAbsent(clazz.getName(), fields);
|
||||
if (cache) {
|
||||
cachedFields.putIfAbsent(clazz.getName(), fields);
|
||||
}
|
||||
return fields;
|
||||
} catch (Exception | Error e) {
|
||||
try {
|
||||
@@ -80,9 +85,13 @@ public class Ref {
|
||||
|
||||
public static Optional<Field> getFieldBySerializedName(Class<?> clazz, String name) {
|
||||
for (Field field : Ref.getDeclaredFields(clazz, 0, false)) {
|
||||
if (field.isAnnotationPresent(SerializedName.class))
|
||||
if (field.getAnnotation(SerializedName.class).value().equals(name)) return Optional.of(field);
|
||||
else if (field.getName().equals(name)) return Optional.of(field);
|
||||
if (field.isAnnotationPresent(SerializedName.class)) {
|
||||
if (field.getAnnotation(SerializedName.class).value().equals(name)) {
|
||||
return Optional.of(field);
|
||||
} else if (field.getName().equals(name)) {
|
||||
return Optional.of(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ public class Strings {
|
||||
* @param args 替换的参数
|
||||
* @return 替换好的字符串
|
||||
*/
|
||||
public static String replaceWithOrder(String template, String... args) {
|
||||
if (args.length == 0 || template.length() == 0) return template;
|
||||
public static String replaceWithOrder(String template, Object... args) {
|
||||
if (args.length == 0 || template.length() == 0) {
|
||||
return template;
|
||||
}
|
||||
char[] arr = template.toCharArray();
|
||||
StringBuilder stringBuilder = new StringBuilder(template.length());
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
@@ -19,8 +21,9 @@ public class Strings {
|
||||
&& arr[Math.min(i + 2, arr.length - 1)] == '}') {
|
||||
stringBuilder.append(args[arr[i + 1] - '0']);
|
||||
i += 2;
|
||||
} else
|
||||
} else {
|
||||
stringBuilder.append(arr[i]);
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ public class AsmAnalyser extends ClassVisitor implements Opcodes {
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||
if ((access & excludeModifier) == 0)
|
||||
if ((access & excludeModifier) == 0) {
|
||||
fields.add(name);
|
||||
}
|
||||
return super.visitField(access, name, descriptor, signature, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,11 +68,13 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
}
|
||||
|
||||
private String replace(String text) {
|
||||
if (text != null)
|
||||
if (text != null) {
|
||||
return text.replace("net/minecraft/server/" + fromVer, "net/minecraft/server/" + toVer)
|
||||
.replace("org/bukkit/craftbukkit/" + fromVer, "org/bukkit/craftbukkit/" + toVer)
|
||||
.replace(prevName, newClassName.replace('.', '/'));
|
||||
else return null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String[] replace(String[] text) {
|
||||
@@ -81,7 +83,9 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
text[i] = replace(text[i]);
|
||||
}
|
||||
return text;
|
||||
} else return null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,9 +107,11 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object value) {
|
||||
if (value instanceof String)
|
||||
if (value instanceof String) {
|
||||
super.visitLdcInsn(replace((String) value));
|
||||
else super.visitLdcInsn(value);
|
||||
} else {
|
||||
super.visitLdcInsn(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user