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>
|
||||
<groupId>com.discord4j</groupId>
|
||||
<artifactId>discord4j-core</artifactId>
|
||||
<version>3.0.10</version>
|
||||
<version>3.0.12</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
|
||||
<dependency>
|
||||
|
|
|
@ -15,11 +15,17 @@ import lombok.val;
|
|||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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() {
|
||||
|
@ -60,8 +83,8 @@ public final class DPUtils {
|
|||
return DiscordPlugin.plugin.getLogger();
|
||||
}
|
||||
|
||||
public static ReadOnlyConfigData<Mono<MessageChannel>> channelData(IHaveConfig config, String key, long defID) {
|
||||
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)
|
||||
public static ReadOnlyConfigData<Mono<MessageChannel>> channelData(IHaveConfig config, String key) {
|
||||
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) {
|
||||
|
@ -73,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,12 +160,27 @@ public final class DPUtils {
|
|||
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) {
|
||||
Mono<MessageChannel> ch;
|
||||
if (channel == null)
|
||||
ch = original.getChannel();
|
||||
else
|
||||
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()
|
||||
? original.getAuthor().get().getMention() + ", " : "") + message));
|
||||
}
|
||||
|
@ -152,7 +193,15 @@ public final class DPUtils {
|
|||
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) {
|
||||
if (id.asLong() == 0L) return Mono.empty();
|
||||
return DiscordPlugin.dc.getChannelById(id).onErrorResume(e -> {
|
||||
getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage());
|
||||
return Mono.empty();
|
||||
|
|
|
@ -44,7 +44,6 @@ import java.awt.*;
|
|||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -56,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);
|
||||
}
|
||||
|
@ -65,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 -> {
|
||||
|
@ -77,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");
|
||||
|
@ -101,6 +110,7 @@ public class DiscordPlugin extends ButtonPlugin {
|
|||
getLogger().info("Initializing...");
|
||||
plugin = this;
|
||||
manager = new Command2DC();
|
||||
getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works
|
||||
String token;
|
||||
File tokenFile = new File("TBMC", "Token.txt");
|
||||
if (tokenFile.exists()) //Legacy support
|
||||
|
@ -114,8 +124,9 @@ public class DiscordPlugin extends ButtonPlugin {
|
|||
conf.set("token", "Token goes here");
|
||||
conf.save(privateFile);
|
||||
|
||||
getLogger().severe("Token not found! Set it in private.yml");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
getLogger().severe("Token not found! Please set it in private.yml then do /discord reset");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -133,8 +144,8 @@ public class DiscordPlugin extends ButtonPlugin {
|
|||
//dc.getEventDispatcher().on(DisconnectEvent.class);
|
||||
dc.login().subscribe();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
TBMCCoreAPI.SendException("Failed to enable the Discord plugin!", e);
|
||||
getLogger().severe("You may be able to reset the plugin using /discord reset");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,10 +155,10 @@ public class DiscordPlugin extends ButtonPlugin {
|
|||
try {
|
||||
if (mainServer != null) { //This is not the first ready event
|
||||
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;
|
||||
}
|
||||
mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards
|
||||
getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works
|
||||
if (mainServer == null) {
|
||||
if (event.size() == 0) {
|
||||
getLogger().severe("Main server not found! Invite the bot and do /discord reset");
|
||||
|
@ -163,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());
|
||||
|
@ -196,14 +207,6 @@ public class DiscordPlugin extends ButtonPlugin {
|
|||
|
||||
getConfig().set("serverup", true);
|
||||
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.SendUnsentDebugMessages();
|
||||
|
||||
|
|
|
@ -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,25 +16,26 @@ 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.
|
||||
*/
|
||||
public ReadOnlyConfigData<Mono<MessageChannel>> channel() {
|
||||
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
|
||||
return DPUtils.channelData(getConfig(), "channel");
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel where distinguished (moderator) posts go.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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", 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) {
|
||||
return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
@ -96,7 +97,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
|
|||
}
|
||||
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;
|
||||
lastlistp = (short) Bukkit.getOnlinePlayers().size();
|
||||
return true; //Handled
|
||||
|
@ -108,7 +109,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
|
|||
if (usableServerReadyStrings.size() == 0)
|
||||
fm.createUsableServerReadyStrings();
|
||||
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;
|
||||
|
@ -119,13 +120,19 @@ 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", 219626707458457603L);
|
||||
return DPUtils.channelData(getConfig(), "fullHouseChannel");
|
||||
}
|
||||
|
||||
private static long lasttime = 0;
|
||||
|
|
|
@ -62,7 +62,7 @@ public class CommandListener {
|
|||
try {
|
||||
timings.printElapsed("F");
|
||||
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);
|
||||
} catch (Exception 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.CommandClass;
|
||||
import buttondevteam.lib.player.TBMCPlayer;
|
||||
import discord4j.core.object.entity.GuildChannel;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
@ -22,6 +27,7 @@ import java.util.Objects;
|
|||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("SimplifyOptionalCallChains") //Java 11
|
||||
@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).", //
|
||||
"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
|
||||
public class ChannelconCommand extends ICommand2DC {
|
||||
private final MinecraftChatModule module;
|
||||
|
||||
@Command2.Subcommand
|
||||
public boolean remove(Command2DCSender sender) {
|
||||
val message = sender.getMessage();
|
||||
if (checkPerms(message)) return true;
|
||||
if (checkPerms(message, null)) return true;
|
||||
if (MCChatCustom.removeCustomChat(message.getChannelId()))
|
||||
DPUtils.reply(message, null, "channel connection removed.").subscribe();
|
||||
DPUtils.reply(message, Mono.empty(), "channel connection removed.").subscribe();
|
||||
else
|
||||
DPUtils.reply(message, null, "this channel isn't connected.").subscribe();
|
||||
DPUtils.reply(message, Mono.empty(), "this channel isn't connected.").subscribe();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Command2.Subcommand
|
||||
public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) {
|
||||
val message = sender.getMessage();
|
||||
if (checkPerms(message)) return true;
|
||||
if (checkPerms(message, null)) return true;
|
||||
val cc = MCChatCustom.getCustomChat(message.getChannelId());
|
||||
if (cc == null)
|
||||
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"))
|
||||
+ "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n"));
|
||||
if (toggle == null) {
|
||||
DPUtils.reply(message, null, "toggles:\n" + togglesString.get()).subscribe();
|
||||
DPUtils.reply(message, Mono.empty(), "toggles:\n" + togglesString.get()).subscribe();
|
||||
return true;
|
||||
}
|
||||
String arg = toggle.toUpperCase();
|
||||
|
@ -65,7 +72,7 @@ public class ChannelconCommand extends ICommand2DC {
|
|||
if (!b.isPresent()) {
|
||||
val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg);
|
||||
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;
|
||||
}
|
||||
final boolean add;
|
||||
|
@ -83,7 +90,7 @@ public class ChannelconCommand extends ICommand2DC {
|
|||
//1 1 | 0
|
||||
// XOR
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -94,12 +101,13 @@ public class ChannelconCommand extends ICommand2DC {
|
|||
sender.sendMessage("channel connection is not allowed on this Minecraft server.");
|
||||
return true;
|
||||
}
|
||||
if (checkPerms(message)) return true;
|
||||
val channel = message.getChannel().block();
|
||||
if (checkPerms(message, channel)) return true;
|
||||
if (MCChatCustom.hasCustomChat(message.getChannelId()))
|
||||
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();
|
||||
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;
|
||||
}
|
||||
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 chp = dp.getAs(TBMCPlayer.class);
|
||||
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;
|
||||
}
|
||||
val channel = message.getChannel().block();
|
||||
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
|
||||
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
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
/*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?
|
||||
MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>());
|
||||
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
|
||||
DPUtils.reply(message, null, "alright, connection made to group `" + groupid + "`!").subscribe();
|
||||
DPUtils.reply(message, channel, "alright, connection made to group `" + groupid + "`!").subscribe();
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private boolean checkPerms(Message message) {
|
||||
if (!message.getAuthorAsMember().block().getBasePermissions().block().contains(Permission.MANAGE_CHANNELS)) {
|
||||
DPUtils.reply(message, null, "you need to have manage permissions for this channel!").subscribe();
|
||||
private boolean checkPerms(Message message, @Nullable MessageChannel channel) {
|
||||
if (channel == null)
|
||||
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 false;
|
||||
|
@ -145,17 +159,17 @@ public class ChannelconCommand extends ICommand2DC {
|
|||
|
||||
@Override
|
||||
public String[] getHelpText(Method method, Command2.Subcommand ann) {
|
||||
return new String[]{ //
|
||||
"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).", //
|
||||
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
|
||||
"You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect <mcname>.", //
|
||||
"Call this command from the channel you want to use.", //
|
||||
return new String[]{ //
|
||||
"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).", //
|
||||
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
|
||||
"You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect <mcname>.", //
|
||||
"Call this command from the channel you want to use.", //
|
||||
"Usage: " + Objects.requireNonNull(DiscordPlugin.dc.getSelf().block()).getMention() + " channelcon <mcchannel>", //
|
||||
"Use the ID (command) of the channel, for example `g` for the global chat.", //
|
||||
"To remove a connection use @ChromaBot channelcon remove in the channel.", //
|
||||
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", //
|
||||
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=" + module.clientID + "&scope=bot&permissions=268509264>"
|
||||
};
|
||||
}
|
||||
"Use the ID (command) of the channel, for example `g` for the global chat.", //
|
||||
"To remove a connection use @ChromaBot channelcon remove in the channel.", //
|
||||
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", //
|
||||
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=" + 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();
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get();
|
||||
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;
|
||||
}
|
||||
try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) {
|
||||
boolean mcchat = !user.isMinecraftChatEnabled();
|
||||
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." //
|
||||
: "disabled.")).subscribe();
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -84,13 +84,14 @@ public class MCChatListener implements Listener {
|
|||
final Consumer<EmbedCreateSpec> embed = ecs -> {
|
||||
ecs.setDescription(e.getMessage()).setColor(new Color(color.getRed(),
|
||||
color.getGreen(), color.getBlue()));
|
||||
String url = module.profileURL().get();
|
||||
if (e.getSender() instanceof Player)
|
||||
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(),
|
||||
"https://tbmcplugins.github.io/profile.html?type=minecraft&id="
|
||||
+ ((Player) e.getSender()).getUniqueId());
|
||||
url.length() > 0 ? url + "?type=minecraft&id="
|
||||
+ ((Player) e.getSender()).getUniqueId() : null);
|
||||
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
|
||||
+ ((DiscordSenderBase) e.getSender()).getUser().getId().asString(),
|
||||
ecs.setAuthor(authorPlayer, url.length() > 0 ? url + "?type=discord&id="
|
||||
+ ((DiscordSenderBase) e.getSender()).getUser().getId().asString() : null,
|
||||
((DiscordSenderBase) e.getSender()).getUser().getAvatarUrl());
|
||||
else
|
||||
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(), null);
|
||||
|
@ -101,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();
|
||||
|
@ -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 = 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 -> //
|
||||
msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage()
|
||||
.getAttachments().stream().map(Attachment::getUrl).collect(Collectors.joining("\n"))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.core.ComponentManager;
|
||||
import buttondevteam.core.MainPlugin;
|
||||
import buttondevteam.discordplugin.*;
|
||||
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
|
@ -13,6 +14,7 @@ import lombok.RequiredArgsConstructor;
|
|||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
|
@ -30,6 +32,7 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
|
@ -81,13 +84,27 @@ public class MCChatUtils {
|
|||
String[] s = topic.split("\\n----\\n");
|
||||
if (s.length < 3)
|
||||
return;
|
||||
s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "")
|
||||
+ " online";
|
||||
String gid;
|
||||
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()
|
||||
.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(", "));
|
||||
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
|
||||
}
|
||||
|
||||
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,
|
||||
User user, T sender) {
|
||||
return addSender(senders, user.getId().asString(), sender);
|
||||
|
|
|
@ -3,7 +3,9 @@ package buttondevteam.discordplugin.mcchat;
|
|||
import buttondevteam.discordplugin.*;
|
||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||
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 discord4j.core.object.entity.Role;
|
||||
import discord4j.core.object.util.Snowflake;
|
||||
|
@ -18,9 +20,7 @@ import org.bukkit.event.EventHandler;
|
|||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerCommandSendEvent;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.event.player.PlayerLoginEvent.Result;
|
||||
import org.bukkit.event.server.BroadcastMessageEvent;
|
||||
import org.bukkit.event.server.TabCompleteEvent;
|
||||
|
@ -44,13 +44,13 @@ class MCListener implements Listener {
|
|||
.ifPresent(dcp -> MCChatUtils.callLogoutEvent(dcp, false));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(TBMCPlayerJoinEvent e) {
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent e) {
|
||||
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
||||
return; // Don't show the joined message for the fake player
|
||||
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
||||
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) {
|
||||
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).flatMap(user -> user.getPrivateChannel().flatMap(chan -> module.chatChannelMono().flatMap(cc -> {
|
||||
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(),
|
||||
|
@ -60,14 +60,15 @@ class MCListener implements Listener {
|
|||
return Mono.empty();
|
||||
}))).subscribe();
|
||||
}
|
||||
final String message = e.GetPlayer().PlayerName().get() + " joined the game";
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||
final String message = e.getJoinMessage();
|
||||
if (message != null && message.trim().length() > 0)
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||
ChromaBot.getInstance().updatePlayerList();
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerLeave(TBMCPlayerQuitEvent e) {
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLeave(PlayerQuitEvent e) {
|
||||
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
||||
return; // Only care about real users
|
||||
MCChatUtils.OnlineSenders.entrySet()
|
||||
|
@ -78,8 +79,9 @@ class MCListener implements Listener {
|
|||
.ifPresent(MCChatUtils::callLoginEvents));
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin,
|
||||
ChromaBot.getInstance()::updatePlayerList, 5);
|
||||
final String message = e.GetPlayer().PlayerName().get() + " left the game";
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||
final String message = e.getQuitMessage();
|
||||
if (message != null && message.trim().length() > 0)
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
protected void enable() {
|
||||
if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono()))
|
||||
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);
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin());
|
||||
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 {
|
||||
@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.");
|
||||
|
@ -73,6 +75,10 @@ public class DiscordMCCommand extends ICommand2MC {
|
|||
})
|
||||
public void reset(CommandSender sender) {
|
||||
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)
|
||||
sender.sendMessage("§bDisabling DiscordPlugin...");
|
||||
Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin);
|
||||
|
@ -97,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);
|
||||
|
@ -128,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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
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 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() {
|
||||
return DPUtils.channelData(getConfig(), "logChannel", 239519012529111040L);
|
||||
return DPUtils.channelData(getConfig(), "logChannel");
|
||||
}
|
||||
|
||||
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
|
||||
GameRoles.add(role.getName());
|
||||
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();
|
||||
}).subscribe();
|
||||
}, 100);
|
||||
|
@ -81,7 +88,7 @@ public class GameRoleModule extends Component<DiscordPlugin> {
|
|||
if (removed)
|
||||
return logChannel.flatMap(ch -> ch.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + "."));
|
||||
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();
|
||||
|
|
|
@ -11,7 +11,6 @@ import lombok.val;
|
|||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@CommandClass
|
||||
public class RoleCommand extends ICommand2DC {
|
||||
|
@ -62,7 +61,20 @@ public class RoleCommand extends ICommand2DC {
|
|||
|
||||
@Command2.Subcommand
|
||||
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) {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
name: Chroma-Discord
|
||||
main: buttondevteam.discordplugin.DiscordPlugin
|
||||
version: 1.0
|
||||
version: '1.0'
|
||||
author: NorbiPeti
|
||||
depend: [ChromaCore]
|
||||
softdepend:
|
||||
- Essentials
|
||||
commands:
|
||||
discord:
|
||||
website: 'https://github.com/TBMCPlugins/DiscordPlugin'
|
||||
|
|
Loading…
Reference in a new issue