Error handling, 1.14 vanilla command support
Error handling (not today) Added support for vanilla commands on 1.14
This commit is contained in:
parent
7a9e7de138
commit
e88684a564
14 changed files with 178 additions and 22 deletions
6
pom.xml
6
pom.xml
|
@ -183,6 +183,12 @@
|
|||
<version>1.12.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc.</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.14.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.discord4j/Discord4J -->
|
||||
<dependency>
|
||||
<groupId>com.discord4j</groupId>
|
||||
|
|
|
@ -163,4 +163,8 @@ public final class DPUtils {
|
|||
return getMessageChannel(config.getPath(), config.get());
|
||||
}
|
||||
|
||||
public static <T> Mono<T> ignoreError(Mono<T> mono) {
|
||||
return mono.onErrorResume(t -> Mono.empty());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DiscordConnectedPlayer> {
|
||||
private @Getter VCMDWrapper<DiscordConnectedPlayer> 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.");
|
||||
}
|
||||
|
|
|
@ -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<DiscordPlayerSender> {
|
||||
|
||||
protected Player player;
|
||||
private @Getter VCMDWrapper<DiscordPlayerSender> 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<DiscordPlayerSender>(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.");
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -3,6 +3,6 @@ package buttondevteam.discordplugin;
|
|||
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface IMCPlayer<T extends DiscordSenderBase & IMCPlayer<T>> extends Player {
|
||||
VCMDWrapper<T> getVanillaCmdListener();
|
||||
public interface IMCPlayer<T> extends Player {
|
||||
VCMDWrapper getVanillaCmdListener();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<T extends DiscordSenderBase & IMCPlayer<T>> {
|
||||
public class VCMDWrapper {
|
||||
@Getter //Needed to mock the player
|
||||
private final VanillaCommandListener<T> 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 <T extends DiscordSenderBase & IMCPlayer<T>> 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 <T extends DiscordSenderBase & IMCPlayer<T>> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public class VanillaCommandListener<T extends DiscordSenderBase & IMCPlayer<T>>
|
|||
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 {
|
||||
|
|
|
@ -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<T extends DiscordSenderBase & IMCPlayer<T>> 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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue