diff --git a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java index a4b8fda..d0efe1e 100644 --- a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java @@ -45,6 +45,7 @@ public class AnnouncerModule extends Component { @Override protected void enable() { + if (DPUtils.disableIfConfigError(this, channel(), modChannel())) return; stop = false; //If not the first time DPUtils.performNoWait(() -> { try { diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index fba8a7b..48d5963 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -1,10 +1,13 @@ package buttondevteam.discordplugin; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.IHaveConfig; import lombok.val; import org.bukkit.Bukkit; import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IGuild; import sx.blah.discord.handle.obj.IIDLinkedObject; import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.util.EmbedBuilder; @@ -114,10 +117,14 @@ public final class DPUtils { } public static ConfigData roleData(IHaveConfig config, String key, String defName) { + return roleData(config, key, defName, DiscordPlugin.mainServer); + } + + public static ConfigData roleData(IHaveConfig config, String key, String defName, IGuild guild) { return config.getDataPrimDef(key, defName, name -> { - val roles = DiscordPlugin.mainServer.getRolesByName((String) name); - return roles.size() > 0 ? roles.get(0) : null; //TODO: May not handle null properly - }, IIDLinkedObject::getLongID); //We can afford to search for the channel in the cache once (instead of using mainServer) + val roles = guild.getRolesByName((String) name); + return roles.size() > 0 ? roles.get(0) : null; + }, IIDLinkedObject::getLongID); } /** @@ -132,4 +139,32 @@ public final class DPUtils { return channel.mention(); } + /** + * Disables the component if one of the given configs return null. Useful for channel/role configs. + * + * @param component The component to disable if needed + * @param configs The configs to check for null + * @return Whether the component got disabled and a warning logged + */ + public static boolean disableIfConfigError(@Nullable Component component, ConfigData... configs) { + for (val config : configs) { + if (config.get() == null) { + String path = null; + try { + if (component != null) + Component.setComponentEnabled(component, false); + val f = ConfigData.class.getDeclaredField("path"); + f.setAccessible(true); //Hacking my own plugin + path = (String) f.get(config); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to disable component after config error!", e); + } + getLogger().warning("The config value " + path + " isn't set correctly " + (component == null ? "in global settings!" : "for component " + component.getClass().getSimpleName() + "!")); + getLogger().warning("Set the correct ID in the config" + (component == null ? "" : " or disable this component") + " to remove this message."); + return true; + } + } + return false; + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index fd5f2fa..498ba31 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -108,7 +108,6 @@ public class DiscordPlugin extends ButtonPlugin implements IListener } public static IGuild mainServer; - public static IGuild devServer; private static volatile BukkitTask task; private static volatile boolean sent = false; @@ -122,17 +121,22 @@ public class DiscordPlugin extends ButtonPlugin implements IListener tries.incrementAndGet(); if (tries.get() > 10) { //5 seconds task.cancel(); - getLogger().severe("Main or dev server not found! Set ID and do /discord reset"); + getLogger().severe("Main server not found! Invite the bot and do /discord reset"); + //getIConfig().getConfig().set("mainServer", 219529124321034241L); //Needed because it won't save as long as it's null - made it save + saveConfig(); //Put default there return; } - if (mainServer == null || devServer == null) { - mainServer = event.getClient().getGuildByID(125813020357165056L); - devServer = event.getClient().getGuildByID(219529124321034241L); - } - if (mainServer == null || devServer == null) - return; // Retry + mainServer = MainServer().get(); //Shouldn't change afterwards + if (mainServer == null) { + val guilds = dc.getGuilds(); + if (guilds.size() == 0) + return; //If there are no guilds in cache, retry + mainServer = guilds.get(0); + getLogger().warning("Main server set to first one: " + mainServer.getName()); + MainServer().set(mainServer); //Save in config + } if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() - dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Chromacraft"); + dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Minecraft"); } else { dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); } @@ -140,6 +144,8 @@ public class DiscordPlugin extends ButtonPlugin implements IListener if (task != null) task.cancel(); if (!sent) { + DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here + Component.registerComponent(this, new GeneralEventBroadcasterModule()); Component.registerComponent(this, new MinecraftChatModule()); Component.registerComponent(this, new ExceptionListenerModule()); @@ -242,7 +248,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); - mainServer = devServer = null; //Fetch servers and channels again + //Configs are emptied so channels and servers are fetched again sent = false; } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java index c2decdb..a0b8fda 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -11,6 +11,7 @@ public class Command2DC extends Command2 { @Override public boolean hasPermission(Command2DCSender sender, ICommand2DC command) { - return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); + //return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); //TODO: ModRole may be null; more customisable way? + return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index b868586..5d21bb1 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -12,6 +12,7 @@ import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IGuild; import sx.blah.discord.handle.obj.IRole; import java.util.ArrayList; @@ -43,15 +44,14 @@ public class ExceptionListenerModule extends Component implements e.setHandled(); } - private static IRole coderRole; - private static void SendException(Throwable e, String sourcemessage) { if (instance == null) return; try { - if (coderRole == null) - coderRole = DiscordPlugin.devServer.getRolesByName("Coder").get(0); + IChannel channel = getChannel(); + assert channel != null; + IRole coderRole = instance.pingRole(channel.getGuild()).get(); StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() - : new StringBuilder(coderRole.mention()).append("\n"); + : new StringBuilder(coderRole == null ? "" : coderRole.mention()).append("\n"); sb.append(sourcemessage).append("\n"); sb.append("```").append("\n"); String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")) @@ -61,7 +61,7 @@ public class ExceptionListenerModule extends Component implements stackTrace = stackTrace.substring(0, 1800); sb.append(stackTrace).append("\n"); sb.append("```"); - DiscordPlugin.sendMessageToChannel(getChannel(), sb.toString()); //Instance isn't null here + DiscordPlugin.sendMessageToChannel(channel, sb.toString()); //Instance isn't null here } catch (Exception ex) { ex.printStackTrace(); } @@ -78,8 +78,13 @@ public class ExceptionListenerModule extends Component implements return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } + private ConfigData pingRole(IGuild guild) { + return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild); + } + @Override protected void enable() { + if (DPUtils.disableIfConfigError(this, channel())) return; instance = this; Bukkit.getPluginManager().registerEvents(new ExceptionListenerModule(), getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new DebugMessageListener(), getPlugin()); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index d7fcc86..f5adf0d 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -13,10 +13,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IMessage; -import sx.blah.discord.handle.obj.IRole; -import sx.blah.discord.handle.obj.StatusType; +import sx.blah.discord.handle.obj.*; import sx.blah.discord.util.EmbedBuilder; import java.util.ArrayList; @@ -27,8 +24,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; public class FunModule extends Component implements Listener { - private static FunModule mod; - private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali "Between now and the heat-death of the universe.", // Ghostise "Soon™", "Ask again this time next month", // Ghostise @@ -68,7 +63,6 @@ public class FunModule extends Component implements Listener { @Override protected void enable() { - mod = this; registerListener(this); } @@ -99,7 +93,7 @@ public class FunModule extends Component implements Listener { return true; //Handled } lastlistp = (short) Bukkit.getOnlinePlayers().size(); //Didn't handle - if (mod.serverReady().get()) { + if (fm.serverReady().get()) { if (!TBMCCoreAPI.IsTestServer() && Arrays.stream(serverReadyQuestions).anyMatch(msglowercased::contains)) { int next; @@ -118,11 +112,8 @@ public class FunModule extends Component implements Listener { ListC = 0; } - private ConfigData fullHouseDevRole() { - return getConfig().getDataPrimDef("fullHouseDevRole", "Developer", name -> { - val list = DiscordPlugin.devServer.getRolesByName((String) name); - return list.size() > 0 ? list.get(0) : null; - }, IRole::getName); + private ConfigData fullHouseDevRole(IGuild guild) { + return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild); } @@ -135,17 +126,19 @@ public class FunModule extends Component implements Listener { public static void handleFullHouse(PresenceUpdateEvent event) { val fm = ComponentManager.getIfEnabled(FunModule.class); if (fm == null) return; - val devrole = fm.fullHouseDevRole().get(); + val channel = fm.fullHouseChannel().get(); + if (channel == null) return; + val devrole = fm.fullHouseDevRole(channel.getGuild()).get(); if (devrole == null) return; if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) - && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() + && event.getUser().getRolesForGuild(channel.getGuild()).stream() .anyMatch(r -> r.getLongID() == devrole.getLongID()) - && DiscordPlugin.devServer.getUsersByRole(devrole).stream() + && channel.getGuild().getUsersByRole(devrole).stream() .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(mod.fullHouseChannel().get(), "Full house!", + DiscordPlugin.sendMessageToChannel(channel, "Full house!", new EmbedBuilder() .withImage( "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index fa11f78..5350b32 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -38,7 +38,8 @@ public class CommonListeners { return; try { boolean handled = false; - if (event.getChannel().getLongID() == DiscordPlugin.plugin.CommandChannel().get().getLongID() //If mentioned, that's higher than chat + val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); + if ((commandChannel != null && event.getChannel().getLongID() == commandChannel.getLongID()) //If mentioned, that's higher than chat || event.getMessage().getContent().contains("channelcon")) //Only 'channelcon' is allowed in other channels handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here if (handled) return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index ceb184b..2bd2bb6 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -144,7 +144,7 @@ public class ChannelconCommand extends ICommand2DC { "Use the ID (command) of the channel, for example `g` for the global chat.", // "To remove a connection use @ChromaBot channelcon remove in the channel.", // "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", // - "Invite link: " // + "Invite link: " // TODO: Set correct client ID }; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index fbf9d27..6cc9f5b 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -108,6 +108,7 @@ class MCListener implements Listener { try { DPUtils.performNoWait(() -> { final IRole role = muteRole().get(); + if (role == null) return; final CommandSource source = e.getAffected().getSource(); if (!source.isPlayer()) return; @@ -120,7 +121,11 @@ class MCListener implements Listener { user.addRole(role); else user.removeRole(role); - DiscordPlugin.sendMessageToChannel(module.modlogChannel().get(), (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); + val modlog = module.modlogChannel().get(); + String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName(); + if (modlog != null) + DiscordPlugin.sendMessageToChannel(modlog, msg); + DPUtils.getLogger().info(msg); }); } catch (DiscordException | MissingPermissionsException ex) { TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", @@ -143,7 +148,7 @@ class MCListener implements Listener { String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() : event.getSender().getName(); //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO - MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); + MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); //TODO: Don't require emoji } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 2d6e50b..789fd2d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -41,6 +41,7 @@ public class MinecraftChatModule extends Component { @Override protected void enable() { + if (DPUtils.disableIfConfigError(this, chatChannel())) return; listener = new MCChatListener(this); DiscordPlugin.dc.getDispatcher().registerListener(listener); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 45fe9ec..8806647 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -40,30 +40,34 @@ public class GameRoleModule extends Component { val grm = ComponentManager.getIfEnabled(GameRoleModule.class); if (grm == null) return; val GameRoles = grm.GameRoles; + val logChannel = grm.logChannel().get(); if (roleEvent instanceof RoleCreateEvent) { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { if (roleEvent.getRole().isDeleted() || !grm.isGameRole(roleEvent.getRole())) return; //Deleted or not a game role GameRoles.add(roleEvent.getRole().getName()); - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + roleEvent.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); + if (logChannel != null) + DiscordPlugin.sendMessageToChannel(logChannel, "Added " + roleEvent.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); }, 100); } else if (roleEvent instanceof RoleDeleteEvent) { - if (GameRoles.remove(roleEvent.getRole().getName())) - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + roleEvent.getRole().getName() + " as a game role."); + if (GameRoles.remove(roleEvent.getRole().getName()) && logChannel != null) + DiscordPlugin.sendMessageToChannel(logChannel, "Removed " + roleEvent.getRole().getName() + " as a game role."); } else if (roleEvent instanceof RoleUpdateEvent) { val event = (RoleUpdateEvent) roleEvent; if (!grm.isGameRole(event.getNewRole())) { - if (GameRoles.remove(event.getOldRole().getName())) - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); + if (GameRoles.remove(event.getOldRole().getName()) && logChannel != null) + DiscordPlugin.sendMessageToChannel(logChannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); } else { if (GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) return; boolean removed = GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role GameRoles.add(event.getNewRole().getName()); //Add it because it has no color - if (removed) - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); - else - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + if (logChannel != null) { + if (removed) + DiscordPlugin.sendMessageToChannel(logChannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); + else + DiscordPlugin.sendMessageToChannel(logChannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + } } } } @@ -73,6 +77,7 @@ public class GameRoleModule extends Component { return false; //Only allow on the main server val rc = new Color(149, 165, 166, 0); return r.getColor().equals(rc) - && r.getPosition() < DiscordPlugin.mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role + && DiscordPlugin.dc.getOurUser().getRolesForGuild(DiscordPlugin.mainServer) + .stream().anyMatch(or -> r.getPosition() < or.getPosition()); //Below one of our roles } }