package com.lifeknight.relaymcbungeemain.utilities; import com.lifeknight.relaymcbungeemain.Main; import com.lifeknight.relaymcbungeemain.player.SmartPlayer; import com.lifeknight.relayutils.RelayUtils; import com.lifeknight.relayutils.basic.Miscellaneous; import com.lifeknight.relayutils.basic.Text; import com.lifeknight.relayutils.player.Group; import com.lifeknight.relayutils.player.data.ProfileColumn; import com.lifeknight.relayutils.player.data.SmartDatabase; import com.lifeknight.relayutils.player.punishments.Punishment; import com.lifeknight.relayutils.utilities.ComponentBuilder; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.channel.Channel; import net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; import net.dv8tion.jda.api.events.GenericEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent; import net.dv8tion.jda.api.events.session.ReadyEvent; import net.dv8tion.jda.api.hooks.EventListener; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.utils.ChunkingFilter; import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.dv8tion.jda.api.utils.cache.CacheFlag; import org.bukkit.ChatColor; import java.awt.*; import java.sql.ResultSet; import java.util.List; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class BotUtils { private static final String SECRET = "jpOOO1vLcqpJcZQxupcrbrmfBtsut5RZ"; public static final String TOKEN = "MTEzNzUyNDcyNDcwMDgxMTMxNQ.GLMeyR.2bwnPNxszMSLiR4_ZYZ2JObwDo3jc6iuvYzuss"; private static final JDA BOT; private static final long TESTING_SERVER_ID = 1091870008449179698L; private static final long SERVER_ID = 792547735919132713L; static { JDABuilder builder = JDABuilder.createDefault(TOKEN); EventListener listener = BotUtils::processEvent; builder.addEventListeners(listener); builder.disableCache(CacheFlag.MEMBER_OVERRIDES, CacheFlag.VOICE_STATE); builder.setBulkDeleteSplittingEnabled(false); builder.setActivity(Activity.playing("relaymc.net")); builder.disableCache(CacheFlag.ACTIVITY); builder.setMemberCachePolicy(MemberCachePolicy.VOICE.or(MemberCachePolicy.OWNER)); builder.setChunkingFilter(ChunkingFilter.NONE); builder.disableIntents(GatewayIntent.GUILD_PRESENCES, GatewayIntent.GUILD_MESSAGE_TYPING); builder.enableIntents(GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MEMBERS); builder.setLargeThreshold(50); BOT = builder.build(); } private static void processEvent(GenericEvent genericEvent) { if (genericEvent instanceof ReadyEvent) { info("Discord bot up!"); onReady((ReadyEvent) genericEvent); } else if (genericEvent instanceof MessageReceivedEvent) { onMessageReceived((MessageReceivedEvent) genericEvent); } else if (genericEvent instanceof MessageUpdateEvent) { } else if (genericEvent instanceof MessageReactionAddEvent) { } else if (genericEvent instanceof MessageReactionRemoveEvent) { } else if (genericEvent instanceof SlashCommandInteractionEvent) { onSlashCommand((SlashCommandInteractionEvent) genericEvent); } } private static void onSlashCommand(SlashCommandInteractionEvent event) { if (event.getName().equals("link")) { String code = event.getOption("code") == null ? null : event.getOption("code").getAsString(); if (code != null) { UUID player = CODE_TO_PLAYER.remove(code); if (player != null) { SmartPlayer smartPlayer = SmartPlayer.getOrCreate(player); long idLong = event.getUser().getIdLong(); smartPlayer.setDiscordId(idLong); ID_TO_UUID.put(idLong, smartPlayer.getUUID()); event.reply("You have successfully linked your Discord account!\n" + smartPlayer.getName()).setEphemeral(true).queue(); smartPlayer.sendSuccessMessage("You have successfully linked your Discord account: %s%s", ChatColor.GOLD, event.getUser().getName()); } else { event.reply("Code \"" + code + "\" not found. Try /discord link in-game again.").setEphemeral(true).queue(); } } else { event.reply("/link [code]").setEphemeral(true).queue(); } } } private static final List<String> REWARD_CHANNELS = Miscellaneous.getList("general", "suggestions", "spam"); private static void onMessageReceived(MessageReceivedEvent event) { if (event.getMessage().getType() == MessageType.DEFAULT) { String message = event.getMessage().getContentStripped(); if (event.isFromGuild() && event.getGuild().getId().equals(String.valueOf(getServerID()))) { Channel channel = event.getChannel(); if (channel instanceof TextChannel) { if (Text.comparablyContains(channel.getName(), "general")) { checkForDiscordLink(event.getAuthor().getIdLong(), message, event.getMessage()); } if (Text.comparablyContains(channel.getName(), REWARD_CHANNELS.toArray())) { Main.async(() -> checkForRewards(event.getAuthor().getIdLong(), message, event.getMessage())); } moderationCheck((TextChannel) channel, event.getMessage()); } } } } public static void moderationCheck(TextChannel channel, Message message) { Member member = getGuild().getMember(message.getAuthor()); if (member != null) { for (Role role : member.getRoles()) { if (Text.comparablyContains(role.getName(), "staff")) { return; } } } String rawContent = message.getContentRaw(); if (!Text.comparablyContains(channel.getName(), "media")) { if (PlayerUtilities.containsWebsiteOrData(rawContent)) { message.delete().queue(); } } if (rawContent.contains(".gg")) { message.delete().queue(); } } public static long getServerID() { return RelayUtils.testing ? TESTING_SERVER_ID : SERVER_ID; } private static void checkForDiscordLink(long idLong, String message, Message originalMessage) { UUID player = CODE_TO_PLAYER.remove(message); if (player != null) { SmartPlayer smartPlayer = SmartPlayer.getOrCreate(player); smartPlayer.setDiscordId(idLong); originalMessage.delete().queue(); ID_TO_UUID.put(idLong, smartPlayer.getUUID()); try { PrivateChannel privateChannel = originalMessage.getAuthor().openPrivateChannel().submit().get(); if (originalMessage.getAuthor().hasPrivateChannel()) { privateChannel.sendMessage("You have successfully linked your Discord account!\n" + smartPlayer.getName()).queue(); } } catch (InterruptedException | ExecutionException ignored) { } smartPlayer.sendSuccessMessage("You have successfully linked your Discord account: %s%s", ChatColor.GOLD, originalMessage.getAuthor().getName()); } } private static void checkForRewards(long idLong, String message, Message originalMessage) { SmartPlayer smartPlayer = getSmartPlayer(idLong); if (smartPlayer == null) { return; } smartPlayer.onDiscordMessage(message); } public static final Map<Long, UUID> ID_TO_UUID = new HashMap<>(); public static SmartPlayer getSmartPlayer(long idLong) { UUID uuid; uuid = ID_TO_UUID.get(idLong); if (uuid == null) { try { ResultSet resultSet = SmartDatabase.getFrom(SmartDatabase.PROFILE_TABLE_NAME, ProfileColumn.DISCORD_ID.getName(), String.valueOf(idLong), ProfileColumn.ID.getName()).get(5, TimeUnit.SECONDS); if (resultSet.first()) { uuid = UUID.fromString(resultSet.getString(ProfileColumn.ID.getName())); ID_TO_UUID.put(idLong, uuid); } } catch (Exception e) { ID_TO_UUID.put(idLong, null); } } return SmartPlayer.getOrCreate(uuid); } private static void onReady(ReadyEvent event) { if (getGuild() == null) { error("Could not find guild!!"); } else { getGuild().updateCommands().addCommands(Commands.slash("link", "Link your Discord account by entering a code.") .addOption(OptionType.STRING, "code", "Code given by /discord link in-game.").setDefaultPermissions(DefaultMemberPermissions.ENABLED)).queue(); } } public static Guild getGuild() { return BOT.getGuildById(RelayUtils.testing ? TESTING_SERVER_ID : SERVER_ID); } public static void updatePlayerCount(boolean playerCount) { if (BOT == null) return; if (playerCount) { BOT.getPresence().setActivity(Activity.watching(Main.getOnlineCount() + " players online")); } else { BOT.getPresence().setActivity(Activity.playing("relaymc.net")); } } public static void startup() { } public static void sendMessage(String channel, String format, Object... data) { if (getGuild() == null) { error("Tried to send message to channel, guild is null"); return; } String message = RelayUtils.format(format, data); GuildChannel ch = getGuildChannel(channel); if (ch == null) { error("No channel by the name of %s", channel); return; } if (ch instanceof TextChannel) { ((TextChannel) ch).sendMessage(message).queue(); } else { error("Couldn't cast %s to TextChannel", channel); } } public static GuildChannel getGuildChannel(String name) { return Miscellaneous.match(getGuild().getChannels(), guildChannel -> guildChannel.getName().equals(name)); } public static TextChannel getTextChannel(String name) { return (TextChannel) getGuildChannel(name); } public static void info(String format, Object... data) { Main.info("BOT > " + format, data); } public static void error(String format, Object... data) { Main.error("BOT > " + format, data); } public static final Map<Report, String> REPORT_TO_MESSAGE = new HashMap<>(); public static final Map<Report, EmbedBuilder> REPORT_TO_CACHED = new HashMap<>(); public static String getPlayerFaceURL(UUID uuid) { return "https://crafatar.com/avatars/" + uuid; } public static void report(Report report) { if (report.getReportType() == ReportType.BUG) { EmbedBuilder embed = new EmbedBuilder().setTitle("ID: " + report.getId()).setDescription(getDeveloperMention() + " Bug Report").setColor(Color.GREEN); embed.addBlankField(false); embed.addField("Reason", report.getReportType().toString().toUpperCase(), true); embed.addField("Reporter", report.getReporter().getName(), true); embed.addField("Server", report.getServer().getName(), true); embed.addField("Message", report.getReason(), true); embed.setThumbnail(getPlayerFaceURL(report.getReporter().getUUID())); MessageEmbed messageEmbed = embed.build(); CompletableFuture<Message> completableFuture = getTextChannel("devalerts").sendMessageEmbeds(messageEmbed).submit(); alertDevs("New bug report!"); } else { EmbedBuilder embed = new EmbedBuilder().setTitle("ID: " + report.getId()).setDescription(getStaffMention() + " Player: " + report.getReported().getName()).setColor(Color.GREEN.darker()); embed.addBlankField(false); embed.addField("Reason", report.getReportType().toString().toUpperCase(), true); embed.addField("Reporter", report.getReporter().getName(), true); embed.addField("Server", report.getServer().getName(), true); embed.addField("Message", report.hasReason() ? report.getReason() : "None", true); embed.setThumbnail(getPlayerFaceURL(report.getReported().getUUID())); alertStaff("reports", "New report!"); try { MessageEmbed messageEmbed = embed.build(); REPORT_TO_CACHED.put(report, embed); CompletableFuture<Message> completableFuture = getTextChannel("reports").sendMessageEmbeds(messageEmbed).submit(); String id = completableFuture.get().getId(); REPORT_TO_MESSAGE.put(report, id); } catch (ExecutionException | InterruptedException ignored) { } } } public static void onReportManaged(Report report) { EmbedBuilder embedBuilder = REPORT_TO_CACHED.get(report); embedBuilder.addField("Dismisser", report.hasDismisser() ? report.getDismisser().getName() : "Console", true); embedBuilder.addField("Accepted", report.isAccepted() ? "YES" : "NO", true); embedBuilder.addField("Tokens Rewarded: ", String.valueOf(report.getTokensRewarded()), true); embedBuilder.addField("Message", report.hasDismissMessage() ? report.getDismissMessage() : "None", true); getTextChannel("reports").editMessageEmbedsById(REPORT_TO_MESSAGE.get(report), embedBuilder.build()).queue(); } public static final Map<Punishment, String> PUNISHMENT_TO_MESSAGE = new HashMap<>(); public static final Map<Punishment, EmbedBuilder> PUNISHMENT_TO_CACHED = new HashMap<>(); public static final String BOT_PFP = "https://media.discordapp.net/attachments/483743463838318613/1141124785187868693/r.png"; public static final String SERVER_ICON = "https://media.discordapp.net/attachments/1060535096509206538/1137921396664696922/Relay_Logo_Square.png?width=604&height=604"; public static void punish(Punishment punishment) { EmbedBuilder embed = new EmbedBuilder().setTitle("ID: " + punishment.getID()).setDescription("Player: " + SmartPlayer.getOrCreate(punishment.getPunished()).getName()) .setColor(ComponentBuilder.GREEN.darker()); embed.addBlankField(false); embed.addField("Type", punishment.getType().toString().toUpperCase(), true); embed.addField("Punisher", punishment.wasPunishedByConsole() ? "Console" : SmartPlayer.getOrCreate(punishment.getPunisher()).getName(), true); embed.addField("Punishment ID", punishment.getBanID(), true); embed.addField("Duration", punishment.isIndefinite() ? "Permanent" : Text.getShortTextualFormattedTime(punishment.getDuration()), true); if (!punishment.isIndefinite()) { embed.addField("Expires", Text.getDateTimeString(punishment.getTime() + punishment.getDuration()), true); } embed.addField("Reason", punishment.hasReason() ? punishment.getReason() : "None", true); embed.setThumbnail(getPlayerFaceURL(punishment.getPunished())); try { PUNISHMENT_TO_CACHED.put(punishment, embed); CompletableFuture<Message> completableFuture = getTextChannel("punishments").sendMessageEmbeds(embed.build()).submit(); String id = completableFuture.get().getId(); PUNISHMENT_TO_MESSAGE.put(punishment, id); } catch (ExecutionException | InterruptedException ignored) { } } public static void shutdown() { for (Punishment punishment : PUNISHMENT_TO_MESSAGE.keySet()) { EmbedBuilder embedBuilder = PUNISHMENT_TO_CACHED.get(punishment); if (!punishment.isActive()) { embedBuilder.setColor(Color.RED); embedBuilder.addField("Revoked", Text.getDateString(punishment.getRevokeTime()) + " " + Text.getTimeString(punishment.getRevokeTime()), true); embedBuilder.addField("Revoker", punishment.wasRevokedByConsole() ? "Console" : SmartPlayer.getOrCreate(punishment.getRevoker()).getName(), true); } else { embedBuilder.setColor(Color.YELLOW); embedBuilder.addField("Status", "NOT SYNCED TO SERVER", false); } getTextChannel("punishments").editMessageEmbedsById(PUNISHMENT_TO_MESSAGE.get(punishment), embedBuilder.build()).queue(); } for (Report report : REPORT_TO_MESSAGE.keySet()) { EmbedBuilder embedBuilder = REPORT_TO_CACHED.get(report); if (!(report.isAccepted() || report.isDismissed())) { embedBuilder.setColor(Color.YELLOW); } embedBuilder.addField("Status", "NO LONGER AVAILABLE", false); getTextChannel("reports").editMessageEmbedsById(REPORT_TO_MESSAGE.get(report), embedBuilder.build()).queue(); } BOT.shutdown(); } public static final List<Long> NULL_SERVER_ISSUES = new ArrayList<>(); public static void onNullServer() { long currentTime = System.currentTimeMillis(); NULL_SERVER_ISSUES.add(currentTime); Main.schedule(() -> NULL_SERVER_ISSUES.remove(currentTime), 60); } public static final Map<Long, Exception> SCHEDULED_TASK_ERRORS = new HashMap<>(); public static void onScheduledTaskError(Exception e) { long currentTime = System.currentTimeMillis(); SCHEDULED_TASK_ERRORS.put(currentTime, e); Main.schedule(() -> SCHEDULED_TASK_ERRORS.remove(currentTime), 60); if (SCHEDULED_TASK_ERRORS.size() > 10) { Exception exception = Miscellaneous.getLastEntry(SCHEDULED_TASK_ERRORS.values()); if (exception == null) { return; } alertDevs("%d Scheduled tasks errors! (Latest: %s \n%s)", SCHEDULED_TASK_ERRORS.size(), exception.getMessage(), Text.separateBy(Miscellaneous.to(exception.getStackTrace(), 5), "\n")); } } private static final String DEVELOPER_MENTION = "<@&793213378654371853>"; private static final String TESTING_DEVELOPER_MENTION = "<@&1141110691760177262>"; public static String getDeveloperMention() { if (RelayUtils.testing) { return TESTING_DEVELOPER_MENTION; } return DEVELOPER_MENTION; } public static void alertDevs(String format, Object... data) { sendMessage("devalerts", getDeveloperMention() + " " + RelayUtils.format(format, data)); } private static final String STAFF_MENTION = "<@&793247946064920608>"; private static final String TESTING_STAFF_MENTION = "<@&1141123648858619998>"; public static String getStaffMention() { if (RelayUtils.testing) { return TESTING_STAFF_MENTION; } return STAFF_MENTION; } public static void alertStaff(String channel, String format, Object... data) { sendMessage(channel, getStaffMention() + " " + RelayUtils.format(format, data)); } public static void onTakenCredits(SmartPlayer smartPlayer, long credits) { sendMessage("purchases", "%s canceled %d credits.", smartPlayer.getName(), credits); } public static void onTakenGroup(SmartPlayer smartPlayer, Group group) { sendMessage("purchases", "%s canceled %s purchase.", smartPlayer.getName(), group.getGroupName()); } public static void onGivenGroup(SmartPlayer smartPlayer, Group group) { sendMessage("purchases", "%s purchased %s.", smartPlayer.getName(), group.getGroupName()); } public static void onGivenTokens(SmartPlayer smartPlayer, long credits) { sendMessage("purchases", "%s purchased %d credits.", smartPlayer.getName(), credits); } public static final Map<String, UUID> CODE_TO_PLAYER = new HashMap<>(); public static void onDiscordCodeGenerated(SmartPlayer smartPlayer, String code) { CODE_TO_PLAYER.put(code, smartPlayer.getUUID()); } public static void onPlayerDataRetrieved(SmartPlayer smartPlayer) { if (smartPlayer.hasDiscordLinked()) { ID_TO_UUID.put(smartPlayer.getDiscordId(), smartPlayer.getUUID()); } } }