Merge pull request #123 from TBMCPlugins/dev
Fixed many issues, default config values, improvements
This commit is contained in:
commit
bcd7f7b810
19 changed files with 283 additions and 128 deletions
2
pom.xml
2
pom.xml
|
@ -183,7 +183,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.discord4j</groupId>
|
<groupId>com.discord4j</groupId>
|
||||||
<artifactId>discord4j-core</artifactId>
|
<artifactId>discord4j-core</artifactId>
|
||||||
<version>3.0.10</version>
|
<version>3.0.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
|
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -15,11 +15,17 @@ import lombok.val;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public final class DPUtils {
|
public final class DPUtils {
|
||||||
|
|
||||||
|
public static final Pattern URL_PATTERN = Pattern.compile("https?://\\S*");
|
||||||
|
public static final Pattern FORMAT_PATTERN = Pattern.compile("[*_~]");
|
||||||
|
|
||||||
public static EmbedCreateSpec embedWithHead(EmbedCreateSpec ecs, String displayname, String playername, String profileUrl) {
|
public static EmbedCreateSpec embedWithHead(EmbedCreateSpec ecs, String displayname, String playername, String profileUrl) {
|
||||||
return ecs.setAuthor(displayname, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png");
|
return ecs.setAuthor(displayname, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png");
|
||||||
}
|
}
|
||||||
|
@ -51,7 +57,24 @@ public final class DPUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String escape(String message) {
|
private static String escape(String message) {
|
||||||
return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\") + "$1");
|
//var ts = new TreeSet<>();
|
||||||
|
var ts = new TreeSet<int[]>(Comparator.comparingInt(a -> a[0])); //Compare the start, then check the end
|
||||||
|
var matcher = URL_PATTERN.matcher(message);
|
||||||
|
while (matcher.find())
|
||||||
|
ts.add(new int[]{matcher.start(), matcher.end()});
|
||||||
|
matcher = FORMAT_PATTERN.matcher(message);
|
||||||
|
/*Function<MatchResult, String> aFunctionalInterface = result ->
|
||||||
|
Optional.ofNullable(ts.floor(new int[]{result.start(), 0})).map(a -> a[1]).orElse(0) < result.start()
|
||||||
|
? "\\\\" + result.group() : result.group();
|
||||||
|
return matcher.replaceAll(aFunctionalInterface); //Find nearest URL match and if it's not reaching to the char then escape*/
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
matcher.appendReplacement(sb, Optional.ofNullable(ts.floor(new int[]{matcher.start(), 0})) //Find a URL start <= our start
|
||||||
|
.map(a -> a[1]).orElse(-1) < matcher.start() //Check if URL end < our start
|
||||||
|
? "\\\\" + matcher.group() : matcher.group());
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Logger getLogger() {
|
public static Logger getLogger() {
|
||||||
|
@ -60,8 +83,8 @@ public final class DPUtils {
|
||||||
return DiscordPlugin.plugin.getLogger();
|
return DiscordPlugin.plugin.getLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReadOnlyConfigData<Mono<MessageChannel>> channelData(IHaveConfig config, String key, long defID) {
|
public static ReadOnlyConfigData<Mono<MessageChannel>> channelData(IHaveConfig config, String key) {
|
||||||
return config.getReadOnlyDataPrimDef(key, defID, id -> getMessageChannel(key, Snowflake.of((Long) id)), ch -> defID); //We can afford to search for the channel in the cache once (instead of using mainServer)
|
return config.getReadOnlyDataPrimDef(key, 0L, id -> getMessageChannel(key, Snowflake.of((Long) id)), ch -> 0L); //We can afford to search for the channel in the cache once (instead of using mainServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReadOnlyConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName) {
|
public static ReadOnlyConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName) {
|
||||||
|
@ -73,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,12 +160,27 @@ public final class DPUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a response in the form of "@User, message". Use Mono.empty() if you don't have a channel object.
|
||||||
|
*
|
||||||
|
* @param original The original message to reply to
|
||||||
|
* @param channel The channel to send the message in, defaults to the original
|
||||||
|
* @param message The message to send
|
||||||
|
* @return A mono to send the message
|
||||||
|
*/
|
||||||
public static Mono<Message> reply(Message original, @Nullable MessageChannel channel, String message) {
|
public static Mono<Message> reply(Message original, @Nullable MessageChannel channel, String message) {
|
||||||
Mono<MessageChannel> ch;
|
Mono<MessageChannel> ch;
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
ch = original.getChannel();
|
ch = original.getChannel();
|
||||||
else
|
else
|
||||||
ch = Mono.just(channel);
|
ch = Mono.just(channel);
|
||||||
|
return reply(original, ch, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #reply(Message, MessageChannel, String)
|
||||||
|
*/
|
||||||
|
public static Mono<Message> reply(Message original, Mono<MessageChannel> ch, String message) {
|
||||||
return ch.flatMap(chan -> chan.createMessage((original.getAuthor().isPresent()
|
return ch.flatMap(chan -> chan.createMessage((original.getAuthor().isPresent()
|
||||||
? original.getAuthor().get().getMention() + ", " : "") + message));
|
? original.getAuthor().get().getMention() + ", " : "") + message));
|
||||||
}
|
}
|
||||||
|
@ -152,7 +193,15 @@ public final class DPUtils {
|
||||||
return "<#" + channelId.asString() + ">";
|
return "<#" + channelId.asString() + ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a message channel for a config. Returns empty for ID 0.
|
||||||
|
*
|
||||||
|
* @param key The config key
|
||||||
|
* @param id The channel ID
|
||||||
|
* @return A message channel
|
||||||
|
*/
|
||||||
public static Mono<MessageChannel> getMessageChannel(String key, Snowflake id) {
|
public static Mono<MessageChannel> getMessageChannel(String key, Snowflake id) {
|
||||||
|
if (id.asLong() == 0L) return Mono.empty();
|
||||||
return DiscordPlugin.dc.getChannelById(id).onErrorResume(e -> {
|
return DiscordPlugin.dc.getChannelById(id).onErrorResume(e -> {
|
||||||
getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage());
|
getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage());
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
|
|
|
@ -44,7 +44,6 @@ import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -56,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);
|
||||||
}
|
}
|
||||||
|
@ -65,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 -> {
|
||||||
|
@ -77,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");
|
||||||
|
@ -101,6 +110,7 @@ public class DiscordPlugin extends ButtonPlugin {
|
||||||
getLogger().info("Initializing...");
|
getLogger().info("Initializing...");
|
||||||
plugin = this;
|
plugin = this;
|
||||||
manager = new Command2DC();
|
manager = new Command2DC();
|
||||||
|
getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works
|
||||||
String token;
|
String token;
|
||||||
File tokenFile = new File("TBMC", "Token.txt");
|
File tokenFile = new File("TBMC", "Token.txt");
|
||||||
if (tokenFile.exists()) //Legacy support
|
if (tokenFile.exists()) //Legacy support
|
||||||
|
@ -114,8 +124,9 @@ public class DiscordPlugin extends ButtonPlugin {
|
||||||
conf.set("token", "Token goes here");
|
conf.set("token", "Token goes here");
|
||||||
conf.save(privateFile);
|
conf.save(privateFile);
|
||||||
|
|
||||||
getLogger().severe("Token not found! Set it in private.yml");
|
getLogger().severe("Token not found! Please set it in private.yml then do /discord reset");
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
getLogger().severe("You need to have a bot account to use with your server.");
|
||||||
|
getLogger().severe("If you don't have one, go to https://discordapp.com/developers/applications/ and create an application, then create a bot for it and copy the bot token.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,8 +144,8 @@ public class DiscordPlugin extends ButtonPlugin {
|
||||||
//dc.getEventDispatcher().on(DisconnectEvent.class);
|
//dc.getEventDispatcher().on(DisconnectEvent.class);
|
||||||
dc.login().subscribe();
|
dc.login().subscribe();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
TBMCCoreAPI.SendException("Failed to enable the Discord plugin!", e);
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
getLogger().severe("You may be able to reset the plugin using /discord reset");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,10 +155,10 @@ public class DiscordPlugin extends ButtonPlugin {
|
||||||
try {
|
try {
|
||||||
if (mainServer != null) { //This is not the first ready event
|
if (mainServer != null) { //This is not the first ready event
|
||||||
getLogger().info("Ready event already handled"); //TODO: It should probably handle disconnections
|
getLogger().info("Ready event already handled"); //TODO: It should probably handle disconnections
|
||||||
|
dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); //Update from the initial presence
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards
|
mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards
|
||||||
getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works
|
|
||||||
if (mainServer == null) {
|
if (mainServer == null) {
|
||||||
if (event.size() == 0) {
|
if (event.size() == 0) {
|
||||||
getLogger().severe("Main server not found! Invite the bot and do /discord reset");
|
getLogger().severe("Main server not found! Invite the bot and do /discord reset");
|
||||||
|
@ -163,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());
|
||||||
|
@ -196,14 +207,6 @@ public class DiscordPlugin extends ButtonPlugin {
|
||||||
|
|
||||||
getConfig().set("serverup", true);
|
getConfig().set("serverup", true);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
if (TBMCCoreAPI.IsTestServer() && !Objects.requireNonNull(dc.getSelf().block()).getUsername().toLowerCase().contains("test")) {
|
|
||||||
TBMCCoreAPI.SendException(
|
|
||||||
"Won't load because we're in testing mode and not using a separate account.",
|
|
||||||
new Exception(
|
|
||||||
"The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in its name.)"
|
|
||||||
+ "\nYou can disable test mode in ThorpeCore config."));
|
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
|
||||||
}
|
|
||||||
TBMCCoreAPI.SendUnsentExceptions();
|
TBMCCoreAPI.SendUnsentExceptions();
|
||||||
TBMCCoreAPI.SendUnsentDebugMessages();
|
TBMCCoreAPI.SendUnsentDebugMessages();
|
||||||
|
|
||||||
|
|
|
@ -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,25 +16,26 @@ 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.
|
||||||
*/
|
*/
|
||||||
public ReadOnlyConfigData<Mono<MessageChannel>> channel() {
|
public ReadOnlyConfigData<Mono<MessageChannel>> channel() {
|
||||||
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
|
return DPUtils.channelData(getConfig(), "channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel where distinguished (moderator) posts go.
|
* Channel where distinguished (moderator) posts go.
|
||||||
*/
|
*/
|
||||||
public ReadOnlyConfigData<Mono<MessageChannel>> modChannel() {
|
public ReadOnlyConfigData<Mono<MessageChannel>> modChannel() {
|
||||||
return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L);
|
return DPUtils.channelData(getConfig(), "modChannel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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", 239519012529111040L);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -96,7 +97,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
|
||||||
}
|
}
|
||||||
if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
|
if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
|
||||||
{
|
{
|
||||||
DPUtils.reply(message, null, "Stop it. You know the answer.").subscribe();
|
DPUtils.reply(message, Mono.empty(), "stop it. You know the answer.").subscribe();
|
||||||
lastlist = 0;
|
lastlist = 0;
|
||||||
lastlistp = (short) Bukkit.getOnlinePlayers().size();
|
lastlistp = (short) Bukkit.getOnlinePlayers().size();
|
||||||
return true; //Handled
|
return true; //Handled
|
||||||
|
@ -108,7 +109,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
|
||||||
if (usableServerReadyStrings.size() == 0)
|
if (usableServerReadyStrings.size() == 0)
|
||||||
fm.createUsableServerReadyStrings();
|
fm.createUsableServerReadyStrings();
|
||||||
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size()));
|
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size()));
|
||||||
DPUtils.reply(message, null, fm.serverReadyAnswers().get().get(next)).subscribe();
|
DPUtils.reply(message, Mono.empty(), fm.serverReadyAnswers().get().get(next)).subscribe();
|
||||||
return false; //Still process it as a command/mcchat if needed
|
return false; //Still process it as a command/mcchat if needed
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -119,13 +120,19 @@ 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", 219626707458457603L);
|
return DPUtils.channelData(getConfig(), "fullHouseChannel");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long lasttime = 0;
|
private static long lasttime = 0;
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class CommandListener {
|
||||||
try {
|
try {
|
||||||
timings.printElapsed("F");
|
timings.printElapsed("F");
|
||||||
if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString))
|
if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString))
|
||||||
return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString)
|
return DPUtils.reply(message, channel, "unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString)
|
||||||
.map(m -> false);
|
.map(m -> false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e);
|
TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e);
|
||||||
|
|
|
@ -9,12 +9,17 @@ import buttondevteam.lib.TBMCSystemChatEvent;
|
||||||
import buttondevteam.lib.chat.Command2;
|
import buttondevteam.lib.chat.Command2;
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
import buttondevteam.lib.chat.CommandClass;
|
||||||
import buttondevteam.lib.player.TBMCPlayer;
|
import buttondevteam.lib.player.TBMCPlayer;
|
||||||
|
import discord4j.core.object.entity.GuildChannel;
|
||||||
import discord4j.core.object.entity.Message;
|
import discord4j.core.object.entity.Message;
|
||||||
|
import discord4j.core.object.entity.MessageChannel;
|
||||||
|
import discord4j.core.object.entity.User;
|
||||||
import discord4j.core.object.util.Permission;
|
import discord4j.core.object.util.Permission;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -22,6 +27,7 @@ import java.util.Objects;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@SuppressWarnings("SimplifyOptionalCallChains") //Java 11
|
||||||
@CommandClass(helpText = {"Channel connect", //
|
@CommandClass(helpText = {"Channel connect", //
|
||||||
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
|
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
|
||||||
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
|
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
|
||||||
|
@ -36,28 +42,29 @@ import java.util.stream.Collectors;
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ChannelconCommand extends ICommand2DC {
|
public class ChannelconCommand extends ICommand2DC {
|
||||||
private final MinecraftChatModule module;
|
private final MinecraftChatModule module;
|
||||||
|
|
||||||
@Command2.Subcommand
|
@Command2.Subcommand
|
||||||
public boolean remove(Command2DCSender sender) {
|
public boolean remove(Command2DCSender sender) {
|
||||||
val message = sender.getMessage();
|
val message = sender.getMessage();
|
||||||
if (checkPerms(message)) return true;
|
if (checkPerms(message, null)) return true;
|
||||||
if (MCChatCustom.removeCustomChat(message.getChannelId()))
|
if (MCChatCustom.removeCustomChat(message.getChannelId()))
|
||||||
DPUtils.reply(message, null, "channel connection removed.").subscribe();
|
DPUtils.reply(message, Mono.empty(), "channel connection removed.").subscribe();
|
||||||
else
|
else
|
||||||
DPUtils.reply(message, null, "this channel isn't connected.").subscribe();
|
DPUtils.reply(message, Mono.empty(), "this channel isn't connected.").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command2.Subcommand
|
@Command2.Subcommand
|
||||||
public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) {
|
public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) {
|
||||||
val message = sender.getMessage();
|
val message = sender.getMessage();
|
||||||
if (checkPerms(message)) return true;
|
if (checkPerms(message, null)) return true;
|
||||||
val cc = MCChatCustom.getCustomChat(message.getChannelId());
|
val cc = MCChatCustom.getCustomChat(message.getChannelId());
|
||||||
if (cc == null)
|
if (cc == null)
|
||||||
return respond(sender, "this channel isn't connected.");
|
return respond(sender, "this channel isn't connected.");
|
||||||
Supplier<String> togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n"))
|
Supplier<String> togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n"))
|
||||||
+ "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n"));
|
+ "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n"));
|
||||||
if (toggle == null) {
|
if (toggle == null) {
|
||||||
DPUtils.reply(message, null, "toggles:\n" + togglesString.get()).subscribe();
|
DPUtils.reply(message, Mono.empty(), "toggles:\n" + togglesString.get()).subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String arg = toggle.toUpperCase();
|
String arg = toggle.toUpperCase();
|
||||||
|
@ -65,7 +72,7 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
if (!b.isPresent()) {
|
if (!b.isPresent()) {
|
||||||
val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg);
|
val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg);
|
||||||
if (bt == null) {
|
if (bt == null) {
|
||||||
DPUtils.reply(message, null, "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe();
|
DPUtils.reply(message, Mono.empty(), "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final boolean add;
|
final boolean add;
|
||||||
|
@ -83,7 +90,7 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
//1 1 | 0
|
//1 1 | 0
|
||||||
// XOR
|
// XOR
|
||||||
cc.toggles ^= b.get().flag;
|
cc.toggles ^= b.get().flag;
|
||||||
DPUtils.reply(message, null, "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe();
|
DPUtils.reply(message, Mono.empty(), "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,12 +101,13 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
sender.sendMessage("channel connection is not allowed on this Minecraft server.");
|
sender.sendMessage("channel connection is not allowed on this Minecraft server.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (checkPerms(message)) return true;
|
val channel = message.getChannel().block();
|
||||||
|
if (checkPerms(message, channel)) return true;
|
||||||
if (MCChatCustom.hasCustomChat(message.getChannelId()))
|
if (MCChatCustom.hasCustomChat(message.getChannelId()))
|
||||||
return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it.");
|
return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it.");
|
||||||
val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(channelID) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(channelID)))).findAny();
|
val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(channelID) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(channelID)))).findAny();
|
||||||
if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
|
if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
|
||||||
DPUtils.reply(message, null, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe();
|
DPUtils.reply(message, channel, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!message.getAuthor().isPresent()) return true;
|
if (!message.getAuthor().isPresent()) return true;
|
||||||
|
@ -107,19 +115,18 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
val dp = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class);
|
val dp = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class);
|
||||||
val chp = dp.getAs(TBMCPlayer.class);
|
val chp = dp.getAs(TBMCPlayer.class);
|
||||||
if (chp == null) {
|
if (chp == null) {
|
||||||
DPUtils.reply(message, null, "you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect <MCname>").subscribe();
|
DPUtils.reply(message, channel, "you need to connect your Minecraft account. On the main server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect <MCname>").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
val channel = message.getChannel().block();
|
|
||||||
DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module);
|
DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module);
|
||||||
//Using a fake player with no login/logout, should be fine for this event
|
//Using a fake player with no login/logout, should be fine for this event
|
||||||
String groupid = chan.get().getGroupID(dcp);
|
String groupid = chan.get().getGroupID(dcp);
|
||||||
if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later
|
if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later
|
||||||
DPUtils.reply(message, null, "sorry, you cannot use that Minecraft channel.").subscribe();
|
DPUtils.reply(message, channel, "sorry, you cannot use that Minecraft channel.").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well
|
if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well
|
||||||
DPUtils.reply(message, null, "chat rooms are not supported yet.").subscribe();
|
DPUtils.reply(message, channel, "chat rooms are not supported yet.").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/*if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) {
|
/*if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) {
|
||||||
|
@ -128,16 +135,23 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
}*/ //TODO: "Channel admins" that can connect channels?
|
}*/ //TODO: "Channel admins" that can connect channels?
|
||||||
MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>());
|
MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>());
|
||||||
if (chan.get() instanceof ChatRoom)
|
if (chan.get() instanceof ChatRoom)
|
||||||
DPUtils.reply(message, null, "alright, connection made to the room!").subscribe();
|
DPUtils.reply(message, channel, "alright, connection made to the room!").subscribe();
|
||||||
else
|
else
|
||||||
DPUtils.reply(message, null, "alright, connection made to group `" + groupid + "`!").subscribe();
|
DPUtils.reply(message, channel, "alright, connection made to group `" + groupid + "`!").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
private boolean checkPerms(Message message) {
|
private boolean checkPerms(Message message, @Nullable MessageChannel channel) {
|
||||||
if (!message.getAuthorAsMember().block().getBasePermissions().block().contains(Permission.MANAGE_CHANNELS)) {
|
if (channel == null)
|
||||||
DPUtils.reply(message, null, "you need to have manage permissions for this channel!").subscribe();
|
channel = message.getChannel().block();
|
||||||
|
if (!(channel instanceof GuildChannel)) {
|
||||||
|
DPUtils.reply(message, channel, "you can only use this command in a server!").subscribe();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var perms = ((GuildChannel) channel).getEffectivePermissions(message.getAuthor().map(User::getId).get()).block();
|
||||||
|
if (!perms.contains(Permission.ADMINISTRATOR) && !perms.contains(Permission.MANAGE_CHANNELS)) {
|
||||||
|
DPUtils.reply(message, channel, "you need to have manage permissions for this channel!").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -155,7 +169,7 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
"Use the ID (command) of the channel, for example `g` for the global chat.", //
|
"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.", //
|
"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() + ".", //
|
"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=" + module.clientID + "&scope=bot&permissions=268509264>"
|
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=" + DiscordPlugin.dc.getApplicationInfo().map(info -> info.getId().asString()).blockOptional().orElse("Unknown") + "&scope=bot&permissions=268509264>"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,13 @@ public class MCChatCommand extends ICommand2DC {
|
||||||
val channel = message.getChannel().block();
|
val channel = message.getChannel().block();
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get();
|
@SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get();
|
||||||
if (!(channel instanceof PrivateChannel)) {
|
if (!(channel instanceof PrivateChannel)) {
|
||||||
DPUtils.reply(message, null, "this command can only be issued in a direct message with the bot.").subscribe();
|
DPUtils.reply(message, channel, "this command can only be issued in a direct message with the bot.").subscribe();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) {
|
try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) {
|
||||||
boolean mcchat = !user.isMinecraftChatEnabled();
|
boolean mcchat = !user.isMinecraftChatEnabled();
|
||||||
MCChatPrivate.privateMCChat(channel, mcchat, author, user);
|
MCChatPrivate.privateMCChat(channel, mcchat, author, user);
|
||||||
DPUtils.reply(message, null, "Minecraft chat " + (mcchat //
|
DPUtils.reply(message, channel, "Minecraft chat " + (mcchat //
|
||||||
? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." //
|
? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." //
|
||||||
: "disabled.")).subscribe();
|
: "disabled.")).subscribe();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -84,13 +84,14 @@ public class MCChatListener implements Listener {
|
||||||
final Consumer<EmbedCreateSpec> embed = ecs -> {
|
final Consumer<EmbedCreateSpec> embed = ecs -> {
|
||||||
ecs.setDescription(e.getMessage()).setColor(new Color(color.getRed(),
|
ecs.setDescription(e.getMessage()).setColor(new Color(color.getRed(),
|
||||||
color.getGreen(), color.getBlue()));
|
color.getGreen(), color.getBlue()));
|
||||||
|
String url = module.profileURL().get();
|
||||||
if (e.getSender() instanceof Player)
|
if (e.getSender() instanceof Player)
|
||||||
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(),
|
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(),
|
||||||
"https://tbmcplugins.github.io/profile.html?type=minecraft&id="
|
url.length() > 0 ? url + "?type=minecraft&id="
|
||||||
+ ((Player) e.getSender()).getUniqueId());
|
+ ((Player) e.getSender()).getUniqueId() : null);
|
||||||
else if (e.getSender() instanceof DiscordSenderBase)
|
else if (e.getSender() instanceof DiscordSenderBase)
|
||||||
ecs.setAuthor(authorPlayer, "https://tbmcplugins.github.io/profile.html?type=discord&id=" // TODO: Constant/method to get URLs like this
|
ecs.setAuthor(authorPlayer, url.length() > 0 ? url + "?type=discord&id="
|
||||||
+ ((DiscordSenderBase) e.getSender()).getUser().getId().asString(),
|
+ ((DiscordSenderBase) e.getSender()).getUser().getId().asString() : null,
|
||||||
((DiscordSenderBase) e.getSender()).getUser().getAvatarUrl());
|
((DiscordSenderBase) e.getSender()).getUser().getAvatarUrl());
|
||||||
else
|
else
|
||||||
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(), null);
|
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(), null);
|
||||||
|
@ -101,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();
|
||||||
|
@ -292,6 +294,8 @@ public class MCChatListener implements Listener {
|
||||||
dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?)
|
dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?)
|
||||||
dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up
|
dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up
|
||||||
|
|
||||||
|
dmessage = dmessage.replaceAll("<a?:(\\S+):(\\d+)>", ":$1:"); //We don't need info about the custom emojis, just display their text
|
||||||
|
|
||||||
Function<String, String> getChatMessage = msg -> //
|
Function<String, String> getChatMessage = msg -> //
|
||||||
msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage()
|
msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage()
|
||||||
.getAttachments().stream().map(Attachment::getUrl).collect(Collectors.joining("\n"))
|
.getAttachments().stream().map(Attachment::getUrl).collect(Collectors.joining("\n"))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package buttondevteam.discordplugin.mcchat;
|
package buttondevteam.discordplugin.mcchat;
|
||||||
|
|
||||||
import buttondevteam.core.ComponentManager;
|
import buttondevteam.core.ComponentManager;
|
||||||
|
import buttondevteam.core.MainPlugin;
|
||||||
import buttondevteam.discordplugin.*;
|
import buttondevteam.discordplugin.*;
|
||||||
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule;
|
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule;
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
import buttondevteam.lib.TBMCCoreAPI;
|
||||||
|
@ -13,6 +14,7 @@ import lombok.RequiredArgsConstructor;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||||
|
@ -30,6 +32,7 @@ import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
@ -81,13 +84,27 @@ public class MCChatUtils {
|
||||||
String[] s = topic.split("\\n----\\n");
|
String[] s = topic.split("\\n----\\n");
|
||||||
if (s.length < 3)
|
if (s.length < 3)
|
||||||
return;
|
return;
|
||||||
s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "")
|
String gid;
|
||||||
+ " online";
|
if (lmd instanceof MCChatCustom.CustomLMD)
|
||||||
|
gid = ((MCChatCustom.CustomLMD) lmd).groupID;
|
||||||
|
else //If we're not using a custom chat then it's either can ("everyone") or can't (null) see at most
|
||||||
|
gid = buttondevteam.core.component.channel.Channel.GROUP_EVERYONE; // (Though it's a public chat then rn)
|
||||||
|
AtomicInteger C = new AtomicInteger();
|
||||||
s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream()
|
s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream()
|
||||||
|
.filter(p -> gid.equals(lmd.mcchannel.getGroupID(p))) //If they can see it
|
||||||
|
.filter(MCChatUtils::checkEssentials)
|
||||||
|
.filter(p -> C.incrementAndGet() > 0) //Always true
|
||||||
.map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", "));
|
.map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", "));
|
||||||
|
s[0] = C + " player" + (C.get() != 1 ? "s" : "") + " online";
|
||||||
((TextChannel) lmd.channel).edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait
|
((TextChannel) lmd.channel).edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean checkEssentials(Player p) {
|
||||||
|
var ess = MainPlugin.ess;
|
||||||
|
if (ess == null) return true;
|
||||||
|
return !ess.getUser(p).isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
public static <T extends DiscordSenderBase> T addSender(HashMap<String, HashMap<Snowflake, T>> senders,
|
public static <T extends DiscordSenderBase> T addSender(HashMap<String, HashMap<Snowflake, T>> senders,
|
||||||
User user, T sender) {
|
User user, T sender) {
|
||||||
return addSender(senders, user.getId().asString(), sender);
|
return addSender(senders, user.getId().asString(), sender);
|
||||||
|
|
|
@ -3,7 +3,9 @@ package buttondevteam.discordplugin.mcchat;
|
||||||
import buttondevteam.discordplugin.*;
|
import buttondevteam.discordplugin.*;
|
||||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||||
import buttondevteam.lib.architecture.ConfigData;
|
import buttondevteam.lib.architecture.ConfigData;
|
||||||
import buttondevteam.lib.player.*;
|
import buttondevteam.lib.player.TBMCPlayer;
|
||||||
|
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||||
|
import buttondevteam.lib.player.TBMCYEEHAWEvent;
|
||||||
import com.earth2me.essentials.CommandSource;
|
import com.earth2me.essentials.CommandSource;
|
||||||
import discord4j.core.object.entity.Role;
|
import discord4j.core.object.entity.Role;
|
||||||
import discord4j.core.object.util.Snowflake;
|
import discord4j.core.object.util.Snowflake;
|
||||||
|
@ -18,9 +20,7 @@ import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
import org.bukkit.event.player.PlayerCommandSendEvent;
|
import org.bukkit.event.player.*;
|
||||||
import org.bukkit.event.player.PlayerKickEvent;
|
|
||||||
import org.bukkit.event.player.PlayerLoginEvent;
|
|
||||||
import org.bukkit.event.player.PlayerLoginEvent.Result;
|
import org.bukkit.event.player.PlayerLoginEvent.Result;
|
||||||
import org.bukkit.event.server.BroadcastMessageEvent;
|
import org.bukkit.event.server.BroadcastMessageEvent;
|
||||||
import org.bukkit.event.server.TabCompleteEvent;
|
import org.bukkit.event.server.TabCompleteEvent;
|
||||||
|
@ -44,13 +44,13 @@ class MCListener implements Listener {
|
||||||
.ifPresent(dcp -> MCChatUtils.callLogoutEvent(dcp, false));
|
.ifPresent(dcp -> MCChatUtils.callLogoutEvent(dcp, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerJoin(TBMCPlayerJoinEvent e) {
|
public void onPlayerJoin(PlayerJoinEvent e) {
|
||||||
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
||||||
return; // Don't show the joined message for the fake player
|
return; // Don't show the joined message for the fake player
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class);
|
DiscordPlayer dp = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class).getAs(DiscordPlayer.class);
|
||||||
if (dp != null) {
|
if (dp != null) {
|
||||||
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).flatMap(user -> user.getPrivateChannel().flatMap(chan -> module.chatChannelMono().flatMap(cc -> {
|
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).flatMap(user -> user.getPrivateChannel().flatMap(chan -> module.chatChannelMono().flatMap(cc -> {
|
||||||
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(),
|
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(),
|
||||||
|
@ -60,14 +60,15 @@ class MCListener implements Listener {
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}))).subscribe();
|
}))).subscribe();
|
||||||
}
|
}
|
||||||
final String message = e.GetPlayer().PlayerName().get() + " joined the game";
|
final String message = e.getJoinMessage();
|
||||||
|
if (message != null && message.trim().length() > 0)
|
||||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||||
ChromaBot.getInstance().updatePlayerList();
|
ChromaBot.getInstance().updatePlayerList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerLeave(TBMCPlayerQuitEvent e) {
|
public void onPlayerLeave(PlayerQuitEvent e) {
|
||||||
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
||||||
return; // Only care about real users
|
return; // Only care about real users
|
||||||
MCChatUtils.OnlineSenders.entrySet()
|
MCChatUtils.OnlineSenders.entrySet()
|
||||||
|
@ -78,7 +79,8 @@ class MCListener implements Listener {
|
||||||
.ifPresent(MCChatUtils::callLoginEvents));
|
.ifPresent(MCChatUtils::callLoginEvents));
|
||||||
Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin,
|
Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin,
|
||||||
ChromaBot.getInstance()::updatePlayerList, 5);
|
ChromaBot.getInstance()::updatePlayerList, 5);
|
||||||
final String message = e.GetPlayer().PlayerName().get() + " left the game";
|
final String message = e.getQuitMessage();
|
||||||
|
if (message != null && message.trim().length() > 0)
|
||||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
@ -58,7 +53,7 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
|
||||||
* The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute
|
* The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute
|
||||||
*/
|
*/
|
||||||
public ReadOnlyConfigData<Mono<MessageChannel>> modlogChannel() {
|
public ReadOnlyConfigData<Mono<MessageChannel>> modlogChannel() {
|
||||||
return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L);
|
return DPUtils.channelData(getConfig(), "modlogChannel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,13 +99,19 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
|
||||||
return getConfig().getData("allowPrivateChat", true);
|
return getConfig().getData("allowPrivateChat", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
String clientID;
|
/**
|
||||||
|
* If set, message authors appearing on Discord will link to this URL. A 'type' and 'id' parameter will be added with the user's platform (Discord, Minecraft, ...) and ID.
|
||||||
|
*/
|
||||||
|
public ConfigData<String> profileURL() {
|
||||||
|
return getConfig().getData("profileURL", "");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void enable() {
|
protected void enable() {
|
||||||
if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono()))
|
if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono()))
|
||||||
return;
|
return;
|
||||||
DiscordPlugin.dc.getApplicationInfo().subscribe(info -> clientID = info.getId().asString());
|
/*clientID = DiscordPlugin.dc.getApplicationInfo().blockOptional().map(info->info.getId().asString())
|
||||||
|
.orElse("Unknown"); //Need to block because otherwise it may not be set in time*/
|
||||||
listener = new MCChatListener(this);
|
listener = new MCChatListener(this);
|
||||||
TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin());
|
TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin());
|
||||||
TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled
|
TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled
|
||||||
|
|
|
@ -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.");
|
||||||
|
@ -73,6 +75,10 @@ public class DiscordMCCommand extends ICommand2MC {
|
||||||
})
|
})
|
||||||
public void reset(CommandSender sender) {
|
public void reset(CommandSender sender) {
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
||||||
|
if (!DiscordPlugin.plugin.tryReloadConfig()) {
|
||||||
|
sender.sendMessage("§cFailed to reload config so not resetting. Check the console.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
resetting = true; //Turned off after sending enable message (ReadyEvent)
|
resetting = true; //Turned off after sending enable message (ReadyEvent)
|
||||||
sender.sendMessage("§bDisabling DiscordPlugin...");
|
sender.sendMessage("§bDisabling DiscordPlugin...");
|
||||||
Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin);
|
Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin);
|
||||||
|
@ -97,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);
|
||||||
|
@ -128,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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically collects roles with a certain color (the second to last in the upper row - #95a5a6).
|
||||||
|
* Users can add these roles to themselves using the /role Discord command.
|
||||||
|
*/
|
||||||
public class GameRoleModule extends Component<DiscordPlugin> {
|
public class GameRoleModule extends Component<DiscordPlugin> {
|
||||||
public List<String> GameRoles;
|
public List<String> GameRoles;
|
||||||
|
|
||||||
|
@ -35,8 +39,11 @@ public class GameRoleModule extends Component<DiscordPlugin> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The channel where the bot logs when it detects a role change that results in a new game role or one being removed.
|
||||||
|
*/
|
||||||
private ReadOnlyConfigData<Mono<MessageChannel>> logChannel() {
|
private ReadOnlyConfigData<Mono<MessageChannel>> logChannel() {
|
||||||
return DPUtils.channelData(getConfig(), "logChannel", 239519012529111040L);
|
return DPUtils.channelData(getConfig(), "logChannel");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void handleRoleEvent(RoleEvent roleEvent) {
|
public static void handleRoleEvent(RoleEvent roleEvent) {
|
||||||
|
@ -52,7 +59,7 @@ public class GameRoleModule extends Component<DiscordPlugin> {
|
||||||
return Mono.empty(); //Deleted or not a game role
|
return Mono.empty(); //Deleted or not a game role
|
||||||
GameRoles.add(role.getName());
|
GameRoles.add(role.getName());
|
||||||
if (logChannel != null)
|
if (logChannel != null)
|
||||||
return logChannel.flatMap(ch -> ch.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the default."));
|
return logChannel.flatMap(ch -> ch.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the game role color."));
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}).subscribe();
|
}).subscribe();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
@ -81,7 +88,7 @@ public class GameRoleModule extends Component<DiscordPlugin> {
|
||||||
if (removed)
|
if (removed)
|
||||||
return logChannel.flatMap(ch -> ch.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + "."));
|
return logChannel.flatMap(ch -> ch.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + "."));
|
||||||
else
|
else
|
||||||
return logChannel.flatMap(ch -> ch.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the default color."));
|
return logChannel.flatMap(ch -> ch.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the color of one."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
|
|
|
@ -11,7 +11,6 @@ import lombok.val;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@CommandClass
|
@CommandClass
|
||||||
public class RoleCommand extends ICommand2DC {
|
public class RoleCommand extends ICommand2DC {
|
||||||
|
@ -62,7 +61,20 @@ public class RoleCommand extends ICommand2DC {
|
||||||
|
|
||||||
@Command2.Subcommand
|
@Command2.Subcommand
|
||||||
public void list(Command2DCSender sender) {
|
public void list(Command2DCSender sender) {
|
||||||
sender.sendMessage("list of roles:\n" + grm.GameRoles.stream().sorted().collect(Collectors.joining("\n")));
|
var sb = new StringBuilder();
|
||||||
|
boolean b = false;
|
||||||
|
for (String role : (Iterable<String>) grm.GameRoles.stream().sorted()::iterator) {
|
||||||
|
sb.append(role);
|
||||||
|
if (!b)
|
||||||
|
for (int j = 0; j < Math.max(1, 20 - role.length()); j++)
|
||||||
|
sb.append(" ");
|
||||||
|
else
|
||||||
|
sb.append("\n");
|
||||||
|
b = !b;
|
||||||
|
}
|
||||||
|
if (sb.charAt(sb.length() - 1) != '\n')
|
||||||
|
sb.append('\n');
|
||||||
|
sender.sendMessage("list of roles:\n```\n" + sb + "```");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Role checkAndGetRole(Command2DCSender sender, String rolename) {
|
private Role checkAndGetRole(Command2DCSender sender, String rolename) {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
name: Chroma-Discord
|
name: Chroma-Discord
|
||||||
main: buttondevteam.discordplugin.DiscordPlugin
|
main: buttondevteam.discordplugin.DiscordPlugin
|
||||||
version: 1.0
|
version: '1.0'
|
||||||
author: NorbiPeti
|
author: NorbiPeti
|
||||||
depend: [ChromaCore]
|
depend: [ChromaCore]
|
||||||
|
softdepend:
|
||||||
|
- Essentials
|
||||||
commands:
|
commands:
|
||||||
discord:
|
discord:
|
||||||
website: 'https://github.com/TBMCPlugins/DiscordPlugin'
|
website: 'https://github.com/TBMCPlugins/DiscordPlugin'
|
||||||
|
|
Loading…
Reference in a new issue