Move chat API into own submodule.
This commit is contained in:
191
chat/src/main/java/net/md_5/bungee/api/ChatColor.java
Normal file
191
chat/src/main/java/net/md_5/bungee/api/ChatColor.java
Normal file
@@ -0,0 +1,191 @@
|
||||
package net.md_5.bungee.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Simplistic enumeration of all supported color values for chat.
|
||||
*/
|
||||
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<>();
|
||||
/**
|
||||
* 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;
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
static
|
||||
{
|
||||
for ( ChatColor colour : values() )
|
||||
{
|
||||
BY_CHAR.put( colour.code, colour );
|
||||
}
|
||||
}
|
||||
|
||||
private 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 );
|
||||
}
|
||||
}
|
391
chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java
Normal file
391
chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java
Normal file
@@ -0,0 +1,391 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.ToString;
|
||||
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
public abstract class BaseComponent
|
||||
{
|
||||
|
||||
@Setter(AccessLevel.NONE)
|
||||
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;
|
||||
|
||||
/**
|
||||
* Appended components that inherit this component's formatting and events
|
||||
*/
|
||||
@Getter
|
||||
private List<BaseComponent> extra;
|
||||
|
||||
/**
|
||||
* The action to preform when this component (and child components) are
|
||||
* clicked
|
||||
*/
|
||||
@Getter
|
||||
private ClickEvent clickEvent;
|
||||
/**
|
||||
* The action to preform when this component (and child components) are
|
||||
* hovered over
|
||||
*/
|
||||
@Getter
|
||||
private HoverEvent hoverEvent;
|
||||
|
||||
BaseComponent(BaseComponent old)
|
||||
{
|
||||
setColor( old.getColorRaw() );
|
||||
setBold( old.isBoldRaw() );
|
||||
setItalic( old.isItalicRaw() );
|
||||
setUnderlined( old.isUnderlinedRaw() );
|
||||
setStrikethrough( old.isStrikethroughRaw() );
|
||||
setObfuscated( old.isObfuscatedRaw() );
|
||||
setClickEvent( old.getClickEvent() );
|
||||
setHoverEvent( old.getHoverEvent() );
|
||||
if ( extra != null )
|
||||
{
|
||||
for ( BaseComponent component : extra )
|
||||
{
|
||||
addExtra( component.duplicate() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the BaseComponent and returns the clone.
|
||||
*
|
||||
* @return The duplicate of this BaseComponent
|
||||
*/
|
||||
public abstract BaseComponent duplicate();
|
||||
|
||||
/**
|
||||
* Converts the components to a string that uses the old formatting codes
|
||||
* ({@link net.md_5.bungee.api.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 net.md_5.bungee.api.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)
|
||||
{
|
||||
for ( BaseComponent component : components )
|
||||
{
|
||||
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 || bold != null
|
||||
|| italic != null || underlined != null
|
||||
|| strikethrough != null || obfuscated != 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 )
|
||||
{
|
||||
for ( BaseComponent e : extra )
|
||||
{
|
||||
e.toPlainText( builder );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the component to a string that uses the old formatting codes
|
||||
* ({@link net.md_5.bungee.api.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 )
|
||||
{
|
||||
for ( BaseComponent e : extra )
|
||||
{
|
||||
e.toLegacyText( builder );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
Normal file
50
chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.chat.ClickEvent.Action;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class ClickEvent
|
||||
{
|
||||
|
||||
/**
|
||||
* The type of action to preform on click
|
||||
*/
|
||||
private final Action action;
|
||||
/**
|
||||
* Depends on action
|
||||
*
|
||||
* @see Action
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
public enum Action
|
||||
{
|
||||
|
||||
/**
|
||||
* Open a url at the path given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||
*/
|
||||
OPEN_URL,
|
||||
/**
|
||||
* Open a file at the path given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||
*/
|
||||
OPEN_FILE,
|
||||
/**
|
||||
* Run the command given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||
*/
|
||||
RUN_COMMAND,
|
||||
/**
|
||||
* Inserts the string given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the players
|
||||
* text box
|
||||
*/
|
||||
SUGGEST_COMMAND
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import net.md_5.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 net.md_5.bungee.api.ChatColor#RED} and "World" would be
|
||||
* {@link net.md_5.bungee.api.ChatColor#BLUE} but "!" would be bold and
|
||||
* {@link net.md_5.bungee.api.ChatColor#BLUE} because append copies the previous
|
||||
* part's formatting
|
||||
* </p>
|
||||
*/
|
||||
public class ComponentBuilder
|
||||
{
|
||||
|
||||
private TextComponent 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 = new TextComponent( original.current );
|
||||
for ( BaseComponent baseComponent : original.parts )
|
||||
{
|
||||
parts.add( baseComponent.duplicate() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text to the builder and makes it the current target for
|
||||
* formatting. The text will have all the formatting from the previous part.
|
||||
*
|
||||
* @param text the text to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(String text)
|
||||
{
|
||||
parts.add( current );
|
||||
current = new TextComponent( current );
|
||||
current.setText( text );
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the components needed to display the message created by this
|
||||
* builder.
|
||||
*
|
||||
* @return the created components
|
||||
*/
|
||||
public BaseComponent[] create()
|
||||
{
|
||||
parts.add( current );
|
||||
return parts.toArray( new BaseComponent[ parts.size() ] );
|
||||
}
|
||||
}
|
23
chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
Normal file
23
chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
final public class HoverEvent
|
||||
{
|
||||
|
||||
private final Action action;
|
||||
private final BaseComponent[] value;
|
||||
|
||||
public enum Action
|
||||
{
|
||||
|
||||
SHOW_TEXT,
|
||||
SHOW_ACHIEVEMENT,
|
||||
SHOW_ITEM
|
||||
}
|
||||
}
|
213
chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java
Normal file
213
chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java
Normal file
@@ -0,0 +1,213 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TextComponent extends BaseComponent
|
||||
{
|
||||
|
||||
private static final Pattern url = Pattern.compile( "^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$" );
|
||||
|
||||
/**
|
||||
* Converts the old formatting system that used
|
||||
* {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based
|
||||
* system.
|
||||
*
|
||||
* @param message the text to convert
|
||||
* @return the components needed to print the message to the client
|
||||
*/
|
||||
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 );
|
||||
if ( c == ChatColor.COLOR_CHAR )
|
||||
{
|
||||
i++;
|
||||
c = message.charAt( i );
|
||||
if ( c >= 'A' && c <= 'Z' )
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
ChatColor format = ChatColor.getByChar( c );
|
||||
if ( format == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( builder.length() > 0 )
|
||||
{
|
||||
TextComponent old = component;
|
||||
component = new TextComponent( old );
|
||||
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;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int pos = message.indexOf( ' ', i );
|
||||
if ( pos == -1 )
|
||||
{
|
||||
pos = message.length();
|
||||
}
|
||||
if ( matcher.region( i, pos ).find() )
|
||||
{ //Web link handling
|
||||
|
||||
if ( builder.length() > 0 )
|
||||
{
|
||||
TextComponent old = component;
|
||||
component = new TextComponent( old );
|
||||
old.setText( builder.toString() );
|
||||
builder = new StringBuilder();
|
||||
components.add( old );
|
||||
}
|
||||
|
||||
TextComponent old = component;
|
||||
component = new TextComponent( old );
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
builder.append( c );
|
||||
}
|
||||
if ( builder.length() > 0 )
|
||||
{
|
||||
component.setText( builder.toString() );
|
||||
components.add( component );
|
||||
}
|
||||
|
||||
// The client will crash if the array is empty
|
||||
if ( components.isEmpty() )
|
||||
{
|
||||
components.add( new TextComponent( "" ) );
|
||||
}
|
||||
|
||||
return components.toArray( new BaseComponent[ components.size() ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* The text of the component that will be displayed to the client
|
||||
*/
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* Creates a TextComponent with formatting and text from the passed
|
||||
* component
|
||||
*
|
||||
* @param textComponent the component to copy from
|
||||
*/
|
||||
public TextComponent(TextComponent textComponent)
|
||||
{
|
||||
super( textComponent );
|
||||
setText( textComponent.getText() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TextComponent with blank text and the extras set to the passed
|
||||
* array
|
||||
*
|
||||
* @param extras the extras to set
|
||||
*/
|
||||
public TextComponent(BaseComponent... extras)
|
||||
{
|
||||
setText( "" );
|
||||
setExtra( Arrays.asList( extras ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a duplicate of this TextComponent.
|
||||
*
|
||||
* @return the duplicate of this TextComponent.
|
||||
*/
|
||||
@Override
|
||||
public BaseComponent duplicate()
|
||||
{
|
||||
return new TextComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
{
|
||||
builder.append( text );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(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 );
|
||||
}
|
||||
builder.append( text );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format( "TextComponent{text=%s, %s}", text, super.toString() );
|
||||
}
|
||||
}
|
@@ -0,0 +1,243 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.md_5.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 lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
public 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;
|
||||
|
||||
/**
|
||||
* 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() );
|
||||
for ( BaseComponent baseComponent : original.getWith() )
|
||||
{
|
||||
with.add( baseComponent.duplicate() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a translatable component with the passed substitutions
|
||||
*
|
||||
* @see #translate
|
||||
* @see #setWith(java.util.List)
|
||||
* @param translate the translation key
|
||||
* @param with the {@link java.lang.String}s and
|
||||
* {@link net.md_5.bungee.api.chat.BaseComponent}s to use into the
|
||||
* translation
|
||||
*/
|
||||
public TranslatableComponent(String translate, Object... with)
|
||||
{
|
||||
setTranslate( translate );
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
for ( BaseComponent component : components )
|
||||
{
|
||||
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)
|
||||
{
|
||||
try
|
||||
{
|
||||
String trans = locales.getString( 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.substring( 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;
|
||||
}
|
||||
}
|
||||
if ( trans.length() != position )
|
||||
{
|
||||
builder.append( trans.substring( position, trans.length() ) );
|
||||
}
|
||||
} catch ( MissingResourceException e )
|
||||
{
|
||||
builder.append( translate );
|
||||
}
|
||||
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
try
|
||||
{
|
||||
String trans = locales.getString( 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.substring( 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;
|
||||
}
|
||||
}
|
||||
if ( trans.length() != position )
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( trans.substring( position, trans.length() ) );
|
||||
}
|
||||
} catch ( MissingResourceException e )
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( translate );
|
||||
}
|
||||
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,141 @@
|
||||
package net.md_5.bungee.chat;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
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() ) );
|
||||
}
|
||||
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.setUnderlined( object.get( "strikethrough" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "obfuscated" ) )
|
||||
{
|
||||
component.setUnderlined( object.get( "obfuscated" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "extra" ) )
|
||||
{
|
||||
component.setExtra( Arrays.<BaseComponent>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() ),
|
||||
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.<BaseComponent>deserialize( event.get( "value" ), BaseComponent.class )
|
||||
};
|
||||
}
|
||||
component.setHoverEvent( new HoverEvent( HoverEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase() ), 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<BaseComponent>() );
|
||||
}
|
||||
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.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() );
|
||||
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() );
|
||||
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,64 @@
|
||||
package net.md_5.bungee.chat;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
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 net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
{
|
||||
|
||||
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)
|
||||
{
|
||||
if ( json.startsWith( "[" ) )
|
||||
{ //Array
|
||||
return gson.fromJson( json, BaseComponent[].class );
|
||||
}
|
||||
return new BaseComponent[]
|
||||
{
|
||||
gson.fromJson( json, BaseComponent.class )
|
||||
};
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent component)
|
||||
{
|
||||
return gson.toJson( component );
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent... components)
|
||||
{
|
||||
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,43 @@
|
||||
package net.md_5.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.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class TextComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TextComponent>, JsonDeserializer<TextComponent>
|
||||
{
|
||||
|
||||
@Override
|
||||
public TextComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
TextComponent component = new TextComponent();
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
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();
|
||||
if ( !src.hasFormatting() && ( extra == null || extra.isEmpty() ) )
|
||||
{
|
||||
return new JsonPrimitive( src.getText() );
|
||||
}
|
||||
JsonObject object = new JsonObject();
|
||||
serialize( object, src, context );
|
||||
object.addProperty( "text", src.getText() );
|
||||
return object;
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package net.md_5.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 net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TranslatableComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TranslatableComponent>, JsonDeserializer<TranslatableComponent>
|
||||
{
|
||||
|
||||
@Override
|
||||
public TranslatableComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
TranslatableComponent component = new TranslatableComponent();
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
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();
|
||||
serialize( object, src, context );
|
||||
object.addProperty( "translate", src.getTranslate() );
|
||||
if ( src.getWith() != null )
|
||||
{
|
||||
object.add( "with", context.serialize( src.getWith() ) );
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user