Minecraft 1.16 support + RGB ChatColor preview

This commit is contained in:
md_5
2020-06-24 07:00:00 +10:00
parent 2f54c94372
commit d0fd673b60
36 changed files with 760 additions and 227 deletions

View File

@@ -1,122 +1,126 @@
package net.md_5.bungee.api;
import com.google.common.base.Preconditions;
import java.awt.Color;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import lombok.Getter;
/**
* Simplistic enumeration of all supported color values for chat.
*/
public enum ChatColor
public final class 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";
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRrXx";
/**
* Pattern to remove all colour codes.
*/
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-OR]" );
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-ORX]" );
/**
* 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.
* Colour instances keyed by their name.
*/
private final char code;
private static final Map<String, ChatColor> BY_NAME = new HashMap<String, ChatColor>();
/**
* Represents black.
*/
public static final ChatColor BLACK = new ChatColor( '0', "black" );
/**
* Represents dark blue.
*/
public static final ChatColor DARK_BLUE = new ChatColor( '1', "dark_blue" );
/**
* Represents dark green.
*/
public static final ChatColor DARK_GREEN = new ChatColor( '2', "dark_green" );
/**
* Represents dark blue (aqua).
*/
public static final ChatColor DARK_AQUA = new ChatColor( '3', "dark_aqua" );
/**
* Represents dark red.
*/
public static final ChatColor DARK_RED = new ChatColor( '4', "dark_red" );
/**
* Represents dark purple.
*/
public static final ChatColor DARK_PURPLE = new ChatColor( '5', "dark_purple" );
/**
* Represents gold.
*/
public static final ChatColor GOLD = new ChatColor( '6', "gold" );
/**
* Represents gray.
*/
public static final ChatColor GRAY = new ChatColor( '7', "gray" );
/**
* Represents dark gray.
*/
public static final ChatColor DARK_GRAY = new ChatColor( '8', "dark_gray" );
/**
* Represents blue.
*/
public static final ChatColor BLUE = new ChatColor( '9', "blue" );
/**
* Represents green.
*/
public static final ChatColor GREEN = new ChatColor( 'a', "green" );
/**
* Represents aqua.
*/
public static final ChatColor AQUA = new ChatColor( 'b', "aqua" );
/**
* Represents red.
*/
public static final ChatColor RED = new ChatColor( 'c', "red" );
/**
* Represents light purple.
*/
public static final ChatColor LIGHT_PURPLE = new ChatColor( 'd', "light_purple" );
/**
* Represents yellow.
*/
public static final ChatColor YELLOW = new ChatColor( 'e', "yellow" );
/**
* Represents white.
*/
public static final ChatColor WHITE = new ChatColor( 'f', "white" );
/**
* Represents magical characters that change around randomly.
*/
public static final ChatColor MAGIC = new ChatColor( 'k', "obfuscated" );
/**
* Makes the text bold.
*/
public static final ChatColor BOLD = new ChatColor( 'l', "bold" );
/**
* Makes a line appear through the text.
*/
public static final ChatColor STRIKETHROUGH = new ChatColor( 'm', "strikethrough" );
/**
* Makes the text appear underlined.
*/
public static final ChatColor UNDERLINE = new ChatColor( 'n', "underline" );
/**
* Makes the text italic.
*/
public static final ChatColor ITALIC = new ChatColor( 'o', "italic" );
/**
* Resets all previous chat colors or formats.
*/
public static final ChatColor RESET = new ChatColor( 'r', "reset" );
/**
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
*/
@@ -124,22 +128,46 @@ public enum ChatColor
@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
} );
BY_CHAR.put( code, this );
BY_NAME.put( name.toUpperCase( Locale.ROOT ), this );
}
private ChatColor(String name, String toString)
{
this.name = name;
this.toString = toString;
}
@Override
public int hashCode()
{
int hash = 7;
hash = 53 * hash + Objects.hashCode( this.toString );
return hash;
}
@Override
public boolean equals(Object obj)
{
if ( this == obj )
{
return true;
}
if ( obj == null || getClass() != obj.getClass() )
{
return false;
}
final ChatColor other = (ChatColor) obj;
return Objects.equals( this.toString, other.toString );
}
@Override
@@ -188,4 +216,82 @@ public enum ChatColor
{
return BY_CHAR.get( code );
}
public static ChatColor of(Color color)
{
return of( "#" + Integer.toHexString( color.getRGB() ).substring( 2 ) );
}
public static ChatColor of(String string)
{
Preconditions.checkArgument( string != null, "string cannot be null" );
if ( string.startsWith( "#" ) && string.length() == 7 )
{
try
{
Integer.parseInt( string.substring( 1 ), 16 );
} catch ( NumberFormatException ex )
{
throw new IllegalArgumentException( "Illegal hex string " + string );
}
StringBuilder magic = new StringBuilder( COLOR_CHAR + "x" );
for ( char c : string.substring( 1 ).toCharArray() )
{
magic.append( COLOR_CHAR ).append( c );
}
return new ChatColor( string, magic.toString() );
}
ChatColor defined = BY_NAME.get( string.toUpperCase( Locale.ROOT ) );
if ( defined != null )
{
return defined;
}
throw new IllegalArgumentException( "Could not parse ChatColor " + string );
}
/**
* See {@link Enum#valueOf(java.lang.Class, java.lang.String)}.
*
* @param name color name
* @return ChatColor
* @deprecated holdover from when this class was an enum
*/
@Deprecated
public static ChatColor valueOf(String name)
{
Preconditions.checkNotNull( name, "Name is null" );
ChatColor defined = BY_NAME.get( name );
Preconditions.checkArgument( defined != null, "No enum constant " + ChatColor.class.getName() + "." + name );
return defined;
}
/**
* Get an array of all defined colors and formats.
*
* @return copied array of all colors and formats
* @deprecated holdover from when this class was an enum
*/
@Deprecated
public ChatColor[] values()
{
return BY_CHAR.values().toArray( new ChatColor[ BY_CHAR.values().size() ] );
}
/**
* See {@link Enum#name()}.
*
* @return constant name
* @deprecated holdover from when this class was an enum
*/
@Deprecated
public String name()
{
return getName().toUpperCase( Locale.ROOT );
}
}

View File

@@ -23,6 +23,10 @@ public abstract class BaseComponent
* The color of this component and any child components (unless overridden)
*/
private ChatColor color;
/**
* The font of this component and any child components (unless overridden)
*/
private String font;
/**
* Whether this component and any child components (unless overridden) is
* bold
@@ -147,6 +151,10 @@ public abstract class BaseComponent
{
setColor( component.getColorRaw() );
}
if ( replace || font == null )
{
setFont( component.getFontRaw() );
}
if ( replace || bold == null )
{
setBold( component.isBoldRaw() );
@@ -283,6 +291,36 @@ public abstract class BaseComponent
return color;
}
/**
* Returns the font of this component. This uses the parent's font if this
* component doesn't have one.
*
* @return the font of this component, or null if default font
*/
public String getFont()
{
if ( color == null )
{
if ( parent == null )
{
return null;
}
return parent.getFont();
}
return font;
}
/**
* Returns the font of this component without checking the parents font. May
* return null
*
* @return the font of this component
*/
public String getFontRaw()
{
return font;
}
/**
* 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
@@ -461,7 +499,7 @@ public abstract class BaseComponent
*/
public boolean hasFormatting()
{
return color != null || bold != null
return color != null || font != null || bold != null
|| italic != null || underlined != null
|| strikethrough != null || obfuscated != null
|| insertion != null || hoverEvent != null || clickEvent != null;

View File

@@ -63,7 +63,27 @@ public final class TextComponent extends BaseComponent
{
c += 32;
}
ChatColor format = ChatColor.getByChar( c );
ChatColor format;
if ( c == 'x' && i + 12 < message.length() )
{
StringBuilder hex = new StringBuilder( "#" );
for ( int j = 0; j < 6; j++ )
{
hex.append( message.charAt( i + 2 + ( j * 2 ) ) );
}
try
{
format = ChatColor.of( hex.toString() );
} catch ( IllegalArgumentException ex )
{
format = null;
}
i += 12;
} else
{
format = ChatColor.getByChar( c );
}
if ( format == null )
{
continue;
@@ -76,29 +96,30 @@ public final class TextComponent extends BaseComponent
builder = new StringBuilder();
components.add( old );
}
switch ( format )
if ( format == ChatColor.BOLD )
{
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 = defaultColor;
default:
component = new TextComponent();
component.setColor( format );
break;
component.setBold( true );
} else if ( format == ChatColor.ITALIC )
{
component.setItalic( true );
} else if ( format == ChatColor.UNDERLINE )
{
component.setUnderlined( true );
} else if ( format == ChatColor.STRIKETHROUGH )
{
component.setStrikethrough( true );
} else if ( format == ChatColor.MAGIC )
{
component.setObfuscated( true );
} else if ( format == ChatColor.RESET )
{
format = defaultColor;
component = new TextComponent();
component.setColor( format );
} else
{
component = new TextComponent();
component.setColor( format );
}
continue;
}

View File

@@ -20,7 +20,11 @@ public class BaseComponentSerializer
{
if ( object.has( "color" ) )
{
component.setColor( ChatColor.valueOf( object.get( "color" ).getAsString().toUpperCase( Locale.ROOT ) ) );
component.setColor( ChatColor.of( object.get( "color" ).getAsString() ) );
}
if ( object.has( "font" ) )
{
component.setFont( object.get( "font" ).getAsString() );
}
if ( object.has( "bold" ) )
{
@@ -93,6 +97,10 @@ public class BaseComponentSerializer
{
object.addProperty( "color", component.getColorRaw().getName() );
}
if ( component.getFontRaw() != null )
{
object.addProperty( "font", component.getFontRaw() );
}
if ( component.isBoldRaw() != null )
{
object.addProperty( "bold", component.isBoldRaw() );