Made the plugin work cleanly (#51)

Clean install works pretty well
Automatically setting first server as main server
Removed devServer variable, getting the guild from the channels
Disabling each component that doesn't have its channel(s)/role(s) set correctly (unless it's not required)
Removed redundant variable from the FunModule
Correctly handling missing channel settings in some places
Checking any role position for game roles, not just "ChromaBot"
The bot is playing Minecraft now
Always giving permission for commands for now
This commit is contained in:
Norbi Peti 2019-03-09 02:07:56 +01:00
parent 14c42614d8
commit cadb53d886
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
11 changed files with 104 additions and 51 deletions

View file

@ -45,6 +45,7 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
@Override
protected void enable() {
if (DPUtils.disableIfConfigError(this, channel(), modChannel())) return;
stop = false; //If not the first time
DPUtils.performNoWait(() -> {
try {

View file

@ -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<IRole> roleData(IHaveConfig config, String key, String defName) {
return roleData(config, key, defName, DiscordPlugin.mainServer);
}
public static ConfigData<IRole> 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<DiscordPlugin> 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;
}
}

View file

@ -108,7 +108,6 @@ public class DiscordPlugin extends ButtonPlugin implements IListener<ReadyEvent>
}
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<ReadyEvent>
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<ReadyEvent>
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<ReadyEvent>
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);

View file

@ -11,6 +11,7 @@ public class Command2DC extends Command2<ICommand2DC, Command2DCSender> {
@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;
}
}

View file

@ -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<DiscordPlugin> 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<DiscordPlugin> 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<DiscordPlugin> implements
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
}
private ConfigData<IRole> 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());

View file

@ -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<DiscordPlugin> 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<DiscordPlugin> implements Listener {
@Override
protected void enable() {
mod = this;
registerListener(this);
}
@ -99,7 +93,7 @@ public class FunModule extends Component<DiscordPlugin> 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<DiscordPlugin> implements Listener {
ListC = 0;
}
private ConfigData<IRole> 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<IRole> fullHouseDevRole(IGuild guild) {
return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild);
}
@ -135,17 +126,19 @@ public class FunModule extends Component<DiscordPlugin> 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")

View file

@ -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;

View file

@ -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: <https://discordapp.com/oauth2/authorize?client_id=226443037893591041&scope=bot&permissions=268509264>" //
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=226443037893591041&scope=bot&permissions=268509264>" // TODO: Set correct client ID
};
}
}

View file

@ -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

View file

@ -41,6 +41,7 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
@Override
protected void enable() {
if (DPUtils.disableIfConfigError(this, chatChannel())) return;
listener = new MCChatListener(this);
DiscordPlugin.dc.getDispatcher().registerListener(listener);
TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin());

View file

@ -40,30 +40,34 @@ public class GameRoleModule extends Component<DiscordPlugin> {
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<DiscordPlugin> {
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
}
}