diff --git a/pom.xml b/pom.xml index 6b7730d9..1f2a77ae 100644 --- a/pom.xml +++ b/pom.xml @@ -178,6 +178,18 @@ + + net.dv8tion + JDA + 3.8.3_463 + compile + + + club.minnced + opus-java + + + com.sk89q.worldedit worldedit-bukkit @@ -369,9 +381,21 @@ worldguardwrapper 1.1.6-SNAPSHOT + + com.jagrosh + jda-utilities + 2.1 + compile + pom + + + central + bintray + http://jcenter.bintray.com + net.coreprotect http://maven.playpro.com/ @@ -392,6 +416,11 @@ maven.sk89q.com http://maven.sk89q.com/repo/ + + jcenter + jcenter-bintray + https://jcenter.bintray.com + repo.mikeprimm.com http://repo.mikeprimm.com/ diff --git a/src/main/java/com/massivecraft/factions/Conf.java b/src/main/java/com/massivecraft/factions/Conf.java index c4cd2fd3..8e02a8f6 100644 --- a/src/main/java/com/massivecraft/factions/Conf.java +++ b/src/main/java/com/massivecraft/factions/Conf.java @@ -97,6 +97,12 @@ public class Conf { public static boolean autoLeaveDeleteFPlayerData = true; // Let them just remove player from Faction. public static boolean worldGuardChecking = false; public static boolean worldGuardBuildPriority = false; + //DISCORD + public static boolean useDiscordSystem = true; + public static String discordBotToken = "NjI3NzUxOTI1MzYxODAzMjc0.XZBOUQ.IFeQmnsCMWk6fmDicVtJKNAewXc"; + public static String fromDiscordFactionChatPrefix = "&f[&dDiscord&f] "; + public static String avatarUrl = "http://cravatar.eu/helmavatar/%uuid%.png"; + public static String webhookName = "SaberFactions Hook"; // server logging options public static boolean logFactionCreate = true; public static boolean logFactionDisband = true; diff --git a/src/main/java/com/massivecraft/factions/Faction.java b/src/main/java/com/massivecraft/factions/Faction.java index 35e03aa7..4ed644b5 100644 --- a/src/main/java/com/massivecraft/factions/Faction.java +++ b/src/main/java/com/massivecraft/factions/Faction.java @@ -23,6 +23,38 @@ import java.util.concurrent.ConcurrentHashMap; public interface Faction extends EconomyParticipator { + String getMemberRoleId(); + + void setMemberRoleId(String roleId); + + String getGuildId(); + + void setGuildId(String id); + + String getWallNotifyChannelId(); + + void setWallNotifyChannelId(String channelId); + + String getBufferNotifyChannelId(); + + void setBufferNotifyChannelId(String channelId); + + String getWeeWooChannelId(); + + void setWeeWooChannelId(String channelId); + + String getNotifyFormat(); + + void setNotifyFormat(String format); + + String getWeeWooFormat(); + + void setWeeWooFormat(String format); + + String getFactionChatChannelId(); + + void setFactionChatChannelId(String channelId); + String getDiscord(); void setDiscord(String link); diff --git a/src/main/java/com/massivecraft/factions/FactionsPlugin.java b/src/main/java/com/massivecraft/factions/FactionsPlugin.java index a4551b47..f749bd88 100755 --- a/src/main/java/com/massivecraft/factions/FactionsPlugin.java +++ b/src/main/java/com/massivecraft/factions/FactionsPlugin.java @@ -12,6 +12,8 @@ import com.massivecraft.factions.cmd.check.CheckTask; import com.massivecraft.factions.cmd.check.WeeWooTask; import com.massivecraft.factions.cmd.chest.AntiChestListener; import com.massivecraft.factions.cmd.chest.ChestLogsHandler; +import com.massivecraft.factions.discord.DiscordListener; +import com.massivecraft.factions.discord.FactionChatHandler; import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.integration.Worldguard; import com.massivecraft.factions.integration.dynmap.EngineDynmap; @@ -257,6 +259,10 @@ public class FactionsPlugin extends MPlugin { this.getServer().getScheduler().runTaskTimer(this, CheckTask::cleanupTask, 0L, 1200L); this.getServer().getScheduler().runTaskTimerAsynchronously(this, new WeeWooTask(this), 600L, 600L); } + if(Conf.useDiscordSystem) { + new FactionChatHandler(this); + } + ShopConfig.setup(); getServer().getPluginManager().registerEvents(factionsPlayerListener = new FactionsPlayerListener(), this); @@ -416,7 +422,6 @@ public class FactionsPlugin extends MPlugin { if (this.loadSuccessful) { // Dont save, as this is kind of pointless, as the /f config command manually saves. // So any edits done are saved, this way manual edits to json can go through. - // Conf.save(); } @@ -424,7 +429,7 @@ public class FactionsPlugin extends MPlugin { this.getServer().getScheduler().cancelTask(AutoLeaveTask); AutoLeaveTask = null; } - + DiscordListener.saveGuilds(); super.onDisable(); } diff --git a/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java b/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java index 540c1e02..25203904 100644 --- a/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java +++ b/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java @@ -20,6 +20,8 @@ import com.massivecraft.factions.cmd.roles.CmdDemote; import com.massivecraft.factions.cmd.roles.CmdPromote; import com.massivecraft.factions.cmd.tnt.CmdTnt; import com.massivecraft.factions.cmd.tnt.CmdTntFill; +import com.massivecraft.factions.discord.CmdInviteBot; +import com.massivecraft.factions.discord.CmdSetGuild; import com.massivecraft.factions.missions.CmdMissions; import com.massivecraft.factions.shop.CmdShop; import com.massivecraft.factions.zcore.util.TL; @@ -149,6 +151,8 @@ public class FCmdRoot extends FCommand implements CommandExecutor { public CmdSpawnerLock cmdSpawnerLock = new CmdSpawnerLock(); public CmdSetDiscord cmdSetDiscord = new CmdSetDiscord(); public CmdSeeDiscord cmdSeeDiscord = new CmdSeeDiscord(); + public CmdInviteBot cmdInviteBot = new CmdInviteBot(); + public CmdSetGuild cmdSetGuild = new CmdSetGuild(); public FCmdRoot() { super(); @@ -260,6 +264,11 @@ public class FCmdRoot extends FCommand implements CommandExecutor { this.addSubCommand(this.cmdConvertConfig); this.addSubCommand(this.cmdSpawnerLock); + if(Conf.useDiscordSystem){ + this.addSubCommand(this.cmdInviteBot); + this.addSubCommand(this.cmdSetGuild); + } + if (Conf.useCheckSystem) { this.addSubCommand(this.cmdCheck); this.addSubCommand(this.cmdWeeWoo); diff --git a/src/main/java/com/massivecraft/factions/cmd/check/CheckTask.java b/src/main/java/com/massivecraft/factions/cmd/check/CheckTask.java index 7d5a895c..cde3263a 100644 --- a/src/main/java/com/massivecraft/factions/cmd/check/CheckTask.java +++ b/src/main/java/com/massivecraft/factions/cmd/check/CheckTask.java @@ -5,10 +5,18 @@ import com.massivecraft.factions.Conf; import com.massivecraft.factions.Faction; import com.massivecraft.factions.Factions; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.discord.FactionChatHandler; import com.massivecraft.factions.zcore.util.TL; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.MessageBuilder; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.TextChannel; +import java.awt.*; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -68,6 +76,29 @@ public class CheckTask implements Runnable { CheckTask.wallChecks.add(faction.getId()); } faction.msg(TL.CHECK_WALLS_CHECK); + + String channelId = faction.getWallNotifyChannelId(); + if (channelId == null) { + continue; + } + if (channelId.isEmpty()) { + continue; + } + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(channelId); + if (textChannel == null) { + continue; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + } else { + String format = faction.getNotifyFormat(); + if (format == null || format.isEmpty()) { + format = "@everyone, check %type%"; + } + format = format.replace("%type%", "walls"); + MessageEmbed embed = new EmbedBuilder().setColor(Color.WHITE).setFooter(this.simpleDateFormat.format(new Date(currentTime)), null).build(); + textChannel.sendMessage(new MessageBuilder(embed).setContent(format).build()).queue(); + } } @@ -91,8 +122,29 @@ public class CheckTask implements Runnable { CheckTask.bufferChecks.add(faction.getId()); } faction.msg(TL.CHECK_BUFFERS_CHECK); + String channelId = faction.getBufferNotifyChannelId(); + if (channelId == null) { + continue; + } + if (channelId.isEmpty()) { + continue; + } + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(channelId); + if (textChannel == null) { + continue; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + } else { + String format = faction.getNotifyFormat(); + if (format == null || format.isEmpty()) { + format = "@everyone, check %type%"; + } + format = format.replace("%type%", "buffers"); + MessageEmbed embed = new EmbedBuilder().setColor(Color.WHITE).setFooter(this.simpleDateFormat.format(new Date(currentTime)), null).build(); + textChannel.sendMessage(new MessageBuilder(embed).setContent(format).build()).queue(); + } } } - } diff --git a/src/main/java/com/massivecraft/factions/cmd/check/CmdCheck.java b/src/main/java/com/massivecraft/factions/cmd/check/CmdCheck.java index 36e7bd8a..e5d5006a 100644 --- a/src/main/java/com/massivecraft/factions/cmd/check/CmdCheck.java +++ b/src/main/java/com/massivecraft/factions/cmd/check/CmdCheck.java @@ -1,17 +1,25 @@ package com.massivecraft.factions.cmd.check; import com.massivecraft.factions.Conf; +import com.massivecraft.factions.Faction; import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.discord.FactionChatHandler; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.entities.Channel; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.TextChannel; import org.bukkit.OfflinePlayer; +import java.awt.*; import java.text.SimpleDateFormat; +import java.util.List; import java.util.*; import java.util.stream.Collectors; @@ -76,6 +84,21 @@ public class CmdCheck extends FCommand { } context.faction.getChecks().put(currentTime, "U" + context.fPlayer.getNameAndTag()); context.msg(TL.CHECK_WALLS_MARKED_CHECKED); + if (!Conf.useDiscordSystem) return; + String channelId = context.faction.getWallNotifyChannelId(); + if (channelId == null || channelId.isEmpty()) { + return; + } + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(channelId); + if (textChannel == null) { + return; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, net.dv8tion.jda.core.Permission.MESSAGE_READ, net.dv8tion.jda.core.Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + return; + } + MessageEmbed embed = new EmbedBuilder().setColor(Color.MAGENTA).setTitle("Walls checked by " + context.fPlayer.getNameAndTag()).setFooter(simpleDateFormat.format(new Date(currentTime)), null).build(); + textChannel.sendMessage(embed).queue(); } } else if (subCommand.equalsIgnoreCase("buffers")) { if (!CheckTask.bufferCheck(context.faction.getId())) { @@ -93,6 +116,21 @@ public class CmdCheck extends FCommand { } context.faction.getChecks().put(System.currentTimeMillis(), "Y" + context.fPlayer.getNameAndTag()); context.msg(TL.CHECK_BUFFERS_MARKED_CHECKED); + if (!Conf.useDiscordSystem) return; + String channelId = context.faction.getBufferNotifyChannelId(); + if (channelId == null || channelId.isEmpty()) { + return; + } + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(channelId); + if (textChannel == null) { + return; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, net.dv8tion.jda.core.Permission.MESSAGE_READ, net.dv8tion.jda.core.Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + return; + } + MessageEmbed embed = new EmbedBuilder().setColor(Color.MAGENTA).setTitle("Buffers checked by " + context.fPlayer.getNameAndTag()).setFooter(simpleDateFormat.format(new Date(currentTime)), null).build(); + textChannel.sendMessage(embed).queue(); } } else if (subCommand.equalsIgnoreCase("settings")) { if (!context.fPlayer.getRole().isAtLeast(Role.COLEADER)) { diff --git a/src/main/java/com/massivecraft/factions/cmd/check/CmdWeeWoo.java b/src/main/java/com/massivecraft/factions/cmd/check/CmdWeeWoo.java index f52c6c2a..1041ca19 100644 --- a/src/main/java/com/massivecraft/factions/cmd/check/CmdWeeWoo.java +++ b/src/main/java/com/massivecraft/factions/cmd/check/CmdWeeWoo.java @@ -1,10 +1,14 @@ package com.massivecraft.factions.cmd.check; +import com.massivecraft.factions.Conf; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.discord.FactionChatHandler; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.zcore.util.TL; +import net.dv8tion.jda.core.entities.Channel; +import net.dv8tion.jda.core.entities.TextChannel; public class CmdWeeWoo extends FCommand { public CmdWeeWoo() { @@ -30,7 +34,19 @@ public class CmdWeeWoo extends FCommand { } context.faction.setWeeWoo(true); context.msg(TL.COMMAND_WEEWOO_STARTED, context.fPlayer.getNameAndTag()); - + if (!Conf.useDiscordSystem) return; + String discordChannelId = context.faction.getWeeWooChannelId(); + if (discordChannelId != null && !discordChannelId.isEmpty()) { + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(discordChannelId); + if (textChannel == null) { + return; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, net.dv8tion.jda.core.Permission.MESSAGE_READ, net.dv8tion.jda.core.Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + return; + } + textChannel.sendMessage(TL.WEEWOO_STARTED_DISCORD.format(context.fPlayer.getNameAndTag())).queue(); + } } else if (argument.equalsIgnoreCase("stop")) { if (!weewoo) { context.msg(TL.COMMAND_WEEWOO_ALREADY_STOPPED); @@ -38,6 +54,19 @@ public class CmdWeeWoo extends FCommand { } context.faction.setWeeWoo(false); context.msg(TL.COMMAND_WEEWOO_STOPPED, context.fPlayer.getNameAndTag()); + if(!Conf.useDiscordSystem) return; + String discordChannelId = context.faction.getWeeWooChannelId(); + if (discordChannelId != null && !discordChannelId.isEmpty()) { + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(discordChannelId); + if (textChannel == null) { + return; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, net.dv8tion.jda.core.Permission.MESSAGE_READ, net.dv8tion.jda.core.Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + return; + } + textChannel.sendMessage(TL.WEEWOO_STOPPED_DISCORD.format(context.fPlayer.getNameAndTag())).queue(); + } } else { context.msg("/f weewoo "); } diff --git a/src/main/java/com/massivecraft/factions/cmd/check/WeeWooTask.java b/src/main/java/com/massivecraft/factions/cmd/check/WeeWooTask.java index ffce2553..168b953f 100644 --- a/src/main/java/com/massivecraft/factions/cmd/check/WeeWooTask.java +++ b/src/main/java/com/massivecraft/factions/cmd/check/WeeWooTask.java @@ -3,7 +3,11 @@ package com.massivecraft.factions.cmd.check; import com.massivecraft.factions.Faction; import com.massivecraft.factions.Factions; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.discord.FactionChatHandler; import com.massivecraft.factions.zcore.util.TL; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.TextChannel; public class WeeWooTask implements Runnable { @@ -20,6 +24,26 @@ public class WeeWooTask implements Runnable { continue; } faction.msg(TL.WEE_WOO_MESSAGE); + if (!FactionChatHandler.jda.getStatus().equals(JDA.Status.CONNECTED)) { + continue; + } + String discordChannelId = faction.getWeeWooChannelId(); + if (discordChannelId == null || discordChannelId.isEmpty()) { + continue; + } + TextChannel textChannel = FactionChatHandler.jda.getTextChannelById(discordChannelId); + if (textChannel == null) { + continue; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + textChannel.getGuild().getOwner().getUser().openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage((":x: Missing read/write in " + textChannel.getAsMention())).queue()); + } else { + String format = faction.getWeeWooFormat(); + if (format == null || format.isEmpty()) { + format = "@everyone, we're being raided! Get online!"; + } + textChannel.sendMessage(format).queue(); + } } } } diff --git a/src/main/java/com/massivecraft/factions/discord/CmdInviteBot.java b/src/main/java/com/massivecraft/factions/discord/CmdInviteBot.java new file mode 100644 index 00000000..63c34ddc --- /dev/null +++ b/src/main/java/com/massivecraft/factions/discord/CmdInviteBot.java @@ -0,0 +1,32 @@ +package com.massivecraft.factions.discord; + +import com.massivecraft.factions.cmd.CommandContext; +import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.zcore.util.TL; +import mkremins.fanciful.FancyMessage; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.Permission; +import org.bukkit.ChatColor; + +public class CmdInviteBot extends FCommand { + + public CmdInviteBot(){ + super(); + this.aliases.add("invitebot"); + } + + @Override + public void perform(CommandContext context) { + JDA jda = FactionChatHandler.jda; + FancyMessage fancyMessage = new FancyMessage(); + fancyMessage.link(jda.asBot().getInviteUrl(Permission.MESSAGE_READ, Permission.MESSAGE_WRITE, Permission.MESSAGE_HISTORY, Permission.MESSAGE_ADD_REACTION, Permission.MESSAGE_EMBED_LINKS)); + fancyMessage.text("Click here to invite the bot"); + fancyMessage.color(ChatColor.BLUE); + fancyMessage.send(context.fPlayer.getPlayer()); + } + + @Override + public TL getUsageTranslation() { + return TL.INVITE_BOT_USAGE; + } +} diff --git a/src/main/java/com/massivecraft/factions/discord/CmdSetGuild.java b/src/main/java/com/massivecraft/factions/discord/CmdSetGuild.java new file mode 100644 index 00000000..c8ed2bc1 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/discord/CmdSetGuild.java @@ -0,0 +1,96 @@ +package com.massivecraft.factions.discord; + +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.Factions; +import com.massivecraft.factions.cmd.CommandContext; +import com.massivecraft.factions.cmd.CommandRequirements; +import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.zcore.util.TL; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.events.message.priv.react.PrivateMessageReactionAddEvent; +import org.bukkit.ChatColor; + +import java.util.concurrent.TimeUnit; + +public class CmdSetGuild extends FCommand { + private EventWaiter eventWaiter; + private boolean waiterAdded; + + public CmdSetGuild() { + super(); + this.eventWaiter = new EventWaiter(); + this.waiterAdded = false; + this.aliases.add("setguild"); + this.optionalArgs.put("id", "none"); + this.optionalArgs.put("faction", "you"); + + this.requirements = new CommandRequirements.Builder(Permission.SET_GUILD) + .playerOnly() + .memberOnly() + .build(); + } + + @Override + public void perform(CommandContext context) { + String guildId = context.argAsString(0, null); + Faction faction = context.argAsFaction(1, context.faction); + JDA jda = FactionChatHandler.jda; + if (jda != null) { + if (!this.waiterAdded) { + jda.addEventListener(new EventWaiter[]{this.eventWaiter}); + this.waiterAdded = true; + } + + if (guildId != null && !guildId.equalsIgnoreCase("null")) { + Guild guild = null; + + try { + guild = jda.getGuildById(guildId); + } catch (NumberFormatException var7) { + } + + if (guild == null) { + context.msg(TL.SET_GUILD_ID_INVALID_ID); + } else if (Factions.getInstance().getAllFactions().stream().anyMatch((f) -> guildId.equals(f.getGuildId()))) { + context.msg(TL.SET_GUILD_ID_GUILD_ALREADY_LINKED); + } else { + context.msg(TL.SET_GUILD_ID_PMING_OWNER); + User user = guild.getOwner().getUser(); + Guild finalGuild = guild; + Guild finalGuild1 = guild; + user.openPrivateChannel().queue((privateChannel) -> privateChannel.sendMessage("Link guild **" + finalGuild1.getName() + "** to faction **" + ChatColor.stripColor(faction.getTag()) + "**?").queue((message) -> { + String checkMark = "✅"; + message.addReaction(checkMark).queue(); + this.eventWaiter.waitForEvent(PrivateMessageReactionAddEvent.class, (event) -> event.getReactionEmote().getName().equals(checkMark) && event.getUser().getId().equals(user.getId()) && event.getMessageId().equals(message.getId()), (event) -> { + faction.setGuildId(context.argAsString(0)); + context.msg(TL.SET_GUILD_ID_SUCCESS); + privateChannel.sendMessage("Successfully linked **" + finalGuild.getName() + " & " + ChatColor.stripColor(faction.getTag()) + "**").queue(); + }, 15L, TimeUnit.SECONDS, () -> { + privateChannel.sendMessage(TL.SET_GUILD_ID_TIMED_OUT_DISCORD.toString()).queue(); + context.msg(TL.SET_GUILD_ID_TIMED_OUT_MINECRAFT); + }); + }, (t) -> { + context.msg(TL.SET_GUILD_ID_UNABLE_TO_MESSAGE_GUILD_OWNER); + }), (t) -> context.msg(TL.SET_GUILD_ID_UNABLE_TO_MESSAGE_GUILD_OWNER)); + } + } else { + faction.setGuildId(null); + faction.setWeeWooChannelId(null); + faction.setBufferNotifyChannelId(null); + faction.setWallNotifyChannelId(null); + faction.setFactionChatChannelId(null); + context.msg(TL.SET_GUILD_ID_RESET_ID); + } + } + } + + @Override + public TL getUsageTranslation() { + return TL.SET_GUILD_ID_USAGE; + } + +} diff --git a/src/main/java/com/massivecraft/factions/discord/DiscordListener.java b/src/main/java/com/massivecraft/factions/discord/DiscordListener.java new file mode 100644 index 00000000..28f44546 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/discord/DiscordListener.java @@ -0,0 +1,526 @@ +package com.massivecraft.factions.discord; + +import com.massivecraft.factions.*; +import com.massivecraft.factions.discord.json.JSONGuilds; +import com.massivecraft.factions.zcore.util.TL; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.*; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.core.exceptions.PermissionException; +import net.dv8tion.jda.core.hooks.ListenerAdapter; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; + +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.FileAttribute; +import java.text.DecimalFormat; +import java.util.List; +import java.util.*; +import java.util.stream.Collectors; + +public class DiscordListener extends ListenerAdapter { + private static File file = new File(FactionsPlugin.getInstance().getDataFolder(), "discord_guilds.json"); + public static JSONGuilds guilds = loadGuilds(); + private final DecimalFormat decimalFormat; + private FactionsPlugin plugin; + + public DiscordListener(FactionsPlugin plugin) { + this.decimalFormat = new DecimalFormat("$#,###.##"); + this.plugin = plugin; + int minute = 3600; + plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, DiscordListener::saveGuilds, (long) (minute * 15), (long) (minute * 15)); + } + + private static JSONGuilds loadGuilds() { + try { + if (!DiscordListener.file.exists()) { + Files.createFile(DiscordListener.file.toPath(), (FileAttribute[]) new FileAttribute[0]); + Files.write(DiscordListener.file.toPath(), "{}".getBytes()); + } + return FactionsPlugin.getInstance().gson.fromJson(String.join("\n", Files.readAllLines(DiscordListener.file.toPath())), JSONGuilds.class); + } catch (IOException e) { + e.printStackTrace(); + throw new NullPointerException(); + } + } + + public static void saveGuilds() { + try { + String content = FactionsPlugin.getInstance().gson.toJson(DiscordListener.guilds); + Files.write(DiscordListener.file.toPath(), content.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + throw new NullPointerException(); + } + } + + public void onGuildMessageReceived(GuildMessageReceivedEvent event) { + try { + if (event.getMessage().isWebhookMessage() || event.getAuthor().isBot()) { + return; + } + String prefix = DiscordListener.guilds.getGuildById(event.getGuild().getId()).getPrefix(); + if (prefix == null || prefix.isEmpty()) { + prefix = "."; + } + String content = event.getMessage().getContentRaw(); + if (!content.startsWith(prefix) && !content.startsWith(event.getGuild().getSelfMember().getAsMention())) { + return; + } + if (content.startsWith(prefix + "help") || content.startsWith(event.getGuild().getSelfMember().getAsMention() + " help")) { + this.help(event, content, prefix); + } else if (content.startsWith(prefix + "stats")) { + this.stats(event, content, prefix); + } else if (content.startsWith(prefix + "fstats")) { + this.fstats(event, content, prefix); + } else if (content.startsWith(event.getGuild().getSelfMember().getAsMention() + " setprefix")) { + this.setPrefix(event, content); + } else if (content.startsWith(prefix + "setfchatchannel")) { + this.setFChatChannel(event); + } else if (content.startsWith(prefix + "setwallnotifychannel") || content.startsWith(prefix + "swnc")) { + this.setWallNotifyChannel(event); + } else if (content.startsWith(prefix + "setbuffernotifychannel") || content.startsWith(prefix + "sbnf")) { + this.setBufferNotifyChannel(event); + } else if (content.startsWith(prefix + "setweewoochannel")) { + this.setWeewooChannel(event); + } else if (content.startsWith(prefix + "setnotifyformat")) { + this.setNotifyFormat(event, content, prefix); + } else if (content.startsWith(prefix + "setweewooformat")) { + this.setWeewooFormat(event, content, prefix); + } else if (content.startsWith(prefix + "setmemberrole")) { + this.setMemberRole(event, content, prefix); + } else if (content.startsWith(prefix + "checkleaderboard") || content.startsWith(prefix + "cl")) { + this.checkLeaderboard(event); + } else if (content.startsWith(prefix + "weewoo")) { + this.weewoo(event, content, prefix); + } else if (content.startsWith(prefix + "settings")) { + this.settings(event); + } + } catch (PermissionException exception) { + if (!event.getGuild().getSelfMember().hasPermission(event.getChannel(), Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + return; + } + event.getChannel().sendMessage((":x: Missing permission, `" + exception.getPermission().toString() + "`")).queue(); + } + } + + private Faction getFaction(Guild guild) { + return Factions.getInstance().getAllFactions().stream().filter(faction -> guild.getId().equals(faction.getGuildId())).findAny().orElse(null); + } + + private Faction getFactionWithWarning(TextChannel textChannel) { + Faction faction = this.getFaction(textChannel.getGuild()); + if (faction == null) { + textChannel.sendMessage((":x: This guild isn't linked to a faction, use `/f setguild " + textChannel.getGuild().getId() + "` in game")).queue(); + } + return faction; + } + + private boolean cantAccessPermissionWithWarning(TextChannel textChannel, Member member) { + boolean can = member.hasPermission(Permission.MANAGE_SERVER); + if (!can) { + textChannel.sendMessage(":x: You need to have the Manage Server permission to do that").queue(); + } + return !can; + } + + private boolean canAccessRole(Faction faction, Member member) { + if (member.hasPermission(Permission.MANAGE_SERVER)) { + return true; + } + Role role = member.getGuild().getRoleById(faction.getMemberRoleId()); + return role != null && member.getRoles().stream().anyMatch(r -> r.getPosition() >= role.getPosition()); + } + + private boolean cantAccessRoleWithWarning(TextChannel textChannel, Faction faction, Member member) { + boolean can = this.canAccessRole(faction, member); + if (!can) { + textChannel.sendMessage(":x: You don't have a faction member role").queue(); + } + return !can; + } + + private void help(GuildMessageReceivedEvent event, String content, String prefix) { + if (content.contains("help ")) { + content = content.substring(content.indexOf("help") + 5).trim(); + EmbedBuilder embedBuilder = new EmbedBuilder().setColor(Color.MAGENTA); + if (content.equalsIgnoreCase("help")) { + embedBuilder.setTitle("Help | Help command").setDescription("Provides a list of commands & docs about commands").addField("Usage", "`" + prefix + "help [command]`", false); + } else if (content.equalsIgnoreCase("stats")) { + embedBuilder.setTitle("Help | Stats command").setDescription("Provides stats about the given player").addField("Usage", "`" + prefix + "stats `", false); + } else if (content.equalsIgnoreCase("fstats")) { + embedBuilder.setTitle("Help | Fstats command").setDescription("Provides stats about the give faction").addField("Usage", "`" + prefix + "fstats `", false); + } else if (content.equalsIgnoreCase("setprefix")) { + embedBuilder.setTitle("Help | Setprefix command").setDescription("Changes the bot's prefix for all commands in the current guild").addField("Usage", "`@" + event.getGuild().getSelfMember().getEffectiveName() + " setprefix `", false); + } else if (content.equalsIgnoreCase("setfchatchannel")) { + embedBuilder.setTitle("Help | Setfchatchannel").setDescription("Sets or removes the channel for Faction chat \"mirroring\", where messages sent in in-game faction chat are sent in the channel & messages sent in the channel are sent to in-game faction chat").addField("Usage", "`" + prefix + "setfchatchannel [#channel]`", false); + } else if (content.equalsIgnoreCase("setwallnotifychannel")) { + embedBuilder.setTitle("Help | Setwallnotifychanel").setDescription("Sets or removes the wall check notification channel").addField("Usage", "`" + prefix + "setwallnotifychannel [#channel]`", false); + } else if (content.equalsIgnoreCase("setbuffernotifychannel")) { + embedBuilder.setTitle("Help | Setbuffernotifychannel").setDescription("Sets or removes the buffer check notification channel").addField("Usage", "`" + prefix + "setbuffernotifychannel [#channel]`", false); + } else if (content.equalsIgnoreCase("setweewoochannel")) { + embedBuilder.setTitle("Help | Setweewoochannel").setDescription("Sets or removes the weewoo (raid alert) channel").addField("Usage", "`" + prefix + "setweewoochannel [#channel>`", false); + } else if (content.equalsIgnoreCase("setnotifyformat")) { + embedBuilder.setTitle("Help | Setnotifyformat").setDescription("Sets the wall & buffer notification format, where `%type%` will be replaced with `walls` or `buffers`").addField("Usage", "`" + prefix + "setnotifyformat `", false).addField("Default", "`@everyone, check %type%`", false); + } else if (content.equalsIgnoreCase("setweewooformat")) { + embedBuilder.setTitle("Help | Setweewooformat").setDescription("Sets the weewoo (raid alert) format").addField("Usage", "`" + prefix + "setweewooformat `", false).addField("Default", "`@everyone, we're being raided! Get online!`", false); + } else if (content.equalsIgnoreCase("setmemberrole")) { + embedBuilder.setTitle("Help | Setmemberrole").setDescription("Sets the __lowest__ member role, where the specified role & any roles above it will be counted as members").addField("Usage", "`" + prefix + "setmemberrole <@role/role name/role id>`", false); + } else if (content.equalsIgnoreCase("checkleaderboard")) { + embedBuilder.setTitle("Help | Checkleaderboard").setDescription("Gets the leaderboard for wall & buffer checks").addField("Usage", "`" + prefix + "checkleaderboard`", false); + } else if (content.equalsIgnoreCase("weewoo")) { + embedBuilder.setTitle("Help | Weewoo").setDescription("Starts/stops the weewoo (raid alert").addField("Usage", "`" + prefix + "weewoo `", false); + } else if (content.equalsIgnoreCase("settings")) { + embedBuilder.setTitle("Help | Settings").setDescription("Gets the current settings").addField("Usage", "`" + prefix + "settings`", false); + } else { + embedBuilder.setColor(Color.RED).setTitle("Command not found"); + } + event.getChannel().sendMessage(embedBuilder.build()).queue(); + } else { + event.getChannel().sendMessage(("`" + prefix + "help [command]` This list or documentation of a command\n" + + prefix + "stats ` Get stats for a player\n`" + + prefix + "fstats ` Get stats for a faction`\n__Requires Manage Server permission__\n@" + event.getGuild().getSelfMember().getEffectiveName() + " setprefix ` Change the bot's prefix for this guild`\n" + + "\n**Requires a linked faction**\n__Requires Manage Server permission__\n`" + prefix + "setfchatchannel [#channel]` Set or reset the fchat channel\n`" + + prefix + "setwallnotifychannel [#channel]` Set or reset the wall check notification channel\n`" + prefix + "setbuffernotifychannel [#channel]` Set or reset the buffer check notification channel\n`" + + prefix + "setweewoochannel [#channel]` Set or reset the weewoo channel\n`" + prefix + "setnotifyformat ` Changes the notification format (`%type%` -> `walls/buffers`)\n`" + prefix + "setweewooformat ` Changes the weewoo format\n`" + + prefix + "setmemberrole <@role/role name/role id>` Changes the *lowest* member role\n__Member role only__\n`" + + prefix + "checkleaderboard` Wall & buffer check leaderboard\n`" + + prefix + "weewoo ` Starts/stops the weewoo\n`" + + prefix + "settings` Displays the current settings")).queue(); + } + } + + private void fstats(GuildMessageReceivedEvent event, String content, String prefix) { + if (!content.contains(" ")) { + event.getChannel().sendMessage((":x: Usage, `" + prefix + "fstats `")).queue(); + return; + } + String[] args = content.split(" "); + Faction faction = Factions.getInstance().getByTag(args[1]); + if (faction == null) { + event.getChannel().sendMessage(":x: Faction not found").queue(); + return; + } + EmbedBuilder embedBuilder = new EmbedBuilder().setColor(Color.MAGENTA).setTitle("Faction Stats").setAuthor(ChatColor.stripColor(faction.getTag())).addField("Description", faction.getDescription(), false).addField("Players Online", String.valueOf(faction.getOnlinePlayers().size()), true).addField("Total players", String.valueOf(faction.getFPlayers().size()), true).addField("Alts", String.valueOf(faction.getAltPlayers().size()), true).addField("Land", String.valueOf(faction.getLandRounded()), true).addField("Power", faction.getPowerRounded() + "/" + faction.getPowerMaxRounded(), true); + Faction guildFaction = this.getFaction(event.getGuild()); + if (guildFaction != null && guildFaction.getId().equals(faction.getId()) && this.canAccessRole(guildFaction, event.getMember())) { + embedBuilder.addField("Kills", String.valueOf(faction.getKills()), true).addField("Deaths", String.valueOf(faction.getDeaths()), true); + } + event.getChannel().sendMessage(embedBuilder.build()).queue(); + } + + private void stats(GuildMessageReceivedEvent event, String content, String prefix) { + if (!content.contains(" ")) { + event.getChannel().sendMessage((":x: Usage, `" + prefix + "stats `")).queue(); + return; + } + String[] args = content.split(" "); + OfflinePlayer offlinePlayer = this.plugin.getServer().getOfflinePlayer(args[1]); + FPlayer fPlayer = FPlayers.getInstance().getByOfflinePlayer(offlinePlayer); + String role = fPlayer.getRole().toString(); + role = role.substring(0, 1).toUpperCase() + role.substring(1).toLowerCase(); + EmbedBuilder embedBuilder = new EmbedBuilder().setColor(Color.MAGENTA).setTitle("Player Stats").setAuthor(offlinePlayer.getName(), null, Conf.avatarUrl.replace("%uuid%", offlinePlayer.getUniqueId().toString())).addField("Balance", this.decimalFormat.format(this.plugin.getEcon().getBalance(offlinePlayer)), false).addField("Faction", ChatColor.stripColor(fPlayer.getFaction().getTag()), true).addField("Faction Role", role, true).addField("Power", fPlayer.getPower() + "/" + fPlayer.getPowerMax(), true).addField("Online", offlinePlayer.isOnline() ? "Yes" : "No", true); + Faction faction = this.getFaction(event.getGuild()); + if (faction != null && fPlayer.getFactionId().equals(faction.getId())) { + embedBuilder.addField("Wall checks", String.valueOf(faction.getPlayerWallCheckCount().getOrDefault(offlinePlayer.getUniqueId(), 0)), true).addField("Buffer checks", String.valueOf(faction.getPlayerBufferCheckCount().getOrDefault(offlinePlayer.getUniqueId(), 0)), true).addField("Kills", String.valueOf(fPlayer.getKills()), true).addField("Deaths", String.valueOf(fPlayer.getDeaths()), true); + } + event.getChannel().sendMessage(embedBuilder.build()).queue(); + } + + private void setPrefix(GuildMessageReceivedEvent event, String content) { + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + String[] split = content.split(" "); + if (split.length != 3) { + event.getChannel().sendMessage((":x: Usage, `@" + event.getGuild().getSelfMember().getEffectiveName() + " setprefix `")).queue(); + return; + } + String newPrefix = split[2]; + if (newPrefix.length() > 16) { + event.getChannel().sendMessage(":x: Prefix may not be longer than 16 characters").queue(); + return; + } + DiscordListener.guilds.getGuildById(event.getGuild().getId()).setPrefix(newPrefix); + event.getMessage().addReaction("\u2705").queue(); + } + + + private void setFChatChannel(GuildMessageReceivedEvent event) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + List mentionedChannels = event.getMessage().getMentionedChannels(); + if (mentionedChannels.isEmpty()) { + faction.setFactionChatChannelId(null); + event.getChannel().sendMessage("Cleared fchat channel").queue(); + } else { + TextChannel textChannel = mentionedChannels.get(0); + if (!event.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + event.getChannel().sendMessage((":x: Missing read/write permission in " + textChannel.getAsMention())).queue(); + return; + } + faction.setFactionChatChannelId(textChannel.getId()); + event.getChannel().sendMessage(("New fchat channel set to " + textChannel.getAsMention())).queue(); + } + } + + private void setWallNotifyChannel(GuildMessageReceivedEvent event) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + List mentionedChannels = event.getMessage().getMentionedChannels(); + if (mentionedChannels.isEmpty()) { + faction.setWallNotifyChannelId(null); + event.getChannel().sendMessage("Cleared wall notify channel").queue(); + } else { + TextChannel textChannel = mentionedChannels.get(0); + if (!event.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + event.getChannel().sendMessage((":x: Missing read/write permission in " + textChannel.getAsMention())).queue(); + return; + } + faction.setWallNotifyChannelId(textChannel.getId()); + event.getChannel().sendMessage(("New wall notify channel set to " + textChannel.getAsMention())).queue(); + } + } + + private void setBufferNotifyChannel(GuildMessageReceivedEvent event) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + List mentionedChannels = event.getMessage().getMentionedChannels(); + if (mentionedChannels.isEmpty()) { + faction.setBufferNotifyChannelId(null); + event.getChannel().sendMessage("Cleared buffer notify channel").queue(); + } else { + TextChannel textChannel = mentionedChannels.get(0); + if (!event.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + event.getChannel().sendMessage((":x: Missing read/write permission in " + textChannel.getAsMention())).queue(); + return; + } + faction.setBufferNotifyChannelId(textChannel.getId()); + event.getChannel().sendMessage(("New buffer notify channel set to " + textChannel.getAsMention())).queue(); + } + } + + private void setWeewooChannel(GuildMessageReceivedEvent event) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (!event.getMember().hasPermission(Permission.MANAGE_SERVER)) { + event.getChannel().sendMessage(":x: You need to have the Manage Server permission to do that").queue(); + return; + } + List mentionedChannels = event.getMessage().getMentionedChannels(); + if (mentionedChannels.isEmpty()) { + faction.setWeeWooChannelId(null); + event.getChannel().sendMessage("Cleared weewoo channel").queue(); + } else { + TextChannel textChannel = mentionedChannels.get(0); + if (!event.getGuild().getSelfMember().hasPermission(textChannel, Permission.MESSAGE_READ, Permission.MESSAGE_WRITE)) { + event.getChannel().sendMessage((":x: Missing read/write permission in " + textChannel.getAsMention())).queue(); + return; + } + faction.setWeeWooChannelId(textChannel.getId()); + event.getChannel().sendMessage(("New weewoo channel set to " + textChannel.getAsMention())).queue(); + } + } + + private void setNotifyFormat(GuildMessageReceivedEvent event, String content, String prefix) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + if (!content.contains(" ")) { + event.getChannel().sendMessage((":x: Usage, `" + prefix + "setnotifyformat ` (%type%)")).queue(); + return; + } + List arguments = new ArrayList<>(Arrays.asList(content.split(" "))); + arguments.remove(0); + String format = String.join(" ", arguments); + if (format.length() > 1000) { + event.getChannel().sendMessage(":x: The notify format may not be longer than 1000 characters").queue(); + return; + } + faction.setNotifyFormat(format); + event.getChannel().sendMessage(("New notify format set to `" + format + "`")).queue(); + } + + private void setWeewooFormat(GuildMessageReceivedEvent event, String content, String prefix) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + if (!content.contains(" ")) { + event.getChannel().sendMessage((":x: Usage, `" + prefix + "setweewooformat `")).queue(); + return; + } + List arguments = new ArrayList<>(Arrays.asList(content.split(" "))); + arguments.remove(0); + String format = String.join(" ", arguments); + if (format.length() > 1000) { + event.getChannel().sendMessage(":x: The weewoo format may not be longer than 1000 characters").queue(); + return; + } + faction.setWeeWooFormat(format); + event.getChannel().sendMessage(("New weewoo format set to `" + format + "`")).queue(); + } + + private void setMemberRole(GuildMessageReceivedEvent event, String content, String prefix) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessPermissionWithWarning(event.getChannel(), event.getMember())) { + return; + } + List split = new ArrayList<>(Arrays.asList(content.split(" "))); + if (split.size() < 2) { + event.getChannel().sendMessage((":x: Usage, `" + prefix + "setmemberrole <@role/role name/role id>`")).queue(); + return; + } + split.remove(0); + Role role = event.getMessage().getMentionedRoles().stream().findFirst().orElse(null); + if (role == null) { + role = event.getGuild().getRolesByName(String.join(" ", split), true).stream().findAny().orElse(null); + } + if (role == null) { + try { + role = event.getGuild().getRoleById(split.get(0)); + } catch (NumberFormatException ex) { + } + } + if (role == null) { + event.getChannel().sendMessage(":x: Role not found").queue(); + return; + } + faction.setMemberRoleId(role.getId()); + event.getChannel().sendMessage(("New *lowest* member role set to `" + role.getName() + "`")).queue(); + } + + private void checkLeaderboard(GuildMessageReceivedEvent event) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessRoleWithWarning(event.getChannel(), faction, event.getMember())) { + return; + } + Map players = new HashMap<>(); + for (Map.Entry entry : faction.getPlayerWallCheckCount().entrySet()) { + players.put(entry.getKey(), entry.getValue()); + } + for (Map.Entry entry : faction.getPlayerBufferCheckCount().entrySet()) { + if (players.containsKey(entry.getKey())) { + players.replace(entry.getKey(), players.get(entry.getKey()) + entry.getValue()); + } else { + players.put(entry.getKey(), entry.getValue()); + } + } + List> entryList = players.entrySet().stream().sorted(Comparator.comparingInt(Map.Entry::getValue)).collect(Collectors.toList()); + EmbedBuilder embedBuilder = new EmbedBuilder().setTitle("Check Leaderboard").setColor(Color.MAGENTA); + StringBuilder stringBuilder = new StringBuilder(); + for (int max = (entryList.size() > 10) ? 10 : entryList.size(), current = 0; current < max; ++current) { + Map.Entry entry2 = entryList.get(current); + OfflinePlayer offlinePlayer = this.plugin.getServer().getOfflinePlayer(entry2.getKey()); + stringBuilder.append("**").append(current + 1).append(".** ").append(offlinePlayer.getName()).append(" __").append(entry2.getValue()).append(" Total (").append(faction.getPlayerBufferCheckCount().getOrDefault(entry2.getKey(), 0)).append(" Buffer, ").append(faction.getPlayerWallCheckCount().getOrDefault(entry2.getKey(), 0)).append(" Wall)__\n"); + } + if (entryList.isEmpty()) { + stringBuilder.append("_No data_"); + } + event.getChannel().sendMessage(embedBuilder.setDescription(stringBuilder.toString()).build()).queue(); + } + + private void weewoo(GuildMessageReceivedEvent event, String content, String prefix) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessRoleWithWarning(event.getChannel(), faction, event.getMember())) { + return; + } + if (!content.contains(" ")) { + event.getChannel().sendMessage((":x: Usage, `" + prefix + "weewoo `")).queue(); + return; + } + List arguments = new ArrayList<>(Arrays.asList(content.split(" "))); + boolean weeWoo = faction.isWeeWoo(); + if (arguments.get(1).equalsIgnoreCase("start")) { + if (weeWoo) { + event.getChannel().sendMessage(TL.WEEWOO_ALREADY_STARTED_DISCORD.toString()).queue(); + return; + } + faction.setWeeWoo(true); + event.getMessage().addReaction("\u2705").queue(); + faction.msg(TL.COMMAND_WEEWOO_STARTED, event.getAuthor().getAsTag()); + String discordChannelId = faction.getWeeWooChannelId(); + if (discordChannelId != null && !discordChannelId.isEmpty()) { + TextChannel textChannel = event.getJDA().getTextChannelById(discordChannelId); + if (textChannel == null) { + return; + } + textChannel.sendMessage(TL.WEEWOO_STARTED_DISCORD.format(event.getAuthor().getAsTag())).queue(); + } + } else if (arguments.get(1).equalsIgnoreCase("stop")) { + if (!weeWoo) { + event.getChannel().sendMessage(TL.WEEWOO_ALREADY_STOPPED_DISCORD.toString()).queue(); + return; + } + faction.setWeeWoo(false); + event.getMessage().addReaction("\u2705").queue(); + faction.msg(TL.COMMAND_WEEWOO_STARTED, event.getAuthor().getAsTag()); + String discordChannelId = faction.getWeeWooChannelId(); + if (discordChannelId != null && !discordChannelId.isEmpty()) { + TextChannel textChannel = event.getJDA().getTextChannelById(discordChannelId); + if (textChannel == null) { + return; + } + textChannel.sendMessage(TL.WEEWOO_STOPPED_DISCORD.format(event.getAuthor().getAsTag())).queue(); + } + } else { + event.getChannel().sendMessage(":x: Usage, `.weewoo `").queue(); + } + } + + private void settings(GuildMessageReceivedEvent event) { + Faction faction = this.getFactionWithWarning(event.getChannel()); + if (faction == null) { + return; + } + if (this.cantAccessRoleWithWarning(event.getChannel(), faction, event.getMember())) { + return; + } + int wallCheck = faction.getWallCheckMinutes(); + int bufferCheck = faction.getBufferCheckMinutes(); + String wallChannel = faction.getWallNotifyChannelId(); + String bufferChannel = faction.getBufferNotifyChannelId(); + String weeWooChannel = faction.getWeeWooChannelId(); + String fChatChannel = faction.getFactionChatChannelId(); + MessageEmbed embed = new EmbedBuilder().setTitle("Settings").setColor(Color.MAGENTA).addField("WeeWoo channel", (weeWooChannel != null && !weeWooChannel.isEmpty()) ? ("<#" + weeWooChannel + ">") : "None", true).addField("Wall check channel", (wallChannel != null && !wallChannel.isEmpty()) ? ("<#" + wallChannel + ">") : "None", true).addField("Buffer check channel", (bufferChannel != null && !bufferChannel.isEmpty()) ? ("<#" + bufferChannel + ">") : "None", true).addField("Faction Chat channel", (fChatChannel != null && !fChatChannel.isEmpty()) ? ("<#" + fChatChannel + ">") : "None", true).addField("Wall check notifications", (wallCheck <= 0) ? "Offline" : (wallCheck + " Minutes"), true).addField("Buffer check notifications", (bufferCheck <= 0) ? "Offline" : (bufferCheck + " Minutes"), true).addField("Notify format", "`" + faction.getNotifyFormat() + "`", false).addField("WeeWoo format", "`" + faction.getWeeWooFormat() + "`", false).build(); + event.getChannel().sendMessage(embed).queue(); + } +} + diff --git a/src/main/java/com/massivecraft/factions/discord/FactionChatHandler.java b/src/main/java/com/massivecraft/factions/discord/FactionChatHandler.java new file mode 100644 index 00000000..d799a0aa --- /dev/null +++ b/src/main/java/com/massivecraft/factions/discord/FactionChatHandler.java @@ -0,0 +1,95 @@ +package com.massivecraft.factions.discord; + +import com.massivecraft.factions.Conf; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.Factions; +import com.massivecraft.factions.FactionsPlugin; +import mkremins.fanciful.FancyMessage; +import net.dv8tion.jda.core.AccountType; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.JDABuilder; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.entities.Webhook; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.core.hooks.ListenerAdapter; +import net.dv8tion.jda.webhook.WebhookClient; +import net.dv8tion.jda.webhook.WebhookMessage; +import net.dv8tion.jda.webhook.WebhookMessageBuilder; +import org.bukkit.ChatColor; + +import javax.security.auth.login.LoginException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class FactionChatHandler extends ListenerAdapter { + public static JDA jda; + private FactionsPlugin plugin; + + public FactionChatHandler(FactionsPlugin plugin) { + this.plugin = plugin; + startBot(); + jda.addEventListener(this); + jda.addEventListener(new DiscordListener(plugin)); + } + + private void startBot() { + try { + jda = new JDABuilder(AccountType.BOT).setToken(Conf.discordBotToken).buildBlocking(); + } catch (LoginException | InterruptedException e) { + e.printStackTrace(); + } + } + + public static void sendMessage(FactionsPlugin plugin, Faction faction, UUID uuid, String username, String message) { + String factionsChatChannelId = faction.getFactionChatChannelId(); + if (factionsChatChannelId == null || factionsChatChannelId.isEmpty()) { + return; + } + if (jda == null) { + return; + } + TextChannel textChannel = jda.getTextChannelById(factionsChatChannelId); + if (textChannel == null) { + return; + } + if (!textChannel.getGuild().getSelfMember().hasPermission(textChannel, Permission.MANAGE_WEBHOOKS)) { + textChannel.sendMessage("Missing `Manage Webhooks` permission in this channel").queue(); + return; + } + Webhook webhook = (textChannel.getWebhooks().complete()).stream().filter(w -> w.getName().equals(Conf.webhookName)).findAny().orElse(null); + WebhookClient webhookClient; + if (webhook != null) { + webhookClient = webhook.newClient().build(); + } else { + webhookClient = textChannel.createWebhook(Conf.webhookName).complete().newClient().build(); + } + WebhookMessage webhookMessage = new WebhookMessageBuilder().setUsername(ChatColor.stripColor(username)).setAvatarUrl(Conf.avatarUrl.replace("%uuid%", uuid.toString())).setContent(ChatColor.stripColor(message)).build(); + webhookClient.send(webhookMessage).join(); + webhookClient.close(); + } + + @Override + public void onGuildMessageReceived(GuildMessageReceivedEvent event) { + if (event.isWebhookMessage() || event.getAuthor().isBot()) { + return; + } + Faction faction = Factions.getInstance().getAllFactions().stream().filter(f -> event.getChannel().getId().equals(f.getFactionChatChannelId())).findAny().orElse(null); + if (faction == null) { + return; + } + String content = event.getMessage().getContentDisplay(); + String message = (content.length() > 500) ? content.substring(0, 500) : content; + FancyMessage fancyMessage = new FancyMessage(); + fancyMessage.text(ChatColor.translateAlternateColorCodes('&', Conf.fromDiscordFactionChatPrefix + String.format(Conf.factionChatFormat, event.getAuthor().getAsTag(), message))); + List messages = new ArrayList<>(); + messages.add(fancyMessage); + for (Message.Attachment attachment : event.getMessage().getAttachments()) { + messages.add(new FancyMessage().text(" [Attachment]").color(ChatColor.AQUA).link(attachment.getUrl()).tooltip(attachment.getFileName())); + } + plugin.getServer().getScheduler().runTask(plugin, () -> messages.forEach(msg -> faction.getOnlinePlayers().forEach(fancyMessage::send))); + } +} + diff --git a/src/main/java/com/massivecraft/factions/discord/json/JSONGuild.java b/src/main/java/com/massivecraft/factions/discord/json/JSONGuild.java new file mode 100644 index 00000000..65561646 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/discord/json/JSONGuild.java @@ -0,0 +1,18 @@ +package com.massivecraft.factions.discord.json; + +public class JSONGuild { + private String prefix; + + public JSONGuild() { + this.prefix = null; + } + + + public String getPrefix() { + return this.prefix; + } + + public void setPrefix(final String prefix) { + this.prefix = prefix; + } +} diff --git a/src/main/java/com/massivecraft/factions/discord/json/JSONGuilds.java b/src/main/java/com/massivecraft/factions/discord/json/JSONGuilds.java new file mode 100644 index 00000000..9a4048e7 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/discord/json/JSONGuilds.java @@ -0,0 +1,26 @@ +package com.massivecraft.factions.discord.json; + + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class JSONGuilds { + private Map guilds; + + public JSONGuilds() { + this.guilds = new ConcurrentHashMap<>(); + } + + public JSONGuild getGuildById(String id) { + JSONGuild[] newGuild = new JSONGuild[1]; + return guilds.computeIfAbsent(id, i -> { + newGuild[0] = new JSONGuild(); + guilds.put(i, newGuild[0]); + return newGuild[0]; + }); + } + + public Map getAllGuilds() { + return this.guilds; + } +} diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsChatListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsChatListener.java index 4b8227cb..da9f52d5 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsChatListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsChatListener.java @@ -1,6 +1,7 @@ package com.massivecraft.factions.listeners; import com.massivecraft.factions.*; +import com.massivecraft.factions.discord.FactionChatHandler; import com.massivecraft.factions.struct.ChatMode; import com.massivecraft.factions.struct.Relation; import com.massivecraft.factions.struct.Role; @@ -82,7 +83,7 @@ public class FactionsChatListener implements Listener { fplayer.sendMessage("[FCspy] " + myFaction.getTag() + ": " + message); } } - + FactionChatHandler.sendMessage(FactionsPlugin.getInstance(), myFaction, me.getPlayer().getUniqueId(), me.getPlayer().getName(), event.getMessage()); event.setCancelled(true); } else if (chat == ChatMode.ALLIANCE) { Faction myFaction = me.getFaction(); diff --git a/src/main/java/com/massivecraft/factions/struct/Permission.java b/src/main/java/com/massivecraft/factions/struct/Permission.java index cbd8dbd9..7a08c686 100755 --- a/src/main/java/com/massivecraft/factions/struct/Permission.java +++ b/src/main/java/com/massivecraft/factions/struct/Permission.java @@ -75,6 +75,7 @@ public enum Permission { OPEN("open"), OWNER("owner"), OWNERLIST("ownerlist"), + SET_GUILD("setguild"), SET_PEACEFUL("setpeaceful"), SET_PERMANENT("setpermanent"), SET_PERMANENTPOWER("setpermanentpower"), diff --git a/src/main/java/com/massivecraft/factions/zcore/fupgrades/UpgradesListener.java b/src/main/java/com/massivecraft/factions/zcore/fupgrades/UpgradesListener.java index f5243e16..078cc1f9 100644 --- a/src/main/java/com/massivecraft/factions/zcore/fupgrades/UpgradesListener.java +++ b/src/main/java/com/massivecraft/factions/zcore/fupgrades/UpgradesListener.java @@ -165,7 +165,9 @@ public class UpgradesListener implements Listener { return; } - FLocation floc = new FLocation((Player) fme.getPlayer().getLocation()); + FLocation floc = new FLocation(fme.getPlayer().getLocation()); + + if(floc == null) return; if (Board.getInstance().getFactionAt(floc) == fme.getFaction()) { if (dame.getFaction() == fme.getFaction()) { diff --git a/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFaction.java b/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFaction.java index 7ec03c95..1a0e23dd 100644 --- a/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFaction.java +++ b/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFaction.java @@ -85,6 +85,14 @@ public abstract class MemoryFaction implements Faction, EconomyParticipator { private double reinforcedArmor; private List completedMissions; protected String discord; + private String factionChatChannelId; + private String wallNotifyChannelId; + private String bufferNotifyChannelId; + private String weeWooChannelId; + private String notifyFormat; + private String weeWooFormat; + private String guildId; + private String memberRoleId; // -------------------------------------------- // @@ -115,6 +123,11 @@ public abstract class MemoryFaction implements Faction, EconomyParticipator { this.playerWallCheckCount = new ConcurrentHashMap<>(); this.playerBufferCheckCount = new ConcurrentHashMap<>(); this.completedMissions = new ArrayList<>(); + this.wallNotifyChannelId = null; + this.bufferNotifyChannelId = null; + this.notifyFormat = "@everyone, check %type%"; + this.weeWooFormat = "@everyone, we're being raided! Get online!"; + this.memberRoleId = null; resetPerms(); // Reset on new Faction so it has default values. } @@ -545,6 +558,86 @@ public abstract class MemoryFaction implements Faction, EconomyParticipator { return this.playerWallCheckCount; } + @Override + public String getGuildId() { + return this.guildId; + } + + @Override + public void setGuildId(final String guildId) { + this.guildId = guildId; + } + + @Override + public String getMemberRoleId() { + return this.memberRoleId; + } + + @Override + public String getFactionChatChannelId() { + return this.factionChatChannelId; + } + + @Override + public String getWallNotifyChannelId() { + return this.wallNotifyChannelId; + } + + @Override + public void setWallNotifyChannelId(final String wallNotifyChannelId) { + this.wallNotifyChannelId = wallNotifyChannelId; + } + + @Override + public String getBufferNotifyChannelId() { + return this.bufferNotifyChannelId; + } + + @Override + public void setBufferNotifyChannelId(final String bufferNotifyChannelId) { + this.bufferNotifyChannelId = bufferNotifyChannelId; + } + + @Override + public String getWeeWooChannelId() { + return this.weeWooChannelId; + } + + @Override + public void setWeeWooChannelId(final String weeWooChannelId) { + this.weeWooChannelId = weeWooChannelId; + } + + @Override + public String getNotifyFormat() { + return this.notifyFormat; + } + + @Override + public void setNotifyFormat(final String notifyFormat) { + this.notifyFormat = notifyFormat; + } + + @Override + public String getWeeWooFormat() { + return this.weeWooFormat; + } + + @Override + public void setWeeWooFormat(final String weeWooFormat) { + this.weeWooFormat = weeWooFormat; + } + + @Override + public void setFactionChatChannelId(final String factionChatChannelId) { + this.factionChatChannelId = factionChatChannelId; + } + + @Override + public void setMemberRoleId(final String memberRoleId) { + this.memberRoleId = memberRoleId; + } + public boolean isWeeWoo() { return this.weeWoo; } diff --git a/src/main/java/com/massivecraft/factions/zcore/util/TL.java b/src/main/java/com/massivecraft/factions/zcore/util/TL.java index b0df2168..162fbdcc 100644 --- a/src/main/java/com/massivecraft/factions/zcore/util/TL.java +++ b/src/main/java/com/massivecraft/factions/zcore/util/TL.java @@ -319,6 +319,25 @@ public enum TL { CHECK_LEADERBOARD_LINE("&f%1$s. &d%2$s: &f%3$s (%4$s Buffer, %5$s Walls)"), CHECK_LEADERBOARD_NO_DATA("&8No data"), + //DISCORD + WEEWOO_ALREADY_STARTED_DISCORD("Weewoo already started"), + WEEWOO_ALREADY_STARTED_INGAME("&cWeewoo already started"), + WEEWOO_STARTED_DISCORD("Weewoo started by %1$s"), + WEEWOO_ALREADY_STOPPED_DISCORD("Weewoo already stopped"), + WEEWOO_STOPPED_DISCORD("Weewoo stopped by %1$s"), + INVITE_BOT_USAGE("Gets the invite for the Discord bot"), + SET_GUILD_ID_USAGE("Sets the guild id for the faction"), + SET_GUILD_ID_SUCCESS("&aSuccesfully set guild id"), + SET_GUILD_ID_INVALID_ID("&cInvalid guild id (is the bot in the guild?)"), + SET_GUILD_ID_UNABLE_TO_MESSAGE_GUILD_OWNER("&cUnable to message guild owner"), + SET_GUILD_ID_TIMED_OUT_MINECRAFT("&cTimed out"), + SET_GUILD_ID_TIMED_OUT_DISCORD("Timed out"), + SET_GUILD_ID_GUILD_ALREADY_LINKED("&cThat guild is already linked to a faction"), + SET_GUILD_ID_RESET_ID("&cGuild id removed"), + SET_GUILD_ID_PMING_OWNER("&aNow Direct messaging the Discord server owner to approve the link, times out in 15 seconds."), + CANT_FORCE_SET_GUILD_ID("&cYou cannot forcefully set guild ids for other guilds."), + + COMMAND_DEINVITE_CANDEINVITE("&c&l[!]&7 Players you can &cdeinvite: "), COMMAND_DEINVITE_CLICKTODEINVITE("&c&l[!]&7 Click to &crevoke&7 invite for &c%1$s"), COMMAND_DEINVITE_ALREADYMEMBER("&c&l[!]&7 &c%1$s&7 is already a member of &c%2$s"),