Major changes

- Convert prefixes to Component
- Styling improvements to the list command
- Fix tab completing on plex command
- Allow console to check ranks of other players
- Add coloring in tab for admins
- Add color field to ranks and titles
- Fix debug logging not working
This commit is contained in:
Telesphoreo 2022-03-17 20:18:35 -05:00
parent 3c0b79ba06
commit 06e51926be
18 changed files with 155 additions and 74 deletions

View File

@ -10,6 +10,8 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
/**
* SQL fetching utilities for players
@ -66,7 +68,7 @@ public class SQLPlayerData
{
String name = set.getString("name");
String loginMSG = set.getString("login_msg");
String prefix = set.getString("prefix");
Component prefix = Component.text(set.getString("prefix"));
String rankName = set.getString("rank").toUpperCase();
long coins = set.getLong("coins");
boolean vanished = set.getBoolean("vanished");
@ -105,7 +107,7 @@ public class SQLPlayerData
PreparedStatement statement = con.prepareStatement(UPDATE);
statement.setString(1, player.getName());
statement.setString(2, player.getLoginMessage());
statement.setString(3, player.getPrefix());
statement.setString(3, LegacyComponentSerializer.legacySection().serialize(player.getPrefix()));
statement.setString(4, player.getRank().toLowerCase());
statement.setString(5, new Gson().toJson(player.getIps()));
statement.setLong(6, player.getCoins());
@ -134,7 +136,7 @@ public class SQLPlayerData
statement.setString(1, player.getUuid());
statement.setString(2, player.getName());
statement.setString(3, player.getLoginMessage());
statement.setString(4, player.getPrefix());
statement.setString(4, LegacyComponentSerializer.legacySection().serialize(player.getPrefix()));
statement.setString(5, player.getRank().toLowerCase());
statement.setString(6, new Gson().toJson(player.getIps()));
statement.setLong(7, player.getCoins());

View File

@ -508,6 +508,11 @@ public abstract class PlexCommand extends Command implements PluginIdentifiableC
return LegacyComponentSerializer.legacyAmpersand().deserialize(s).colorIfAbsent(NamedTextColor.GRAY);
}
protected Component noColorComponentFromString(String s)
{
return LegacyComponentSerializer.legacyAmpersand().deserialize(s);
}
/**
* Converts a String to a MiniMessage Component
*

View File

@ -17,7 +17,7 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@CommandParameters(name = "debug", description = "Debug command", usage = "/<command> <redis-reset | gamerules> [player]")
@CommandParameters(name = "pdebug", description = "Plex's debug command", usage = "/<command> <redis-reset <player> | gamerules>")
@CommandPermissions(level = Rank.EXECUTIVE, permission = "plex.debug")
public class DebugCMD extends PlexCommand
{

View File

@ -8,7 +8,6 @@ import dev.plex.rank.enums.Rank;
import java.util.List;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -23,7 +22,8 @@ public class ListCMD extends PlexCommand
protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, String[] args)
{
List<Player> players = Lists.newArrayList(Bukkit.getOnlinePlayers());
Component component = Component.text("There " + (players.size() == 1 ? "is" : "are") + " currently").color(NamedTextColor.GRAY)
Component list = Component.empty();
Component header = Component.text("There " + (players.size() == 1 ? "is" : "are") + " currently").color(NamedTextColor.GRAY)
.append(Component.space())
.append(Component.text(players.size()).color(NamedTextColor.YELLOW))
.append(Component.space())
@ -33,18 +33,17 @@ public class ListCMD extends PlexCommand
.append(Component.space())
.append(Component.text(Bukkit.getMaxPlayers()).color(NamedTextColor.YELLOW))
.append(Component.space())
.append(Component.text(Bukkit.getMaxPlayers() == 1 ? "player." : "players.").color(NamedTextColor.GRAY))
.append(Component.newline());
.append(Component.text(Bukkit.getMaxPlayers() == 1 ? "player." : "players.").color(NamedTextColor.GRAY));
send(sender, header);
for (int i = 0; i < players.size(); i++)
{
Player player = players.get(i);
component = component.append(LegacyComponentSerializer.legacyAmpersand().deserialize(getPlexPlayer(player).getRankFromString().getPrefix())).append(Component.space()).append(Component.text(player.getName()).color(NamedTextColor.WHITE));
list = list.append(getPlexPlayer(player).getRankFromString().getPrefix()).append(Component.space()).append(Component.text(player.getName()).color(NamedTextColor.WHITE));
if (i != players.size() - 1)
{
component = component.append(Component.text(",")).append(Component.space());
list = list.append(Component.text(",")).append(Component.space());
}
}
return component;
return list;
}
}

View File

@ -26,5 +26,4 @@ public class OpAllCMD extends PlexCommand
PlexUtils.broadcast(messageComponent("oppedAllPlayers", sender.getName()));
return null;
}
}

View File

@ -1,6 +1,5 @@
package dev.plex.command.impl;
import com.google.common.collect.ImmutableList;
import dev.plex.command.PlexCommand;
import dev.plex.command.annotation.CommandParameters;
import dev.plex.command.annotation.CommandPermissions;
@ -9,6 +8,7 @@ import dev.plex.command.source.RequiredCommandSource;
import dev.plex.module.PlexModule;
import dev.plex.module.PlexModuleFile;
import dev.plex.rank.enums.Rank;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -75,7 +75,7 @@ public class PlexCMD extends PlexCommand
plugin.getModuleManager().loadAllModules();
plugin.getModuleManager().loadModules();
plugin.getModuleManager().enableModules();
return null;
return componentFromString("All modules reloaded!");
}
}
else
@ -88,13 +88,13 @@ public class PlexCMD extends PlexCommand
@Override
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException
{
if (args.length == 0)
if (args.length == 1)
{
return ImmutableList.of("reload", "redis", "modules");
return Arrays.asList("reload", "redis", "modules");
}
if (args[0].equalsIgnoreCase("modules"))
else if (args[0].equalsIgnoreCase("modules"))
{
return ImmutableList.of("reload");
return List.of("reload");
}
return Collections.emptyList();
}

View File

@ -22,7 +22,7 @@ public class PunishmentsCMD extends PlexCommand
@Override
protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, String[] args)
{
new PunishmentMenu().openInv(((Player)sender), 0);
new PunishmentMenu().openInv(playerSender, 0);
return null;
}

View File

@ -3,6 +3,7 @@ package dev.plex.command.impl;
import dev.plex.command.PlexCommand;
import dev.plex.command.annotation.CommandParameters;
import dev.plex.command.annotation.CommandPermissions;
import dev.plex.command.exception.CommandFailException;
import dev.plex.command.source.RequiredCommandSource;
import dev.plex.rank.enums.Rank;
import net.kyori.adventure.text.Component;
@ -11,7 +12,7 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@CommandPermissions(level = Rank.OP, permission = "plex.rank", source = RequiredCommandSource.IN_GAME)
@CommandPermissions(level = Rank.OP, permission = "plex.rank", source = RequiredCommandSource.ANY)
@CommandParameters(name = "rank", description = "Displays your rank")
public class RankCMD extends PlexCommand
{
@ -20,6 +21,10 @@ public class RankCMD extends PlexCommand
{
if (args.length == 0)
{
if (isConsole(sender))
{
throw new CommandFailException("<red>When using the console, you must specify a player's rank.");
}
if (!(playerSender == null))
{
Rank rank = getPlexPlayer(playerSender).getRankFromString();

View File

@ -19,7 +19,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@CommandPermissions(level = Rank.OP, permission = "plex.tag", source = RequiredCommandSource.ANY)
@CommandParameters(name = "tag", aliases = "prefix", description = "Manages your prefix", usage = "/<command> <set | clear> <prefix | player>")
@CommandParameters(name = "tag", aliases = "prefix", description = "Set or clear your prefix", usage = "/<command> <set <prefix> | clear <player>>")
public class TagCMD extends PlexCommand
{
@Override
@ -47,8 +47,7 @@ public class TagCMD extends PlexCommand
return usage("/tag set <prefix>");
}
String prefix = StringUtils.join(args, " ", 1, args.length);
Component convertedComponent = removeEvents(componentFromString(prefix));
Component convertedComponent = removeEvents(noColorComponentFromString(prefix));
convertedComponent = removeEvents(MiniMessage.miniMessage().deserialize(LegacyComponentSerializer.legacySection().serialize(convertedComponent)));
if (PlainTextComponentSerializer.plainText().serialize(convertedComponent).length() > plugin.config.getInt("chat.max-tag-length", 16))
@ -56,7 +55,7 @@ public class TagCMD extends PlexCommand
return messageComponent("maximumPrefixLength", plugin.config.getInt("chat.max-tag-length", 16));
}
player.setPrefix(MiniMessage.miniMessage().serialize(convertedComponent));
player.setPrefix(Component.text(MiniMessage.miniMessage().serialize(convertedComponent)));
return messageComponent("prefixSetTo", MiniMessage.miniMessage().serialize(convertedComponent));
}
@ -70,14 +69,14 @@ public class TagCMD extends PlexCommand
}
PlexPlayer player = DataUtils.getPlayer(playerSender.getUniqueId());
player.setPrefix("");
player.setPrefix(null);
return messageComponent("prefixCleared");
}
checkRank(sender, Rank.ADMIN, "plex.tag.clear.others");
Player target = getNonNullPlayer(args[1]);
PlexPlayer plexTarget = DataUtils.getPlayer(target.getUniqueId());
plexTarget.setPrefix("");
plexTarget.setPrefix(null);
messageComponent("otherPrefixCleared");
}
return usage();

View File

@ -10,6 +10,7 @@ import dev.plex.listener.impl.FreezeListener;
import dev.plex.listener.impl.GameModeListener;
import dev.plex.listener.impl.PlayerListener;
import dev.plex.listener.impl.ServerListener;
import dev.plex.listener.impl.TabListener;
import dev.plex.listener.impl.WorldListener;
import dev.plex.util.PlexLog;
import java.util.List;
@ -28,6 +29,7 @@ public class ListenerHandler
listeners.add(new GameModeListener());
listeners.add(new PlayerListener());
listeners.add(new ServerListener());
listeners.add(new TabListener());
listeners.add(new WorldListener());
PlexLog.log(String.format("Registered %s listeners!", listeners.size()));
}

View File

@ -4,13 +4,13 @@ import dev.plex.cache.PlayerCache;
import dev.plex.listener.PlexListener;
import dev.plex.player.PlexPlayer;
import dev.plex.rank.enums.Rank;
import dev.plex.util.PlexLog;
import dev.plex.util.PlexUtils;
import io.papermc.paper.chat.ChatRenderer;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
@ -56,8 +56,8 @@ public class ChatListener extends PlexListener
return;
}
String prefix = plugin.getRankManager().getPrefix(plexPlayer);
if (!prefix.isEmpty())
Component prefix = plugin.getRankManager().getPrefix(plexPlayer);
if (prefix != null)
{
renderer.hasPrefix = true;
renderer.prefix = prefix;
@ -73,14 +73,14 @@ public class ChatListener extends PlexListener
public static class PlexChatRenderer implements ChatRenderer
{
public boolean hasPrefix;
public String prefix;
public Component prefix;
@Override
public @NotNull Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer)
{
if (hasPrefix)
{
return Component.empty().append(MiniMessage.miniMessage().deserialize(prefix))
return Component.empty().append(prefix)
.append(Component.space())
.append(LegacyComponentSerializer.legacyAmpersand().deserialize("&" + plugin.config.getString("chat.name-color") + LegacyComponentSerializer.legacyAmpersand().serialize(sourceDisplayName)))
.append(Component.space())

View File

@ -11,11 +11,8 @@ import dev.plex.util.PlexLog;
import dev.plex.util.PlexUtils;
import java.util.Collections;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -69,14 +66,10 @@ public class PlayerListener extends PlexListener
}
assert plexPlayer != null;
String loginMessage = plugin.getRankManager().getLoginMessage(plexPlayer);
if (!loginMessage.isEmpty())
{
PlexUtils.broadcast(
Component.text(ChatColor.AQUA + player.getName() + " is ").color(NamedTextColor.AQUA)
.append(LegacyComponentSerializer.legacyAmpersand().deserialize(loginMessage)));
PlexUtils.broadcast(MiniMessage.miniMessage().deserialize("<aqua>" + player.getName() + " is " + loginMessage));
}
}

View File

@ -0,0 +1,48 @@
package dev.plex.listener.impl;
import dev.plex.cache.DataUtils;
import dev.plex.event.AdminAddEvent;
import dev.plex.event.AdminRemoveEvent;
import dev.plex.event.AdminSetRankEvent;
import dev.plex.listener.PlexListener;
import dev.plex.player.PlexPlayer;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
public class TabListener extends PlexListener
{
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerJoin(PlayerJoinEvent event)
{
Player player = event.getPlayer();
PlexPlayer plexPlayer = DataUtils.getPlayer(player.getUniqueId());
player.playerListName(Component.text(player.getName()).color(plugin.getRankManager().getColor(plexPlayer)));
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onAdminAdd(AdminAddEvent event)
{
PlexPlayer plexPlayer = event.getPlexPlayer();
Player player = event.getPlexPlayer().getPlayer();
player.playerListName(Component.text(player.getName()).color(plugin.getRankManager().getColor(plexPlayer)));
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onAdminRemove(AdminRemoveEvent event)
{
PlexPlayer plexPlayer = event.getPlexPlayer();
Player player = event.getPlexPlayer().getPlayer();
player.playerListName(Component.text(player.getName()).color(plugin.getRankManager().getColor(plexPlayer)));
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onAdminSetRank(AdminSetRankEvent event)
{
PlexPlayer plexPlayer = event.getPlexPlayer();
Player player = event.getPlexPlayer().getPlayer();
player.playerListName(Component.text(player.getName()).color(plugin.getRankManager().getColor(plexPlayer)));
}
}

View File

@ -11,6 +11,7 @@ import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@ -34,7 +35,7 @@ public class PlexPlayer
private Player player;
private String loginMessage;
private String prefix;
private Component prefix;
private boolean vanished;
private boolean commandSpy;
@ -59,7 +60,7 @@ public class PlexPlayer
this.player = Bukkit.getPlayer(name);
this.loginMessage = "";
this.prefix = "";
this.prefix = null;
this.vanished = false;
this.commandSpy = false;

View File

@ -12,6 +12,8 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Collectors;
import lombok.SneakyThrows;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
@ -88,9 +90,9 @@ public class RankManager
}
}
public String getPrefix(PlexPlayer player)
public Component getPrefix(PlexPlayer player)
{
if (!player.getPrefix().isEmpty())
if (Component.IS_NOT_EMPTY.test(player.getPrefix()))
{
return player.getPrefix();
}
@ -110,7 +112,7 @@ public class RankManager
{
return player.getRankFromString().getPrefix();
}
return "";
return null;
}
public String getLoginMessage(PlexPlayer player)
@ -138,6 +140,27 @@ public class RankManager
return "";
}
public NamedTextColor getColor(PlexPlayer player)
{
if (Plex.get().config.contains("titles.owners") && Plex.get().config.getStringList("titles.owners").contains(player.getName()))
{
return Title.OWNER.getColor();
}
if (PlexUtils.DEVELOPERS.contains(player.getUuid())) // don't remove or we will front door ur mother
{
return Title.DEV.getColor();
}
if (Plex.get().config.contains("titles.masterbuilders") && Plex.get().config.getStringList("titles.masterbuilders").contains(player.getName()))
{
return Title.MASTER_BUILDER.getColor();
}
if (Plex.get().getSystem().equalsIgnoreCase("ranks") && isAdmin(player))
{
return player.getRankFromString().getColor();
}
return NamedTextColor.WHITE;
}
public boolean isAdmin(PlexPlayer plexPlayer)
{
return !plexPlayer.getRank().isEmpty() && plexPlayer.getRankFromString().isAtLeast(Rank.ADMIN);

View File

@ -1,22 +1,21 @@
package dev.plex.rank.enums;
import dev.plex.util.PlexUtils;
import lombok.Getter;
import lombok.Setter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.ChatColor;
import org.json.JSONObject;
@Getter
public enum Rank
{
IMPOSTOR(-1, ChatColor.AQUA + "an " + ChatColor.YELLOW + "Impostor", "Impostor", "&8[&eImp&8]"),
NONOP(0, "a " + ChatColor.WHITE + "Non-Op", "Non-Op", ""),
OP(1, "an " + ChatColor.GREEN + "Operator", "Operator", "&8[&aOP&8]"),
ADMIN(2, "an " + ChatColor.DARK_GREEN + "Admin", "Admin", "&8[&2Admin&8]"),
SENIOR_ADMIN(3, "a " + ChatColor.GOLD + "Senior Admin", "Senior Admin", "&8[&6SrA&8]"),
EXECUTIVE(4, "an " + ChatColor.RED + "Executive", "Executive", "&8[&cExec&8]");
IMPOSTOR(-1, "<aqua>an <yellow>Impostor", "Impostor", "<dark_gray>[<yellow>Imp<dark_gray>]", NamedTextColor.YELLOW),
NONOP(0, "a <white>Non-Op", "Non-Op", "", NamedTextColor.WHITE),
OP(1, "an <green>Op", "Operator", "<dark_gray>[<green>OP<dark_gray>]", NamedTextColor.GREEN),
ADMIN(2, "an <dark_green>Admin", "Admin", "<dark_gray>[<green>Admin<dark_gray>]", NamedTextColor.DARK_GREEN),
SENIOR_ADMIN(3, "a <gold>Senior Admin", "Senior Admin", "<dark_gray>[<gold>SrA<dark_gray>]", NamedTextColor.GOLD),
EXECUTIVE(4, "an <red>Executive", "Executive", "<dark_gray>[<red>Exec<dark_gray>]", NamedTextColor.RED);
private final int level;
@ -29,12 +28,16 @@ public enum Rank
@Setter
private String prefix;
Rank(int level, String loginMessage, String readable, String prefix)
@Getter
private NamedTextColor color;
Rank(int level, String loginMessage, String readable, String prefix, NamedTextColor color)
{
this.level = level;
this.loginMessage = loginMessage;
this.readable = readable;
this.prefix = prefix;
this.color = color;
}
public boolean isAtLeast(Rank rank)
@ -42,9 +45,9 @@ public enum Rank
return this.level >= rank.getLevel();
}
public String getPrefix()
public Component getPrefix()
{
return PlexUtils.colorize(this.prefix);
return MiniMessage.miniMessage().deserialize(this.prefix);
}
public JSONObject toJSON()

View File

@ -2,17 +2,17 @@ package dev.plex.rank.enums;
import lombok.Getter;
import lombok.Setter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.ChatColor;
import org.json.JSONObject;
@Getter
public enum Title
{
MASTER_BUILDER(0, ChatColor.AQUA + "a " + ChatColor.DARK_AQUA + "Master Builder", "Master Builder", "&8[&3Master Builder&8]"),
DEV(1, ChatColor.AQUA + "a " + ChatColor.DARK_PURPLE + "Developer", "Developer", "&8[&5Developer&8]"),
OWNER(2, ChatColor.AQUA + "an " + ChatColor.BLUE + "Owner", "Owner", "&8[&9Owner&8]");
MASTER_BUILDER(0, "<aqua>a <dark_aqua>Master Builder", "Master Builder", "<dark_gray>[<dark_aqua>Master Builder<dark_gray>]", NamedTextColor.DARK_AQUA),
DEV(1, "<aqua>a <dark_purple>Developer", "Developer", "<dark_gray>[<dark_purple>Developer<dark_gray>]", NamedTextColor.DARK_PURPLE),
OWNER(2, "<aqua>an <blue>Owner", "Owner", "<dark_gray>[<blue>Owner<dark_gray>]", NamedTextColor.BLUE);
private final int level;
@ -25,17 +25,21 @@ public enum Title
@Setter
private String prefix;
Title(int level, String loginMessage, String readable, String prefix)
@Getter
private NamedTextColor color;
Title(int level, String loginMessage, String readable, String prefix, NamedTextColor color)
{
this.level = level;
this.loginMessage = loginMessage;
this.readable = readable;
this.prefix = prefix;
this.color = color;
}
public String getPrefix()
public Component getPrefix()
{
return MiniMessage.miniMessage().serialize(LegacyComponentSerializer.legacyAmpersand().deserialize(this.prefix));
return MiniMessage.miniMessage().deserialize(this.prefix);
}
public JSONObject toJSON()

View File

@ -1,13 +1,11 @@
package dev.plex.util;
import dev.plex.PlexBase;
import dev.plex.Plex;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
public class PlexLog extends PlexBase
public class PlexLog
{
private static final boolean debugEnabled = plugin.config.getBoolean("debug");
public static void log(String message, Object... strings)
{
for (int i = 0; i < strings.length; i++)
@ -41,7 +39,7 @@ public class PlexLog extends PlexBase
message = message.replace("{" + i + "}", strings[i].toString());
}
}
if (debugEnabled)
if (Plex.get().config.getBoolean("debug"))
{
Bukkit.getConsoleSender().sendMessage(String.format(ChatColor.DARK_PURPLE + "[Plex Debug] " + ChatColor.GOLD + "%s", message));
}