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) {
return config.getReadOnlyDataPrimDef(key, defName, name -> {
if (!(name instanceof String)) return Mono.empty();
return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).next();
if (!(name instanceof String) || ((String) name).length() == 0) return Mono.empty();
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);
}
public static ConfigData<Snowflake> snowflakeData(IHaveConfig config, String key, long defID) {
return config.getDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong);
public static ReadOnlyConfigData<Snowflake> snowflakeData(IHaveConfig config, String key, long defID) {
return config.getReadOnlyDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong);
}
/**

View file

@ -55,6 +55,9 @@ public class DiscordPlugin extends ButtonPlugin {
@Getter
private Command2DC manager;
/**
* The prefix to use with Discord commands like /role. It only works in the bot channel.
*/
private ConfigData<Character> prefix() {
return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString);
}
@ -64,6 +67,9 @@ public class DiscordPlugin extends ButtonPlugin {
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() {
return getIConfig().getDataPrimDef("mainServer", 0L,
id -> {
@ -76,12 +82,16 @@ public class DiscordPlugin extends ButtonPlugin {
g -> g.map(gg -> gg.getId().asLong()).orElse(0L));
}
/**
* The (bot) channel to use for Discord commands like /role.
*/
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() {
return DPUtils.roleData(getIConfig(), "modRole", "Moderator");
@ -164,7 +174,7 @@ public class DiscordPlugin extends ButtonPlugin {
}
SafeMode = false;
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 MinecraftChatModule());

View file

@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ReadOnlyConfigData;
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.MessageChannel;
import lombok.val;
import org.bukkit.configuration.file.YamlConfiguration;
import reactor.core.publisher.Flux;
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> {
/**
* Channel to post new posts.
@ -51,7 +53,13 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
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;
@Override
@ -62,11 +70,6 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
if (keepPinned == 0) return;
Flux<Message> msgs = channel().get().flatMapMany(MessageChannel::getPinnedMessages);
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();
}
@ -82,7 +85,7 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
Thread.sleep(10000);
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()
.get("children").getAsJsonArray();
StringBuilder msgsb = new StringBuilder();

View file

@ -6,6 +6,10 @@ import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component;
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> {
private static @Getter boolean hooked = false;

View file

@ -3,6 +3,7 @@ package buttondevteam.discordplugin.commands;
import buttondevteam.discordplugin.DPUtils;
import buttondevteam.lib.chat.Command2Sender;
import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.User;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.val;
@ -30,4 +31,9 @@ public class Command2DCSender implements Command2Sender {
public void sendMessage(String[] 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.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 {
private List<Throwable> lastthrown = new ArrayList<>();
private List<String> lastsourcemsg = new ArrayList<>();
@ -84,10 +87,16 @@ public class ExceptionListenerModule extends Component<DiscordPlugin> implements
return Mono.empty();
}
/**
* The channel to post the errors to.
*/
private ReadOnlyConfigData<Mono<MessageChannel>> 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) {
return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild);
}

View file

@ -26,23 +26,24 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
/**
* All kinds of random things.
* The YEEHAW event uses an emoji named :YEEHAW: if available
*/
public class FunModule extends Component<DiscordPlugin> implements Listener {
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
"In about 3 seconds", // Nicolai
"After we finish 8 plugins", // Ali
"Tomorrow.", // Ali
"After one tiiiny feature", // Ali
"Next commit", // Ali
"After we finish strangling Towny", // Ali
"When we kill every *fucking* bug", // Ali
"Once the server stops screaming.", // Ali
"After HL3 comes out", // Ali
"Next time you ask", // Ali
"When will *you* be open?" // Ali
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
"in about 3 seconds", // Nicolai
"after we finish 8 plugins", // Ali
"tomorrow.", // Ali
"after one tiiiny feature", // Ali
"next commit", // Ali
"after we finish strangling Towny", // Ali
"when we kill every *fucking* bug", // Ali
"once the server stops screaming.", // Ali
"after HL3 comes out", // Ali
"next time you ask", // 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",
"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",
"Vhen vill ze server be open?"});
"vhen vill ze server be open?"});
}
/**
* Answers for a recognized question. Selected randomly.
*/
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();
@ -119,11 +120,17 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
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) {
return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild);
}
/**
* The channel to post the full house to.
*/
private ReadOnlyConfigData<Mono<MessageChannel>> fullHouseChannel() {
return DPUtils.channelData(getConfig(), "fullHouseChannel");
}

View file

@ -102,7 +102,8 @@ public class MCChatListener implements Listener {
if (lastmsgdata.message == null
|| !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().map(Embed.Author::getName).orElse(null))
|| 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.time = nanoTime;
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.
*/
public class MinecraftChatModule extends Component<DiscordPlugin> {
private @Getter
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...
}*/
private @Getter MCChatListener listener;
/**
* 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
*/
public ConfigData<Snowflake> chatChannel() {
return DPUtils.snowflakeData(getConfig(), "chatChannel", 239519012529111040L);
public ReadOnlyConfigData<Snowflake> chatChannel() {
return DPUtils.snowflakeData(getConfig(), "chatChannel", 0L);
}
public Mono<MessageChannel> chatChannelMono() {

View file

@ -27,6 +27,7 @@ import java.lang.reflect.Method;
public class DiscordMCCommand extends ICommand2MC {
@Command2.Subcommand
public boolean accept(Player player) {
if (checkSafeMode(player)) return true;
String did = ConnectCommand.WaitingToConnect.get(player.getName());
if (did == null) {
player.sendMessage("§cYou don't have a pending connection to Discord.");
@ -45,6 +46,7 @@ public class DiscordMCCommand extends ICommand2MC {
@Command2.Subcommand
public boolean decline(Player player) {
if (checkSafeMode(player)) return true;
String did = ConnectCommand.WaitingToConnect.remove(player.getName());
if (did == null) {
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"
})
public void invite(CommandSender sender) {
if (checkSafeMode(sender)) return;
String invi = DiscordPlugin.plugin.inviteLink().get();
if (invi.length() > 0) {
sender.sendMessage("§bInvite link: " + invi);
@ -132,4 +135,12 @@ public class DiscordMCCommand extends ICommand2MC {
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;
}
}