package net.essentialsx.discord; import com.earth2me.essentials.IConf; import com.earth2me.essentials.config.ConfigurateUtil; import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.utils.FormatUtil; import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.entities.Activity; import net.essentialsx.api.v2.ChatType; import org.apache.logging.log4j.Level; import org.bukkit.entity.Player; import java.io.File; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import static com.earth2me.essentials.I18n.tl; public class DiscordSettings implements IConf { private final EssentialsConfiguration config; private final EssentialsDiscord plugin; private final Map nameToChannelIdMap = new HashMap<>(); private final Map> channelIdToNamesMap = new HashMap<>(); private OnlineStatus status; private Activity statusActivity; private List discordFilter; private MessageFormat consoleFormat; private Level consoleLogLevel; private List consoleFilter; private MessageFormat discordToMcFormat; private MessageFormat tempMuteFormat; private MessageFormat tempMuteReasonFormat; private MessageFormat permMuteFormat; private MessageFormat permMuteReasonFormat; private MessageFormat unmuteFormat; private MessageFormat kickFormat; public DiscordSettings(EssentialsDiscord plugin) { this.plugin = plugin; this.config = new EssentialsConfiguration(new File(plugin.getDataFolder(), "config.yml"), "/config.yml", EssentialsDiscord.class); reloadConfig(); } public String getBotToken() { return config.getString("token", ""); } public long getGuildId() { return config.getLong("guild", 0); } public String getDiscordUrl() { return config.getString("discord-url", "https://discord.gg/invite-code"); } public long getPrimaryChannelId() { return config.getLong("channels.primary", 0); } public long getChannelId(String key) { try { return Long.parseLong(key); } catch (NumberFormatException ignored) { return nameToChannelIdMap.getOrDefault(key, 0L); } } public List getChannelNames() { return new ArrayList<>(nameToChannelIdMap.keySet()); } public List getKeysFromChannelId(long channelId) { return channelIdToNamesMap.get(channelId); } public String getMessageChannel(String key) { return config.getString("message-types." + key, "none"); } public boolean isShowDiscordAttachments() { return config.getBoolean("show-discord-attachments", true); } public List getPermittedFormattingRoles() { return config.getList("permit-formatting-roles", String.class); } public OnlineStatus getStatus() { return status; } public Activity getStatusActivity() { return statusActivity; } public boolean isAlwaysReceivePrimary() { return config.getBoolean("always-receive-primary", false); } public boolean isUseEssentialsEvents() { return config.getBoolean("use-essentials-events", false); } public int getChatDiscordMaxLength() { return config.getInt("chat.discord-max-length", 2000); } public boolean isChatFilterNewlines() { return config.getBoolean("chat.filter-newlines", true); } public List getDiscordFilters() { return discordFilter; } public boolean isShowWebhookMessages() { return config.getBoolean("chat.show-webhook-messages", false); } public boolean isShowBotMessages() { return config.getBoolean("chat.show-bot-messages", false); } public boolean isShowAllChat() { return config.getBoolean("chat.show-all-chat", false); } public List getRelayToConsoleList() { return config.getList("chat.relay-to-console", String.class); } public String getConsoleChannelDef() { return config.getString("console.channel", "none"); } public MessageFormat getConsoleFormat() { return consoleFormat; } public String getConsoleWebhookName() { return config.getString("console.webhook-name", "EssentialsX Console Relay"); } public boolean isConsoleCommandRelay() { return config.getBoolean("console.command-relay", false); } public boolean isConsoleBotCommandRelay() { return config.getBoolean("console.bot-command-relay", false); } public Level getConsoleLogLevel() { return consoleLogLevel; } public List getConsoleFilters() { return consoleFilter; } public boolean isShowAvatar() { return config.getBoolean("show-avatar", false); } public boolean isShowName() { return config.getBoolean("show-name", false); } public boolean isShowDisplayName() { return config.getBoolean("show-displayname", false); } public String getAvatarURL() { return config.getString("avatar-url", "https://crafthead.net/helm/{uuid}"); } public boolean isVanishFakeJoinLeave() { return config.getBoolean("vanish-fake-join-leave", true); } public boolean isVanishHideMessages() { return config.getBoolean("vanish-hide-messages", true); } // General command settings public boolean isCommandEnabled(String command) { return config.getBoolean("commands." + command + ".enabled", true); } public boolean isCommandEphemeral(String command) { return config.getBoolean("commands." + command + ".hide-command", true); } public List getCommandSnowflakes(String command) { if (config.isList("commands." + command + ".allowed-roles")) { return config.getList("commands." + command + ".allowed-roles", String.class); } return null; } public List getCommandAdminSnowflakes(String command) { return config.getList("commands." + command + ".admin-roles", String.class); } // Message formats public MessageFormat getDiscordToMcFormat() { return discordToMcFormat; } public MessageFormat getMcToDiscordFormat(Player player) { return getMcToDiscordFormat(player, ChatType.UNKNOWN); } public MessageFormat getMcToDiscordFormat(Player player, ChatType chatType) { final String format = getFormatString(getMcToDiscordFormatKey(chatType)); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, getMcToDiscordDefaultFormat(chatType), false, "username", "displayname", "message", "world", "prefix", "suffix"); } private String getMcToDiscordFormatKey(ChatType chatType) { switch (chatType) { case LOCAL: return "mc-to-discord-local"; case QUESTION: return "mc-to-discord-question"; case SHOUT: return "mc-to-discord-shout"; default: return "mc-to-discord"; } } private String getMcToDiscordDefaultFormat(ChatType chatType) { switch (chatType) { case LOCAL: return "**[Local]** {displayname}: {message}"; case QUESTION: return "**[Question]** {displayname}: {message}"; case SHOUT: return "**[Shout]** {displayname}: {message}"; default: return "{displayname}: {message}"; } } public String getLegacyNameFormat() { // For compatibility with old configs if (isShowDisplayName()) { return "{displayname}"; } else if (isShowName()) { return "{username}"; } else { // Will default to "{botname}" in the format return null; } } public MessageFormat getMcToDiscordNameFormat(Player player) { String format = getFormatString("mc-to-discord-name-format"); if (format == null) { format = getLegacyNameFormat(); } final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, "{botname}", false, "username", "displayname", "world", "prefix", "suffix", "botname"); } public MessageFormat getTempMuteFormat() { return tempMuteFormat; } public MessageFormat getTempMuteReasonFormat() { return tempMuteReasonFormat; } public MessageFormat getPermMuteFormat() { return permMuteFormat; } public MessageFormat getPermMuteReasonFormat() { return permMuteReasonFormat; } public MessageFormat getUnmuteFormat() { return unmuteFormat; } public MessageFormat getJoinFormat(Player player) { final String format = getFormatString("join"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":arrow_right: {displayname} has joined!", false, "username", "displayname", "joinmessage", "online", "unique"); } public MessageFormat getFirstJoinFormat(Player player) { final String format = getFormatString("first-join"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":arrow_right: :first_place: {displayname} has joined the server for the first time!", false, "username", "displayname", "joinmessage", "online", "unique"); } public MessageFormat getQuitFormat(Player player) { final String format = getFormatString("quit"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":arrow_left: {displayname} has left!", false, "username", "displayname", "quitmessage", "online", "unique"); } public MessageFormat getDeathFormat(Player player) { final String format = getFormatString("death"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":skull: {deathmessage}", false, "username", "displayname", "deathmessage"); } public MessageFormat getAfkFormat(Player player) { final String format = getFormatString("afk"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":person_walking: {displayname} is now AFK!", false, "username", "displayname"); } public MessageFormat getUnAfkFormat(Player player) { final String format = getFormatString("un-afk"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":keyboard: {displayname} is no longer AFK!", false, "username", "displayname"); } public MessageFormat getAdvancementFormat(Player player) { final String format = getFormatString("advancement"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":medal: {displayname} has completed the advancement **{advancement}**!", false, "username", "displayname", "advancement"); } public MessageFormat getActionFormat(Player player) { final String format = getFormatString("action"); final String filled; if (plugin.isPAPI() && format != null) { filled = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, format); } else { filled = format; } return generateMessageFormat(filled, ":person_biking: {displayname} *{action}*", false, "username", "displayname", "action"); } public String getStartMessage() { return config.getString("messages.server-start", ":white_check_mark: The server has started!"); } public String getStopMessage() { return config.getString("messages.server-stop", ":octagonal_sign: The server has stopped!"); } public MessageFormat getKickFormat() { return kickFormat; } private String getFormatString(String node) { final String pathPrefix = node.startsWith(".") ? "" : "messages."; return config.getString(pathPrefix + (pathPrefix.isEmpty() ? node.substring(1) : node), null); } private MessageFormat generateMessageFormat(String content, String defaultStr, boolean format, String... arguments) { content = content == null ? defaultStr : content; content = format ? FormatUtil.replaceFormat(content) : FormatUtil.stripFormat(content); content = content.replace("'", "''"); for (int i = 0; i < arguments.length; i++) { content = content.replace("{" + arguments[i] + "}", "{" + i + "}"); content = content.replace("{" + arguments[i].toUpperCase() + "}", "{" + i + "}"); } content = content.replaceAll("\\{([^0-9]+)}", "'{$1}'"); return new MessageFormat(content); } @Override public void reloadConfig() { if (plugin.isInvalidStartup()) { plugin.getLogger().warning(tl("discordReloadInvalid")); return; } config.load(); // Build channel maps nameToChannelIdMap.clear(); channelIdToNamesMap.clear(); final Map section = ConfigurateUtil.getRawMap(config, "channels"); for (Map.Entry entry : section.entrySet()) { if (entry.getValue() instanceof Long) { final long value = (long) entry.getValue(); nameToChannelIdMap.put(entry.getKey(), value); channelIdToNamesMap.computeIfAbsent(value, o -> new ArrayList<>()).add(entry.getKey()); } } // Presence stuff status = OnlineStatus.fromKey(config.getString("presence.status", "online")); if (status == OnlineStatus.UNKNOWN) { // Default invalid status to online status = OnlineStatus.ONLINE; } final String activity = config.getString("presence.activity", "default").trim().toUpperCase().replace("CUSTOM_STATUS", "DEFAULT"); statusActivity = null; Activity.ActivityType activityType = null; try { if (!activity.equals("NONE")) { activityType = Activity.ActivityType.valueOf(activity); } } catch (IllegalArgumentException e) { activityType = Activity.ActivityType.DEFAULT; } if (activityType != null) { statusActivity = Activity.of(activityType, config.getString("presence.message", "Minecraft")); } if (config.isList("chat.discord-filter")) { final List filters = new ArrayList<>(); for (final String chatFilterString : config.getList("chat.discord-filter", String.class)) { if (chatFilterString != null && !chatFilterString.trim().isEmpty()) { try { filters.add(Pattern.compile(chatFilterString)); } catch (PatternSyntaxException e) { plugin.getLogger().log(java.util.logging.Level.WARNING, "Invalid pattern for \"chat.discord-filter\": " + e.getMessage()); } } } discordFilter = Collections.unmodifiableList(filters); } else { try { final String chatFilter = config.getString("chat.discord-filter", null); if (chatFilter != null && !chatFilter.trim().isEmpty()) { discordFilter = Collections.singletonList(Pattern.compile(chatFilter)); } else { discordFilter = Collections.emptyList(); } } catch (PatternSyntaxException e) { plugin.getLogger().log(java.util.logging.Level.WARNING, "Invalid pattern for \"chat.discord-filter\": " + e.getMessage()); discordFilter = Collections.emptyList(); } } consoleLogLevel = Level.toLevel(config.getString("console.log-level", null), Level.INFO); if (config.isList("console.console-filter")) { final List filters = new ArrayList<>(); for (final String filterString : config.getList("console.console-filter", String.class)) { if (filterString != null && !filterString.trim().isEmpty()) { try { filters.add(Pattern.compile(filterString)); } catch (PatternSyntaxException e) { plugin.getLogger().log(java.util.logging.Level.WARNING, "Invalid pattern for \"console.log-level\": " + e.getMessage()); } } } consoleFilter = Collections.unmodifiableList(filters); } else { try { final String cFilter = config.getString("console.console-filter", null); if (cFilter != null && !cFilter.trim().isEmpty()) { consoleFilter = Collections.singletonList(Pattern.compile(cFilter)); } else { consoleFilter = Collections.emptyList(); } } catch (PatternSyntaxException e) { plugin.getLogger().log(java.util.logging.Level.WARNING, "Invalid pattern for \"console.log-level\": " + e.getMessage()); consoleFilter = Collections.emptyList(); } } consoleFormat = generateMessageFormat(getFormatString(".console.format"), "[{timestamp} {level}] {message}", false, "timestamp", "level", "message"); discordToMcFormat = generateMessageFormat(getFormatString("discord-to-mc"), "&6[#{channel}] &3{fullname}&7: &f{message}", true, "channel", "username", "discriminator", "fullname", "nickname", "color", "message", "role"); unmuteFormat = generateMessageFormat(getFormatString("unmute"), "{displayname} unmuted.", false, "username", "displayname"); tempMuteFormat = generateMessageFormat(getFormatString("temporary-mute"), "{controllerdisplayname} has muted player {displayname} for {time}.", false, "username", "displayname", "controllername", "controllerdisplayname", "time"); permMuteFormat = generateMessageFormat(getFormatString("permanent-mute"), "{controllerdisplayname} permanently muted {displayname}.", false, "username", "displayname", "controllername", "controllerdisplayname"); tempMuteReasonFormat = generateMessageFormat(getFormatString("temporary-mute-reason"), "{controllerdisplayname} has muted player {displayname} for {time}. Reason: {reason}.", false, "username", "displayname", "controllername", "controllerdisplayname", "time", "reason"); permMuteReasonFormat = generateMessageFormat(getFormatString("permanent-mute-reason"), "{controllerdisplayname} has muted player {displayname}. Reason: {reason}.", false, "username", "displayname", "controllername", "controllerdisplayname", "reason"); kickFormat = generateMessageFormat(getFormatString("kick"), "{displayname} was kicked with reason: {reason}", false, "username", "displayname", "reason"); plugin.onReload(); } }