Migrate chat formatting to Paper's text component API (#130)

- Also updated the configs to use the interfaces
- Also updated the fun component to use a list config
- The text component change adds Paper as a requirement for this plugin
This commit is contained in:
Norbi Peti 2023-06-19 00:42:29 +02:00
parent 51cf31713b
commit e35e94e87c
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
16 changed files with 256 additions and 268 deletions

31
pom.xml
View file

@ -100,18 +100,23 @@
<id>Dynmap</id> <id>Dynmap</id>
<url>https://repo.mikeprimm.com</url> <url>https://repo.mikeprimm.com</url>
</repository> </repository>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>io.papermc.paper</groupId>
<artifactId>spigot-api</artifactId> <artifactId>paper-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version> <version>1.20.1-R0.1-SNAPSHOT</version>
</dependency> <scope>provided</scope>
<dependency> </dependency>
<groupId>com.github.TBMCPlugins.ChromaCore</groupId> <dependency>
<artifactId>Chroma-Core</artifactId> <groupId>com.github.TBMCPlugins.ChromaCore</groupId>
<artifactId>Chroma-Core</artifactId>
<version>v2.0.0-SNAPSHOT</version> <version>v2.0.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.essentialsx</groupId> <groupId>net.essentialsx</groupId>
<artifactId>EssentialsX</artifactId> <artifactId>EssentialsX</artifactId>
@ -141,12 +146,6 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- <dependency> <!-- <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId> <artifactId>spigot</artifactId>

View file

@ -1,8 +1,8 @@
package buttondevteam.chat; package buttondevteam.chat;
import buttondevteam.chat.components.flair.FlairStates; import buttondevteam.chat.components.flair.FlairStates;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.architecture.ListConfigData; import buttondevteam.lib.architecture.config.IListConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.player.PlayerClass; import buttondevteam.lib.player.PlayerClass;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
@ -13,22 +13,22 @@ import java.util.Collections;
@PlayerClass(pluginname = "Chroma-Chat") @PlayerClass(pluginname = "Chroma-Chat")
public class ChatPlayer extends TBMCPlayerBase { public class ChatPlayer extends TBMCPlayerBase {
public final ConfigData<String> UserName = getConfig().getData("UserName", ""); public final IConfigData<String> UserName = getConfig().getData("UserName", "");
public final ListConfigData<String> UserNames = getConfig().getListData("UserNames", Collections.emptyList()); public final IListConfigData<String> UserNames = getConfig().getListData("UserNames", Collections.emptyList());
public final ConfigData<Integer> FlairTime = getConfig().getData("FlairTime", FlairTimeNone); public final IConfigData<Integer> FlairTime = getConfig().getData("FlairTime", FlairTimeNone);
public final ConfigData<FlairStates> FlairState = getConfig().getData("FlairState", FlairStates.NoComment, public final IConfigData<FlairStates> FlairState = getConfig().getData("FlairState", FlairStates.NoComment,
fs -> FlairStates.valueOf((String) fs), FlairStates::toString); fs -> FlairStates.valueOf((String) fs), FlairStates::toString);
public final ConfigData<Integer> FCount = getConfig().getData("FCount", 0); public final IConfigData<Integer> FCount = getConfig().getData("FCount", 0);
public final ConfigData<Integer> FDeaths = getConfig().getData("FDeaths", 0); public final IConfigData<Integer> FDeaths = getConfig().getData("FDeaths", 0);
public final ConfigData<Boolean> FlairCheater = getConfig().getData("FlairCheater", false); public final IConfigData<Boolean> FlairCheater = getConfig().getData("FlairCheater", false);
public final ListConfigData<Integer> NameColorLocations = getConfig().getListData("NameColorLocations", Collections.emptyList()); // No byte[], no TIntArrayList public final IListConfigData<Integer> NameColorLocations = getConfig().getListData("NameColorLocations", Collections.emptyList()); // No byte[], no TIntArrayList
public boolean Working; public boolean Working;
// public int Tables = 10; // public int Tables = 10;

View file

@ -21,7 +21,7 @@ import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import com.earth2me.essentials.Essentials; import com.earth2me.essentials.Essentials;
@ -38,7 +38,7 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
* If enabled, stores and displays the last 10 messages the player can see (public, their town chat etc.) * If enabled, stores and displays the last 10 messages the player can see (public, their town chat etc.)
* Can be used with the Discord plugin so players can see some of the conversation they missed that's visible on Discord anyways. * Can be used with the Discord plugin so players can see some of the conversation they missed that's visible on Discord anyways.
*/ */
public ConfigData<Boolean> storeChatHistory = getIConfig().getData("storeChatHistory", true); public IConfigData<Boolean> storeChatHistory = getIConfig().getData("storeChatHistory", true);
// Fired when plugin is first enabled // Fired when plugin is first enabled
@Override @Override

View file

@ -5,8 +5,8 @@ import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.architecture.ListConfigData; import buttondevteam.lib.architecture.config.IListConfigData;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -20,12 +20,12 @@ public class AnnouncerComponent extends Component<PluginMain> implements Runnabl
/** /**
* The messages to display to players. * The messages to display to players.
*/ */
public ListConfigData<String> announceMessages = getConfig().getListData("announceMessages", Collections.emptyList()); public IListConfigData<String> announceMessages = getConfig().getListData("announceMessages", Collections.emptyList());
/** /**
* The time in milliseconds between the messages. Use /u announce settime to set minutes. * The time in milliseconds between the messages. Use /u announce settime to set minutes.
*/ */
public ConfigData<Integer> announceTime = getConfig().getData("announceTime", 15 * 60 * 1000); public IConfigData<Integer> announceTime = getConfig().getData("announceTime", 15 * 60 * 1000);
private TBMCSystemChatEvent.BroadcastTarget target; private TBMCSystemChatEvent.BroadcastTarget target;

View file

@ -2,8 +2,8 @@ package buttondevteam.chat.components.appendext;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.chat.*; import buttondevteam.lib.chat.*;
import lombok.val; import lombok.val;
@ -19,7 +19,7 @@ import java.util.function.Consumer;
public class AppendTextComponent extends Component<PluginMain> { public class AppendTextComponent extends Component<PluginMain> {
private Map<String, IHaveConfig> appendTexts; private Map<String, IHaveConfig> appendTexts;
private ConfigData<String[]> helpText(IHaveConfig config) { private IConfigData<String[]> helpText(IHaveConfig config) {
return config.getData("helpText", new String[]{ return config.getData("helpText", new String[]{
"Tableflip", // "Tableflip", //
"This command appends a tableflip after your message", // "This command appends a tableflip after your message", //
@ -27,7 +27,7 @@ public class AppendTextComponent extends Component<PluginMain> {
}); });
} }
private ConfigData<String> appendedText(IHaveConfig config) { private IConfigData<String> appendedText(IHaveConfig config) {
return config.getData("appendedText", "tableflip"); return config.getData("appendedText", "tableflip");
} }

View file

@ -2,13 +2,12 @@ package buttondevteam.chat.components.chatonly;
import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent;
import buttondevteam.chat.components.formatter.formatting.TellrawPart;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import lombok.val; import lombok.val;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@ -17,6 +16,10 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
/** /**
* Allows players to enter chat-only mode which puts them into spectator mode and disallows moving. * Allows players to enter chat-only mode which puts them into spectator mode and disallows moving.
*/ */
@ -43,12 +46,11 @@ public class ChatOnlyComponent extends Component<PluginMain> implements Listener
} }
} }
public static void tellrawCreate(ChatPlayer mp, TellrawPart json) { public static void tellrawCreate(ChatPlayer mp, TextComponent.Builder json) {
if (!ComponentManager.isEnabled(ChatOnlyComponent.class)) if (!ComponentManager.isEnabled(ChatOnlyComponent.class))
return; return;
if (mp != null && mp.ChatOnly) { if (mp != null && mp.ChatOnly) {
json.addExtra(new TellrawPart("[C]") json.append(text("[C]").hoverEvent(hoverEvent(SHOW_TEXT, text("Chat only"))));
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Chat only")));
} }
} }

View file

@ -5,7 +5,7 @@ import buttondevteam.chat.PluginMain;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -27,7 +27,7 @@ public class FlairComponent extends Component<PluginMain> {
/** /**
* The Reddit thread to check for account connections. Re-enable the component if this was empty. * The Reddit thread to check for account connections. Re-enable the component if this was empty.
*/ */
ConfigData<String> flairThreadURL = getConfig().getData("flairThreadURL", ""); IConfigData<String> flairThreadURL = getConfig().getData("flairThreadURL", "");
/** /**
* <p> * <p>

View file

@ -15,7 +15,6 @@ import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCChatEventBase;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TellrawSerializableEnum; import buttondevteam.lib.chat.TellrawSerializableEnum;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
@ -27,6 +26,10 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import lombok.val; import lombok.val;
import net.ess3.api.events.AfkStatusChangeEvent; import net.ess3.api.events.AfkStatusChangeEvent;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -39,12 +42,18 @@ import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.suggestCommand;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
import static net.kyori.adventure.text.format.NamedTextColor.*;
public class ChatProcessing { public class ChatProcessing {
private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)"); private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)");
private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)"); private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)");
private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)"); private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)");
private static final Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, private static final NamedTextColor[] RainbowPresserColors = new NamedTextColor[]{RED, GOLD, YELLOW, GREEN,
Color.Blue, Color.DarkPurple}; BLUE, DARK_PURPLE};
private static final Pattern WORD_PATTERN = Pattern.compile("\\S+"); private static final Pattern WORD_PATTERN = Pattern.compile("\\S+");
private static final Pattern GREENTEXT_PATTERN = Pattern.compile("^>(?:.|\\s)*"); private static final Pattern GREENTEXT_PATTERN = Pattern.compile("^>(?:.|\\s)*");
private static boolean pingedconsole = false; private static boolean pingedconsole = false;
@ -60,8 +69,8 @@ public class ChatProcessing {
cf.setHoverText(match); cf.setHoverText(match);
return match; return match;
}).build()), }).build()),
new StringMatchProvider("nullMention", FormatSettings.builder().color(Color.DarkRed).build(), true, "null"), // Properly added a bug as a feature new StringMatchProvider("nullMention", FormatSettings.builder().color(DARK_RED).build(), true, "null"), // Properly added a bug as a feature
new StringMatchProvider("consolePing", FormatSettings.builder().color(Color.Aqua) new StringMatchProvider("consolePing", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
if (!pingedconsole) { if (!pingedconsole) {
System.out.print("\007"); System.out.print("\007");
@ -70,8 +79,8 @@ public class ChatProcessing {
return "@console"; return "@console";
}).build(), true, "@console"), }).build(), true, "@console"),
new StringMatchProvider("cyan", FormatSettings.builder().color(Color.Aqua).build(), true, "cyan"), // #55 new StringMatchProvider("cyan", FormatSettings.builder().color(AQUA).build(), true, "cyan"), // #55
new RangeMatchProvider("code", "`", FormatSettings.builder().color(Color.DarkGray).build()), new RangeMatchProvider("code", "`", FormatSettings.builder().color(DARK_GRAY).build()),
new RegexMatchProvider("maskedLink", MASKED_LINK_PATTERN, FormatSettings.builder().underlined(true) new RegexMatchProvider("maskedLink", MASKED_LINK_PATTERN, FormatSettings.builder().underlined(true)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
String text, link; String text, link;
@ -81,8 +90,8 @@ public class ChatProcessing {
return text; return text;
}).build()), }).build()),
new RegexMatchProvider("url", URL_PATTERN, FormatSettings.builder().underlined(true).openlink("$1").build()), new RegexMatchProvider("url", URL_PATTERN, FormatSettings.builder().underlined(true).openlink("$1").build()),
new RegexMatchProvider("hashtag", HASHTAG_PATTERN, FormatSettings.builder().color(Color.Blue).openlink("https://twitter.com/hashtag/$1").build()), new RegexMatchProvider("hashtag", HASHTAG_PATTERN, FormatSettings.builder().color(BLUE).openlink("https://twitter.com/hashtag/$1").build()),
new StringMatchProvider("someone", FormatSettings.builder().color(Color.Aqua) new StringMatchProvider("someone", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
if (Bukkit.getOnlinePlayers().size() == 0) return match; if (Bukkit.getOnlinePlayers().size() == 0) return match;
var players = ImmutableList.copyOf(Bukkit.getOnlinePlayers()); var players = ImmutableList.copyOf(Bukkit.getOnlinePlayers());
@ -91,7 +100,7 @@ public class ChatProcessing {
playPingSound(player, ComponentManager.getIfEnabled(FormatterComponent.class)); playPingSound(player, ComponentManager.getIfEnabled(FormatterComponent.class));
return "@someone (" + player.getDisplayName() + "§r)"; return "@someone (" + player.getDisplayName() + "§r)";
}).build(), true, "@someone"), }).build(), true, "@someone"),
new RegexMatchProvider("greentext", GREENTEXT_PATTERN, FormatSettings.builder().color(Color.Green).build())); new RegexMatchProvider("greentext", GREENTEXT_PATTERN, FormatSettings.builder().color(GREEN).build()));
private static final Gson gson = new GsonBuilder() private static final Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum()) .registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum())
.registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection()) .registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection())
@ -145,42 +154,39 @@ public class ChatProcessing {
if (Bukkit.getOnlinePlayers().size() == 0) return false; //Don't try to send to nobody (errors on 1.14) if (Bukkit.getOnlinePlayers().size() == 0) return false; //Don't try to send to nobody (errors on 1.14)
Color colormode = channel.color.get(); TextColor colormode = NAMES.value(channel.color.get().getName());
if (mp != null && mp.OtherColorMode != null) boolean colorModeChanged = false;
colormode = mp.OtherColorMode; if (mp != null && mp.OtherColorMode != null) {
colormode = NAMES.value(mp.OtherColorMode.getName());
colorModeChanged = true;
}
ArrayList<MatchProviderBase> formatters; ArrayList<MatchProviderBase> formatters;
if (component.allowFormatting.get()) { if (component.allowFormatting.get()) {
formatters = addFormatters(sender -> e.shouldSendTo(ChromaGamerBase.getFromSender(sender)), component); formatters = addFormatters(sender -> e.shouldSendTo(ChromaGamerBase.getFromSender(sender)), component);
if (colormode == channel.color.get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color if (colorModeChanged && mp.RainbowPresserColorMode) { // Only overwrite channel color
createRPC(colormode, formatters); createRPC(colormode, formatters);
} }
pingedconsole = false; // Will set it to true onmatch (static constructor) pingedconsole = false; // Will set it to true onmatch (static constructor)
} else } else
formatters = Lists.newArrayList(); formatters = Lists.newArrayList();
TellrawPart json = createTellraw(cuser, message, player, mp, e.getUser(), channelidentifier, e.getOrigin()); TextComponent.Builder builder = createEmptyMessageLine(cuser, message, player, channelidentifier, e.getOrigin());
long combinetime = System.nanoTime(); long combinetime = System.nanoTime();
ChatFormatter.Combine(formatters, message, json, component.getConfig(), FormatSettings.builder().color(colormode).build()); ChatFormatter.Combine(formatters, message, builder, component.getConfig(), FormatSettings.builder().color(colormode).build());
combinetime = System.nanoTime() - combinetime; combinetime = System.nanoTime() - combinetime;
String jsonstr = toJson(json);
if (jsonstr.length() >= 32767) {
cuser.sendMessage("§cError: Message too long. Try shortening it, or remove hashtags and other formatting.");
return true;
}
DebugCommand.SendDebugMessage(jsonstr);
try { try {
if (!channel.isGlobal()) { if (!channel.isGlobal()) {
String senderGroup = e.getGroupID(sender); String senderGroup = e.getGroupID(cuser);
if (senderGroup == null) { // Never send messages if the group is null if (senderGroup == null) { // Never send messages if the group is null
sender.sendMessage("§cYou don't have permission to send this message or something went wrong"); cuser.sendMessage("§cYou don't have permission to send this message or something went wrong");
return true; return true;
} }
val tc = ComponentManager.getIfEnabled(TownyComponent.class); val tc = ComponentManager.getIfEnabled(TownyComponent.class);
Consumer<Player> spyConsumer = null; Consumer<Player> spyConsumer = null;
if (tc != null) if (tc != null)
spyConsumer = tc.handleSpiesInit(channel, json, ChatProcessing::toJson, cuser, message); spyConsumer = tc.handleSpiesInit(channel, builder);
for (Player p : Bukkit.getOnlinePlayers()) { for (Player p : Bukkit.getOnlinePlayers()) {
final String group; final String group;
if (player != null if (player != null
@ -188,19 +194,18 @@ public class ChatProcessing {
group = null; // Don't send the message to them group = null; // Don't send the message to them
else else
group = VanillaUtils.getGroupIfChatOn(p, e); group = VanillaUtils.getGroupIfChatOn(p, e);
if (senderGroup.equals(group)) if (senderGroup.equals(group)) {
if (!VanillaUtils.tellRaw(p, jsonstr)) p.sendMessage(builder.build());
p.sendMessage(ChatUtils.getMessageString(channel, sender, message)); if (tc != null) spyConsumer.accept(p);
else if (tc != null) spyConsumer.accept(p); }
//Only sends if didn't send normally //Only sends if didn't send normally
} }
} else } else
for (Player p : Bukkit.getOnlinePlayers()) for (Player p : Bukkit.getOnlinePlayers())
if (!VanillaUtils.tellRaw(p, jsonstr)) p.sendMessage(builder.build());
ChatUtils.sendChatMessage(channel, sender, message, p);
} catch (Exception ex) { } catch (Exception ex) {
TBMCCoreAPI.SendException("An error occured while sending a chat message!", ex, PluginMain.Instance); TBMCCoreAPI.SendException("An error occured while sending a chat message!", ex, PluginMain.Instance);
sender.sendMessage("§cAn error occured while sending the message."); cuser.sendMessage("§cAn error occured while sending the message.");
return true; return true;
} }
DebugCommand.SendDebugMessage( DebugCommand.SendDebugMessage(
@ -209,7 +214,7 @@ public class ChatProcessing {
return false; return false;
} }
static void createRPC(Color colormode, ArrayList<MatchProviderBase> formatters) { static void createRPC(TextColor colormode, ArrayList<MatchProviderBase> formatters) {
final AtomicInteger rpc = new AtomicInteger(0); final AtomicInteger rpc = new AtomicInteger(0);
formatters.add(new RegexMatchProvider("rpc", WORD_PATTERN, FormatSettings.builder().color(colormode).onmatch((match, cf, s) -> { formatters.add(new RegexMatchProvider("rpc", WORD_PATTERN, FormatSettings.builder().color(colormode).onmatch((match, cf, s) -> {
cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]);
@ -221,40 +226,25 @@ public class ChatProcessing {
return gson.toJson(json); return gson.toJson(json);
} }
static TellrawPart createTellraw(ChromaGamerBase user, String message, @Nullable Player player, static TextComponent.Builder createEmptyMessageLine(ChromaGamerBase user, String message, @Nullable Player player,
@Nullable ChatPlayer mp, @Nullable ChromaGamerBase cg, final String channelidentifier, final String channelidentifier, String origin) {
String origin) { val json = text();
TellrawPart json = new TellrawPart(""); ChatOnlyComponent.tellrawCreate(user.getAs(ChatPlayer.class), json);
ChatOnlyComponent.tellrawCreate(mp, json); //TODO: Use nice API (Paper) val channelHover = (ChatUtils.MCORIGIN.equals(origin) ? "" : "From " + origin + "\n") + "Copy message";
json.addExtra( json.append(text(channelidentifier)
new TellrawPart(channelidentifier) .hoverEvent(hoverEvent(SHOW_TEXT, text(channelHover).color(BLUE))).clickEvent(suggestCommand(message)));
.setHoverEvent( if (PluginMain.permission.has(player, "tbmc.badge.diamond")) // TODO: Cross-platform permissions
TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, json.append(text("[P]").color(AQUA).decorate(TextDecoration.BOLD)
new TellrawPart((ChatUtils.MCORIGIN.equals(origin) ? "" : "From " + origin + "\n") .hoverEvent(hoverEvent(SHOW_TEXT, text("Diamond Patreon supporter"))));
+ "Copy message").setColor(Color.Blue))) else if (PluginMain.permission.has(player, "tbmc.badge.gold"))
.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.SUGGEST_COMMAND, message))); json.append(text("[P]").color(GOLD).decorate(TextDecoration.BOLD)
if (PluginMain.permission.has(sender, "tbmc.badge.diamond")) .hoverEvent(hoverEvent(SHOW_TEXT, text("Gold Patreon supporter"))));
json.addExtra(new TellrawPart("[P]").setColor(Color.Aqua).setBold(true) json.append(text(" <"));
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Diamond Patreon supporter"))); json.append(text(user.getName()).hoverEvent(hoverEvent(SHOW_TEXT, text(user.getInfo(ChromaGamerBase.InfoTarget.MCHover)))));
else if (PluginMain.permission.has(sender, "tbmc.badge.gold")) json.append(text("> "));
json.addExtra(new TellrawPart("[P]").setColor(Color.Gold).setBold(true)
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Gold Patreon supporter")));
json.addExtra(new TellrawPart(" <"));
TellrawPart hovertp = new TellrawPart("");
if (cg != null)
hovertp.addExtra(new TellrawPart(cg.getInfo(ChromaGamerBase.InfoTarget.MCHover)));
json.addExtra(new TellrawPart(user.getName())
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, hovertp)));
json.addExtra(new TellrawPart("> "));
return json; return json;
} }
private static String getSenderName(CommandSender sender, Player player) {
if (player == null)
return sender.getName();
return player.getDisplayName();
}
static String getChannelID(Channel channel, String origin) { static String getChannelID(Channel channel, String origin) {
return ("[" + (ChatUtils.MCORIGIN.equals(origin) ? "" : "§8" + origin.charAt(0) + "§r|") + channel.displayName.get()) return ("[" + (ChatUtils.MCORIGIN.equals(origin) ? "" : "§8" + origin.charAt(0) + "§r|") + channel.displayName.get())
+ "]"; + "]";
@ -284,12 +274,12 @@ public class ChatProcessing {
}; };
if (names.length > 0) //Add as first so it handles special characters (_) - though the order of the different types are defined if (names.length > 0) //Add as first so it handles special characters (_) - though the order of the different types are defined
formatters.add(0, new StringMatchProvider("name", FormatSettings.builder().color(Color.Aqua) formatters.add(0, new StringMatchProvider("name", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
Player p = Bukkit.getPlayer(match); Player p = Bukkit.getPlayer(match);
Optional<String> pn = nottest ? Optional.empty() Optional<String> pn = nottest ? Optional.empty()
: Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny(); : Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny();
if (nottest ? p == null : !pn.isPresent()) { if (nottest ? p == null : pn.isEmpty()) {
error.accept("Error: Can't find player " + match + " but was reported as online."); error.accept("Error: Can't find player " + match + " but was reported as online.");
return "§c" + match + "§r"; return "§c" + match + "§r";
} }
@ -302,7 +292,7 @@ public class ChatProcessing {
}).build(), true, names)); }).build(), true, names));
if (nicknames.length > 0) //Add as first so it handles special characters if (nicknames.length > 0) //Add as first so it handles special characters
formatters.add(0, new StringMatchProvider("nickname", FormatSettings.builder().color(Color.Aqua) formatters.add(0, new StringMatchProvider("nickname", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased
Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase())); Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase()));

View file

@ -5,7 +5,7 @@ import buttondevteam.core.ComponentManager;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
/** /**
* This component handles the custom processing of chat messages. If this component is disabled channels won't be supported in Minecraft. * This component handles the custom processing of chat messages. If this component is disabled channels won't be supported in Minecraft.
@ -16,22 +16,22 @@ public class FormatterComponent extends Component<PluginMain> {
/** /**
* Determines whether Markdown formatting, name mentioning and similar features are enabled. * Determines whether Markdown formatting, name mentioning and similar features are enabled.
*/ */
ConfigData<Boolean> allowFormatting = getConfig().getData("allowFormatting", true); IConfigData<Boolean> allowFormatting = getConfig().getData("allowFormatting", true);
/** /**
* The sound to play when a player is mentioned. Leave empty to use default. * The sound to play when a player is mentioned. Leave empty to use default.
*/ */
public ConfigData<String> notificationSound = getConfig().getData("notificationSound", ""); public IConfigData<String> notificationSound = getConfig().getData("notificationSound", "");
/** /**
* The pitch of the notification sound. * The pitch of the notification sound.
*/ */
public ConfigData<Float> notificationPitch = getConfig().getData("notificationPitch", 1.0f); public IConfigData<Float> notificationPitch = getConfig().getData("notificationPitch", 1.0f);
/** /**
* The minimum time between messages in milliseconds. * The minimum time between messages in milliseconds.
*/ */
public ConfigData<Integer> minTimeBetweenMessages = getConfig().getData("minTimeBetweenMessages", 100); public IConfigData<Integer> minTimeBetweenMessages = getConfig().getData("minTimeBetweenMessages", 100);
@Override @Override
protected void enable() { protected void enable() {

View file

@ -2,15 +2,24 @@ package buttondevteam.chat.components.formatter.formatting;
import buttondevteam.chat.commands.ucmds.admin.DebugCommand; import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.chat.Color;
import lombok.val; import lombok.val;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.Action.OPEN_URL;
import static net.kyori.adventure.text.event.ClickEvent.clickEvent;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
/** /**
* A {@link MatchProvider} finds where the given {@link FormatSettings} need to be applied. {@link ChatFormatter#Combine(List, String, TellrawPart, IHaveConfig, FormatSettings)}} is used to turn it into a {@link TellrawPart}, combining * A {@link MatchProvider} finds where the given {@link FormatSettings} need to be applied. {@link ChatFormatter#Combine(List, String, TextComponent.Builder, IHaveConfig, FormatSettings)}} is used to turn it into a {@link TellrawPart}, combining
* intersecting parts found, for example when {@code _abc*def*ghi_} is said in chat, it'll turn it into an underlined part, then an underlined <i>and italics</i> part, finally an underlined part * intersecting parts found, for example when {@code _abc*def*ghi_} is said in chat, it'll turn it into an underlined part, then an underlined <i>and italics</i> part, finally an underlined part
* again. * again.
* *
@ -26,7 +35,7 @@ public final class ChatFormatter {
} }
//synchronized: Some of the formatters are reused, see createSections(...) //synchronized: Some of the formatters are reused, see createSections(...)
public static synchronized void Combine(List<MatchProviderBase> formatters, String str, TellrawPart tp, IHaveConfig config, FormatSettings defaults) { public static synchronized void Combine(List<MatchProviderBase> formatters, String str, TextComponent.Builder tp, IHaveConfig config, FormatSettings defaults) {
/* /*
* A global formatter is no longer needed * A global formatter is no longer needed
*/ */
@ -152,11 +161,11 @@ public final class ChatFormatter {
DebugCommand.SendDebugMessage("To sections"); DebugCommand.SendDebugMessage("To sections");
if (!removeIfNeeded.test(firstSection)) { if (!removeIfNeeded.test(firstSection)) {
DebugCommand.SendDebugMessage(" 1:" + firstSection + ""); DebugCommand.SendDebugMessage(" 1:" + firstSection);
ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End); ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End);
} }
if (!removeIfNeeded.test(section)) { if (!removeIfNeeded.test(section)) {
DebugCommand.SendDebugMessage(" 2:" + section + ""); DebugCommand.SendDebugMessage(" 2:" + section);
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End); ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
} }
if (!removeIfNeeded.test(lastSection)) { if (!removeIfNeeded.test(lastSection)) {
@ -169,8 +178,8 @@ public final class ChatFormatter {
} }
} }
private static void applySections(String str, TellrawPart tp, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) { private static void applySections(String str, TextComponent.Builder tp, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
TellrawPart lasttp = null; TextComponent lasttp = null;
String lastlink = null; String lastlink = null;
for (FormattedSection section : sections) { for (FormattedSection section : sections) {
DebugCommand.SendDebugMessage("Applying section: " + section); DebugCommand.SendDebugMessage("Applying section: " + section);
@ -178,21 +187,9 @@ public final class ChatFormatter {
int start = section.Start, end = section.End; int start = section.Start, end = section.End;
DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end); DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end);
ChatFormatUtils.sendMessageWithPointer(str, start, end); ChatFormatUtils.sendMessageWithPointer(str, start, end);
/*DebugCommand.SendDebugMessage("RCS: "+remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).count());
DebugCommand.SendDebugMessage("RCE: "+remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).count());
DebugCommand.SendDebugMessage("RCI: "+remchars.stream().filter(rc -> start < rc[0] || rc[1] < end).count());*/
val rci = remchars.stream().filter(rc -> (rc[0] <= start && rc[1] >= start) val rci = remchars.stream().filter(rc -> (rc[0] <= start && rc[1] >= start)
|| (rc[0] >= start && rc[1] <= end) || (rc[0] >= start && rc[1] <= end)
|| (rc[0] <= end && rc[1] >= end)).sorted(Comparator.comparingInt(rc -> rc[0] * 10000 + rc[1])).toArray(int[][]::new); || (rc[0] <= end && rc[1] >= end)).sorted(Comparator.comparingInt(rc -> rc[0] * 10000 + rc[1])).toArray(int[][]::new);
/*if (rcs.isPresent())
s = rcs.get()[1] + 1;
if (rce.isPresent())
e = rce.get()[0] - 1;
DebugCommand.SendDebugMessage("After RC - Start: " + s + " - End: " + e);
if (e - s < 0) { //e-s==0 means the end char is the same as start char, so one char message
DebugCommand.SendDebugMessage("Skipping section because of remchars (length would be " + (e - s + 1) + ")");
continue;
}*/
DebugCommand.SendDebugMessage("Applying RC: " + Arrays.stream(rci).map(Arrays::toString).collect(Collectors.joining(", ", "[", "]"))); DebugCommand.SendDebugMessage("Applying RC: " + Arrays.stream(rci).map(Arrays::toString).collect(Collectors.joining(", ", "[", "]")));
originaltext = str.substring(start, end + 1); originaltext = str.substring(start, end + 1);
val sb = new StringBuilder(originaltext); val sb = new StringBuilder(originaltext);
@ -205,50 +202,52 @@ public final class ChatFormatter {
} }
DebugCommand.SendDebugMessage("Section text: " + originaltext); DebugCommand.SendDebugMessage("Section text: " + originaltext);
String openlink = null; String openlink = null;
//section.Formatters.sort(Comparator.comparing(cf2 -> cf2.priority.GetValue())); //Apply the highest last, to overwrite previous ones
TellrawPart newtp = new TellrawPart("");
var settings = section.Settings; var settings = section.Settings;
DebugCommand.SendDebugMessage("Applying settings: " + settings); DebugCommand.SendDebugMessage("Applying settings: " + settings);
if (lasttp != null && hasSameDecorations(lasttp, settings) && Objects.equals(lastlink, settings.openlink)) {
DebugCommand.SendDebugMessage("This part has the same properties as the previous one, combining.");
lasttp = lasttp.content(lasttp.content() + originaltext);
continue; //Combine parts with the same properties
}
TextComponent.@NotNull Builder newtp = text();
if (settings.onmatch != null) if (settings.onmatch != null)
originaltext = settings.onmatch.apply(originaltext, settings, section); originaltext = settings.onmatch.apply(originaltext, settings, section);
if (settings.color != null) if (settings.color != null)
newtp.setColor(settings.color); newtp.color(settings.color);
if (settings.bold) if (settings.bold)
newtp.setBold(true); newtp.decorate(TextDecoration.BOLD);
if (settings.italic) if (settings.italic)
newtp.setItalic(true); newtp.decorate(TextDecoration.ITALIC);
if (settings.underlined) if (settings.underlined)
newtp.setUnderlined(true); newtp.decorate(TextDecoration.UNDERLINED);
if (settings.strikethrough) if (settings.strikethrough)
newtp.setStrikethrough(true); newtp.decorate(TextDecoration.STRIKETHROUGH);
if (settings.obfuscated) if (settings.obfuscated)
newtp.setObfuscated(true); newtp.decorate(TextDecoration.OBFUSCATED);
if (settings.openlink != null) if (settings.openlink != null)
openlink = settings.openlink; openlink = settings.openlink;
if (settings.hoverText != null) if (settings.hoverText != null)
newtp.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, settings.hoverText)); newtp.hoverEvent(hoverEvent(SHOW_TEXT, text(settings.hoverText)));
if (lasttp != null && newtp.getColor() == lasttp.getColor() if (lasttp != null) tp.append(lasttp);
&& newtp.isBold() == lasttp.isBold()
&& newtp.isItalic() == lasttp.isItalic()
&& newtp.isUnderlined() == lasttp.isUnderlined()
&& newtp.isStrikethrough() == lasttp.isStrikethrough()
&& newtp.isObfuscated() == lasttp.isObfuscated()
&& Objects.equals(openlink, lastlink)) {
DebugCommand.SendDebugMessage("This part has the same properties as the previous one, combining.");
lasttp.setText(lasttp.getText() + originaltext);
continue; //Combine parts with the same properties
}
lastlink = openlink; lastlink = openlink;
newtp.setText(originaltext); newtp.content(originaltext);
if (openlink != null && openlink.length() > 0) { if (openlink != null && openlink.length() > 0) {
newtp.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.OPEN_URL, if (section.Matches.size() > 0)
(section.Matches.size() > 0 ? openlink.replace("$1", section.Matches.get(0)) : openlink))) openlink = openlink.replace("$1", section.Matches.get(0));
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, newtp.clickEvent(clickEvent(OPEN_URL, openlink)).hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(NamedTextColor.BLUE)));
new TellrawPart("Click to open").setColor(Color.Blue)));
} }
tp.addExtra(newtp); lasttp = newtp.build();
lasttp = newtp;
} }
if (lasttp != null) tp.append(lasttp);
}
private static boolean hasSameDecorations(TextComponent c1, FormatSettings settings) {
return Objects.equals(c1.color(), settings.color)
&& c1.hasDecoration(TextDecoration.BOLD) == settings.bold
&& c1.hasDecoration(TextDecoration.ITALIC) == settings.italic
&& c1.hasDecoration(TextDecoration.UNDERLINED) == settings.underlined
&& c1.hasDecoration(TextDecoration.STRIKETHROUGH) == settings.strikethrough
&& c1.hasDecoration(TextDecoration.OBFUSCATED) == settings.obfuscated;
} }
private static void sortSections(ArrayList<FormattedSection> sections) { private static void sortSections(ArrayList<FormattedSection> sections) {

View file

@ -1,8 +1,8 @@
package buttondevteam.chat.components.formatter.formatting; package buttondevteam.chat.components.formatter.formatting;
import buttondevteam.lib.chat.Color;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import net.kyori.adventure.text.format.TextColor;
/** /**
* Describes how a matched section of the message should look. May be combined with other format settings. * Describes how a matched section of the message should look. May be combined with other format settings.
@ -15,7 +15,7 @@ public class FormatSettings {
boolean underlined; boolean underlined;
boolean strikethrough; boolean strikethrough;
boolean obfuscated; boolean obfuscated;
Color color; TextColor color;
ChatFormatter.TriFunc<String, FormatSettings, FormattedSection, String> onmatch; ChatFormatter.TriFunc<String, FormatSettings, FormattedSection, String> onmatch;
String openlink; String openlink;
String hoverText; String hoverText;

View file

@ -1,7 +1,7 @@
package buttondevteam.chat.components.formatter.formatting; package buttondevteam.chat.components.formatter.formatting;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.architecture.config.IConfigData;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -31,7 +31,7 @@ public abstract class MatchProviderBase implements MatchProvider {
resetSubclass(); resetSubclass();
} }
ConfigData<Boolean> enabled(IHaveConfig config) { IConfigData<Boolean> enabled(IHaveConfig config) {
return config.getData(name + ".enabled", true); return config.getData(name + ".enabled", true);
} }

View file

@ -7,11 +7,13 @@ import buttondevteam.lib.TBMCChatEventBase;
import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCCommandPreprocessEvent;
import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.architecture.config.IListConfigData;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import com.google.common.collect.Lists;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -44,20 +46,20 @@ public class FunComponent extends Component<PluginMain> implements Listener {
/** /**
* The strings that count as laughs, see unlol. * The strings that count as laughs, see unlol.
*/ */
private final ConfigData<String[]> laughStrings = getConfig().getData("laughStrings", new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"}); private final IListConfigData<String> laughStrings = getConfig().getListData("laughStrings", Lists.newArrayList("xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"));
/** /**
* The "Press F to pay respects" meme in Minecraft. It will randomly appear on player death and keep track of how many "F"s are said in chat. * The "Press F to pay respects" meme in Minecraft. It will randomly appear on player death and keep track of how many "F"s are said in chat.
* You can hover over a player's name to see their respect. * You can hover over a player's name to see their respect.
*/ */
private final ConfigData<Boolean> respect = getConfig().getData("respect", true); private final IConfigData<Boolean> respect = getConfig().getData("respect", true);
/** /**
* This is an inside joke on our server. * This is an inside joke on our server.
* It keeps track of laughs (lols and what's defined in laughStrings) and if someone does /unlol or /unlaugh it will unlaugh the last person who laughed. * It keeps track of laughs (lols and what's defined in laughStrings) and if someone does /unlol or /unlaugh it will unlaugh the last person who laughed.
* Which also blinds the laughing person for a few seconds. This action can only be performed once per laugh. * Which also blinds the laughing person for a few seconds. This action can only be performed once per laugh.
*/ */
private final ConfigData<Boolean> unlol = getConfig().getData("unlol", true); private final IConfigData<Boolean> unlol = getConfig().getData("unlol", true);
@Override @Override
protected void enable() { protected void enable() {
@ -90,7 +92,7 @@ public class FunComponent extends Component<PluginMain> implements Listener {
if (add) if (add)
lld.setLolornot(true); lld.setLolornot(true);
else { else {
String[] laughs = laughStrings.get(); val laughs = laughStrings.get();
for (String laugh : laughs) { for (String laugh : laughs) {
add = msg.contains(laugh); add = msg.contains(laugh);
if (add) { if (add) {

View file

@ -8,7 +8,7 @@ import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
@ -53,13 +53,13 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
/** /**
* The amount of town colors allowed. If more than one is used (or nation colors are enabled), players can change how many letters to be in a specific color using /u ncolor. * The amount of town colors allowed. If more than one is used (or nation colors are enabled), players can change how many letters to be in a specific color using /u ncolor.
*/ */
public final ConfigData<Byte> colorCount = getConfig().getData("colorCount", (byte) 1, cc -> ((Integer) cc).byteValue(), Byte::intValue); public final IConfigData<Byte> colorCount = getConfig().getData("colorCount", (byte) 1, cc -> ((Integer) cc).byteValue(), Byte::intValue);
/** /**
* If enabled, players will have a nation-defined color in addition to town colors, white by default. * If enabled, players will have a nation-defined color in addition to town colors, white by default.
* They can change how much of each color they want with this as well. * They can change how much of each color they want with this as well.
*/ */
public final ConfigData<Boolean> useNationColors = getConfig().getData("useNationColors", true); public final IConfigData<Boolean> useNationColors = getConfig().getData("useNationColors", true);
@Getter @Getter
private static TownColorComponent component; private static TownColorComponent component;

View file

@ -1,9 +1,6 @@
package buttondevteam.chat.components.towny; package buttondevteam.chat.components.towny;
import buttondevteam.chat.ChatUtils;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.chat.VanillaUtils;
import buttondevteam.chat.components.formatter.formatting.TellrawPart;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
@ -17,12 +14,11 @@ import com.palmergames.bukkit.towny.object.Nation;
import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.Town;
import lombok.val; import lombok.val;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -55,25 +51,23 @@ public class TownyComponent extends Component<PluginMain> {
TownyAnnouncer.setdown(); TownyAnnouncer.setdown();
} }
public Consumer<Player> handleSpiesInit(Channel channel, TellrawPart json, Function<TellrawPart, String> toJson, public Consumer<Player> handleSpiesInit(Channel channel, TextComponent.Builder json) {
ChromaGamerBase sender, String message) {
if (channel.getIdentifier().equals(TownChat.getIdentifier()) || channel.getIdentifier().equals(NationChat.getIdentifier())) { if (channel.getIdentifier().equals(TownChat.getIdentifier()) || channel.getIdentifier().equals(NationChat.getIdentifier())) {
((List<TellrawPart>) json.getExtra()).add(0, new TellrawPart("[SPY]")); // TODO: Cannot prepend to json, so we need to run this ealier
String jsonstr = toJson.apply(json); //((List<TellrawPart>) json.getExtra()).add(0, new TellrawPart("[SPY]"));
return p -> handleSpies(channel, p, jsonstr, sender, message); return p -> handleSpies(channel, p, json);
} }
return p -> {}; return p -> {};
} }
private void handleSpies(Channel channel, Player p, String jsonstr, ChromaGamerBase sender, String message) { private void handleSpies(Channel channel, Player p, TextComponent.Builder jsonstr) {
if (channel.getIdentifier().equals(TownChat.getIdentifier()) || channel.getIdentifier().equals(NationChat.getIdentifier())) { if (channel.getIdentifier().equals(TownChat.getIdentifier()) || channel.getIdentifier().equals(NationChat.getIdentifier())) {
val res = dataSource.getResident(p.getName()); val res = dataSource.getResident(p.getName());
if (res == null) { if (res == null) {
return; return;
} }
if (res.hasMode("spy")) if (res.hasMode("spy"))
if (!VanillaUtils.tellRaw(p, jsonstr)) p.sendMessage(jsonstr.build());
ChatUtils.sendChatMessage(channel, sender, message, p);
} }
} }

View file

@ -1,21 +1,23 @@
package buttondevteam.chat.components.formatter; package buttondevteam.chat.components.formatter;
import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.ChatUtils; import buttondevteam.chat.ChatUtils;
import buttondevteam.chat.ObjectTestRunner; import buttondevteam.chat.ObjectTestRunner;
import buttondevteam.chat.ObjectTestRunner.Objects; import buttondevteam.chat.ObjectTestRunner.Objects;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.chat.commands.ucmds.admin.DebugCommand; import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
import buttondevteam.chat.components.formatter.formatting.*; import buttondevteam.chat.components.formatter.formatting.ChatFormatter;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent.ClickAction; import buttondevteam.chat.components.formatter.formatting.FormatSettings;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent.HoverAction; import buttondevteam.chat.components.formatter.formatting.MatchProviderBase;
import buttondevteam.core.TestPrepare; import buttondevteam.core.TestPrepare;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.milkbowl.vault.permission.Permission; import net.milkbowl.vault.permission.Permission;
import org.bukkit.command.CommandSender;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -25,101 +27,101 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.Action.OPEN_URL;
import static net.kyori.adventure.text.event.ClickEvent.clickEvent;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
import static net.kyori.adventure.text.format.NamedTextColor.*;
import static net.kyori.adventure.text.format.TextDecoration.*;
@RunWith(ObjectTestRunner.class) @RunWith(ObjectTestRunner.class)
public class ChatFormatIT { public class ChatFormatIT {
@Objects @Objects
public static List<Object> data() { public static List<Object> data() {
TestPrepare.PrepareServer(); TestPrepare.PrepareServer();
final CommandSender sender = Mockito.mock(CommandSender.class); var sender = ChromaGamerBase.getUser("test", ChatPlayer.class);
DebugCommand.DebugMode = true; DebugCommand.DebugMode = true;
PluginMain.permission = Mockito.mock(Permission.class); PluginMain.permission = Mockito.mock(Permission.class);
TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class, TBMCPlayer::new); TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class, TBMCPlayer::new);
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
list.add(new ChatFormatIT(sender, "*test*", new TellrawPart("test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "*test*", text("test").decorate(ITALIC).color(WHITE)));
list.add(new ChatFormatIT(sender, "**test**", new TellrawPart("test").setBold(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test**", text("test").decorate(BOLD).color(WHITE)));
list.add(new ChatFormatIT(sender, "***test***", list.add(new ChatFormatIT(sender, "***test***", text("test").decorate(BOLD, ITALIC).color(WHITE)));
new TellrawPart("test").setBold(true).setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "***__test__***", text("test").decorate(BOLD, ITALIC, UNDERLINED).color(WHITE)));
list.add(new ChatFormatIT(sender, "***__test__***", list.add(new ChatFormatIT(sender, "***__~~test~~__***", text("test").decorate(BOLD, ITALIC, UNDERLINED, STRIKETHROUGH).color(WHITE)));
new TellrawPart("test").setBold(true).setItalic(true).setUnderlined(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "¯\\\\\\_(ツ)\\_/¯", text("¯\\_(ツ)_/¯").color(WHITE)));
list.add(new ChatFormatIT(sender, "***__~~test~~__***", new TellrawPart("test").setBold(true).setItalic(true)
.setUnderlined(true).setStrikethrough(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "¯\\\\\\_(ツ)\\_/¯", new TellrawPart("¯\\_(ツ)_/¯").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "https://google.hu/", list.add(new ChatFormatIT(sender, "https://google.hu/",
new TellrawPart("https://google.hu/").setColor(Color.White).setUnderlined(true) text("https://google.hu/").color(WHITE).decorate(UNDERLINED)
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
new TellrawPart("Click to open").setColor(Color.Blue))) .clickEvent(clickEvent(OPEN_URL, "https://google.hu/"))));
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://google.hu/")))); list.add(new ChatFormatIT(sender, "*test", text("*test").color(WHITE)));
list.add(new ChatFormatIT(sender, "*test", new TellrawPart("*test").setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test*", text("**test*").color(WHITE)));
list.add(new ChatFormatIT(sender, "**test*", new TellrawPart("**test*").setColor(Color.White))); list.add(new ChatFormatIT(sender, "***test", text("***test").color(WHITE)));
list.add(new ChatFormatIT(sender, "***test", new TellrawPart("***test").setColor(Color.White))); list.add(new ChatFormatIT(sender, "Koiiev", text("§bKoiiev§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "Koiiev", new TellrawPart("§bKoiiev§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "norbipeti", text("§bNorbiPeti§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "norbipeti", new TellrawPart("§bNorbiPeti§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "Arsen_Derby_FTW", text("§bArsen_Derby_FTW§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "Arsen_Derby_FTW", new TellrawPart("§bArsen_Derby_FTW§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "carrot_lynx", text("§bcarrot_lynx§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "carrot_lynx", new TellrawPart("§bcarrot_lynx§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "*carrot_lynx*", text("§bcarrot_lynx§r").decorate(ITALIC).color(AQUA)));
list.add(new ChatFormatIT(sender, "*carrot_lynx*", new TellrawPart("§bcarrot_lynx§r").setItalic(true).setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/", text("https://norbipeti.github.io/")
list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/", new TellrawPart("https://norbipeti.github.io/") .color(WHITE).decorate(UNDERLINED)
.setColor(Color.White).setUnderlined(true) .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/"))));
new TellrawPart("Click to open").setColor(Color.Blue))) list.add(new ChatFormatIT(sender, "*https://norbipeti.github.io/ heh*", text("https://norbipeti.github.io/").decorate(ITALIC).decorate(UNDERLINED)
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")))); .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
list.add(new ChatFormatIT(sender, "*https://norbipeti.github.io/ heh*", new TellrawPart("https://norbipeti.github.io/").setItalic(true).setUnderlined(true) .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/")).color(WHITE), text(" heh").decorate(ITALIC).color(WHITE)));
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, list.add(new ChatFormatIT(sender, "*test _test_ test*", text("test test test").decorate(ITALIC).color(WHITE)));
new TellrawPart("Click to open").setColor(Color.Blue))) list.add(new ChatFormatIT(sender, "*test __test__ test*", text("test ").decorate(ITALIC).color(WHITE),
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")).setColor(Color.White), new TellrawPart(" heh").setItalic(true).setColor(Color.White))); text("test").decorate(ITALIC).decorate(UNDERLINED).color(WHITE), text(" test").decorate(ITALIC).color(WHITE)));
list.add(new ChatFormatIT(sender, "*test _test_ test*", new TellrawPart("test test test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test __test__ test**", text("test ").decorate(BOLD).color(WHITE),
list.add(new ChatFormatIT(sender, "*test __test__ test*", new TellrawPart("test ").setItalic(true).setColor(Color.White), text("test").decorate(BOLD).decorate(UNDERLINED).color(WHITE), text(" test").decorate(BOLD).color(WHITE)));
new TellrawPart("test").setItalic(true).setUnderlined(true).setColor(Color.White), new TellrawPart(" test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test _test_ test**", text("test ").decorate(BOLD).color(WHITE),
list.add(new ChatFormatIT(sender, "**test __test__ test**", new TellrawPart("test ").setBold(true).setColor(Color.White), text("test").decorate(ITALIC).decorate(BOLD).color(WHITE), text(" test").decorate(BOLD).color(WHITE)));
new TellrawPart("test").setBold(true).setUnderlined(true).setColor(Color.White), new TellrawPart(" test").setBold(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/test?test&test#test", text("https://norbipeti.github.io/test?test&test#test")
list.add(new ChatFormatIT(sender, "**test _test_ test**", new TellrawPart("test ").setBold(true).setColor(Color.White), .color(WHITE).decorate(UNDERLINED)
new TellrawPart("test").setItalic(true).setBold(true).setColor(Color.White), new TellrawPart(" test").setBold(true).setColor(Color.White))); .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/test?test&test#test", new TellrawPart("https://norbipeti.github.io/test?test&test#test") .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/test?test&test#test"))));
.setColor(Color.White).setUnderlined(true) list.add(new ChatFormatIT(sender, "[hmm](https://norbipeti.github.io/test)", text("hmm")
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .color(WHITE).decorate(UNDERLINED)
new TellrawPart("Click to open").setColor(Color.Blue))) .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test?test&test#test")))); .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/test"))));
list.add(new ChatFormatIT(sender, "[hmm](https://norbipeti.github.io/test)", new TellrawPart("hmm") var space = text(" ").color(WHITE);
.setColor(Color.White).setUnderlined(true) list.add(new ChatFormatIT(sender, "A rainbow text for testing. O", text("A").color(RED),
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, space, text("rainbow").color(GOLD), space, text("text").color(YELLOW),
new TellrawPart("Click to open").setColor(Color.Blue))) space, text("for").color(GREEN), space, text("testing.").color(BLUE),
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test")))); space, text("O").color(DARK_PURPLE)).setRainbowMode());
TellrawPart space = new TellrawPart(" ").setColor(Color.White); list.add(new ChatFormatIT(sender, "***test*** test", text("test").color(WHITE)
list.add(new ChatFormatIT(sender, "A rainbow text for testing. O", new TellrawPart("A").setColor(Color.Red), .decorate(ITALIC).decorate(BOLD), text(" test").color(WHITE)));
space, new TellrawPart("rainbow").setColor(Color.Gold), space, new TellrawPart("text").setColor(Color.Yellow), list.add(new ChatFormatIT(sender, ">test message\nheh", text(">test message\nheh").color(GREEN)));
space, new TellrawPart("for").setColor(Color.Green), space, new TellrawPart("testing.").setColor(Color.Blue), list.add(new ChatFormatIT(sender, "[here's a link]()", text("[here's a link]()").color(WHITE)));
space, new TellrawPart("O").setColor(Color.DarkPurple)).setRainbowMode()); list.add(new ChatFormatIT(sender, "[](fakelink)", text("[](fakelink)").color(WHITE)));
list.add(new ChatFormatIT(sender, "***test*** test", new TellrawPart("test").setColor(Color.White) list.add(new ChatFormatIT(sender, "||this is a spoiler||", text("this is a spoiler").color(WHITE)
.setItalic(true).setBold(true), new TellrawPart(" test").setColor(Color.White))); .decorate(OBFUSCATED).hoverEvent(hoverEvent(SHOW_TEXT, text("this is a spoiler").color(WHITE)))));
list.add(new ChatFormatIT(sender, ">test message\nheh", new TellrawPart(">test message\nheh").setColor(Color.Green))); Function<String, TextComponent> whiteBoldItalic = text -> text(text).color(WHITE).decorate(BOLD).decorate(ITALIC);
list.add(new ChatFormatIT(sender, "[here's a link]()", new TellrawPart("[here's a link]()").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "[](fakelink)", new TellrawPart("[](fakelink)").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "||this is a spoiler||", new TellrawPart("this is a spoiler").setColor(Color.White)
.setObfuscated(true).setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, "this is a spoiler"))));
Function<String, TellrawPart> whiteBoldItalic = text -> new TellrawPart(text).setColor(Color.White).setBold(true).setItalic(true);
list.add(new ChatFormatIT(sender, "***some complicated ||test message|| with [links](https://chromagaming.figytuna.com) and other __greatness__ by NorbiPeti***", list.add(new ChatFormatIT(sender, "***some complicated ||test message|| with [links](https://chromagaming.figytuna.com) and other __greatness__ by NorbiPeti***",
whiteBoldItalic.apply("some complicated "), whiteBoldItalic.apply("some complicated "),
whiteBoldItalic.apply("test message").setObfuscated(true).setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, "test message")), whiteBoldItalic.apply("test message").decorate(OBFUSCATED).hoverEvent(hoverEvent(SHOW_TEXT, text("test message"))),
whiteBoldItalic.apply(" with "), whiteBoldItalic.apply(" with "),
whiteBoldItalic.apply("links").setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://chromagaming.figytuna.com")).setUnderlined(true) whiteBoldItalic.apply("links").clickEvent(clickEvent(OPEN_URL, "https://chromagaming.figytuna.com"))
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, new TellrawPart("Click to open").setColor(Color.Blue))), .decorate(UNDERLINED).hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE))),
whiteBoldItalic.apply(" and other "), whiteBoldItalic.apply(" and other "),
whiteBoldItalic.apply("greatness").setUnderlined(true), whiteBoldItalic.apply("greatness").decorate(UNDERLINED),
whiteBoldItalic.apply(" by "), whiteBoldItalic.apply(" by "),
whiteBoldItalic.apply("§bNorbiPeti§r").setColor(Color.Aqua))); //§b: flair color whiteBoldItalic.apply("§bNorbiPeti§r").color(AQUA))); //§b: flair color
list.add(new ChatFormatIT(sender, "hey @console", new TellrawPart("hey ").setColor(Color.White), list.add(new ChatFormatIT(sender, "hey @console", text("hey ").color(WHITE),
new TellrawPart("@console").setColor(Color.Aqua))); text("@console").color(AQUA)));
return list; return list;
} }
private final CommandSender sender; private final ChromaGamerBase sender;
private final String message; private final String message;
private final TellrawPart[] extras; private final Component[] extras;
private boolean rainbowMode; private boolean rainbowMode;
public ChatFormatIT(CommandSender sender, String message, TellrawPart... expectedExtras) { public ChatFormatIT(ChromaGamerBase sender, String message, Component... expectedExtras) {
this.sender = sender; this.sender = sender;
this.message = message; this.message = message;
this.extras = expectedExtras; this.extras = expectedExtras;
@ -136,12 +138,12 @@ public class ChatFormatIT {
ArrayList<MatchProviderBase> cfs = ChatProcessing.addFormatters(p -> true, null); ArrayList<MatchProviderBase> cfs = ChatProcessing.addFormatters(p -> true, null);
final String chid = ChatProcessing.getChannelID(Channel.globalChat, ChatUtils.MCORIGIN); final String chid = ChatProcessing.getChannelID(Channel.globalChat, ChatUtils.MCORIGIN);
if (rainbowMode) if (rainbowMode)
ChatProcessing.createRPC(Color.White, cfs); ChatProcessing.createRPC(WHITE, cfs);
final TellrawPart tp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN); final TextComponent.Builder tp = ChatProcessing.createEmptyMessageLine(sender, message, null, chid, ChatUtils.MCORIGIN);
ChatFormatter.Combine(cfs, message, tp, null, FormatSettings.builder().color(Color.White).build()); ChatFormatter.Combine(cfs, message, tp, null, FormatSettings.builder().color(WHITE).build());
final TellrawPart expectedtp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN); final TextComponent.Builder expectedtp = ChatProcessing.createEmptyMessageLine(sender, message, null, chid, ChatUtils.MCORIGIN);
for (TellrawPart extra : extras) for (Component extra : extras)
expectedtp.addExtra(extra); expectedtp.append(extra);
Assert.assertEquals(ChatProcessing.toJson(expectedtp), ChatProcessing.toJson(tp)); Assert.assertEquals(expectedtp.build(), tp.build());
} }
} }