#2725: Various improvements to chat API
* More versatile ComponentBuilder system - Allow creating a builder without an initial component - Duplicate the parts when component is created - Add getter for 'parts' * Added cursor API for more fluid component modifying * Don't legacy convert Titles on 1.11 or newer * Simplify plain and legacy text converting code - Shares the addFormat method between all superclasses - Duplicate code in TranslatableComponent moved in separate method
This commit is contained in:
parent
7ed4c41d39
commit
d2ceccd646
@ -505,4 +505,29 @@ public abstract class BaseComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package net.md_5.bungee.api.chat;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,11 +25,29 @@ import net.md_5.bungee.api.ChatColor;
|
|||||||
* part's formatting
|
* part's formatting
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
public final class ComponentBuilder
|
public final class ComponentBuilder
|
||||||
{
|
{
|
||||||
|
|
||||||
private BaseComponent current;
|
/**
|
||||||
|
* The position for the current part to modify. Modified cursors will
|
||||||
|
* automatically reset to the last part after appending new components.
|
||||||
|
* Default value at -1 to assert that the builder has no parts.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private int cursor = -1;
|
||||||
|
@Getter
|
||||||
private final List<BaseComponent> parts = new ArrayList<BaseComponent>();
|
private final List<BaseComponent> parts = new ArrayList<BaseComponent>();
|
||||||
|
private BaseComponent dummy;
|
||||||
|
|
||||||
|
private ComponentBuilder(BaseComponent[] parts)
|
||||||
|
{
|
||||||
|
for ( BaseComponent baseComponent : parts )
|
||||||
|
{
|
||||||
|
this.parts.add( baseComponent.duplicate() );
|
||||||
|
}
|
||||||
|
resetCursor();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a ComponentBuilder from the other given ComponentBuilder to clone
|
* Creates a ComponentBuilder from the other given ComponentBuilder to clone
|
||||||
@ -37,11 +57,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder(ComponentBuilder original)
|
public ComponentBuilder(ComponentBuilder original)
|
||||||
{
|
{
|
||||||
current = original.current.duplicate();
|
this( original.parts.toArray( new BaseComponent[ original.parts.size() ] ) );
|
||||||
for ( BaseComponent baseComponent : original.parts )
|
|
||||||
{
|
|
||||||
parts.add( baseComponent.duplicate() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +67,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder(String text)
|
public ComponentBuilder(String text)
|
||||||
{
|
{
|
||||||
current = new TextComponent( text );
|
this( new TextComponent( text ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +77,58 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder(BaseComponent component)
|
public ComponentBuilder(BaseComponent component)
|
||||||
{
|
{
|
||||||
current = component.duplicate();
|
|
||||||
|
this( new BaseComponent[]
|
||||||
|
{
|
||||||
|
component
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseComponent getDummy()
|
||||||
|
{
|
||||||
|
if ( dummy == null )
|
||||||
|
{
|
||||||
|
dummy = new BaseComponent()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public BaseComponent duplicate()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the cursor to index of the last element.
|
||||||
|
*
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder resetCursor()
|
||||||
|
{
|
||||||
|
cursor = parts.size() - 1;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the position of the current component to be modified
|
||||||
|
*
|
||||||
|
* @param pos the cursor position synonymous to an element position for a
|
||||||
|
* list
|
||||||
|
* @throws IndexOutOfBoundsException if the index is out of range
|
||||||
|
* ({@code index < 0 || index >= size()})
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder setCursor(int pos) throws IndexOutOfBoundsException
|
||||||
|
{
|
||||||
|
if ( ( this.cursor != pos ) && ( pos < 0 || pos >= parts.size() ) )
|
||||||
|
{
|
||||||
|
throw new IndexOutOfBoundsException( "Cursor out of bounds (expected between 0 + " + ( parts.size() - 1 ) + ")" );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cursor = pos;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,11 +155,18 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder append(BaseComponent component, FormatRetention retention)
|
public ComponentBuilder append(BaseComponent component, FormatRetention retention)
|
||||||
{
|
{
|
||||||
parts.add( current );
|
BaseComponent previous = ( parts.isEmpty() ) ? null : parts.get( parts.size() - 1 );
|
||||||
|
if ( previous == null )
|
||||||
BaseComponent previous = current;
|
{
|
||||||
current = component.duplicate();
|
previous = dummy;
|
||||||
current.copyFormatting( previous, retention, false );
|
dummy = null;
|
||||||
|
}
|
||||||
|
if ( previous != null )
|
||||||
|
{
|
||||||
|
component.copyFormatting( previous, retention, false );
|
||||||
|
}
|
||||||
|
parts.add( component );
|
||||||
|
resetCursor();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,13 +196,9 @@ public final class ComponentBuilder
|
|||||||
{
|
{
|
||||||
Preconditions.checkArgument( components.length != 0, "No components to append" );
|
Preconditions.checkArgument( components.length != 0, "No components to append" );
|
||||||
|
|
||||||
BaseComponent previous = current;
|
|
||||||
for ( BaseComponent component : components )
|
for ( BaseComponent component : components )
|
||||||
{
|
{
|
||||||
parts.add( current );
|
append( component, retention );
|
||||||
|
|
||||||
current = component.duplicate();
|
|
||||||
current.copyFormatting( previous, retention, false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -170,13 +240,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder append(String text, FormatRetention retention)
|
public ComponentBuilder append(String text, FormatRetention retention)
|
||||||
{
|
{
|
||||||
parts.add( current );
|
return append( new TextComponent( text ), retention );
|
||||||
|
|
||||||
BaseComponent old = current;
|
|
||||||
current = new TextComponent( text );
|
|
||||||
current.copyFormatting( old, retention, false );
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,6 +274,44 @@ public final class ComponentBuilder
|
|||||||
return joiner.join( this, retention );
|
return joiner.join( this, retention );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the component part at the position of given index.
|
||||||
|
*
|
||||||
|
* @param pos the index to remove at
|
||||||
|
* @throws IndexOutOfBoundsException if the index is out of range
|
||||||
|
* ({@code index < 0 || index >= size()})
|
||||||
|
*/
|
||||||
|
public void removeComponent(int pos) throws IndexOutOfBoundsException
|
||||||
|
{
|
||||||
|
if ( parts.remove( pos ) != null )
|
||||||
|
{
|
||||||
|
resetCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the component part at the position of given index.
|
||||||
|
*
|
||||||
|
* @param pos the index to find
|
||||||
|
* @return the component
|
||||||
|
* @throws IndexOutOfBoundsException if the index is out of range
|
||||||
|
* ({@code index < 0 || index >= size()})
|
||||||
|
*/
|
||||||
|
public BaseComponent getComponent(int pos) throws IndexOutOfBoundsException
|
||||||
|
{
|
||||||
|
return parts.get( pos );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the component at the position of the cursor.
|
||||||
|
*
|
||||||
|
* @return the active component or null if builder is empty
|
||||||
|
*/
|
||||||
|
public BaseComponent getCurrentComponent()
|
||||||
|
{
|
||||||
|
return ( cursor == -1 ) ? getDummy() : parts.get( cursor );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color of the current part.
|
* Sets the color of the current part.
|
||||||
*
|
*
|
||||||
@ -218,7 +320,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder color(ChatColor color)
|
public ComponentBuilder color(ChatColor color)
|
||||||
{
|
{
|
||||||
current.setColor( color );
|
getCurrentComponent().setColor( color );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +332,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder bold(boolean bold)
|
public ComponentBuilder bold(boolean bold)
|
||||||
{
|
{
|
||||||
current.setBold( bold );
|
getCurrentComponent().setBold( bold );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +344,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder italic(boolean italic)
|
public ComponentBuilder italic(boolean italic)
|
||||||
{
|
{
|
||||||
current.setItalic( italic );
|
getCurrentComponent().setItalic( italic );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +356,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder underlined(boolean underlined)
|
public ComponentBuilder underlined(boolean underlined)
|
||||||
{
|
{
|
||||||
current.setUnderlined( underlined );
|
getCurrentComponent().setUnderlined( underlined );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +368,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder strikethrough(boolean strikethrough)
|
public ComponentBuilder strikethrough(boolean strikethrough)
|
||||||
{
|
{
|
||||||
current.setStrikethrough( strikethrough );
|
getCurrentComponent().setStrikethrough( strikethrough );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +380,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder obfuscated(boolean obfuscated)
|
public ComponentBuilder obfuscated(boolean obfuscated)
|
||||||
{
|
{
|
||||||
current.setObfuscated( obfuscated );
|
getCurrentComponent().setObfuscated( obfuscated );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +392,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder insertion(String insertion)
|
public ComponentBuilder insertion(String insertion)
|
||||||
{
|
{
|
||||||
current.setInsertion( insertion );
|
getCurrentComponent().setInsertion( insertion );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +404,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder event(ClickEvent clickEvent)
|
public ComponentBuilder event(ClickEvent clickEvent)
|
||||||
{
|
{
|
||||||
current.setClickEvent( clickEvent );
|
getCurrentComponent().setClickEvent( clickEvent );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +416,7 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder event(HoverEvent hoverEvent)
|
public ComponentBuilder event(HoverEvent hoverEvent)
|
||||||
{
|
{
|
||||||
current.setHoverEvent( hoverEvent );
|
getCurrentComponent().setHoverEvent( hoverEvent );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,24 +438,28 @@ public final class ComponentBuilder
|
|||||||
*/
|
*/
|
||||||
public ComponentBuilder retain(FormatRetention retention)
|
public ComponentBuilder retain(FormatRetention retention)
|
||||||
{
|
{
|
||||||
current.retain( retention );
|
getCurrentComponent().retain( retention );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the components needed to display the message created by this
|
* Returns the components needed to display the message created by this
|
||||||
* builder.
|
* builder.git
|
||||||
*
|
*
|
||||||
* @return the created components
|
* @return the created components
|
||||||
*/
|
*/
|
||||||
public BaseComponent[] create()
|
public BaseComponent[] create()
|
||||||
{
|
{
|
||||||
BaseComponent[] result = parts.toArray( new BaseComponent[ parts.size() + 1 ] );
|
BaseComponent[] cloned = new BaseComponent[ parts.size() ];
|
||||||
result[parts.size()] = current;
|
int i = 0;
|
||||||
return result;
|
for ( BaseComponent part : parts )
|
||||||
|
{
|
||||||
|
cloned[i++] = part.duplicate();
|
||||||
|
}
|
||||||
|
return cloned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum FormatRetention
|
public enum FormatRetention
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,6 @@ import lombok.Getter;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -60,29 +59,8 @@ public final class KeybindComponent extends BaseComponent
|
|||||||
@Override
|
@Override
|
||||||
protected void toLegacyText(StringBuilder builder)
|
protected void toLegacyText(StringBuilder builder)
|
||||||
{
|
{
|
||||||
builder.append( getColor() );
|
addFormat( builder );
|
||||||
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( getKeybind() );
|
builder.append( getKeybind() );
|
||||||
|
|
||||||
super.toLegacyText( builder );
|
super.toLegacyText( builder );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,17 @@ public final class ScoreComponent extends BaseComponent
|
|||||||
return new ScoreComponent( this );
|
return new ScoreComponent( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toPlainText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.append( this.value );
|
||||||
|
super.toPlainText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void toLegacyText(StringBuilder builder)
|
protected void toLegacyText(StringBuilder builder)
|
||||||
{
|
{
|
||||||
|
addFormat( builder );
|
||||||
builder.append( this.value );
|
builder.append( this.value );
|
||||||
super.toLegacyText( builder );
|
super.toLegacyText( builder );
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,17 @@ public final class SelectorComponent extends BaseComponent
|
|||||||
return new SelectorComponent( this );
|
return new SelectorComponent( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toPlainText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.append( this.selector );
|
||||||
|
super.toPlainText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void toLegacyText(StringBuilder builder)
|
protected void toLegacyText(StringBuilder builder)
|
||||||
{
|
{
|
||||||
|
addFormat( builder );
|
||||||
builder.append( this.selector );
|
builder.append( this.selector );
|
||||||
super.toLegacyText( builder );
|
super.toLegacyText( builder );
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package net.md_5.bungee.api.chat;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -172,8 +173,26 @@ public final class TextComponent extends BaseComponent
|
|||||||
*/
|
*/
|
||||||
public TextComponent(BaseComponent... extras)
|
public TextComponent(BaseComponent... extras)
|
||||||
{
|
{
|
||||||
setText( "" );
|
if ( extras.length == 0 )
|
||||||
setExtra( new ArrayList<BaseComponent>( Arrays.asList( extras ) ) );
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( extras.length == 1 && extras[0] instanceof TextComponent )
|
||||||
|
{
|
||||||
|
setText( ( (TextComponent) extras[0] ).getText() );
|
||||||
|
List<BaseComponent> headExtra = extras[0].getExtra();
|
||||||
|
if ( headExtra != null )
|
||||||
|
{
|
||||||
|
for ( BaseComponent extra : headExtra )
|
||||||
|
{
|
||||||
|
addExtra( extra.duplicate() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
setText( "" );
|
||||||
|
setExtra( new ArrayList<BaseComponent>( Arrays.asList( extras ) ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -197,27 +216,7 @@ public final class TextComponent extends BaseComponent
|
|||||||
@Override
|
@Override
|
||||||
protected void toLegacyText(StringBuilder builder)
|
protected void toLegacyText(StringBuilder builder)
|
||||||
{
|
{
|
||||||
builder.append( getColor() );
|
addFormat( builder );
|
||||||
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 );
|
builder.append( text );
|
||||||
super.toLegacyText( builder );
|
super.toLegacyText( builder );
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import lombok.Getter;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.chat.TranslationRegistry;
|
import net.md_5.bungee.chat.TranslationRegistry;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -139,43 +138,18 @@ public final class TranslatableComponent extends BaseComponent
|
|||||||
@Override
|
@Override
|
||||||
protected void toPlainText(StringBuilder builder)
|
protected void toPlainText(StringBuilder builder)
|
||||||
{
|
{
|
||||||
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
convert( builder, false );
|
||||||
|
|
||||||
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() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
super.toPlainText( builder );
|
super.toPlainText( builder );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void toLegacyText(StringBuilder builder)
|
protected void toLegacyText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
convert( builder, true );
|
||||||
|
super.toLegacyText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convert(StringBuilder builder, boolean applyFormat)
|
||||||
{
|
{
|
||||||
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
||||||
|
|
||||||
@ -187,7 +161,10 @@ public final class TranslatableComponent extends BaseComponent
|
|||||||
int pos = matcher.start();
|
int pos = matcher.start();
|
||||||
if ( pos != position )
|
if ( pos != position )
|
||||||
{
|
{
|
||||||
addFormat( builder );
|
if ( applyFormat )
|
||||||
|
{
|
||||||
|
addFormat( builder );
|
||||||
|
}
|
||||||
builder.append( trans.substring( position, pos ) );
|
builder.append( trans.substring( position, pos ) );
|
||||||
}
|
}
|
||||||
position = matcher.end();
|
position = matcher.end();
|
||||||
@ -198,44 +175,32 @@ public final class TranslatableComponent extends BaseComponent
|
|||||||
case 's':
|
case 's':
|
||||||
case 'd':
|
case 'd':
|
||||||
String withIndex = matcher.group( 1 );
|
String withIndex = matcher.group( 1 );
|
||||||
with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toLegacyText( builder );
|
|
||||||
|
BaseComponent withComponent = with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ );
|
||||||
|
if ( applyFormat )
|
||||||
|
{
|
||||||
|
withComponent.toLegacyText( builder );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
withComponent.toPlainText( builder );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
addFormat( builder );
|
if ( applyFormat )
|
||||||
|
{
|
||||||
|
addFormat( builder );
|
||||||
|
}
|
||||||
builder.append( '%' );
|
builder.append( '%' );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( trans.length() != position )
|
if ( trans.length() != position )
|
||||||
{
|
{
|
||||||
addFormat( builder );
|
if ( applyFormat )
|
||||||
|
{
|
||||||
|
addFormat( builder );
|
||||||
|
}
|
||||||
builder.append( trans.substring( position, trans.length() ) );
|
builder.append( trans.substring( 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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public class TranslatableComponentSerializer extends BaseComponentSerializer imp
|
|||||||
component.setTranslate( object.get( "translate" ).getAsString() );
|
component.setTranslate( object.get( "translate" ).getAsString() );
|
||||||
if ( object.has( "with" ) )
|
if ( object.has( "with" ) )
|
||||||
{
|
{
|
||||||
component.setWith( Arrays.asList( (BaseComponent[]) context.deserialize( object.get( "with" ), BaseComponent[].class ) ) );
|
component.setWith( Arrays.asList( context.<BaseComponent>deserialize( object.get( "with" ), BaseComponent[].class ) ) );
|
||||||
}
|
}
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,112 @@ import org.junit.Test;
|
|||||||
public class ComponentsTest
|
public class ComponentsTest
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyComponentBuilder()
|
||||||
|
{
|
||||||
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
|
||||||
|
BaseComponent[] parts = builder.create();
|
||||||
|
Assert.assertEquals( parts.length, 0 );
|
||||||
|
|
||||||
|
for ( int i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
builder.append( "part:" + i );
|
||||||
|
parts = builder.create();
|
||||||
|
Assert.assertEquals( parts.length, i + 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDummyRetaining()
|
||||||
|
{
|
||||||
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
Assert.assertNotNull( builder.getCurrentComponent() );
|
||||||
|
builder.color( ChatColor.GREEN );
|
||||||
|
builder.append( "test ", ComponentBuilder.FormatRetention.ALL );
|
||||||
|
Assert.assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testComponentGettingExceptions()
|
||||||
|
{
|
||||||
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
builder.getComponent( -1 );
|
||||||
|
builder.getComponent( 0 );
|
||||||
|
builder.getComponent( 1 );
|
||||||
|
BaseComponent component = new TextComponent( "Hello" );
|
||||||
|
builder.append( component );
|
||||||
|
Assert.assertEquals( builder.getComponent( 0 ), component );
|
||||||
|
builder.getComponent( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComponentParting()
|
||||||
|
{
|
||||||
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
TextComponent apple = new TextComponent( "apple" );
|
||||||
|
builder.append( apple );
|
||||||
|
Assert.assertEquals( builder.getCurrentComponent(), apple );
|
||||||
|
Assert.assertEquals( builder.getComponent( 0 ), apple );
|
||||||
|
|
||||||
|
TextComponent mango = new TextComponent( "mango" );
|
||||||
|
TextComponent orange = new TextComponent( "orange" );
|
||||||
|
builder.append( mango );
|
||||||
|
builder.append( orange );
|
||||||
|
builder.removeComponent( 1 ); // Removing mango
|
||||||
|
Assert.assertEquals( builder.getComponent( 0 ), apple );
|
||||||
|
Assert.assertEquals( builder.getComponent( 1 ), orange );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToLegacyFromLegacy()
|
||||||
|
{
|
||||||
|
String text = "§a§lHello §f§kworld§7!";
|
||||||
|
Assert.assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testComponentBuilderCursorInvalidPos()
|
||||||
|
{
|
||||||
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
builder.append( new TextComponent( "Apple, " ) );
|
||||||
|
builder.append( new TextComponent( "Orange, " ) );
|
||||||
|
builder.setCursor( -1 );
|
||||||
|
builder.setCursor( 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComponentBuilderCursor()
|
||||||
|
{
|
||||||
|
TextComponent t1, t2, t3;
|
||||||
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
Assert.assertEquals( builder.getCursor(), -1 );
|
||||||
|
builder.append( t1 = new TextComponent( "Apple, " ) );
|
||||||
|
Assert.assertEquals( builder.getCursor(), 0 );
|
||||||
|
builder.append( t2 = new TextComponent( "Orange, " ) );
|
||||||
|
builder.append( t3 = new TextComponent( "Mango, " ) );
|
||||||
|
Assert.assertEquals( builder.getCursor(), 2 );
|
||||||
|
|
||||||
|
builder.setCursor( 0 );
|
||||||
|
Assert.assertEquals( builder.getCurrentComponent(), t1 );
|
||||||
|
|
||||||
|
// Test that appending new components updates the position to the new list size
|
||||||
|
// after having previously set it to 0 (first component)
|
||||||
|
builder.append( new TextComponent( "and Grapefruit" ) );
|
||||||
|
Assert.assertEquals( builder.getCursor(), 3 );
|
||||||
|
|
||||||
|
builder.setCursor( 0 );
|
||||||
|
builder.resetCursor();
|
||||||
|
Assert.assertEquals( builder.getCursor(), 3 );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLegacyComponentBuilderAppend()
|
public void testLegacyComponentBuilderAppend()
|
||||||
{
|
{
|
||||||
String text = "§a§lHello §r§kworld§7!";
|
String text = "§a§lHello §r§kworld§7!";
|
||||||
BaseComponent[] components = TextComponent.fromLegacyText( text );
|
BaseComponent[] components = TextComponent.fromLegacyText( text );
|
||||||
BaseComponent[] builderComponents = new ComponentBuilder( "" ).append( components ).create();
|
BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create();
|
||||||
List<BaseComponent> list = new ArrayList<BaseComponent>( Arrays.asList( builderComponents ) );
|
List<BaseComponent> list = new ArrayList<BaseComponent>( Arrays.asList( builderComponents ) );
|
||||||
// Remove the first element (empty text component). This needs to be done because toLegacyText always
|
|
||||||
// appends &f regardless if the color is non null or not and would otherwise mess with our unit test.
|
|
||||||
list.remove( 0 );
|
|
||||||
Assert.assertEquals(
|
Assert.assertEquals(
|
||||||
TextComponent.toLegacyText( components ),
|
TextComponent.toLegacyText( components ),
|
||||||
TextComponent.toLegacyText( list.toArray( new BaseComponent[ list.size() ] ) )
|
TextComponent.toLegacyText( list.toArray( new BaseComponent[ list.size() ] ) )
|
||||||
@ -28,7 +124,7 @@ public class ComponentsTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComponentFormatRetention()
|
public void testFormatRetentionCopyFormatting()
|
||||||
{
|
{
|
||||||
TextComponent first = new TextComponent( "Hello" );
|
TextComponent first = new TextComponent( "Hello" );
|
||||||
first.setBold( true );
|
first.setBold( true );
|
||||||
@ -47,7 +143,7 @@ public class ComponentsTest
|
|||||||
@Test
|
@Test
|
||||||
public void testBuilderClone()
|
public void testBuilderClone()
|
||||||
{
|
{
|
||||||
ComponentBuilder builder = new ComponentBuilder( "Hel" ).color( ChatColor.RED ).append( "lo" ).color( ChatColor.DARK_RED );
|
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED );
|
||||||
ComponentBuilder cloned = new ComponentBuilder( builder );
|
ComponentBuilder cloned = new ComponentBuilder( builder );
|
||||||
|
|
||||||
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
|
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
|
||||||
|
@ -40,7 +40,7 @@ public class CommandServer extends Command implements TabExecutor
|
|||||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) );
|
sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentBuilder serverList = new ComponentBuilder( "" ).appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) );
|
ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) );
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for ( ServerInfo server : servers.values() )
|
for ( ServerInfo server : servers.values() )
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,7 @@ import net.md_5.bungee.protocol.MinecraftDecoder;
|
|||||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||||
import net.md_5.bungee.protocol.PacketWrapper;
|
import net.md_5.bungee.protocol.PacketWrapper;
|
||||||
import net.md_5.bungee.protocol.Protocol;
|
import net.md_5.bungee.protocol.Protocol;
|
||||||
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import net.md_5.bungee.protocol.packet.Chat;
|
import net.md_5.bungee.protocol.packet.Chat;
|
||||||
import net.md_5.bungee.protocol.packet.ClientSettings;
|
import net.md_5.bungee.protocol.packet.ClientSettings;
|
||||||
import net.md_5.bungee.protocol.packet.Kick;
|
import net.md_5.bungee.protocol.packet.Kick;
|
||||||
@ -453,10 +454,20 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
// transform score components
|
// transform score components
|
||||||
message = ChatComponentTransformer.getInstance().transform( this, message );
|
message = ChatComponentTransformer.getInstance().transform( this, message );
|
||||||
|
|
||||||
// Action bar doesn't display the new JSON formattings, legacy works - send it using this for now
|
|
||||||
if ( position == ChatMessageType.ACTION_BAR )
|
if ( position == ChatMessageType.ACTION_BAR )
|
||||||
{
|
{
|
||||||
sendMessage( position, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) );
|
// Versions older than 1.11 cannot send the Action bar with the new JSON formattings
|
||||||
|
// Fix by converting to a legacy message, see https://bugs.mojang.com/browse/MC-119145
|
||||||
|
if ( ProxyServer.getInstance().getProtocolVersion() <= ProtocolConstants.MINECRAFT_1_10 )
|
||||||
|
{
|
||||||
|
sendMessage( position, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
net.md_5.bungee.protocol.packet.Title title = new net.md_5.bungee.protocol.packet.Title();
|
||||||
|
title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR );
|
||||||
|
title.setText( ComponentSerializer.toString( message ) );
|
||||||
|
unsafe.sendPacket( title );
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
sendMessage( position, ComponentSerializer.toString( message ) );
|
sendMessage( position, ComponentSerializer.toString( message ) );
|
||||||
|
Loading…
Reference in New Issue
Block a user