diff --git a/pom.xml b/pom.xml
index 6d68328..c9d1eb8 100755
--- a/pom.xml
+++ b/pom.xml
@@ -183,6 +183,12 @@
1.12.2-R0.1-SNAPSHOT
provided
+
+ org.spigotmc.
+ spigot
+ 1.14.4-R0.1-SNAPSHOT
+ provided
+
com.discord4j
diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java
index 616b750..84d2ced 100755
--- a/src/main/java/buttondevteam/discordplugin/DPUtils.java
+++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java
@@ -163,4 +163,8 @@ public final class DPUtils {
return getMessageChannel(config.getPath(), config.get());
}
+ public static Mono ignoreError(Mono mono) {
+ return mono.onErrorResume(t -> Mono.empty());
+ }
+
}
diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java
index da5ccd4..b5d7da4 100644
--- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java
+++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java
@@ -2,7 +2,6 @@ package buttondevteam.discordplugin;
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
-import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.entity.User;
import lombok.Getter;
@@ -21,7 +20,7 @@ import java.util.HashSet;
import java.util.UUID;
public abstract class DiscordConnectedPlayer extends DiscordSenderBase implements IMCPlayer {
- private @Getter VCMDWrapper vanillaCmdListener;
+ private @Getter VCMDWrapper vanillaCmdListener;
@Getter
@Setter
private boolean loggedIn = false;
@@ -56,7 +55,9 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement
uniqueId = uuid;
displayName = mcname;
try {
- vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener<>(this));
+ vanillaCmdListener = new VCMDWrapper(VCMDWrapper.createListener(this));
+ if (vanillaCmdListener.getListener() == null)
+ DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
} catch (NoClassDefFoundError e) {
DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
}
diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java
index 62949c5..1e94b14 100755
--- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java
+++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java
@@ -1,7 +1,6 @@
package buttondevteam.discordplugin;
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
-import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.entity.User;
import lombok.Getter;
@@ -37,13 +36,15 @@ import java.util.*;
public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer {
protected Player player;
- private @Getter VCMDWrapper vanillaCmdListener;
+ private @Getter VCMDWrapper vanillaCmdListener;
public DiscordPlayerSender(User user, MessageChannel channel, Player player) {
super(user, channel);
this.player = player;
try {
- vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener(this, player));
+ vanillaCmdListener = new VCMDWrapper(VCMDWrapper.createListener(this, player));
+ if (vanillaCmdListener.getListener() == null)
+ DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
} catch (NoClassDefFoundError e) {
DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
}
diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java
index 9eda278..0381e66 100755
--- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java
+++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java
@@ -12,6 +12,7 @@ import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
+import reactor.core.publisher.Mono;
import java.util.Set;
@@ -23,7 +24,8 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender {
public DiscordSender(User user, MessageChannel channel) {
super(user, channel);
val def = "Discord user";
- name = user == null ? def : user.asMember(DiscordPlugin.mainServer.getId()).blockOptional().map(Member::getDisplayName).orElse(def);
+ name = user == null ? def : user.asMember(DiscordPlugin.mainServer.getId())
+ .onErrorResume(t -> Mono.empty()).blockOptional().map(Member::getDisplayName).orElse(def);
}
public DiscordSender(User user, MessageChannel channel, String name) {
diff --git a/src/main/java/buttondevteam/discordplugin/IMCPlayer.java b/src/main/java/buttondevteam/discordplugin/IMCPlayer.java
index 7943f21..c2ee28e 100755
--- a/src/main/java/buttondevteam/discordplugin/IMCPlayer.java
+++ b/src/main/java/buttondevteam/discordplugin/IMCPlayer.java
@@ -3,6 +3,6 @@ package buttondevteam.discordplugin;
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
import org.bukkit.entity.Player;
-public interface IMCPlayer> extends Player {
- VCMDWrapper getVanillaCmdListener();
+public interface IMCPlayer extends Player {
+ VCMDWrapper getVanillaCmdListener();
}
diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java
index e1c0686..65e0663 100644
--- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java
+++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java
@@ -19,7 +19,7 @@ public class DebugCommand extends ICommand2DC {
.flatMap(m -> DiscordPlugin.plugin.modRole().get()
.map(mr -> m.getRoleIds().stream().anyMatch(r -> r.equals(mr.getId())))
.switchIfEmpty(Mono.fromSupplier(() -> DiscordPlugin.mainServer.getOwnerId().asLong() == m.getId().asLong()))) //Role not found
- .subscribe(success -> {
+ .onErrorReturn(false).subscribe(success -> {
if (success)
sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled"));
else
diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java
index 6c9acd6..3afc038 100755
--- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java
+++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java
@@ -38,7 +38,7 @@ public class MCListener implements Listener {
if (!userOpt.isPresent()) return;
User user = userOpt.get();
e.addInfo("Discord tag: " + user.getUsername() + "#" + user.getDiscriminator());
- val memberOpt = user.asMember(DiscordPlugin.mainServer.getId()).blockOptional();
+ val memberOpt = user.asMember(DiscordPlugin.mainServer.getId()).onErrorResume(t -> Mono.empty()).blockOptional();
if (!memberOpt.isPresent()) return;
Member member = memberOpt.get();
val prOpt = member.getPresence().blockOptional();
diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java
index 790edfb..4ff36cb 100755
--- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java
+++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java
@@ -10,6 +10,7 @@ import buttondevteam.discordplugin.DiscordSenderBase;
import buttondevteam.discordplugin.listeners.CommandListener;
import buttondevteam.discordplugin.listeners.CommonListeners;
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
+import buttondevteam.discordplugin.playerfaker.VanillaCommandListener14;
import buttondevteam.discordplugin.util.Timings;
import buttondevteam.lib.*;
import buttondevteam.lib.chat.ChatMessage;
@@ -277,10 +278,11 @@ public class MCChatListener implements Listener {
for (User u : event.getMessage().getUserMentions().toIterable()) { //TODO: Role mentions
dmessage = dmessage.replace(u.getMention(), "@" + u.getUsername()); // TODO: IG Formatting
- val m = u.asMember(DiscordPlugin.mainServer.getId()).block();
- if (m != null) {
- final String nick = m.getDisplayName();
- dmessage = dmessage.replace(m.getNicknameMention(), "@" + nick);
+ val m = u.asMember(DiscordPlugin.mainServer.getId()).onErrorResume(t -> Mono.empty()).blockOptional();
+ if (m.isPresent()) {
+ val mm = m.get();
+ final String nick = mm.getDisplayName();
+ dmessage = dmessage.replace(mm.getNicknameMention(), "@" + nick);
}
}
for (GuildChannel ch : event.getGuild().flux().flatMap(Guild::getChannels).toIterable()) {
@@ -340,7 +342,11 @@ public class MCChatListener implements Listener {
channel.set(clmd.mcchannel); //Hack to send command in the channel
} //TODO: Permcheck isn't implemented for commands
try {
- VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd);
+ String mcpackage = Bukkit.getServer().getClass().getPackage().getName();
+ if (mcpackage.contains("1_12"))
+ VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd);
+ else if (mcpackage.contains("1_14"))
+ VanillaCommandListener14.runBukkitOrVanillaCommand(dsender, cmd);
} catch (NoClassDefFoundError e) {
Bukkit.dispatchCommand(dsender, cmd);
}
diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java
index 0880bd9..c3ad14a 100644
--- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java
+++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java
@@ -118,7 +118,7 @@ class MCListener implements Listener {
final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class)
.getAs(DiscordPlayer.class);
if (p == null) return;
- DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID()))
+ DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID()))
.flatMap(user -> user.asMember(DiscordPlugin.mainServer.getId()))
.flatMap(user -> role.flatMap(r -> {
if (e.getValue())
@@ -131,7 +131,7 @@ class MCListener implements Listener {
if (modlog != null)
return modlog.flatMap(ch -> ch.createMessage(msg));
return Mono.empty();
- })).subscribe();
+ }))).subscribe();
}
@EventHandler
diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java
index 1902516..25b505e 100755
--- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java
+++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java
@@ -1,7 +1,9 @@
package buttondevteam.discordplugin.playerfaker;
+import buttondevteam.discordplugin.DPUtils;
import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
+import discord4j.core.object.entity.Member;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.entity.User;
import lombok.Getter;
@@ -143,7 +145,8 @@ public class DiscordFakePlayer extends DiscordHumanEntity implements Player {
@Override
public String getDisplayName() {
- return Objects.requireNonNull(user.asMember(DiscordPlugin.mainServer.getId()).block()).getDisplayName();
+ return DPUtils.ignoreError(user.asMember(DiscordPlugin.mainServer.getId())).blockOptional()
+ .map(Member::getDisplayName).orElse(name);
}
@Override
diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java
index 95a7811..4bcf5eb 100644
--- a/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java
+++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java
@@ -4,9 +4,36 @@ import buttondevteam.discordplugin.DiscordSenderBase;
import buttondevteam.discordplugin.IMCPlayer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
@RequiredArgsConstructor
-public class VCMDWrapper> {
+public class VCMDWrapper {
@Getter //Needed to mock the player
- private final VanillaCommandListener listener;
+ private final Object listener;
+
+ /**
+ * This constructor will only send raw vanilla messages to the sender in plain text.
+ *
+ * @param player The Discord sender player (the wrapper)
+ */
+ public static > Object createListener(T player) {
+ return createListener(player, null);
+ }
+
+ /**
+ * This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player.
+ *
+ * @param player The Discord sender player (the wrapper)
+ * @param bukkitplayer The Bukkit player to send the raw message to
+ */
+ public static > Object createListener(T player, Player bukkitplayer) {
+ String mcpackage = Bukkit.getServer().getClass().getPackage().getName();
+ if (mcpackage.contains("1_12"))
+ return bukkitplayer == null ? new VanillaCommandListener<>(player) : new VanillaCommandListener<>(player, bukkitplayer);
+ else if (mcpackage.contains("1_14"))
+ return bukkitplayer == null ? new VanillaCommandListener14<>(player) : new VanillaCommandListener14<>(player, bukkitplayer);
+ else
+ return null;
+ }
}
diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java
index 9f2db22..c12a308 100755
--- a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java
+++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java
@@ -87,7 +87,7 @@ public class VanillaCommandListener>
if (!vcmd.testPermission(sender))
return true;
- ICommandListener icommandlistener = sender.getVanillaCmdListener().getListener();
+ ICommandListener icommandlistener = (ICommandListener) sender.getVanillaCmdListener().getListener();
String[] args = cmdstr.split(" ");
args = Arrays.copyOfRange(args, 1, args.length);
try {
diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java
new file mode 100644
index 0000000..fbaf958
--- /dev/null
+++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java
@@ -0,0 +1,106 @@
+package buttondevteam.discordplugin.playerfaker;
+
+import buttondevteam.discordplugin.DiscordSenderBase;
+import buttondevteam.discordplugin.IMCPlayer;
+import lombok.Getter;
+import lombok.val;
+import net.minecraft.server.v1_14_R1.*;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_14_R1.command.ProxiedNativeCommandSender;
+import org.bukkit.craftbukkit.v1_14_R1.command.VanillaCommandWrapper;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+import java.util.Arrays;
+
+public class VanillaCommandListener14> implements ICommandListener {
+ private @Getter T player;
+ private Player bukkitplayer;
+
+ /**
+ * This constructor will only send raw vanilla messages to the sender in plain text.
+ *
+ * @param player The Discord sender player (the wrapper)
+ */
+ public VanillaCommandListener14(T player) {
+ this.player = player;
+ this.bukkitplayer = null;
+ }
+
+ /**
+ * This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player.
+ *
+ * @param player The Discord sender player (the wrapper)
+ * @param bukkitplayer The Bukkit player to send the raw message to
+ */
+ public VanillaCommandListener14(T player, Player bukkitplayer) {
+ this.player = player;
+ this.bukkitplayer = bukkitplayer;
+ if (!(bukkitplayer instanceof CraftPlayer))
+ throw new ClassCastException("bukkitplayer must be a Bukkit player!");
+ }
+
+ @Override
+ public void sendMessage(IChatBaseComponent arg0) {
+ player.sendMessage(arg0.getString());
+ if (bukkitplayer != null)
+ ((CraftPlayer) bukkitplayer).getHandle().sendMessage(arg0);
+ }
+
+ @Override
+ public boolean shouldSendSuccess() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldSendFailure() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldBroadcastCommands() {
+ return true; //Broadcast to in-game admins
+ }
+
+ @Override
+ public CommandSender getBukkitSender(CommandListenerWrapper commandListenerWrapper) {
+ return player;
+ }
+
+ public static boolean runBukkitOrVanillaCommand(DiscordSenderBase dsender, String cmdstr) {
+ val cmd = ((CraftServer) Bukkit.getServer()).getCommandMap().getCommand(cmdstr.split(" ")[0].toLowerCase());
+ if (!(dsender instanceof Player) || !(cmd instanceof VanillaCommandWrapper))
+ return Bukkit.dispatchCommand(dsender, cmdstr); // Unconnected users are treated well in vanilla cmds
+
+ if (!(dsender instanceof IMCPlayer))
+ throw new ClassCastException(
+ "dsender needs to implement IMCPlayer to use vanilla commands as it implements Player.");
+
+ IMCPlayer> sender = (IMCPlayer>) dsender; // Don't use val on recursive interfaces :P
+
+ val vcmd = (VanillaCommandWrapper) cmd;
+ if (!vcmd.testPermission(sender))
+ return true;
+
+ val world = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle();
+ ICommandListener icommandlistener = (ICommandListener) sender.getVanillaCmdListener().getListener();
+ val wrapper = new CommandListenerWrapper(icommandlistener, new Vec3D(0, 0, 0),
+ new Vec2F(0, 0), world, 0, sender.getName(),
+ new ChatComponentText(sender.getName()), world.getMinecraftServer(), null);
+ val pncs = new ProxiedNativeCommandSender(wrapper, sender, sender);
+ String[] args = cmdstr.split(" ");
+ args = Arrays.copyOfRange(args, 1, args.length);
+ try {
+ return vcmd.execute(pncs, cmd.getLabel(), args);
+ } catch (CommandException commandexception) {
+ // Taken from CommandHandler
+ ChatMessage chatmessage = new ChatMessage(commandexception.getMessage(), commandexception.a());
+ chatmessage.getChatModifier().setColor(EnumChatFormat.RED);
+ icommandlistener.sendMessage(chatmessage);
+ }
+ return true;
+ }
+}