diff --git a/.gitignore b/.gitignore index da21785..da438c0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /build /classes /run +/out /*.iml /bin/ /.settings/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ff9b095..4110633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ - Change JavaCord to JDA for Discord API support - Upgrade to Minecraft 1.12 +## 2.4.2 +- Add support for sending a player first join message when Nucleus is present. + +## 2.4.1 +- Update Discord API to support categories. +- Add Custom Emoji Handling. +- Fix pinning a message on Discord sending a blank message to Minecraft. + ## 2.4.0 - Support sending message to Discord when a player die (check `deathTemplate`). - Discord Bridge now ignores only messages from Discord Bridge and from the same server. Previously, the plugin ignores all messages from Discord Bridge regardless different servers. diff --git a/README.md b/README.md index f75f43f..0d75ac6 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Configuration is stored in `config.json` file. - `authenticatedChatTemplate`: (optional) template for messages from Minecraft to Discord for authenticated user - `broadcastTemplate`: (optional) template for messages in Discord from `/discord broadcast` command - `deathTemplate`: (optional) template for a message in Discord when a player dies _(thanks, Mohron)_ + - `firstJoinTemplate`: (optional, requires Nucleus) template for a message in Discord when a player first joins _(thanks, Mohron)_ - `minecraft`: templates in Minecraft - `chatTemplate`: (optional) template for messages from Discord to Minecraft. For supporting placeholders in the template, check the section **Chat placeholder** - `attachment`: _(thanks, Mohron)_ diff --git a/build.gradle b/build.gradle index 6463fc7..d890ce7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'com.github.johnrengelman.shadow' version '1.2.3' + id 'com.github.johnrengelman.shadow' version '2.0.2' } defaultTasks 'build', 'shadowJar' @@ -13,29 +13,29 @@ sourceCompatibility = 1.8 repositories { mavenCentral() maven { - name 'Sonatype' - url 'https://oss.sonatype.org/content/repositories/snapshots/' + name = 'Sonatype' + url = 'https://oss.sonatype.org/content/repositories/snapshots/' } maven { - name 'sponge' - url 'http://repo.spongepowered.org/maven' + name = 'sponge' + url = 'http://repo.spongepowered.org/maven' + } + maven { + name = 'jitpack.io' + url = 'https://jitpack.io' + } + maven { + name = "Nucleus" + url = "http://repo.drnaylor.co.uk/artifactory/list/minecraft" } jcenter() } dependencies { - compile('org.spongepowered:spongeapi:7.0.0') - //compile('org.spongepowered:spongeapi:5.0.0') - //compile files('libs/javacord-2.0.14-shaded.jar') - compile 'net.dv8tion:JDA:3.4.0_320' + compile 'org.spongepowered:spongeapi:7.+' + compile 'net.dv8tion:JDA:3.5.1_339' compile 'com.mashape.unirest:unirest-java:1.4.9' -// compile('de.btobastian.javacord:javacord:2.0.11:shaded') -// compile "com.github.austinv11:Discord4j:2.4.9:shaded" -// compile 'org.apache.httpcomponents:httpcore:4.3.2' -// compile 'org.apache.httpcomponents:httpclient:4.3.3' -// compile 'org.java-websocket:Java-WebSocket:1.3.0' -// compile 'com.googlecode.json-simple:json-simple:1.1.1' -// compile 'net.jodah:typetools:0.4.3' + compile 'io.github.nucleuspowered:nucleus-api:+' } task fatJar(type: Jar) { @@ -50,11 +50,10 @@ shadowJar { include dependency('org.apache.commons:commons-lang3') include dependency('org.apache.httpcomponents:httpcore') include dependency('org.apache.httpcomponents:httpclient') -// include dependency('com.googlecode.json-simple:json-simple') -// include dependency('org.java-websocket:Java-WebSocket') -// include dependency('net.jodah:typetools') relocate 'org.apache.http', 'shaded.apache.http' relocate 'org.apache.commons', 'shaded.apache.commons' } -} \ No newline at end of file +} + +build.dependsOn(shadowJar) diff --git a/examples/config-multiple.json b/examples/config-multiple.json index 6403816..30aa24d 100644 --- a/examples/config-multiple.json +++ b/examples/config-multiple.json @@ -52,6 +52,7 @@ "leftTemplate": "_%s just left the server_", "serverUpMessage": "Server has started.", "serverDownMessage": "Server has stopped.", + "firstJoinTemplate": "_Welcome **%a** to the server!_", "deathTemplate": "**%s**" } }, diff --git a/examples/config-simple.json b/examples/config-simple.json index 4255d26..a4653df 100644 --- a/examples/config-simple.json +++ b/examples/config-simple.json @@ -18,6 +18,7 @@ "leftTemplate": "_%s just left the server_", "serverUpMessage": "Server has started.", "serverDownMessage": "Server has stopped.", + "firstJoinTemplate": "_Welcome **%a** to the server!_", "broadcastTemplate": "_ %s_", "deathTemplate": "**%s**" }, diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2322723..99340b4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8c70571..ea720f9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Wed Jan 06 14:03:12 SGT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..cccdd3d 100644 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282..f955316 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/src/main/java/com/nguyenquyhy/discordbridge/DiscordBridge.java b/src/main/java/com/nguyenquyhy/discordbridge/DiscordBridge.java index 8a8b382..8473453 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/DiscordBridge.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/DiscordBridge.java @@ -5,6 +5,7 @@ import com.nguyenquyhy.discordbridge.listeners.ChatListener; import com.nguyenquyhy.discordbridge.listeners.ClientConnectionListener; import com.nguyenquyhy.discordbridge.listeners.DeathListener; +import com.nguyenquyhy.discordbridge.listeners.FirstJoinListener; import com.nguyenquyhy.discordbridge.logics.ConfigHandler; import com.nguyenquyhy.discordbridge.logics.LoginHandler; import com.nguyenquyhy.discordbridge.models.ChannelConfig; @@ -12,7 +13,7 @@ import com.nguyenquyhy.discordbridge.utils.ChannelUtil; import com.nguyenquyhy.discordbridge.utils.ErrorMessages; import net.dv8tion.jda.core.JDA; -import net.dv8tion.jda.core.entities.*; +import net.dv8tion.jda.core.entities.TextChannel; import ninja.leaping.configurate.objectmapping.ObjectMappingException; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -20,7 +21,9 @@ import org.spongepowered.api.Sponge; import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.game.state.*; +import org.spongepowered.api.event.game.state.GameInitializationEvent; +import org.spongepowered.api.event.game.state.GameStartingServerEvent; +import org.spongepowered.api.event.game.state.GameStoppingServerEvent; import org.spongepowered.api.plugin.Plugin; import java.io.IOException; @@ -55,6 +58,7 @@ public class DiscordBridge { private IStorage storage; private static DiscordBridge instance; + private int playerCount = 0; @Listener public void onInitialization(GameInitializationEvent event) throws IOException, ObjectMappingException { @@ -64,10 +68,14 @@ public void onInitialization(GameInitializationEvent event) throws IOException, Sponge.getEventManager().registerListeners(this, new ChatListener()); Sponge.getEventManager().registerListeners(this, new ClientConnectionListener()); Sponge.getEventManager().registerListeners(this, new DeathListener()); + + if (Sponge.getPluginManager().isLoaded("nucleus")) { + Sponge.getEventManager().registerListeners(this, new FirstJoinListener()); + } } @Listener - public void onServerStart(GameStartedServerEvent event) { + public void onServerStarting(GameStartingServerEvent event) { CommandRegistry.register(); LoginHandler.loginBotAccount(); } @@ -82,6 +90,7 @@ public void onServerStop(GameStoppingServerEvent event) { TextChannel channel = botClient.getTextChannelById(channelConfig.discordId); if (channel != null) { ChannelUtil.sendMessage(channel, channelConfig.discord.serverDownMessage); + ChannelUtil.setDescription(channel, "Offline"); } else { ErrorMessages.CHANNEL_NOT_FOUND.log(channelConfig.discordId); } @@ -146,6 +155,14 @@ public void addClient(UUID player, JDA client) { } } + public void setPlayerCount(int change) { + playerCount += change; + } + + public int getPlayerCount() { + return playerCount; + } + public void removeAndLogoutClient(UUID player) { if (player == null) { consoleClient.shutdown(); diff --git a/src/main/java/com/nguyenquyhy/discordbridge/hooks/Boop.java b/src/main/java/com/nguyenquyhy/discordbridge/hooks/Boop.java new file mode 100644 index 0000000..1e818c9 --- /dev/null +++ b/src/main/java/com/nguyenquyhy/discordbridge/hooks/Boop.java @@ -0,0 +1,8 @@ +package com.nguyenquyhy.discordbridge.hooks; + +public class Boop { + + public static String getMessageChannelClass() { + return "flavor.pie.boop.BoopableChannel"; + } +} diff --git a/src/main/java/com/nguyenquyhy/discordbridge/hooks/Nucleus.java b/src/main/java/com/nguyenquyhy/discordbridge/hooks/Nucleus.java new file mode 100644 index 0000000..cff22c1 --- /dev/null +++ b/src/main/java/com/nguyenquyhy/discordbridge/hooks/Nucleus.java @@ -0,0 +1,8 @@ +package com.nguyenquyhy.discordbridge.hooks; + +public class Nucleus { + + public static String getStaffMessageChannelClass() { + return "io.github.nucleuspowered.nucleus.modules.staffchat.StaffChatMessageChannel"; + } +} \ No newline at end of file diff --git a/src/main/java/com/nguyenquyhy/discordbridge/listeners/ChatListener.java b/src/main/java/com/nguyenquyhy/discordbridge/listeners/ChatListener.java index d92393f..a68bd60 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/listeners/ChatListener.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/listeners/ChatListener.java @@ -1,6 +1,8 @@ package com.nguyenquyhy.discordbridge.listeners; import com.nguyenquyhy.discordbridge.DiscordBridge; +import com.nguyenquyhy.discordbridge.hooks.Boop; +import com.nguyenquyhy.discordbridge.hooks.Nucleus; import com.nguyenquyhy.discordbridge.models.ChannelConfig; import com.nguyenquyhy.discordbridge.models.GlobalConfig; import com.nguyenquyhy.discordbridge.utils.ChannelUtil; @@ -12,41 +14,43 @@ import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Order; +import org.spongepowered.api.event.filter.cause.First; import org.spongepowered.api.event.message.MessageChannelEvent; -import org.spongepowered.api.text.Text; import org.spongepowered.api.text.channel.MessageChannel; -import java.util.Optional; -import java.util.UUID; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Created by Hy on 10/13/2016. */ public class ChatListener { + DiscordBridge mod = DiscordBridge.getInstance(); + //0 - CustomNPC's + List fakePlayerUUIDs = new ArrayList(Collections.singletonList("c9c843f8-4cb1-4c82-aa61-e264291b7bd6")); + /** * Send chat from Minecraft to Discord * * @param event */ @Listener(order = Order.LATE) - public void onChat(MessageChannelEvent.Chat event) { + public void onChat(MessageChannelEvent.Chat event, @First Player player) { - if (event.isCancelled() || event.isMessageCancelled()) return; - - sendToDiscord(event); - formatForMinecraft(event); - } + if (event.isMessageCancelled()) return; - private void sendToDiscord(MessageChannelEvent.Chat event) { GlobalConfig config = mod.getConfig(); boolean isStaffChat = false; if (event.getChannel().isPresent()) { MessageChannel channel = event.getChannel().get(); - if (channel.getClass().getName().equals("io.github.nucleuspowered.nucleus.modules.staffchat.StaffChatMessageChannel")) + if (channel.getClass().getName().equals(Nucleus.getStaffMessageChannelClass())) isStaffChat = true; + else if (channel.getClass().getName().equals(Boop.getMessageChannelClass())) + isStaffChat = false; else if (!channel.getClass().getName().startsWith("org.spongepowered.api.text.channel.MessageChannel")) return; // Ignore all other types } @@ -54,95 +58,60 @@ else if (!channel.getClass().getName().startsWith("org.spongepowered.api.text.ch String plainString = event.getRawMessage().toPlain().trim(); if (StringUtils.isBlank(plainString) || plainString.startsWith("/")) return; + // Replace with processed message body - Allows token processing to occur + plainString = event.getFormatter().getBody().toText().toPlain().trim(); + plainString = TextUtil.formatMinecraftMessage(plainString); - Optional player = event.getCause().first(Player.class); - if (player.isPresent()) { - UUID playerId = player.get().getUniqueId(); + //Filters out fake player messages, such as CustomNPC messages. + if (fakePlayerUUIDs.contains(player.getUniqueId().toString())) return; - JDA client = mod.getBotClient(); - boolean isBotAccount = true; - if (mod.getHumanClients().containsKey(playerId)) { - client = mod.getHumanClients().get(playerId); - isBotAccount = false; - } + JDA client = mod.getBotClient(); + boolean isBotAccount = true; + if (mod.getHumanClients().containsKey(player.getUniqueId())) { + client = mod.getHumanClients().get(player.getUniqueId()); + isBotAccount = false; + } - if (client != null) { - for (ChannelConfig channelConfig : config.channels) { - if (StringUtils.isNotBlank(channelConfig.discordId) && channelConfig.discord != null) { - String template = null; - if (!isStaffChat && channelConfig.discord.publicChat != null) { - template = isBotAccount ? channelConfig.discord.publicChat.anonymousChatTemplate : channelConfig.discord.publicChat.authenticatedChatTemplate; - } else if (isStaffChat && channelConfig.discord.staffChat != null) { - template = isBotAccount ? channelConfig.discord.staffChat.anonymousChatTemplate : channelConfig.discord.staffChat.authenticatedChatTemplate; - } + if (client != null) { + for (ChannelConfig channelConfig : config.channels) { + if (StringUtils.isNotBlank(channelConfig.discordId) && channelConfig.discord != null) { + String template = null; + if (!isStaffChat && channelConfig.discord.publicChat != null) { + template = isBotAccount ? channelConfig.discord.publicChat.anonymousChatTemplate : channelConfig.discord.publicChat.authenticatedChatTemplate; + } else if (isStaffChat && channelConfig.discord.staffChat != null) { + template = isBotAccount ? channelConfig.discord.staffChat.anonymousChatTemplate : channelConfig.discord.staffChat.authenticatedChatTemplate; + } - if (StringUtils.isNotBlank(template)) { - TextChannel channel = client.getTextChannelById(channelConfig.discordId); + if (StringUtils.isNotBlank(template)) { + TextChannel channel = client.getTextChannelById(channelConfig.discordId); - if (channel == null) { - ErrorMessages.CHANNEL_NOT_FOUND.log(channelConfig.discordId); - return; - } + if (channel == null) { + ErrorMessages.CHANNEL_NOT_FOUND.log(channelConfig.discordId); + return; + } - // Format Mentions for Discord - plainString = TextUtil.formatMinecraftMention(plainString, channel.getGuild(), player.get(), isBotAccount); + // Format Mentions for Discord + plainString = TextUtil.formatMinecraftMention(plainString, channel.getGuild(), player, isBotAccount); - if (isBotAccount) { + if (isBotAccount) { // if (channel == null) { // LoginHandler.loginBotAccount(); // } - String content = String.format( - template.replace("%a", - TextUtil.escapeForDiscord(player.get().getName(), template, "%a")), - plainString); - ChannelUtil.sendMessage(channel, content); - } else { + String content = String.format( + template.replace("%a", + TextUtil.escapeForDiscord(player.getName(), template, "%a")), + plainString); + ChannelUtil.sendMessage(channel, content); + } else { // if (channel == null) { // LoginHandler.loginHumanAccount(player.get()); // } - ChannelUtil.sendMessage(channel, String.format(template, plainString)); - } + ChannelUtil.sendMessage(channel, String.format(template, plainString)); } } } } } } - - private void formatForMinecraft(MessageChannelEvent.Chat event) { - Text rawMessage = event.getRawMessage(); - Optional player = event.getCause().first(Player.class); - - if (player.isPresent()) { -/* UUID playerId = player.get().getUniqueId(); - - for (ChannelConfig channelConfig : config.channels) { - String template = null; - - Channel channel = client.getChannelById(channelConfig.discordId); - - Optional userOptional = DiscordUtil.getUserByName(player.get().getName(), channel.getServer()); - if (userOptional.isPresent()) { - User user = userOptional.get(); - } - - ChannelMinecraftConfigCore minecraftConfig = channelConfig.minecraft; - if (channelConfig.minecraft.roles != null) { - Collection roles = message.getAuthor().getRoles(message.getChannelReceiver().getServer()); - for (String roleName : channelConfig.minecraft.roles.keySet()) { - if (roles.stream().anyMatch(r -> r.getName().equals(roleName))) { - ChannelMinecraftConfigCore roleConfig = channelConfig.minecraft.roles.get(roleName); - roleConfig.inherit(channelConfig.minecraft); - minecraftConfig = roleConfig; - break; - } - } - } - } - - event.setMessage(rawMessage);*/ - } - - } -} \ No newline at end of file +} diff --git a/src/main/java/com/nguyenquyhy/discordbridge/listeners/ClientConnectionListener.java b/src/main/java/com/nguyenquyhy/discordbridge/listeners/ClientConnectionListener.java index 73e3c7e..abf8114 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/listeners/ClientConnectionListener.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/listeners/ClientConnectionListener.java @@ -12,26 +12,27 @@ import org.apache.commons.lang3.StringUtils; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.filter.cause.First; import org.spongepowered.api.event.network.ClientConnectionEvent; -import java.util.Optional; import java.util.UUID; /** * Created by Hy on 10/13/2016. */ public class ClientConnectionListener { + @Listener - public void onJoin(ClientConnectionEvent.Join event) { - DiscordBridge mod = DiscordBridge.getInstance(); - GlobalConfig config = mod.getConfig(); + public void onJoin(ClientConnectionEvent.Join event, @First Player player) { + if (!player.hasPermission("nucleus.connectionmessages.disable")) { + DiscordBridge mod = DiscordBridge.getInstance(); + GlobalConfig config = mod.getConfig(); + + UUID playerId = player.getUniqueId(); - Optional player = event.getCause().first(Player.class); - if (player.isPresent()) { - UUID playerId = player.get().getUniqueId(); boolean loggingIn = false; if (!mod.getHumanClients().containsKey(playerId)) { - loggingIn = LoginHandler.loginHumanAccount(player.get()); + loggingIn = LoginHandler.loginHumanAccount(player); } if (!loggingIn && mod.getBotClient() != null) { @@ -43,11 +44,13 @@ public void onJoin(ClientConnectionEvent.Join event) { TextChannel channel = mod.getBotClient().getTextChannelById(channelConfig.discordId); if (channel != null) { String content = String.format(channelConfig.discord.joinedTemplate, - TextUtil.escapeForDiscord(player.get().getName(), channelConfig.discord.joinedTemplate, "%s")); + TextUtil.escapeForDiscord(player.getName(), channelConfig.discord.joinedTemplate, "%s")); ChannelUtil.sendMessage(channel, content); } else { ErrorMessages.CHANNEL_NOT_FOUND.log(channelConfig.discordId); } + mod.setPlayerCount(1); + ChannelUtil.setDescription(channel, "Online - Number of Players: " + mod.getPlayerCount()); } } } @@ -55,13 +58,12 @@ public void onJoin(ClientConnectionEvent.Join event) { } @Listener - public void onDisconnect(ClientConnectionEvent.Disconnect event) { - DiscordBridge mod = DiscordBridge.getInstance(); - GlobalConfig config = mod.getConfig(); + public void onDisconnect(ClientConnectionEvent.Disconnect event, @First Player player) { + if (!player.hasPermission("nucleus.connectionmessages.disable")) { + DiscordBridge mod = DiscordBridge.getInstance(); + GlobalConfig config = mod.getConfig(); - Optional player = event.getCause().first(Player.class); - if (player.isPresent()) { - UUID playerId = player.get().getUniqueId(); + UUID playerId = player.getUniqueId(); JDA client = mod.getHumanClients().get(playerId); if (client == null) client = mod.getBotClient(); @@ -73,15 +75,17 @@ public void onDisconnect(ClientConnectionEvent.Disconnect event) { TextChannel channel = client.getTextChannelById(channelConfig.discordId); if (channel != null) { String content = String.format(channelConfig.discord.leftTemplate, - TextUtil.escapeForDiscord(player.get().getName(), channelConfig.discord.leftTemplate, "%s")); + TextUtil.escapeForDiscord(player.getName(), channelConfig.discord.leftTemplate, "%s")); ChannelUtil.sendMessage(channel, content); } else { ErrorMessages.CHANNEL_NOT_FOUND.log(channelConfig.discordId); } + mod.setPlayerCount(-1); + ChannelUtil.setDescription(channel, "Online - Number of Players: " + mod.getPlayerCount()); } mod.removeAndLogoutClient(playerId); //unauthenticatedPlayers.remove(playerId); - mod.getLogger().info(player.get().getName() + " has disconnected!"); + mod.getLogger().info(player.getName() + " has disconnected!"); } } } diff --git a/src/main/java/com/nguyenquyhy/discordbridge/listeners/FirstJoinListener.java b/src/main/java/com/nguyenquyhy/discordbridge/listeners/FirstJoinListener.java new file mode 100644 index 0000000..f452e9a --- /dev/null +++ b/src/main/java/com/nguyenquyhy/discordbridge/listeners/FirstJoinListener.java @@ -0,0 +1,50 @@ +package com.nguyenquyhy.discordbridge.listeners; + +import com.nguyenquyhy.discordbridge.DiscordBridge; +import com.nguyenquyhy.discordbridge.models.ChannelConfig; +import com.nguyenquyhy.discordbridge.models.GlobalConfig; +import com.nguyenquyhy.discordbridge.utils.ChannelUtil; +import com.nguyenquyhy.discordbridge.utils.ErrorMessages; +import io.github.nucleuspowered.nucleus.api.events.NucleusFirstJoinEvent; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.entities.TextChannel; +import org.apache.commons.lang3.StringUtils; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.filter.Getter; + +public class FirstJoinListener { + + private DiscordBridge mod = DiscordBridge.getInstance(); + + @Listener + public void onPlayerFirstJoin(NucleusFirstJoinEvent event, @Getter("getTargetEntity") Player player) { + + if (event.isMessageCancelled()) { + return; + } + + JDA client = mod.getBotClient(); + GlobalConfig config = mod.getConfig(); + + if (client != null) { + for (ChannelConfig channelConfig : config.channels) { + if (StringUtils.isNotBlank(channelConfig.discordId) + && channelConfig.discord != null + && StringUtils.isNotBlank(channelConfig.discord.firstJoinTemplate)) { + TextChannel channel = client.getTextChannelById(channelConfig.discordId); + + if (channel == null) { + ErrorMessages.CHANNEL_NOT_FOUND.log(channelConfig.discordId); + return; + } + + String message = channelConfig.discord.firstJoinTemplate + .replace("%a", player.getName()); + + ChannelUtil.sendMessage(channel, message); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/nguyenquyhy/discordbridge/logics/LoginHandler.java b/src/main/java/com/nguyenquyhy/discordbridge/logics/LoginHandler.java index c2de4f3..03dc6f0 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/logics/LoginHandler.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/logics/LoginHandler.java @@ -304,6 +304,7 @@ private static void channelJoined(JDA client, GlobalConfig config, ChannelConfig logger.info("Bot account has connected to Discord channel " + channelConfig.discordId + "."); if (StringUtils.isNotBlank(channelConfig.discord.serverUpMessage)) { ChannelUtil.sendMessage(channel, channelConfig.discord.serverUpMessage); + ChannelUtil.setDescription(channel, "Online - Number of Players: " + mod.getPlayerCount()); } } } diff --git a/src/main/java/com/nguyenquyhy/discordbridge/logics/MessageHandler.java b/src/main/java/com/nguyenquyhy/discordbridge/logics/MessageHandler.java index 65f7c85..cc6515b 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/logics/MessageHandler.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/logics/MessageHandler.java @@ -35,7 +35,7 @@ public static void discordMessageReceived(Message message) { for (ChannelConfig channelConfig : config.channels) { if (config.prefixBlacklist != null) { for (String prefix : config.prefixBlacklist) { - if (StringUtils.isNotBlank(prefix) && message.getContent().startsWith(prefix)) { + if (StringUtils.isNotBlank(prefix) && message.getContentDisplay().startsWith(prefix)) { return; } } @@ -76,7 +76,7 @@ public static void discordMessageReceived(Message message) { && StringUtils.isNotBlank(minecraftConfig.attachment.template) && message.getAttachments() != null) { for (Message.Attachment attachment : message.getAttachments()) { - String spacing = StringUtils.isBlank(message.getContent()) ? "" : " "; + String spacing = StringUtils.isBlank(message.getContentDisplay()) ? "" : " "; Text.Builder builder = Text.builder() .append(TextSerializers.FORMATTING_CODE.deserialize(spacing + minecraftConfig.attachment.template)); if (minecraftConfig.attachment.allowLink) { diff --git a/src/main/java/com/nguyenquyhy/discordbridge/models/ChannelDiscordConfig.java b/src/main/java/com/nguyenquyhy/discordbridge/models/ChannelDiscordConfig.java index 34b29c8..158cac2 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/models/ChannelDiscordConfig.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/models/ChannelDiscordConfig.java @@ -22,6 +22,7 @@ void initializeDefault() { serverDownMessage = "Server has stopped."; broadcastTemplate = "_ %s_"; deathTemplate = "**%s**"; + firstJoinTemplate = "_Welcome **%a** to the server!_"; } @Setting @@ -40,6 +41,8 @@ void initializeDefault() { public String broadcastTemplate; @Setting public String deathTemplate; + @Setting + public String firstJoinTemplate; @Deprecated diff --git a/src/main/java/com/nguyenquyhy/discordbridge/utils/ChannelUtil.java b/src/main/java/com/nguyenquyhy/discordbridge/utils/ChannelUtil.java index 6e6a960..3c730a6 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/utils/ChannelUtil.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/utils/ChannelUtil.java @@ -14,4 +14,8 @@ public class ChannelUtil { public static void sendMessage(TextChannel channel, String content) { channel.sendMessage(content).nonce(SPECIAL_CHAR + BOT_RANDOM).queue(); } + + public static void setDescription(TextChannel channel, String content){ + channel.getManager().setTopic(content); + } } diff --git a/src/main/java/com/nguyenquyhy/discordbridge/utils/ColorUtil.java b/src/main/java/com/nguyenquyhy/discordbridge/utils/ColorUtil.java index 4931862..0c1b388 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/utils/ColorUtil.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/utils/ColorUtil.java @@ -4,8 +4,8 @@ import org.spongepowered.api.text.format.TextColors; import java.awt.*; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.List; public class ColorUtil { private static Map minecraftColors = new HashMap<>(); @@ -65,4 +65,12 @@ public static TextColor getColor(Color color) { } return result; } + + public static String removeColor(String text) { + List listColorCodes = new ArrayList<>(Arrays.asList("&0", "&1", "&2", "&3", "&4", "&5", "&6", "&7", "&8", "&9", "&A", "&B", "&C", "&D", "&E", "&F", "&M", "&N", "&L", "&K", "&O")); + for (String s : listColorCodes) { + text = text.replaceAll(s, ""); + } + return text; + } } \ No newline at end of file diff --git a/src/main/java/com/nguyenquyhy/discordbridge/utils/TextUtil.java b/src/main/java/com/nguyenquyhy/discordbridge/utils/TextUtil.java index bf97f87..15f2709 100644 --- a/src/main/java/com/nguyenquyhy/discordbridge/utils/TextUtil.java +++ b/src/main/java/com/nguyenquyhy/discordbridge/utils/TextUtil.java @@ -151,7 +151,7 @@ public static Text formatForMinecraft(ChannelMinecraftConfigCore config, Message if (game != null) s = s.replace("%g", game); // Add the actual message - s = String.format(s, message.getContent()); + s = String.format(s, message.getContentDisplay()); // Replace Discord-specific stuffs s = TextUtil.formatDiscordMessage(s);