Merge pull request #231 from allinkdev/discord

Merge allinkdev:discord into AtlasMediaGroup:discord branch
This commit is contained in:
Allink 2022-06-06 00:31:13 +01:00 committed by GitHub
commit 9a54ef66d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 884 additions and 168 deletions

View File

@ -175,15 +175,15 @@ public class ChatManager extends FreedomService
});
}
public void reportAction(Player reporter, Player reported, String report)
public void reportAction(Player reporter, String reportedName, String report)
{
for (Player player : server.getOnlinePlayers())
{
if (plugin.al.isAdmin(player))
{
playerMsg(player, ChatColor.RED + "[REPORTS] " + ChatColor.GOLD + reporter.getName() + " has reported " + reported.getName() + " for " + report);
playerMsg(player, ChatColor.RED + "[REPORTS] " + ChatColor.GOLD + reporter.getName() + " has reported " + reportedName + " for " + report);
}
}
FLog.info("[REPORTS] " + reporter.getName() + " has reported " + reported.getName() + " for " + report);
FLog.info("[REPORTS] " + reporter.getName() + " has reported " + reportedName + " for " + report);
}
}

View File

@ -4,6 +4,7 @@ import me.totalfreedom.totalfreedommod.rank.Rank;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -22,36 +23,40 @@ public class Command_report extends FreedomCommand
}
Player player = getPlayer(args[0], true);
OfflinePlayer offlinePlayer = getOfflinePlayer(args[0]);
if (player == null)
if (player == null && offlinePlayer == null)
{
msg(PLAYER_NOT_FOUND);
return true;
}
if (sender instanceof Player)
else if (player != null)
{
if (player.equals(playerSender))
if (sender instanceof Player)
{
msg(ChatColor.RED + "Please, don't try to report yourself.");
if (player.equals(playerSender))
{
msg(ChatColor.RED + "Please, don't try to report yourself.");
return true;
}
}
if (plugin.al.isAdmin(player))
{
msg(ChatColor.RED + "You can not report admins.");
return true;
}
}
if (plugin.al.isAdmin(player))
{
msg(ChatColor.RED + "You can not report admins.");
return true;
}
String report = StringUtils.join(ArrayUtils.subarray(args, 1, args.length), " ");
plugin.cm.reportAction(playerSender, player, report);
plugin.cm.reportAction(playerSender, (player == null) ? offlinePlayer.getName() : player.getName(), report);
boolean logged = false;
if (plugin.dc.enabled)
{
logged = plugin.dc.sendReport(playerSender, player, report);
logged = (player == null) ? plugin.dc.sendReportOffline(playerSender, offlinePlayer, report) : plugin.dc.sendReport(playerSender, player, report);
}
msg(ChatColor.GREEN + "Thank you, your report has been successfully logged."

View File

@ -45,7 +45,7 @@ public class Command_vanish extends FreedomCommand
msg("You have unvanished.", ChatColor.GOLD);
FUtil.bcastMsg(plugin.rm.craftLoginMessage(playerSender, null));
FUtil.bcastMsg(playerSender.getName() + " joined the game.", ChatColor.YELLOW);
plugin.dc.messageChatChannel("**" + playerSender.getName() + " joined the server" + "**");
plugin.dc.messageChatChannel("**" + playerSender.getName() + " joined the server" + "**", true);
}
PlayerData playerData = plugin.pl.getData(playerSender);
@ -91,7 +91,7 @@ public class Command_vanish extends FreedomCommand
{
msg("You have vanished.", ChatColor.GOLD);
FUtil.bcastMsg(playerSender.getName() + " left the game.", ChatColor.YELLOW);
plugin.dc.messageChatChannel("**" + playerSender.getName() + " left the server" + "**");
plugin.dc.messageChatChannel("**" + playerSender.getName() + " left the server" + "**", true);
}
FLog.info(playerSender.getName() + " is now vanished.");

View File

@ -1,14 +1,10 @@
package me.totalfreedom.totalfreedommod.command;
import com.google.common.collect.Lists;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.*;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.player.PlayerData;
@ -18,12 +14,14 @@ import me.totalfreedom.totalfreedommod.util.FUtil;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class FreedomCommand implements CommandExecutor, TabCompleter
{
@ -229,6 +227,16 @@ public abstract class FreedomCommand implements CommandExecutor, TabCompleter
return player;
}
@Nullable
protected OfflinePlayer getOfflinePlayer(String name)
{
return Arrays.stream(Bukkit.getOfflinePlayers())
.filter(player -> player.getName() != null)
.filter(player -> player.getName().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
}
protected Admin getAdmin(CommandSender sender)
{
return plugin.al.getAdmin(sender);

View File

@ -74,7 +74,9 @@ public enum ConfigEntry
SERVER_FULL_MOTD(String.class, "server.motds.full"),
//
DISCORD_TOKEN(String.class, "discord.token"),
DISCORD_PREFIX(String.class, "discord.prefix"),
DISCORD_REPORT_CHANNEL_ID(String.class, "discord.report_channel_id"),
DISCORD_REPORT_ARCHIVE_CHANNEL_ID(String.class, "discord.report_archive_channel_id"),
DISCORD_CHAT_CHANNEL_ID(String.class, "discord.chat_channel_id"),
DISCORD_ADMINCHAT_CHANNEL_ID(String.class, "discord.adminchat_channel_id"),

View File

@ -13,9 +13,12 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.security.auth.login.LoginException;
import com.google.common.collect.ImmutableList;
import me.totalfreedom.totalfreedommod.FreedomService;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandManager;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.rank.Rank;
import me.totalfreedom.totalfreedommod.util.FLog;
@ -37,9 +40,14 @@ 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.internal.utils.concurrent.CountingThreadFactory;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.bukkit.GameRule;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -53,9 +61,11 @@ public class Discord extends FreedomService
public static HashMap<String, PlayerData> LINK_CODES = new HashMap<>();
public static JDA bot = null;
public static DiscordCommandManager DISCORD_COMMAND_MANAGER;
public ScheduledThreadPoolExecutor RATELIMIT_EXECUTOR;
public List<CompletableFuture<Message>> sentMessages = new ArrayList<>();
public Boolean enabled = false;
private static final ImmutableList<String> DISCORD_SUBDOMAINS = ImmutableList.of("discordapp.com", "discord.com", "discord.gg");
private final Pattern DISCORD_MENTION_PATTERN = Pattern.compile("(<@!?([0-9]{16,20})>)");
public static String getCode(PlayerData playerData)
@ -146,6 +156,9 @@ public class Discord extends FreedomService
public void startBot()
{
DISCORD_COMMAND_MANAGER = new DiscordCommandManager();
DISCORD_COMMAND_MANAGER.init(this);
enabled = !Strings.isNullOrEmpty(ConfigEntry.DISCORD_TOKEN.getString());
if (!enabled)
{
@ -168,6 +181,7 @@ public class Discord extends FreedomService
.addEventListeners(new PrivateMessageListener(),
new DiscordToMinecraftListener(),
new DiscordToAdminChatListener(),
new MessageReactionListener(),
new ListenerAdapter()
{
@Override
@ -215,7 +229,7 @@ public class Discord extends FreedomService
}
}
sentMessages.clear();
messageChatChannel("**Message queue cleared**");
messageChatChannel("**Message queue cleared**", true);
}
public void sendPteroInfo(PlayerData playerData, String username, String password)
@ -246,13 +260,7 @@ public class Discord extends FreedomService
public String generateCode(int size)
{
StringBuilder code = new StringBuilder();
SplittableRandom random = new SplittableRandom();
for (int i = 0; i < size; i++)
{
code.append(random.nextInt(10));
}
return code.toString();
return RandomStringUtils.randomNumeric(size);
}
@EventHandler(priority = EventPriority.MONITOR)
@ -265,9 +273,11 @@ public class Discord extends FreedomService
return;
}
if (event.getDeathMessage() != null)
Component deathMessage = event.deathMessage();
if (deathMessage != null)
{
messageChatChannel("**" + event.getDeathMessage() + "**");
messageChatChannel("**" + PlainTextComponentSerializer.plainText().serialize(deathMessage) + "**", true);
}
}
@ -282,7 +292,7 @@ public class Discord extends FreedomService
{
if (!plugin.al.isVanished(event.getPlayer().getName()))
{
messageChatChannel("**" + event.getPlayer().getName() + " joined the server" + "**");
messageChatChannel("**" + event.getPlayer().getName() + " joined the server" + "**", true);
}
}
@ -291,69 +301,78 @@ public class Discord extends FreedomService
{
if (!plugin.al.isVanished(event.getPlayer().getName()))
{
messageChatChannel("**" + event.getPlayer().getName() + " left the server" + "**");
messageChatChannel("**" + event.getPlayer().getName() + " left the server" + "**", true);
}
}
public static String sanitizeChatMessage(String message)
{
String newMessage = message;
if (message.contains("@"))
{
// \u200B is Zero Width Space, invisible on Discord
newMessage = message.replaceAll("@", "@\u200B");
}
if (message.toLowerCase().contains("discord.gg")) // discord.gg/invite works as an invite
{
return "";
}
for (String subdomain : DISCORD_SUBDOMAINS)
{
if (message.toLowerCase().contains(subdomain + "/invite"))
{
return "";
}
}
if (message.contains("§"))
{
newMessage = message.replaceAll("§", "");
}
return deformat(newMessage);
}
public void messageChatChannel(String message)
{
messageChatChannel(message, false);
}
public void messageChatChannel(String message, boolean system)
{
String chat_channel_id = ConfigEntry.DISCORD_CHAT_CHANNEL_ID.getString();
if (message.contains("@everyone") || message.contains("@here"))
{
message = StringUtils.remove(message, "@");
}
if (message.toLowerCase().contains("discord.gg"))
{
return;
}
if (message.contains("§"))
{
message = StringUtils.remove(message, "§");
}
String sanitizedMessage = (system) ? message : sanitizeChatMessage(message);
Matcher DISCORD_MENTION_MATCHER = DISCORD_MENTION_PATTERN.matcher(message);
while (DISCORD_MENTION_MATCHER.find())
{
String mention = DISCORD_MENTION_MATCHER.group(1);
message = message.replace(mention, mention.replace("@",""));
}
if (sanitizedMessage.isBlank()) return;
if (enabled && !chat_channel_id.isEmpty())
{
CompletableFuture<Message> sentMessage = Objects.requireNonNull(bot.getTextChannelById(chat_channel_id)).sendMessage(deformat(message)).submit(true);
CompletableFuture<Message> sentMessage = Objects.requireNonNull(bot.getTextChannelById(chat_channel_id)).sendMessage(sanitizedMessage).submit(true);
sentMessages.add(sentMessage);
}
}
public void messageAdminChatChannel(String message)
{
messageAdminChatChannel(message, false);
}
public void messageAdminChatChannel(String message, boolean system)
{
String chat_channel_id = ConfigEntry.DISCORD_ADMINCHAT_CHANNEL_ID.getString();
if (message.contains("@everyone") || message.contains("@here"))
{
message = StringUtils.remove(message, "@");
}
if (message.toLowerCase().contains("discord.gg"))
{
return;
}
if (message.contains("§"))
{
message = StringUtils.remove(message, "§");
}
String sanitizedMessage = sanitizeChatMessage(message);
if (sanitizedMessage.isBlank()) return;
Matcher DISCORD_MENTION_MATCHER = DISCORD_MENTION_PATTERN.matcher(message);
while (DISCORD_MENTION_MATCHER.find())
if (enabled && !chat_channel_id.isEmpty())
{
String mention = DISCORD_MENTION_MATCHER.group(1);
message = message.replace(mention, mention.replace("@",""));
CompletableFuture<Message> sentMessage = Objects.requireNonNull(bot.getTextChannelById(chat_channel_id)).sendMessage(sanitizedMessage).submit(true);
sentMessages.add(sentMessage);
}
if (enabled && !chat_channel_id.isEmpty())
@ -366,7 +385,7 @@ public class Discord extends FreedomService
public String formatBotTag()
{
SelfUser user = bot.getSelfUser();
return user.getName() + "#" + user.getDiscriminator();
return user.getAsTag();
}
@Override
@ -374,18 +393,18 @@ public class Discord extends FreedomService
{
if (bot != null)
{
messageChatChannel("**Server has stopped**");
messageChatChannel("**Server has stopped**", true);
}
FLog.info("Discord integration has successfully shutdown.");
}
public String deformat(String input)
public static String deformat(String input)
{
return input.replace("_", "\\_");
return input.replaceAll("([_\\\\`*>|])", "\\\\$1");
}
public boolean sendReport(Player reporter, Player reported, String reason)
public boolean shouldISendReport()
{
if (ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString().isEmpty())
{
@ -400,6 +419,7 @@ public class Discord extends FreedomService
Guild server = bot.getGuildById(ConfigEntry.DISCORD_SERVER_ID.getString());
if (server == null)
{
FLog.severe("The Discord server ID specified is invalid, or the bot is not on the server.");
return false;
@ -412,7 +432,54 @@ public class Discord extends FreedomService
return false;
}
EmbedBuilder embedBuilder = new EmbedBuilder();
return true;
}
public boolean sendReportOffline(Player reporter, OfflinePlayer reported, String reason)
{
if (!shouldISendReport())
{
return false;
}
final Guild server = bot.getGuildById(ConfigEntry.DISCORD_SERVER_ID.getString());
final TextChannel channel = server.getTextChannelById(ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString());
final EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setTitle("Report for " + reported.getName() + " (offline)");
embedBuilder.setDescription(reason);
embedBuilder.setFooter("Reported by " + reporter.getName(), "https://minotar.net/helm/" + reporter.getName() + ".png");
embedBuilder.setTimestamp(Instant.from(ZonedDateTime.now()));
com.earth2me.essentials.User user = plugin.esb.getEssentialsUser(reported.getName());
String location = "World: " + Objects.requireNonNull(user.getLastLocation().getWorld()).getName() + ", X: " + user.getLastLocation().getBlockX() + ", Y: " + user.getLastLocation().getBlockY() + ", Z: " + user.getLastLocation().getBlockZ();
embedBuilder.addField("Location", location, true);
embedBuilder.addField("God Mode", WordUtils.capitalizeFully(String.valueOf(user.isGodModeEnabled())), true);
if (user.getNickname() != null)
{
embedBuilder.addField("Nickname", user.getNickname(), true);
}
MessageEmbed embed = embedBuilder.build();
Message message = channel.sendMessage(embed).complete();
if (!ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString().isEmpty())
{
message.addReaction("\uD83D\uDCCB").complete();
}
return true;
}
public boolean sendReport(Player reporter, Player reported, String reason)
{
if (!shouldISendReport())
{
return false;
}
final Guild server = bot.getGuildById(ConfigEntry.DISCORD_SERVER_ID.getString());
final TextChannel channel = server.getTextChannelById(ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString());
final EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setTitle("Report for " + reported.getName());
embedBuilder.setDescription(reason);
embedBuilder.setFooter("Reported by " + reporter.getName(), "https://minotar.net/helm/" + reporter.getName() + ".png");
@ -427,7 +494,13 @@ public class Discord extends FreedomService
embedBuilder.addField("Nickname", user.getNickname(), true);
}
MessageEmbed embed = embedBuilder.build();
channel.sendMessage(embed).complete();
Message message = channel.sendMessage(embed).complete();
if (!ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString().isEmpty())
{
message.addReaction("\uD83D\uDCCB").complete();
}
return true;
}
@ -436,7 +509,7 @@ public class Discord extends FreedomService
{
public void start()
{
messageChatChannel("**Server has started**");
messageChatChannel("**Server has started**", true);
}
}
}

View File

@ -2,12 +2,12 @@ package me.totalfreedom.totalfreedommod.discord;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandManager;
import me.totalfreedom.totalfreedommod.rank.Rank;
import me.totalfreedom.totalfreedommod.rank.Title;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.md_5.bungee.api.chat.BaseComponent;
@ -24,77 +24,108 @@ public class DiscordToMinecraftListener extends ListenerAdapter
{
public void onMessageReceived(MessageReceivedEvent event)
{
String chat_channel_id = ConfigEntry.DISCORD_CHAT_CHANNEL_ID.getString();
if (event.getMember() != null && !chat_channel_id.isEmpty() && event.getChannel().getId().equals(chat_channel_id))
final String chat_channel_id = ConfigEntry.DISCORD_CHAT_CHANNEL_ID.getString();
final MessageChannel genericChannel = event.getChannel();
if (event.getMember() == null)
{
if (!event.getAuthor().getId().equals(Discord.bot.getSelfUser().getId()))
{
Member member = event.getMember();
String tag = getDisplay(member);
Message msg = event.getMessage();
return;
}
ComponentBuilder emsg = new ComponentBuilder();
if (chat_channel_id.isEmpty())
{
return;
}
// Prefix
emsg.append(ChatColor.DARK_GRAY + "[");
TextComponent inviteLink = new TextComponent("Discord");
inviteLink.setColor(ChatColor.DARK_AQUA.asBungee());
inviteLink.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new Text("Click here to get the invite link!")));
inviteLink.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL,
ConfigEntry.DISCORD_INVITE_LINK.getString()));
emsg.append(inviteLink);
emsg.append(ChatColor.DARK_GRAY + "] ", ComponentBuilder.FormatRetention.NONE);
if (event.getAuthor().getId().equals(Discord.bot.getSelfUser().getId()))
{
return;
}
// Tag (if they have one)
if (tag != null)
{
emsg.append(tag);
}
if (!genericChannel.getId().equals(chat_channel_id))
{
return;
}
if (!(genericChannel instanceof TextChannel))
{
return;
}
final TextChannel textChannel = (TextChannel) genericChannel;
final Member member = event.getMember();
final String tag = getDisplay(member);
final Message msg = event.getMessage();
final String content = msg.getContentStripped();
if (content.startsWith(ConfigEntry.DISCORD_PREFIX.getString()))
{
Discord.DISCORD_COMMAND_MANAGER.parse(content, member, textChannel);
return;
}
ComponentBuilder emsg = new ComponentBuilder();
// Prefix
emsg.append(ChatColor.DARK_GRAY + "[");
TextComponent inviteLink = new TextComponent("Discord");
inviteLink.setColor(ChatColor.DARK_AQUA.asBungee());
inviteLink.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new Text("Click here to get the invite link!")));
inviteLink.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL,
ConfigEntry.DISCORD_INVITE_LINK.getString()));
emsg.append(inviteLink);
emsg.append(ChatColor.DARK_GRAY + "] ", ComponentBuilder.FormatRetention.NONE);
// Tag (if they have one)
if (tag != null)
{
emsg.append(tag);
}
emsg.append(" ");
// User
TextComponent user = new TextComponent(FUtil.stripColors(member.getEffectiveName()));
user.setColor(ChatColor.RED.asBungee());
emsg.append(user);
// Message
emsg.append(ChatColor.DARK_GRAY + ": " + ChatColor.RESET
+ FUtil.stripColors(msg.getContentDisplay()), ComponentBuilder.FormatRetention.NONE);
// Attachments
if (!msg.getAttachments().isEmpty())
{
if (!msg.getContentDisplay().isEmpty())
emsg.append(" ");
// User
TextComponent user = new TextComponent(ChatColor.stripColor(member.getEffectiveName()));
user.setColor(ChatColor.RED.asBungee());
emsg.append(user);
for (Message.Attachment attachment : msg.getAttachments())
{
TextComponent media = new TextComponent("[Media] ");
media.setColor(ChatColor.YELLOW.asBungee());
media.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, attachment.getUrl()));
media.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(attachment.getUrl())));
// Message
emsg.append(ChatColor.DARK_GRAY + ": " + ChatColor.RESET
+ ChatColor.stripColor(msg.getContentDisplay()), ComponentBuilder.FormatRetention.NONE);
// Attachments
if (!msg.getAttachments().isEmpty())
{
if (!msg.getContentDisplay().isEmpty())
emsg.append(" ");
for (Message.Attachment attachment : msg.getAttachments())
{
TextComponent media = new TextComponent("[Media] ");
media.setColor(ChatColor.YELLOW.asBungee());
media.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, attachment.getUrl()));
media.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(attachment.getUrl())));
emsg.append(media, ComponentBuilder.FormatRetention.NONE);
}
}
BaseComponent[] components = emsg.create();
for (Player player : Bukkit.getOnlinePlayers())
{
if (TotalFreedomMod.getPlugin().pl.getData(player).doesDisplayDiscord())
{
player.spigot().sendMessage(components);
}
}
FLog.info(TextComponent.toLegacyText(components), true);
emsg.append(media, ComponentBuilder.FormatRetention.NONE);
}
}
BaseComponent[] components = emsg.create();
for (Player player : Bukkit.getOnlinePlayers())
{
if (TotalFreedomMod.getPlugin().pl.getData(player).doesDisplayDiscord())
{
player.sendMessage(components);
}
}
FLog.info(TextComponent.toLegacyText(components), true);
}
public String getDisplay(Member member)
{
Guild server = Discord.bot.getGuildById(ConfigEntry.DISCORD_SERVER_ID.getString());

View File

@ -0,0 +1,68 @@
package me.totalfreedom.totalfreedommod.discord;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
public class MessageReactionListener extends ListenerAdapter
{
public void onMessageReactionAdd(MessageReactionAddEvent messageReactionAddEvent)
{
if (!messageReactionAddEvent.isFromGuild())
{
return;
}
if (messageReactionAddEvent.getMember() == null)
{
return;
}
if (messageReactionAddEvent.getMember().getUser().getId().equals(Discord.bot.getSelfUser().getId()))
{
return;
}
if (!messageReactionAddEvent.getChannel().getId().equals(ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString()))
{
return;
}
if (!messageReactionAddEvent.getReactionEmote().getEmoji().equals("\uD83D\uDCCB"))
{
return;
}
final TextChannel archiveChannel = Discord.bot.getTextChannelById(ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString());
if (archiveChannel == null)
{
FLog.warning("Report archive channel is defined in the config, yet doesn't actually exist!");
return;
}
final Message message = messageReactionAddEvent.retrieveMessage().complete();
final Member completer = messageReactionAddEvent.getMember();
if (!message.getAuthor().getId().equals(Discord.bot.getSelfUser().getId()))
{
return;
}
// We don't need other embeds... yet?
final MessageEmbed embed = message.getEmbeds().get(0);
final MessageBuilder archiveMessageBuilder = new MessageBuilder();
archiveMessageBuilder.setContent("Report completed by " + completer.getUser().getAsMention() + " (" + Discord.deformat(completer.getUser().getAsTag() + ")"));
archiveMessageBuilder.setEmbed(embed);
final Message archiveMessage = archiveMessageBuilder.build();
archiveChannel.sendMessage(archiveMessage).complete();
message.delete().complete();
}
}

View File

@ -0,0 +1,25 @@
package me.totalfreedom.totalfreedommod.discord.command;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import java.util.List;
public interface DiscordCommand
{
String getCommandName();
String getDescription();
String getCategory();
List<String> getAliases();
boolean isAdmin();
boolean canExecute(Member member);
MessageBuilder execute(Member member, List<String> args);
}

View File

@ -0,0 +1,13 @@
package me.totalfreedom.totalfreedommod.discord.command;
import net.dv8tion.jda.api.entities.Member;
public abstract class DiscordCommandImpl implements DiscordCommand
{
@Override
public boolean canExecute(Member member)
{
//return !isAdmin() || member.getRoles().stream().filter((role -> role.getName().toLowerCase().contains("admin") && !role.getName().toLowerCase().contains("discord"))).toList().size() > 0;
return !isAdmin();
}
}

View File

@ -0,0 +1,84 @@
package me.totalfreedom.totalfreedommod.discord.command;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.discord.Discord;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import org.reflections.Reflections;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class DiscordCommandManager
{
public static final String PREFIX = ConfigEntry.DISCORD_PREFIX.getString();
private Discord discord;
public final List<DiscordCommand> commands = new ArrayList<>();
public void init(Discord discord)
{
this.discord = discord;
final Reflections discordCommandsDir = new Reflections("me.totalfreedom.totalfreedommod.discord.commands");
final Set<Class<? extends DiscordCommand>> commandClasses = discordCommandsDir.getSubTypesOf(DiscordCommand.class);
for (Class<? extends DiscordCommand> commandClass : commandClasses)
{
try
{
commands.add(commandClass.getDeclaredConstructor().newInstance());
}
catch (Exception e)
{
FLog.warning("Failed to load Discord command: " + commandClass.getName());
}
}
FLog.info("Loaded " + commands.size() + " Discord commands.");
}
public void parse(String content, Member member, TextChannel channel)
{
List<String> args = new ArrayList<>(Arrays.asList(content.split(" ")));
final String alias = args.remove(0).split(PREFIX)[1]; // The joys of command parsing
for (DiscordCommand command : commands)
{
if (command.getCommandName().equalsIgnoreCase(alias) || command.getAliases().contains(alias.toLowerCase()))
{
if (command.canExecute(member))
{
final MessageBuilder messageBuilder = command.execute(member, args);
final Message message = messageBuilder.build();
final CompletableFuture<Message> futureMessage = channel.sendMessage(message).submit(true);
this.discord.sentMessages.add(futureMessage);
}
else
{
final MessageBuilder messageBuilder = new MessageBuilder();
final EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setTitle("Command error");
embedBuilder.setColor(Color.RED);
embedBuilder.setDescription("You don't have permission to execute this command.");
messageBuilder.setEmbed(embedBuilder.build());
final Message message = messageBuilder.build();
final CompletableFuture<Message> futureMessage = channel.sendMessage(message).submit(true);
this.discord.sentMessages.add(futureMessage);
}
}
}
}
}

View File

@ -0,0 +1,86 @@
package me.totalfreedom.totalfreedommod.discord.commands;
import me.totalfreedom.totalfreedommod.discord.Discord;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommand;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandImpl;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandManager;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Member;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HelpCommand extends DiscordCommandImpl
{
@Override
public String getCommandName()
{
return "help";
}
@Override
public String getDescription()
{
return "Displays the help command";
}
@Override
public String getCategory()
{
return "Help";
}
@Override
public List<String> getAliases()
{
return List.of("cmds", "commands", "elp");
}
@Override
public boolean isAdmin()
{
return false;
}
@Override
public MessageBuilder execute(Member member, List<String> args)
{
final EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Color.GREEN);
embedBuilder.setTitle("Help Command");
final Map<String, List<DiscordCommand>> commandCategories = new HashMap<>();
for (DiscordCommand command : Discord.DISCORD_COMMAND_MANAGER.commands)
{
if (!commandCategories.containsKey(command.getCategory()))
{
commandCategories.put(command.getCategory(), new ArrayList<>(List.of(command)));
}
else
{
commandCategories.get(command.getCategory()).add(command);
}
}
for (Map.Entry<String, List<DiscordCommand>> entry : commandCategories.entrySet())
{
final String category = entry.getKey();
final List<DiscordCommand> commands = entry.getValue();
final StringBuilder fieldValue = new StringBuilder();
for (DiscordCommand command : commands)
{
fieldValue.append("**").append(DiscordCommandManager.PREFIX).append(command.getCommandName()).append("** - ").append(command.getDescription()).append("\n");
}
embedBuilder.addField(category, fieldValue.toString().trim(), false);
}
return new MessageBuilder().setEmbed(embedBuilder.build());
}
}

View File

@ -0,0 +1,106 @@
package me.totalfreedom.totalfreedommod.discord.commands;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.admin.AdminList;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommand;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandImpl;
import me.totalfreedom.totalfreedommod.rank.Displayable;
import me.totalfreedom.totalfreedommod.rank.RankManager;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListCommand extends DiscordCommandImpl
{
private static final TotalFreedomMod PLUGIN = TotalFreedomMod.plugin();
@Override
public String getCommandName()
{
return "list";
}
@Override
public String getDescription()
{
return "Gives a list of online players.";
}
@Override
public String getCategory()
{
return "Server Commands";
}
@Override
public List<String> getAliases()
{
return List.of("online", "who", "l", "lsit");
}
@Override
public boolean isAdmin()
{
return false;
}
@Override
public MessageBuilder execute(Member member, List<String> args)
{
if (PLUGIN == null)
{
throw new IllegalStateException("TotalFreedomMod somehow null while executing a command!");
}
final AdminList adminList = PLUGIN.al;
final RankManager rankManager = PLUGIN.rm;
EmbedBuilder embedBuilder = new EmbedBuilder()
.setTitle("Player List - " + ConfigEntry.SERVER_NAME.getString())
.setDescription("There are " + FUtil.getFakePlayerCount() + " / " + Bukkit.getMaxPlayers() + " online players");
Map<Displayable, List<String>> displayables = new HashMap<>();
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
{
if (adminList.isVanished(onlinePlayer.getName()))
{
continue;
}
Displayable displayable = rankManager.getDisplay(onlinePlayer);
if (displayables.containsKey(displayable))
{
displayables.get(displayable).add(onlinePlayer.getName());
}
else
{
displayables.put(displayable, new ArrayList<>(List.of(onlinePlayer.getName())));
}
}
for (Map.Entry<Displayable, List<String>> entry : displayables.entrySet())
{
final Displayable displayable = entry.getKey();
final List<String> players = entry.getValue();
embedBuilder.addField(displayable.getPlural() + " (" + players.size() + ")",
String.join(", ", players), false);
}
return new MessageBuilder().setEmbed(embedBuilder.build());
}
}

View File

@ -0,0 +1,60 @@
package me.totalfreedom.totalfreedommod.discord.commands;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommand;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandImpl;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Member;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import java.util.Collections;
import java.util.List;
public class TPSCommand extends DiscordCommandImpl
{
@Override
public String getCommandName()
{
return "tps";
}
@Override
public String getDescription()
{
return "Lag information regarding the server.";
}
@Override
public String getCategory()
{
return "Server Commands";
}
@Override
public List<String> getAliases()
{
return Collections.singletonList("lag");
}
@Override
public boolean isAdmin()
{
return false;
}
@Override
public MessageBuilder execute(Member member, List<String> args)
{
final EmbedBuilder builder = new EmbedBuilder();
builder.setTitle("Server lag information");
builder.addField("TPS", String.valueOf(Math.round(FUtil.getMeanAverageDouble(Bukkit.getServer().getTPS()))), false);
builder.addField("Uptime", FUtil.getUptime(), false);
builder.addField("Maximum Memory", Math.ceil(FUtil.getMaxMem()) + " MB", false);
builder.addField("Allocated Memory", Math.ceil(FUtil.getTotalMem()) + " MB", false);
builder.addField("Free Memory", Math.ceil(FUtil.getFreeMem()) + " MB", false);
return new MessageBuilder().setEmbed(builder.build());
}
}

View File

@ -0,0 +1,79 @@
package me.totalfreedom.totalfreedommod.discord.commands;
import me.totalfreedom.totalfreedommod.discord.command.DiscordCommandImpl;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Member;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.List;
public class UptimeCommand extends DiscordCommandImpl
{
@Override
public String getCommandName()
{
return "uptime";
}
@Override
public String getDescription()
{
return "Returns the uptime of the host.";
}
@Override
public String getCategory()
{
return "Server Commands";
}
@Override
public List<String> getAliases()
{
return Collections.emptyList();
}
@Override
public boolean isAdmin()
{
return false;
}
@Override
public MessageBuilder execute(Member member, List<String> args)
{
final EmbedBuilder embedBuilder = new EmbedBuilder();
try
{
final Process uptimeProcess = Runtime.getRuntime().exec(new String[]{"uptime"});
BufferedReader input = new BufferedReader(new InputStreamReader(uptimeProcess.getInputStream()));
String line = input.readLine();
if (line != null)
{
embedBuilder.setTitle("Host Uptime Information");
embedBuilder.setDescription(line.trim());
}
else
{
throw new IllegalStateException("No output from uptime command.");
}
}
catch (Exception e)
{
FLog.warning("Error while executing uptime Discord command");
e.printStackTrace();
embedBuilder.setTitle("Command error");
embedBuilder.setColor(Color.RED);
embedBuilder.setDescription("Something went wrong");
}
return new MessageBuilder().setEmbed(embedBuilder.build());
}
}

View File

@ -13,6 +13,8 @@ public interface Displayable
String getAbbr();
String getPlural();
ChatColor getColor();
org.bukkit.ChatColor getTeamColor();

View File

@ -4,19 +4,19 @@ import net.md_5.bungee.api.ChatColor;
public enum Rank implements Displayable
{
NON_OP("a", "Non-Op", Type.PLAYER, "", ChatColor.WHITE, null, false, false),
OP("an", "Operator", Type.PLAYER, "OP", ChatColor.GREEN, null, false, false),
ADMIN("an", "Admin", Type.ADMIN, "Admin", ChatColor.DARK_GREEN, org.bukkit.ChatColor.DARK_GREEN, true, true),
SENIOR_ADMIN("a", "Senior Admin", Type.ADMIN, "SrA", ChatColor.GOLD, org.bukkit.ChatColor.GOLD, true, true),
ADMIN_CONSOLE("the", "Console", Type.ADMIN_CONSOLE, "Console", ChatColor.DARK_PURPLE, null, false, false),
SENIOR_CONSOLE("the", "Console", Type.ADMIN_CONSOLE, "Console", ChatColor.DARK_PURPLE, null, false, false);
NON_OP("a", "Non-Op", Type.PLAYER, "", "Non-Ops", ChatColor.WHITE, null, false, false),
OP("an", "Operator", Type.PLAYER, "OP", "Operators", ChatColor.GREEN, null, false, false),
ADMIN("an", "Admin", Type.ADMIN, "Admin", "Administrators", ChatColor.DARK_GREEN, org.bukkit.ChatColor.DARK_GREEN, true, true),
SENIOR_ADMIN("a", "Senior Admin", Type.ADMIN, "SrA", "Senior Administrators", ChatColor.GOLD, org.bukkit.ChatColor.GOLD, true, true),
ADMIN_CONSOLE("the", "Console", Type.ADMIN_CONSOLE, "Console", "Administrator Consoles", ChatColor.DARK_PURPLE, null, false, false),
SENIOR_CONSOLE("the", "Console", Type.ADMIN_CONSOLE, "Console", "Senior Consoles", ChatColor.DARK_PURPLE, null, false, false);
private final Type type;
private final String name;
private final String abbr;
private final String plural;
private final String article;
private final String tag;
@ -31,11 +31,12 @@ public enum Rank implements Displayable
private final boolean hasDefaultLoginMessage;
Rank(String article, String name, Type type, String abbr, ChatColor color, org.bukkit.ChatColor teamColor, Boolean hasTeam, Boolean hasDefaultLoginMessage)
Rank(String article, String name, Type type, String abbr, String plural, ChatColor color, org.bukkit.ChatColor teamColor, Boolean hasTeam, Boolean hasDefaultLoginMessage)
{
this.type = type;
this.name = name;
this.abbr = abbr;
this.plural = plural;
this.article = article;
this.tag = abbr.isEmpty() ? "" : "[" + abbr + "]";
this.coloredTag = abbr.isEmpty() ? "" : ChatColor.DARK_GRAY + "[" + color + abbr + ChatColor.DARK_GRAY + "]" + color;
@ -88,6 +89,11 @@ public enum Rank implements Displayable
return abbr;
}
public String getPlural()
{
return plural;
}
public boolean isConsole()
{
return getType() == Type.ADMIN_CONSOLE;

View File

@ -5,11 +5,11 @@ import net.md_5.bungee.api.ChatColor;
public enum Title implements Displayable
{
MASTER_BUILDER("a", "Master Builder", ChatColor.DARK_AQUA, org.bukkit.ChatColor.DARK_AQUA, "MB", true, true),
EXECUTIVE("an", "Executive", ChatColor.RED, org.bukkit.ChatColor.RED, "Exec", true, true),
ASSTEXEC("an", "Assistant Executive", ChatColor.RED, org.bukkit.ChatColor.RED, "Asst Exec", true, true),
DEVELOPER("a", "Developer", ChatColor.DARK_PURPLE, org.bukkit.ChatColor.DARK_PURPLE, "Dev", true, true),
OWNER("the", "Owner", ChatColor.DARK_RED, org.bukkit.ChatColor.DARK_RED, "Owner", true, true);
MASTER_BUILDER("a", "Master Builder", "Master Builders", ChatColor.DARK_AQUA, org.bukkit.ChatColor.DARK_AQUA, "MB", true, true),
EXECUTIVE("an", "Executive", "Executives", ChatColor.RED, org.bukkit.ChatColor.RED, "Exec", true, true),
ASSTEXEC("an", "Assistant Executive", "Assistant Executives", ChatColor.RED, org.bukkit.ChatColor.RED, "Asst Exec", true, true),
DEVELOPER("a", "Developer", "Developers", ChatColor.DARK_PURPLE, org.bukkit.ChatColor.DARK_PURPLE, "Dev", true, true),
OWNER("the", "Owner", "Owners", ChatColor.DARK_RED, org.bukkit.ChatColor.DARK_RED, "Owner", true, true);
private final String article;
@ -17,6 +17,7 @@ public enum Title implements Displayable
private final String name;
private final String abbr;
private final String plural;
private final String tag;
@ -29,10 +30,11 @@ public enum Title implements Displayable
private final boolean hasTeam;
private final boolean hasDefaultLoginMessage;
Title(String article, String name, ChatColor color, org.bukkit.ChatColor teamColor, String tag, Boolean hasTeam, Boolean hasDefaultLoginMessage)
Title(String article, String name, String plural, ChatColor color, org.bukkit.ChatColor teamColor, String tag, Boolean hasTeam, Boolean hasDefaultLoginMessage)
{
this.article = article;
this.name = name;
this.plural = plural;
this.coloredTag = ChatColor.DARK_GRAY + "[" + color + tag + ChatColor.DARK_GRAY + "]" + color;
this.abbr = tag;
this.tag = "[" + tag + "]";
@ -84,6 +86,12 @@ public enum Title implements Displayable
return abbr;
}
@Override
public String getPlural()
{
return plural;
}
@Override
public String getTag()
{

View File

@ -1,16 +1,12 @@
package me.totalfreedom.totalfreedommod.util;
import com.earth2me.essentials.utils.DateUtil;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.*;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@ -19,10 +15,9 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import org.json.simple.JSONArray;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.management.ManagementFactory;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
@ -550,6 +545,11 @@ public class FUtil
return string;
}
public static String stripColors(String string)
{
return string.replaceAll("§", "");
}
public static Date getUnixDate(long unix)
{
return new Date(unix);
@ -795,6 +795,62 @@ public class FUtil
return getServer().getOnlinePlayers().size() - i;
}
public static double getMeanAverageDouble(double[] doubles)
{
double total = 0;
for (double aDouble : doubles)
{
total += aDouble;
}
return total / doubles.length;
}
public static int getMeanAverageInt(int[] ints)
{
int total = 0;
for (int anInt : ints)
{
total += anInt;
}
return total / ints.length;
}
public static long getMeanAverageLong(long[] longs)
{
long total = 0;
for (long aLong : longs)
{
total += aLong;
}
return total / longs.length;
}
public static String getUptime()
{
return DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime());
}
public static double getMaxMem()
{
return Runtime.getRuntime().maxMemory() / 1024f / 1024f;
}
public static double getTotalMem()
{
return Runtime.getRuntime().totalMemory() / 1024f / 1024f;
}
public static double getFreeMem()
{
return Runtime.getRuntime().freeMemory() / 1024f / 1024f;
}
public static class PaginationList<T> extends ArrayList<T>
{

View File

@ -58,10 +58,14 @@ server:
discord:
# If you do not have a token, make a bot account and get one at https://discordapp.com/developers/applications/me
token: ''
# The prefix for the integrated bot commands
prefix: 'tf!'
# The official discord server's ID for this server
server_id: ''
# Channel to send /report messages to
report_channel_id: ''
# Channel to send archived reports to
report_archive_channel_id: ''
# Channel for Discord to Minecraft and vice-versa
chat_channel_id: ''
# Channel for Discord to AdminChat and vice-versa