#2363: Chat Component API Improvements
- duplicateWithoutFormatting deprecated and now works to include extra. Less maintenance required for any component implementations. - Improved copyFormatting API to allow for retention copying. - API to append a single BaseComponent in a ComponentBuilder, previously had to wrap a component in its own array to do this. - BaseComponent retain API that functions the same as from ComponentBuilder.
This commit is contained in:
parent
74e077e0fb
commit
7653a5f0f8
@ -9,6 +9,7 @@ import net.md_5.bungee.api.ChatColor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder.FormatRetention;
|
||||
|
||||
@Setter
|
||||
@ToString(exclude = "parent")
|
||||
@ -62,13 +63,13 @@ public abstract class BaseComponent
|
||||
private List<BaseComponent> extra;
|
||||
|
||||
/**
|
||||
* The action to preform when this component (and child components) are
|
||||
* The action to perform when this component (and child components) are
|
||||
* clicked
|
||||
*/
|
||||
@Getter
|
||||
private ClickEvent clickEvent;
|
||||
/**
|
||||
* The action to preform when this component (and child components) are
|
||||
* The action to perform when this component (and child components) are
|
||||
* hovered over
|
||||
*/
|
||||
@Getter
|
||||
@ -76,29 +77,118 @@ public abstract class BaseComponent
|
||||
|
||||
BaseComponent(BaseComponent old)
|
||||
{
|
||||
copyFormatting( old );
|
||||
}
|
||||
copyFormatting( old, FormatRetention.ALL, true );
|
||||
|
||||
public void copyFormatting(BaseComponent component)
|
||||
if ( old.getExtra() != null )
|
||||
{
|
||||
setColor( component.getColorRaw() );
|
||||
setBold( component.isBoldRaw() );
|
||||
setItalic( component.isItalicRaw() );
|
||||
setUnderlined( component.isUnderlinedRaw() );
|
||||
setStrikethrough( component.isStrikethroughRaw() );
|
||||
setObfuscated( component.isObfuscatedRaw() );
|
||||
setInsertion( component.getInsertion() );
|
||||
setClickEvent( component.getClickEvent() );
|
||||
setHoverEvent( component.getHoverEvent() );
|
||||
if ( component.getExtra() != null )
|
||||
{
|
||||
for ( BaseComponent extra : component.getExtra() )
|
||||
for ( BaseComponent extra : old.getExtra() )
|
||||
{
|
||||
addExtra( extra.duplicate() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the events and formatting of a BaseComponent. Already set
|
||||
* formatting will be replaced.
|
||||
*
|
||||
* @param component the component to copy from
|
||||
*/
|
||||
public void copyFormatting(BaseComponent component)
|
||||
{
|
||||
copyFormatting( component, FormatRetention.ALL, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the events and formatting of a BaseComponent.
|
||||
*
|
||||
* @param component the component to copy from
|
||||
* @param replace if already set formatting should be replaced by the new
|
||||
* component
|
||||
*/
|
||||
public void copyFormatting(BaseComponent component, boolean replace)
|
||||
{
|
||||
copyFormatting( component, FormatRetention.ALL, replace );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the specified formatting of a BaseComponent.
|
||||
*
|
||||
* @param component the component to copy from
|
||||
* @param retention the formatting to copy
|
||||
* @param replace if already set formatting should be replaced by the new
|
||||
* component
|
||||
*/
|
||||
public void copyFormatting(BaseComponent component, FormatRetention retention, boolean replace)
|
||||
{
|
||||
if ( retention == FormatRetention.EVENTS || retention == FormatRetention.ALL )
|
||||
{
|
||||
if ( replace || clickEvent == null )
|
||||
{
|
||||
setClickEvent( component.getClickEvent() );
|
||||
}
|
||||
if ( replace || hoverEvent == null )
|
||||
{
|
||||
setHoverEvent( component.getHoverEvent() );
|
||||
}
|
||||
}
|
||||
if ( retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL )
|
||||
{
|
||||
if ( replace || color == null )
|
||||
{
|
||||
setColor( component.getColorRaw() );
|
||||
}
|
||||
if ( replace || bold == null )
|
||||
{
|
||||
setBold( component.isBoldRaw() );
|
||||
}
|
||||
if ( replace || italic == null )
|
||||
{
|
||||
setItalic( component.isItalicRaw() );
|
||||
}
|
||||
if ( replace || underlined == null )
|
||||
{
|
||||
setUnderlined( component.isUnderlinedRaw() );
|
||||
}
|
||||
if ( replace || strikethrough == null )
|
||||
{
|
||||
setStrikethrough( component.isStrikethroughRaw() );
|
||||
}
|
||||
if ( replace || obfuscated == null )
|
||||
{
|
||||
setObfuscated( component.isObfuscatedRaw() );
|
||||
}
|
||||
if ( replace || insertion == null )
|
||||
{
|
||||
setInsertion( component.getInsertion() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only the specified formatting.
|
||||
*
|
||||
* @param retention the formatting to retain
|
||||
*/
|
||||
public void retain(FormatRetention retention)
|
||||
{
|
||||
if ( retention == FormatRetention.FORMATTING || retention == FormatRetention.NONE )
|
||||
{
|
||||
setClickEvent( null );
|
||||
setHoverEvent( null );
|
||||
}
|
||||
if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE )
|
||||
{
|
||||
setColor( null );
|
||||
setBold( null );
|
||||
setItalic( null );
|
||||
setUnderlined( null );
|
||||
setStrikethrough( null );
|
||||
setObfuscated( null );
|
||||
setInsertion( null );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the BaseComponent and returns the clone.
|
||||
*
|
||||
@ -110,8 +200,15 @@ public abstract class BaseComponent
|
||||
* Clones the BaseComponent without formatting and returns the clone.
|
||||
*
|
||||
* @return The duplicate of this BaseComponent
|
||||
* @deprecated API use discouraged, use traditional duplicate
|
||||
*/
|
||||
public abstract BaseComponent duplicateWithoutFormatting();
|
||||
@Deprecated
|
||||
public BaseComponent duplicateWithoutFormatting()
|
||||
{
|
||||
BaseComponent component = duplicate();
|
||||
component.retain( FormatRetention.NONE );
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the components to a string that uses the old formatting codes
|
||||
|
@ -55,8 +55,51 @@ public final class ComponentBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the components to the builder and makes it the current target for
|
||||
* formatting. The text will have all the formatting from the previous part.
|
||||
* Creates a ComponentBuilder with the given component as the first part.
|
||||
*
|
||||
* @param component the first component element
|
||||
*/
|
||||
public ComponentBuilder(BaseComponent component)
|
||||
{
|
||||
current = component.duplicate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component to the builder and makes it the current target for
|
||||
* formatting. The component will have all the formatting from previous
|
||||
* part.
|
||||
*
|
||||
* @param component the component to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent component)
|
||||
{
|
||||
return append( component, FormatRetention.ALL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component to the builder and makes it the current target for
|
||||
* formatting. You can specify the amount of formatting retained from
|
||||
* previous part.
|
||||
*
|
||||
* @param component the component to append
|
||||
* @param retention the formatting to retain
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent component, FormatRetention retention)
|
||||
{
|
||||
parts.add( current );
|
||||
|
||||
BaseComponent previous = current;
|
||||
current = component.duplicate();
|
||||
current.copyFormatting( previous, retention, false );
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the components to the builder and makes the last element the
|
||||
* current target for formatting. The components will have all the
|
||||
* formatting from previous part.
|
||||
*
|
||||
* @param components the components to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
@ -67,8 +110,9 @@ public final class ComponentBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the components to the builder and makes it the current target for
|
||||
* formatting. You can specify the amount of formatting retained.
|
||||
* Appends the components to the builder and makes the last element the
|
||||
* current target for formatting. You can specify the amount of formatting
|
||||
* retained from previous part.
|
||||
*
|
||||
* @param components the components to append
|
||||
* @param retention the formatting to retain
|
||||
@ -82,8 +126,9 @@ public final class ComponentBuilder
|
||||
{
|
||||
parts.add( current );
|
||||
|
||||
BaseComponent previous = current;
|
||||
current = component.duplicate();
|
||||
retain( retention );
|
||||
current.copyFormatting( previous, retention, false );
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -91,7 +136,7 @@ public final class ComponentBuilder
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* formatting. The text will have all the formatting from previous part.
|
||||
*
|
||||
* @param text the text to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
@ -103,7 +148,8 @@ public final class ComponentBuilder
|
||||
|
||||
/**
|
||||
* Appends the text to the builder and makes it the current target for
|
||||
* formatting. You can specify the amount of formatting retained.
|
||||
* formatting. You can specify the amount of formatting retained from
|
||||
* previous part.
|
||||
*
|
||||
* @param text the text to append
|
||||
* @param retention the formatting to retain
|
||||
@ -115,8 +161,7 @@ public final class ComponentBuilder
|
||||
|
||||
BaseComponent old = current;
|
||||
current = new TextComponent( text );
|
||||
current.copyFormatting( old );
|
||||
retain( retention );
|
||||
current.copyFormatting( old, retention, false );
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -247,27 +292,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder retain(FormatRetention retention)
|
||||
{
|
||||
BaseComponent previous = current;
|
||||
|
||||
switch ( retention )
|
||||
{
|
||||
case NONE:
|
||||
current = current.duplicateWithoutFormatting();
|
||||
break;
|
||||
case ALL:
|
||||
// No changes are required
|
||||
break;
|
||||
case EVENTS:
|
||||
current = current.duplicateWithoutFormatting();
|
||||
current.setInsertion( previous.getInsertion() );
|
||||
current.setClickEvent( previous.getClickEvent() );
|
||||
current.setHoverEvent( previous.getHoverEvent() );
|
||||
break;
|
||||
case FORMATTING:
|
||||
current.setClickEvent( null );
|
||||
current.setHoverEvent( null );
|
||||
break;
|
||||
}
|
||||
current.retain( retention );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -48,12 +48,6 @@ public final class KeybindComponent extends BaseComponent
|
||||
return new KeybindComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent duplicateWithoutFormatting()
|
||||
{
|
||||
return new KeybindComponent( keybind );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
{
|
||||
|
@ -82,12 +82,6 @@ public final class ScoreComponent extends BaseComponent
|
||||
return new ScoreComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoreComponent duplicateWithoutFormatting()
|
||||
{
|
||||
return new ScoreComponent( this.name, this.objective, this.value );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
|
@ -48,12 +48,6 @@ public final class SelectorComponent extends BaseComponent
|
||||
return new SelectorComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectorComponent duplicateWithoutFormatting()
|
||||
{
|
||||
return new SelectorComponent( this.selector );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
|
@ -180,12 +180,6 @@ public final class TextComponent extends BaseComponent
|
||||
return new TextComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent duplicateWithoutFormatting()
|
||||
{
|
||||
return new TextComponent( this.text );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
{
|
||||
|
@ -94,12 +94,6 @@ public final class TranslatableComponent extends BaseComponent
|
||||
return new TranslatableComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent duplicateWithoutFormatting()
|
||||
{
|
||||
return new TranslatableComponent( this.translate, this.with );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the translation substitutions to be used in this component. Removes
|
||||
* any previously set substitutions
|
||||
|
@ -7,6 +7,7 @@ import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.KeybindComponent;
|
||||
import net.md_5.bungee.api.chat.ScoreComponent;
|
||||
@ -20,6 +21,7 @@ import java.util.HashSet;
|
||||
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
{
|
||||
|
||||
private final static JsonParser JSON_PARSER = new JsonParser();
|
||||
private final static Gson gson = new GsonBuilder().
|
||||
registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ).
|
||||
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
|
||||
@ -33,15 +35,19 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
|
||||
public static BaseComponent[] parse(String json)
|
||||
{
|
||||
if ( json.startsWith( "[" ) )
|
||||
{ //Array
|
||||
return gson.fromJson( json, BaseComponent[].class );
|
||||
}
|
||||
JsonElement jsonElement = JSON_PARSER.parse( json );
|
||||
|
||||
if ( jsonElement.isJsonArray() )
|
||||
{
|
||||
return gson.fromJson( jsonElement, BaseComponent[].class );
|
||||
} else
|
||||
{
|
||||
return new BaseComponent[]
|
||||
{
|
||||
gson.fromJson( json, BaseComponent.class )
|
||||
gson.fromJson( jsonElement, BaseComponent.class )
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent component)
|
||||
{
|
||||
@ -49,9 +55,15 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent... components)
|
||||
{
|
||||
if ( components.length == 1 )
|
||||
{
|
||||
return gson.toJson( components[0] );
|
||||
} else
|
||||
{
|
||||
return gson.toJson( new TextComponent( components ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
|
@ -8,6 +8,23 @@ import org.junit.Test;
|
||||
public class ComponentsTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testComponentFormatRetention()
|
||||
{
|
||||
TextComponent first = new TextComponent( "Hello" );
|
||||
first.setBold( true );
|
||||
first.setColor( ChatColor.RED );
|
||||
first.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "test" ) );
|
||||
first.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
|
||||
|
||||
TextComponent second = new TextComponent( " world" );
|
||||
second.copyFormatting( first, ComponentBuilder.FormatRetention.ALL, true );
|
||||
Assert.assertEquals( first.isBold(), second.isBold() );
|
||||
Assert.assertEquals( first.getColor(), second.getColor() );
|
||||
Assert.assertEquals( first.getClickEvent(), second.getClickEvent() );
|
||||
Assert.assertEquals( first.getHoverEvent(), second.getHoverEvent() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilderClone()
|
||||
{
|
||||
@ -17,6 +34,25 @@ public class ComponentsTest
|
||||
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilderAppendMixedComponents()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder( "Hello " );
|
||||
TextComponent textComponent = new TextComponent( "world " );
|
||||
TranslatableComponent translatableComponent = new TranslatableComponent( "item.swordGold.name" );
|
||||
builder.append( new BaseComponent[] { // array based BaseComponent append
|
||||
textComponent,
|
||||
translatableComponent
|
||||
} );
|
||||
ScoreComponent scoreComponent = new ScoreComponent( "myscore", "myobjective" );
|
||||
builder.append( scoreComponent ); // non array based BaseComponent append
|
||||
BaseComponent[] components = builder.create();
|
||||
Assert.assertEquals( "Hello ", components[0].toPlainText() );
|
||||
Assert.assertEquals( textComponent.toPlainText(), components[1].toPlainText() );
|
||||
Assert.assertEquals( translatableComponent.toPlainText(), components[2].toPlainText() );
|
||||
Assert.assertEquals( scoreComponent.toPlainText(), components[3].toPlainText() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilderAppend()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user