Documentation, split messages that are too big

#122
Removed some default values
Disallowing MC commands that could error when not loaded (#121)
Other fixes
This commit is contained in:
Norbi Peti 2020-02-01 19:10:13 +01:00
parent bdb7381ab4
commit de07503bc3
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
10 changed files with 91 additions and 42 deletions

View file

@ -96,13 +96,16 @@ public final class DPUtils {
*/ */
public static ReadOnlyConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName, Mono<Guild> guild) { public static ReadOnlyConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName, Mono<Guild> guild) {
return config.getReadOnlyDataPrimDef(key, defName, name -> { return config.getReadOnlyDataPrimDef(key, defName, name -> {
if (!(name instanceof String)) return Mono.empty(); if (!(name instanceof String) || ((String) name).length() == 0) return Mono.empty();
return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).next(); return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).onErrorResume(e -> {
getLogger().warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage());
return Mono.empty();
}).next();
}, r -> defName); }, r -> defName);
} }
public static ConfigData<Snowflake> snowflakeData(IHaveConfig config, String key, long defID) { public static ReadOnlyConfigData<Snowflake> snowflakeData(IHaveConfig config, String key, long defID) {
return config.getDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong); return config.getReadOnlyDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong);
} }
/** /**

View file

@ -55,6 +55,9 @@ public class DiscordPlugin extends ButtonPlugin {
@Getter @Getter
private Command2DC manager; private Command2DC manager;
/**
* The prefix to use with Discord commands like /role. It only works in the bot channel.
*/
private ConfigData<Character> prefix() { private ConfigData<Character> prefix() {
return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString);
} }
@ -64,6 +67,9 @@ public class DiscordPlugin extends ButtonPlugin {
return plugin.prefix().get(); return plugin.prefix().get();
} }
/**
* The main server where the roles and other information is pulled from. It's automatically set to the first server the bot's invited to.
*/
private ConfigData<Optional<Guild>> mainServer() { private ConfigData<Optional<Guild>> mainServer() {
return getIConfig().getDataPrimDef("mainServer", 0L, return getIConfig().getDataPrimDef("mainServer", 0L,
id -> { id -> {
@ -76,12 +82,16 @@ public class DiscordPlugin extends ButtonPlugin {
g -> g.map(gg -> gg.getId().asLong()).orElse(0L)); g -> g.map(gg -> gg.getId().asLong()).orElse(0L));
} }
/**
* The (bot) channel to use for Discord commands like /role.
*/
public ConfigData<Snowflake> commandChannel() { public ConfigData<Snowflake> commandChannel() {
return DPUtils.snowflakeData(getIConfig(), "commandChannel", 239519012529111040L); return DPUtils.snowflakeData(getIConfig(), "commandChannel", 0L);
} }
/** /**
* If the role doesn't exist, then it will only allow for the owner. * The role that allows using mod-only Discord commands.
* If empty (''), then it will only allow for the owner.
*/ */
public ConfigData<Mono<Role>> modRole() { public ConfigData<Mono<Role>> modRole() {
return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); return DPUtils.roleData(getIConfig(), "modRole", "Moderator");
@ -164,7 +174,7 @@ public class DiscordPlugin extends ButtonPlugin {
} }
SafeMode = false; SafeMode = false;
DPUtils.disableIfConfigErrorRes(null, commandChannel(), DPUtils.getMessageChannel(commandChannel())); DPUtils.disableIfConfigErrorRes(null, commandChannel(), DPUtils.getMessageChannel(commandChannel()));
DPUtils.disableIfConfigError(null, modRole()); //Won't disable, just prints the warning here //Won't disable, just prints the warning here
Component.registerComponent(this, new GeneralEventBroadcasterModule()); Component.registerComponent(this, new GeneralEventBroadcasterModule());
Component.registerComponent(this, new MinecraftChatModule()); Component.registerComponent(this, new MinecraftChatModule());

View file

@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ReadOnlyConfigData; import buttondevteam.lib.architecture.ReadOnlyConfigData;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
@ -15,12 +16,13 @@ import com.google.gson.JsonParser;
import discord4j.core.object.entity.Message; import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.MessageChannel;
import lombok.val; import lombok.val;
import org.bukkit.configuration.file.YamlConfiguration;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.io.File; /**
* Posts new posts from Reddit to the specified channel(s). It will pin the regular posts (not the mod posts).
*/
@ComponentMetadata(enabledByDefault = false)
public class AnnouncerModule extends Component<DiscordPlugin> { public class AnnouncerModule extends Component<DiscordPlugin> {
/** /**
* Channel to post new posts. * Channel to post new posts.
@ -51,7 +53,13 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
return getConfig().getData("lastSeenTime", 0L); return getConfig().getData("lastSeenTime", 0L);
} }
private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; /**
* The subreddit to pull the posts from
*/
private ConfigData<String> subredditURL() {
return getConfig().getData("subredditURL", "https://www.reddit.com/r/ChromaGamers");
}
private static boolean stop = false; private static boolean stop = false;
@Override @Override
@ -62,11 +70,6 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
if (keepPinned == 0) return; if (keepPinned == 0) return;
Flux<Message> msgs = channel().get().flatMapMany(MessageChannel::getPinnedMessages); Flux<Message> msgs = channel().get().flatMapMany(MessageChannel::getPinnedMessages);
msgs.subscribe(Message::unpin); msgs.subscribe(Message::unpin);
val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change
if (lastAnnouncementTime().get() == 0) //Load old data
lastAnnouncementTime().set(yc.getLong("lastannouncementtime"));
if (lastSeenTime().get() == 0)
lastSeenTime().set(yc.getLong("lastseentime"));
new Thread(this::AnnouncementGetterThreadMethod).start(); new Thread(this::AnnouncementGetterThreadMethod).start();
} }
@ -82,7 +85,7 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
Thread.sleep(10000); Thread.sleep(10000);
continue; continue;
} }
String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10"); String body = TBMCCoreAPI.DownloadString(subredditURL().get() + "/new/.json?limit=10");
JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject() JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject()
.get("children").getAsJsonArray(); .get("children").getAsJsonArray();
StringBuilder msgsb = new StringBuilder(); StringBuilder msgsb = new StringBuilder();

View file

@ -6,6 +6,10 @@ import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import lombok.Getter; import lombok.Getter;
/**
* Uses a bit of a hacky method of getting all broadcasted messages, including advancements and any other message that's for everyone.
* If this component is enabled then these messages will show up on Discord.
*/
public class GeneralEventBroadcasterModule extends Component<DiscordPlugin> { public class GeneralEventBroadcasterModule extends Component<DiscordPlugin> {
private static @Getter boolean hooked = false; private static @Getter boolean hooked = false;

View file

@ -3,6 +3,7 @@ package buttondevteam.discordplugin.commands;
import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DPUtils;
import buttondevteam.lib.chat.Command2Sender; import buttondevteam.lib.chat.Command2Sender;
import discord4j.core.object.entity.Message; import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.User;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
@ -30,4 +31,9 @@ public class Command2DCSender implements Command2Sender {
public void sendMessage(String[] message) { public void sendMessage(String[] message) {
sendMessage(String.join("\n", message)); sendMessage(String.join("\n", message));
} }
@Override
public String getName() {
return message.getAuthor().map(User::getUsername).orElse("Discord");
}
} }

View file

@ -23,6 +23,9 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
* Listens for errors from the Chroma plugins and posts them to Discord, ignoring repeating errors so it's not that spammy.
*/
public class ExceptionListenerModule extends Component<DiscordPlugin> implements Listener { public class ExceptionListenerModule extends Component<DiscordPlugin> implements Listener {
private List<Throwable> lastthrown = new ArrayList<>(); private List<Throwable> lastthrown = new ArrayList<>();
private List<String> lastsourcemsg = new ArrayList<>(); private List<String> lastsourcemsg = new ArrayList<>();
@ -84,10 +87,16 @@ public class ExceptionListenerModule extends Component<DiscordPlugin> implements
return Mono.empty(); return Mono.empty();
} }
/**
* The channel to post the errors to.
*/
private ReadOnlyConfigData<Mono<MessageChannel>> channel() { private ReadOnlyConfigData<Mono<MessageChannel>> channel() {
return DPUtils.channelData(getConfig(), "channel"); return DPUtils.channelData(getConfig(), "channel");
} }
/**
* The role to ping if an error occurs. Set to empty ('') to disable.
*/
private ConfigData<Mono<Role>> pingRole(Mono<Guild> guild) { private ConfigData<Mono<Role>> pingRole(Mono<Guild> guild) {
return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild); return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild);
} }

View file

@ -26,23 +26,24 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream; import java.util.stream.IntStream;
/** /**
* All kinds of random things.
* The YEEHAW event uses an emoji named :YEEHAW: if available * The YEEHAW event uses an emoji named :YEEHAW: if available
*/ */
public class FunModule extends Component<DiscordPlugin> implements Listener { public class FunModule extends Component<DiscordPlugin> implements Listener {
private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali private static final String[] serverReadyStrings = new String[]{"in one week from now", // Ali
"Between now and the heat-death of the universe.", // Ghostise "between now and the heat-death of the universe.", // Ghostise
"Soon™", "Ask again this time next month", // Ghostise "soon™", "ask again this time next month", // Ghostise
"In about 3 seconds", // Nicolai "in about 3 seconds", // Nicolai
"After we finish 8 plugins", // Ali "after we finish 8 plugins", // Ali
"Tomorrow.", // Ali "tomorrow.", // Ali
"After one tiiiny feature", // Ali "after one tiiiny feature", // Ali
"Next commit", // Ali "next commit", // Ali
"After we finish strangling Towny", // Ali "after we finish strangling Towny", // Ali
"When we kill every *fucking* bug", // Ali "when we kill every *fucking* bug", // Ali
"Once the server stops screaming.", // Ali "once the server stops screaming.", // Ali
"After HL3 comes out", // Ali "after HL3 comes out", // Ali
"Next time you ask", // Ali "next time you ask", // Ali
"When will *you* be open?" // Ali "when will *you* be open?" // Ali
}; };
/** /**
@ -52,14 +53,14 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
return getConfig().getData("serverReady", () -> new String[]{"when will the server be open", return getConfig().getData("serverReady", () -> new String[]{"when will the server be open",
"when will the server be ready", "when will the server be done", "when will the server be complete", "when will the server be ready", "when will the server be done", "when will the server be complete",
"when will the server be finished", "when's the server ready", "when's the server open", "when will the server be finished", "when's the server ready", "when's the server open",
"Vhen vill ze server be open?"}); "vhen vill ze server be open?"});
} }
/** /**
* Answers for a recognized question. Selected randomly. * Answers for a recognized question. Selected randomly.
*/ */
private ConfigData<ArrayList<String>> serverReadyAnswers() { private ConfigData<ArrayList<String>> serverReadyAnswers() {
return getConfig().getData("serverReadyAnswers", () -> Lists.newArrayList(serverReadyStrings)); //TODO: Test return getConfig().getData("serverReadyAnswers", () -> Lists.newArrayList(serverReadyStrings));
} }
private static final Random serverReadyRandom = new Random(); private static final Random serverReadyRandom = new Random();
@ -119,11 +120,17 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
ListC = 0; ListC = 0;
} }
/**
* If all of the people who have this role are online, the bot will post a full house.
*/
private ConfigData<Mono<Role>> fullHouseDevRole(Mono<Guild> guild) { private ConfigData<Mono<Role>> fullHouseDevRole(Mono<Guild> guild) {
return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild); return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild);
} }
/**
* The channel to post the full house to.
*/
private ReadOnlyConfigData<Mono<MessageChannel>> fullHouseChannel() { private ReadOnlyConfigData<Mono<MessageChannel>> fullHouseChannel() {
return DPUtils.channelData(getConfig(), "fullHouseChannel"); return DPUtils.channelData(getConfig(), "fullHouseChannel");
} }

View file

@ -102,7 +102,8 @@ public class MCChatListener implements Listener {
if (lastmsgdata.message == null if (lastmsgdata.message == null
|| !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().map(Embed.Author::getName).orElse(null)) || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().map(Embed.Author::getName).orElse(null))
|| lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120 || lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120
|| !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) { || !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)
|| lastmsgdata.content.length() + e.getMessage().length() + 1 > 2048) {
lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block(); lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block();
lastmsgdata.time = nanoTime; lastmsgdata.time = nanoTime;
lastmsgdata.mcchannel = e.getChannel(); lastmsgdata.mcchannel = e.getChannel();

View file

@ -28,12 +28,7 @@ import java.util.stream.Collectors;
* Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM. * Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM.
*/ */
public class MinecraftChatModule extends Component<DiscordPlugin> { public class MinecraftChatModule extends Component<DiscordPlugin> {
private @Getter private @Getter MCChatListener listener;
MCChatListener listener;
/*public MCChatListener getListener() { //It doesn't want to generate
return listener; - And now ButtonProcessor didn't look beyond this - return instead of continue...
}*/
/** /**
* A list of commands that can be used in public chats - Warning: Some plugins will treat players as OPs, always test before allowing a command! * A list of commands that can be used in public chats - Warning: Some plugins will treat players as OPs, always test before allowing a command!
@ -46,8 +41,8 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
/** /**
* The channel to use as the public Minecraft chat - everything public gets broadcasted here * The channel to use as the public Minecraft chat - everything public gets broadcasted here
*/ */
public ConfigData<Snowflake> chatChannel() { public ReadOnlyConfigData<Snowflake> chatChannel() {
return DPUtils.snowflakeData(getConfig(), "chatChannel", 239519012529111040L); return DPUtils.snowflakeData(getConfig(), "chatChannel", 0L);
} }
public Mono<MessageChannel> chatChannelMono() { public Mono<MessageChannel> chatChannelMono() {

View file

@ -27,6 +27,7 @@ import java.lang.reflect.Method;
public class DiscordMCCommand extends ICommand2MC { public class DiscordMCCommand extends ICommand2MC {
@Command2.Subcommand @Command2.Subcommand
public boolean accept(Player player) { public boolean accept(Player player) {
if (checkSafeMode(player)) return true;
String did = ConnectCommand.WaitingToConnect.get(player.getName()); String did = ConnectCommand.WaitingToConnect.get(player.getName());
if (did == null) { if (did == null) {
player.sendMessage("§cYou don't have a pending connection to Discord."); player.sendMessage("§cYou don't have a pending connection to Discord.");
@ -45,6 +46,7 @@ public class DiscordMCCommand extends ICommand2MC {
@Command2.Subcommand @Command2.Subcommand
public boolean decline(Player player) { public boolean decline(Player player) {
if (checkSafeMode(player)) return true;
String did = ConnectCommand.WaitingToConnect.remove(player.getName()); String did = ConnectCommand.WaitingToConnect.remove(player.getName());
if (did == null) { if (did == null) {
player.sendMessage("§cYou don't have a pending connection to Discord."); player.sendMessage("§cYou don't have a pending connection to Discord.");
@ -101,6 +103,7 @@ public class DiscordMCCommand extends ICommand2MC {
"Shows an invite link to the server" "Shows an invite link to the server"
}) })
public void invite(CommandSender sender) { public void invite(CommandSender sender) {
if (checkSafeMode(sender)) return;
String invi = DiscordPlugin.plugin.inviteLink().get(); String invi = DiscordPlugin.plugin.inviteLink().get();
if (invi.length() > 0) { if (invi.length() > 0) {
sender.sendMessage("§bInvite link: " + invi); sender.sendMessage("§bInvite link: " + invi);
@ -132,4 +135,12 @@ public class DiscordMCCommand extends ICommand2MC {
return super.getHelpText(method, ann); return super.getHelpText(method, ann);
} }
} }
private boolean checkSafeMode(CommandSender sender) {
if (DiscordPlugin.SafeMode) {
sender.sendMessage("§cThe plugin isn't initialized. Check console for details.");
return true;
}
return false;
}
} }