Skip to content

Commit

Permalink
[Chat components] Rework component creation and converters
Browse files Browse the repository at this point in the history
  • Loading branch information
NEZNAMY committed Feb 1, 2025
1 parent 8749b3b commit 511acbd
Show file tree
Hide file tree
Showing 92 changed files with 589 additions and 652 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
package me.neznamy.tab.platforms.paper;

import me.neznamy.tab.platforms.bukkit.nms.converter.ComponentConverter;
import me.neznamy.tab.shared.chat.*;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.KeybindComponent;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.TextDecoration;
import me.neznamy.tab.shared.chat.ChatModifier;
import me.neznamy.tab.shared.chat.component.KeybindComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.chat.component.TextComponent;
import me.neznamy.tab.shared.chat.component.TranslatableComponent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextColor;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;

/**
* Component converter using direct mojang-mapped code for versions 1.20.5+.
Expand All @@ -26,81 +22,29 @@ public class PaperComponentConverter extends ComponentConverter {
@Override
@NotNull
public Component convert(@NotNull TabComponent component) {
switch (component) {
case SimpleComponent simpleComponent -> {
return Component.literal(simpleComponent.getText());
}
case StructuredComponent component1 -> {
MutableComponent nmsComponent = Component.literal(component1.getText());
ChatModifier modifier = component1.getModifier();
TextColor color = null;
if (modifier.getColor() != null) {
color = TextColor.fromRgb(modifier.getColor().getRgb());
}
nmsComponent.setStyle(newStyle(
color,
modifier.getBold(),
modifier.getItalic(),
modifier.getUnderlined(),
modifier.getStrikethrough(),
modifier.getObfuscated(),
modifier.getFont()
));
for (StructuredComponent extra : component1.getExtra()) {
nmsComponent.append(convert(extra));
}
return nmsComponent;
}
case AdventureComponent component1 -> {
return fromAdventure(component1.getComponent());
}
default -> throw new IllegalStateException("Unexpected component type: " + component.getClass().getName());
}
}

@NotNull
private Component fromAdventure(@NotNull net.kyori.adventure.text.Component component) {
// Component type
MutableComponent nmsComponent = switch (component) {
case TextComponent text -> Component.literal(text.content());
case TranslatableComponent translate -> Component.translatable(translate.key());
case KeybindComponent keyBind -> Component.keybind(keyBind.keybind());
default -> throw new IllegalStateException("Cannot convert " + component.getClass().getName());
case TextComponent text -> Component.literal(text.getText());
case TranslatableComponent translatable -> Component.translatable(translatable.getKey());
case KeybindComponent keybind -> Component.keybind(keybind.getKeybind());
default -> throw new IllegalStateException("Unexpected component type: " + component.getClass().getName());
};

net.kyori.adventure.text.format.TextColor color = component.color();
Key font = component.style().font();
Map<TextDecoration, TextDecoration.State> decorations = component.style().decorations();
nmsComponent.setStyle(newStyle(
color == null ? null : TextColor.fromRgb(color.value()),
getDecoration(decorations.get(TextDecoration.BOLD)),
getDecoration(decorations.get(TextDecoration.ITALIC)),
getDecoration(decorations.get(TextDecoration.UNDERLINED)),
getDecoration(decorations.get(TextDecoration.STRIKETHROUGH)),
getDecoration(decorations.get(TextDecoration.OBFUSCATED)),
font == null ? null : font.asString()
));
for (net.kyori.adventure.text.Component extra : component.children()) {
nmsComponent.append(fromAdventure(extra));
// Component style
ChatModifier modifier = component.getModifier();
nmsComponent.setStyle(Style.EMPTY
.withColor(modifier.getColor() == null ? null : TextColor.fromRgb(modifier.getColor().getRgb()))
.withBold(modifier.getBold())
.withItalic(modifier.getItalic())
.withUnderlined(modifier.getUnderlined())
.withStrikethrough(modifier.getStrikethrough())
.withObfuscated(modifier.getObfuscated())
.withFont(modifier.getFont() == null ? null : ResourceLocation.tryParse(modifier.getFont())));

// Extra
for (TabComponent extra : component.getExtra()) {
nmsComponent.append(convert(extra));
}
return nmsComponent;
}

@Nullable
private Boolean getDecoration(@Nullable TextDecoration.State state) {
if (state == null || state == TextDecoration.State.NOT_SET) return null;
return state == TextDecoration.State.TRUE;
}

@NotNull
private Style newStyle(@Nullable TextColor color, @Nullable Boolean bold, @Nullable Boolean italic, @Nullable Boolean underlined,
@Nullable Boolean strikethrough, @Nullable Boolean obfuscated, @Nullable String font) {
return Style.EMPTY
.withColor(color)
.withBold(bold)
.withItalic(italic)
.withUnderlined(underlined)
.withStrikethrough(strikethrough)
.withObfuscated(obfuscated)
.withFont(font == null ? null : ResourceLocation.tryParse(font));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.tablist.TabListBase;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.platform.TabList;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.minecraft.network.chat.Component;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
import me.neznamy.tab.platforms.bukkit.tablist.TabListBase;
import me.neznamy.tab.shared.backend.BackendTabPlayer;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.platform.TabList;
import org.bukkit.entity.Player;
import org.bukkit.metadata.MetadataValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lombok.RequiredArgsConstructor;
import me.neznamy.tab.api.bossbar.BarColor;
import me.neznamy.tab.api.bossbar.BarStyle;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.shared.platform.decorators.SafeBossBar;
import org.bukkit.Bukkit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import me.neznamy.tab.api.bossbar.BarColor;
import me.neznamy.tab.api.bossbar.BarStyle;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.platform.decorators.SafeBossBar;
import org.jetbrains.annotations.NotNull;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import lombok.Getter;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.util.ReflectionUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lombok.Getter;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.platforms.bukkit.BukkitUtils;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import me.neznamy.tab.platforms.bukkit.nms.BukkitReflection;
import me.neznamy.tab.platforms.bukkit.nms.converter.ComponentConverter;
import me.neznamy.tab.platforms.bukkit.nms.PacketSender;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.util.function.BiFunctionWithException;
import me.neznamy.tab.shared.util.ReflectionUtils;
import org.jetbrains.annotations.NotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import lombok.Getter;
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import me.neznamy.tab.platforms.bukkit.BukkitUtils;
import me.neznamy.tab.shared.ProtocolVersion;
import me.neznamy.tab.shared.chat.TabComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.util.ReflectionUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@

import lombok.SneakyThrows;
import me.neznamy.tab.platforms.bukkit.nms.BukkitReflection;
import me.neznamy.tab.shared.chat.*;
import me.neznamy.tab.shared.util.function.FunctionWithException;
import me.neznamy.tab.shared.chat.ChatModifier;
import me.neznamy.tab.shared.chat.component.KeybindComponent;
import me.neznamy.tab.shared.chat.component.TabComponent;
import me.neznamy.tab.shared.chat.component.TextComponent;
import me.neznamy.tab.shared.chat.component.TranslatableComponent;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.KeybindComponent;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.TextDecoration;
import me.neznamy.tab.shared.util.function.FunctionWithException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
Expand Down Expand Up @@ -77,7 +74,7 @@ public ReflectionComponentConverter() throws ReflectiveOperationException {
newTranslatableComponent = text -> newChatMessage.newInstance(text, new Object[0]);

newKeybindComponent = text -> {
throw new UnsupportedOperationException("Keybind component conversion is not implemented");
throw new UnsupportedOperationException("Keybind component conversion is not implemented on < 1.19");
};

Class<?> ChatBaseComponent = BukkitReflection.getClass("network.chat.BaseComponent", "network.chat.ChatBaseComponent", "ChatBaseComponent");
Expand Down Expand Up @@ -112,59 +109,28 @@ public ReflectionComponentConverter() throws ReflectiveOperationException {
@SneakyThrows
@NotNull
public Object convert(@NotNull TabComponent component) {
if (component instanceof SimpleComponent) {
return newTextComponent.apply(((SimpleComponent) component).getText());
} else if (component instanceof StructuredComponent) {
StructuredComponent component1 = (StructuredComponent) component;
Object nmsComponent = newTextComponent.apply(component1.getText());
Component_modifier.set(nmsComponent, convertModifier.apply(component1.getModifier()));
for (StructuredComponent extra : component1.getExtra()) {
ChatBaseComponent_addSibling.invoke(nmsComponent, convert(extra));
}
return nmsComponent;
} else {
return fromAdventure(((AdventureComponent)component).getComponent());
}
}

@SneakyThrows
@NotNull
private Object fromAdventure(@NotNull Component component) {
// Component type
Object nmsComponent;
if (component instanceof TextComponent) {
nmsComponent = newTextComponent.apply(((TextComponent) component).content());
nmsComponent = newTextComponent.apply(((TextComponent) component).getText());
} else if (component instanceof TranslatableComponent) {
nmsComponent = newTranslatableComponent.apply(((TranslatableComponent)component).key());
nmsComponent = newTranslatableComponent.apply(((TranslatableComponent) component).getKey());
} else if (component instanceof KeybindComponent) {
nmsComponent = newKeybindComponent.apply(((KeybindComponent)component).keybind());
nmsComponent = newKeybindComponent.apply(((KeybindComponent) component).getKeybind());
} else {
throw new IllegalStateException("Cannot convert " + component.getClass().getName());
throw new IllegalStateException("Unexpected component type: " + component.getClass().getName());
}

net.kyori.adventure.text.format.TextColor color = component.color();
Key font = component.style().font();
Map<TextDecoration, TextDecoration.State> decorations = component.style().decorations();
Component_modifier.set(nmsComponent, newStyleModern(
color == null ? null : ChatHexColor_fromRGB.invoke(null, color.value()),
getDecoration(decorations.get(TextDecoration.BOLD)),
getDecoration(decorations.get(TextDecoration.ITALIC)),
getDecoration(decorations.get(TextDecoration.UNDERLINED)),
getDecoration(decorations.get(TextDecoration.STRIKETHROUGH)),
getDecoration(decorations.get(TextDecoration.OBFUSCATED)),
font == null ? null : font.asString()
));
for (Component extra : component.children()) {
ChatBaseComponent_addSibling.invoke(nmsComponent, fromAdventure(extra));
// Component style
Component_modifier.set(nmsComponent, convertModifier.apply(component.getModifier()));

// Extra
for (TabComponent extra : component.getExtra()) {
ChatBaseComponent_addSibling.invoke(nmsComponent, convert(extra));
}
return nmsComponent;
}

@Nullable
private Boolean getDecoration(@Nullable TextDecoration.State state) {
if (state == null || state == TextDecoration.State.NOT_SET) return null;
return state == TextDecoration.State.TRUE;
}

@SneakyThrows
private Object createModifierModern(@NotNull ChatModifier modifier) {
return newStyleModern(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.backend.BackendPlatform;
import me.neznamy.tab.shared.chat.*;
import me.neznamy.tab.shared.chat.component.*;
import me.neznamy.tab.shared.features.PerWorldPlayerListConfiguration;
import me.neznamy.tab.shared.features.PlaceholderManagerImpl;
import me.neznamy.tab.shared.features.injection.PipelineInjector;
Expand All @@ -38,7 +38,6 @@
import me.neznamy.tab.shared.util.PerformanceUtil;
import me.neznamy.tab.shared.util.ReflectionUtils;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.milkbowl.vault.chat.Chat;
import net.milkbowl.vault.permission.Permission;
import org.bstats.bukkit.Metrics;
Expand Down Expand Up @@ -233,7 +232,7 @@ public void registerCommand() {
command.setExecutor(cmd);
command.setTabCompleter(cmd);
} else {
logWarn(TabComponent.fromColoredText("Failed to register command, is it defined in plugin.yml?"));
logWarn(new SimpleTextComponent("Failed to register command, is it defined in plugin.yml?"));
}
}

Expand Down Expand Up @@ -361,29 +360,30 @@ public void runSync(@NotNull Entity entity, @NotNull Runnable task) {
*/
@NotNull
public String toBukkitFormat(@NotNull TabComponent component) {
if (component instanceof SimpleComponent) {
return ((SimpleComponent) component).getText();
}
if (component instanceof StructuredComponent) {
StructuredComponent iComponent = (StructuredComponent) component;
StringBuilder sb = new StringBuilder();
if (iComponent.getModifier().getColor() != null) {
if (serverVersion.supportsRGB()) {
String hexCode = iComponent.getModifier().getColor().getHexCode();
sb.append('§').append("x").append('§').append(hexCode.charAt(0)).append('§').append(hexCode.charAt(1))
.append('§').append(hexCode.charAt(2)).append('§').append(hexCode.charAt(3))
.append('§').append(hexCode.charAt(4)).append('§').append(hexCode.charAt(5));
} else {
sb.append(iComponent.getModifier().getColor().getLegacyColor().getFormat());
}
}
sb.append(iComponent.getModifier().getMagicCodes());
sb.append(iComponent.getText());
for (StructuredComponent extra : iComponent.getExtra()) {
sb.append(toBukkitFormat(extra));
StringBuilder sb = new StringBuilder();
if (component.getModifier().getColor() != null) {
if (serverVersion.supportsRGB()) {
String hexCode = component.getModifier().getColor().getHexCode();
sb.append('§').append("x").append('§').append(hexCode.charAt(0)).append('§').append(hexCode.charAt(1))
.append('§').append(hexCode.charAt(2)).append('§').append(hexCode.charAt(3))
.append('§').append(hexCode.charAt(4)).append('§').append(hexCode.charAt(5));
} else {
sb.append(component.getModifier().getColor().getLegacyColor().getFormat());
}
return sb.toString();
}
return LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().build().serialize(((AdventureComponent)component).getComponent());
sb.append(component.getModifier().getMagicCodes());
if (component instanceof TextComponent) {
sb.append(((TextComponent) component).getText());
} else if (component instanceof TranslatableComponent) {
sb.append(((TranslatableComponent) component).getKey());
} else if (component instanceof KeybindComponent) {
sb.append(((KeybindComponent) component).getKeybind());
} else {
throw new IllegalStateException("Unexpected component type: " + component.getClass().getName());
}
for (TabComponent extra : component.getExtra()) {
sb.append(toBukkitFormat(extra));
}
return sb.toString();
}
}
Loading

0 comments on commit 511acbd

Please sign in to comment.