Skip to content

Commit

Permalink
Improve chat api toLegacy conversion
Browse files Browse the repository at this point in the history
The target is to output less redundant legacy codes, this has been achieved by using context-aware toLegacy conversion which keeps track of the current end-of-string style.
Fixes behaviour change introduced in f4144eb8c2e83f43f41b24b4ea8b03b0f4c9c44e of array toLegacy conversion where the next array element would no longer reset to white color.
  • Loading branch information
Janmm14 committed Apr 21, 2024
1 parent 7a64e0d commit 32dfedc
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 78 deletions.
183 changes: 154 additions & 29 deletions chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,29 @@ public BaseComponent duplicateWithoutFormatting()
public static String toLegacyText(BaseComponent... components)
{
StringBuilder builder = new StringBuilder();
ComponentStyle currentLegacy = new ComponentStyle();
currentLegacy.setColor( ChatColor.RESET );

toLegacyText( builder, currentLegacy, components );
return builder.toString();
}

/**
* Converts the components to a string that uses the old formatting codes
* ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR}
*
* @param builder the StringBuilder to append to
* @param currentLegacy the style at the end of {@code builder}
* @param components the components to convert
* @return the style at the end of the legacy string
*/
public static ComponentStyle toLegacyText(StringBuilder builder, ComponentStyle currentLegacy, BaseComponent... components)
{
for ( BaseComponent msg : components )
{
builder.append( msg.toLegacyText() );
currentLegacy = msg.toLegacyText( builder, currentLegacy );
}
return builder.toString();
return currentLegacy;
}

/**
Expand Down Expand Up @@ -273,15 +291,20 @@ public void setColor(ChatColor color)
*/
public ChatColor getColor()
{
if ( !style.hasColor() )
return getColor( ChatColor.WHITE );
}

ChatColor getColor(ChatColor def)
{
if ( style.hasColor() )
{
if ( parent == null )
{
return ChatColor.WHITE;
}
return parent.getColor();
return style.getColor();
}
return style.getColor();
if ( parent == null )
{
return def;
}
return parent.getColor( def );
}

/**
Expand Down Expand Up @@ -651,46 +674,148 @@ void toPlainText(StringBuilder builder)
public String toLegacyText()
{
StringBuilder builder = new StringBuilder();
toLegacyText( builder );
ComponentStyle currentLegacy = new ComponentStyle();
currentLegacy.setColor( ChatColor.RESET );
toLegacyText( builder, currentLegacy );
return builder.toString();
}

void toLegacyText(StringBuilder builder)
/**
* Converts the component to a string that uses the old formatting codes
* ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR}
*
* @param currentLegacy the style at the end of the string the result of this method will be appended to
* @return the string in the old format
*/
public String toLegacyText(ComponentStyle currentLegacy)
{
if ( extra != null )
StringBuilder builder = new StringBuilder();
toLegacyText( builder, currentLegacy );
return builder.toString();
}

/**
* Converts the component to a string that uses the old formatting codes
* ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR}
*
* @param builder the StringBuilder to append to
* @param currentLegacy the style at the end of {@code builder}
* @return the style at the end of the legacy string
*/
public ComponentStyle toLegacyText(StringBuilder builder, ComponentStyle currentLegacy)
{
currentLegacy = currentLegacy.clone();
if ( !currentLegacy.hasColor() )
{
for ( BaseComponent e : extra )
{
e.toLegacyText( builder );
}
currentLegacy.setColor( ChatColor.RESET );
}
return toLegacyText( builder, currentLegacy.hasColor() ? currentLegacy.getColor() : ChatColor.RESET, currentLegacy );
}

/**
* Converts the component to a string that uses the old formatting codes
* ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR}
*
* @param builder the StringBuilder to append to
* @param baseColor the color to use if no color is set, but a format downgrade is needed
* @param currentLegacy the style at the end of {@code builder}
* @return the new current style at the end of the {@code builder}
*/
ComponentStyle toLegacyText(StringBuilder builder, ChatColor baseColor, ComponentStyle currentLegacy)
{
if ( extra == null )
{
return currentLegacy;
}
for ( BaseComponent e : extra )
{
currentLegacy = e.toLegacyText( builder, baseColor, currentLegacy );
}
return currentLegacy;
}

void addFormat(StringBuilder builder)
private static boolean colorEquals(ChatColor a, ChatColor b)
{
if ( style.hasColor() || parent != null )
if ( a == b )
{
builder.append( getColor() );
return true;
}
if ( isBold() )
if ( a == null || b == null )
{
builder.append( ChatColor.BOLD );
return false;
}
if ( isItalic() )
if ( ChatColor.RESET.equals( a ) )
{
builder.append( ChatColor.ITALIC );
return ChatColor.WHITE.equals( b ) || ChatColor.RESET.equals( b );
}
if ( isUnderlined() )
if ( ChatColor.RESET.equals( b ) )
{
builder.append( ChatColor.UNDERLINE );
return ChatColor.WHITE.equals( a ) || ChatColor.RESET.equals( a );
}
if ( isStrikethrough() )
return a.equals( b );
}

/**
* @param builder the StringBuilder to append to
* @param baseColor the color to use if no color is set, but a format downgrade is needed
* @param currentLegacy the style at the end of {@code builder}
* @return the new current style at the end of {@code builder}
*/
ComponentStyle addFormat(StringBuilder builder, ChatColor baseColor, ComponentStyle currentLegacy)
{
// Check if we can skip adding color code
if ( colorEquals( getColor(), currentLegacy.getColor() ) && currentLegacy.isLegacyFormattingUpgrade( style ) )
{
if ( isBold() && !currentLegacy.isBold() )
{
builder.append( ChatColor.BOLD );
}
if ( isItalic() && !currentLegacy.isItalic() )
{
builder.append( ChatColor.ITALIC );
}
if ( isUnderlined() && !currentLegacy.isUnderlined() )
{
builder.append( ChatColor.UNDERLINE );
}
if ( isStrikethrough() && !currentLegacy.isStrikethrough() )
{
builder.append( ChatColor.STRIKETHROUGH );
}
if ( isObfuscated() && !currentLegacy.isObfuscated() )
{
builder.append( ChatColor.MAGIC );
}
} else
{
builder.append( ChatColor.STRIKETHROUGH );
builder.append( getColor( baseColor ) == null ? baseColor : getColor( baseColor ) );
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 );
}
}
if ( isObfuscated() )
currentLegacy = style;
if ( currentLegacy.getColor() == null )
{
builder.append( ChatColor.MAGIC );
currentLegacy = style.clone();
currentLegacy.setColor( getColor( baseColor ) == null ? baseColor : getColor( baseColor ) );
}
return currentLegacy;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ public boolean isEmpty()
&& strikethrough == null && obfuscated == null;
}

boolean isLegacyFormattingUpgrade(ComponentStyle newStyle)
{
return ( newStyle.isBold() || !isBold() )
&& ( newStyle.isItalic() || !isItalic() )
&& ( newStyle.isUnderlined() || !isUnderlined() )
&& ( newStyle.isStrikethrough() || !isStrikethrough() )
&& ( newStyle.isObfuscated() || !isObfuscated() );
}

@Override
public ComponentStyle clone()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import net.md_5.bungee.api.ChatColor;

@Getter
@Setter
Expand Down Expand Up @@ -57,10 +58,10 @@ protected void toPlainText(StringBuilder builder)
}

@Override
protected void toLegacyText(StringBuilder builder)
ComponentStyle toLegacyText(StringBuilder builder, ChatColor baseColor, ComponentStyle currentLegacy)
{
addFormat( builder );
currentLegacy = addFormat( builder, baseColor, currentLegacy );
builder.append( getKeybind() );
super.toLegacyText( builder );
return super.toLegacyText( builder, baseColor, currentLegacy );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import net.md_5.bungee.api.ChatColor;

/**
* This component displays the score based on a player score on the scoreboard.
Expand Down Expand Up @@ -92,10 +93,10 @@ protected void toPlainText(StringBuilder builder)
}

@Override
protected void toLegacyText(StringBuilder builder)
ComponentStyle toLegacyText(StringBuilder builder, ChatColor baseColor, ComponentStyle currentLegacy)
{
addFormat( builder );
currentLegacy = addFormat( builder, baseColor, currentLegacy );
builder.append( this.value );
super.toLegacyText( builder );
return super.toLegacyText( builder, baseColor, currentLegacy );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import net.md_5.bungee.api.ChatColor;

/**
* This component processes a target selector into a pre-formatted set of
Expand Down Expand Up @@ -76,10 +77,10 @@ protected void toPlainText(StringBuilder builder)
}

@Override
protected void toLegacyText(StringBuilder builder)
ComponentStyle toLegacyText(StringBuilder builder, ChatColor baseColor, ComponentStyle currentLegacy)
{
addFormat( builder );
currentLegacy = addFormat( builder, baseColor, currentLegacy );
builder.append( this.selector );
super.toLegacyText( builder );
return super.toLegacyText( builder, baseColor, currentLegacy );
}
}
11 changes: 7 additions & 4 deletions chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public TextComponent(BaseComponent... extras)
{
return;
}
setExtra( new ArrayList<BaseComponent>( Arrays.asList( extras ) ) );
setExtra( new ArrayList<>( Arrays.asList( extras ) ) );
}

/**
Expand All @@ -287,11 +287,14 @@ protected void toPlainText(StringBuilder builder)
}

@Override
protected void toLegacyText(StringBuilder builder)
ComponentStyle toLegacyText(StringBuilder builder, ChatColor baseColor, ComponentStyle currentLegacy)
{
addFormat( builder );
// cannot eliminate formatting codes if text is empty to keep test case testFormattingOnlyTextConversion happy
// (this could be solved to always add formatting if (parent == null) and to not ignore formatting at the end in
// general in case plugins are doing weird combinations with conversions
currentLegacy = addFormat( builder, baseColor, currentLegacy );
builder.append( text );
super.toLegacyText( builder );
return super.toLegacyText( builder, baseColor, currentLegacy );
}

@Override
Expand Down
Loading

0 comments on commit 32dfedc

Please sign in to comment.