Made DCP version-independent & msg reset
Some things may not be implemented yet Also added a wrapper around the vanilla cmd listener so Mockito doesn't complain about the missing class Msg reset fixed (#101)
This commit is contained in:
parent
5a5f653b86
commit
7db3b17090
10 changed files with 164 additions and 18 deletions
140
src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java
Executable file → Normal file
140
src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java
Executable file → Normal file
|
@ -1,29 +1,155 @@
|
||||||
package buttondevteam.discordplugin;
|
package buttondevteam.discordplugin;
|
||||||
|
|
||||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
|
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
|
||||||
import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer;
|
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
|
||||||
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
||||||
import discord4j.core.object.entity.MessageChannel;
|
import discord4j.core.object.entity.MessageChannel;
|
||||||
import discord4j.core.object.entity.User;
|
import discord4j.core.object.entity.User;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.experimental.Delegate;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
|
import org.bukkit.permissions.PermissibleBase;
|
||||||
|
import org.bukkit.permissions.ServerOperator;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlayer<DiscordConnectedPlayer> {
|
public abstract class DiscordConnectedPlayer extends DiscordSenderBase implements IMCPlayer<DiscordConnectedPlayer> {
|
||||||
private static int nextEntityId = 10000;
|
private @Getter VCMDWrapper<DiscordConnectedPlayer> vanillaCmdListener;
|
||||||
private @Getter VanillaCommandListener<DiscordConnectedPlayer> vanillaCmdListener;
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private boolean loggedIn = false;
|
private boolean loggedIn = false;
|
||||||
|
|
||||||
public DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) {
|
@Delegate(excludes = ServerOperator.class)
|
||||||
super(user, channel, nextEntityId++, uuid, mcname, module);
|
private PermissibleBase origPerm;
|
||||||
|
|
||||||
|
private @Getter String name;
|
||||||
|
|
||||||
|
private @Getter OfflinePlayer basePlayer;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private PermissibleBase perm;
|
||||||
|
|
||||||
|
private Location location = Bukkit.getWorlds().get(0).getSpawnLocation();
|
||||||
|
|
||||||
|
private final MinecraftChatModule module;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final UUID uniqueId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters must match with {@link #create(User, MessageChannel, UUID, String, MinecraftChatModule)}
|
||||||
|
*/
|
||||||
|
protected DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname,
|
||||||
|
MinecraftChatModule module) {
|
||||||
|
super(user, channel);
|
||||||
|
origPerm = perm = new PermissibleBase(basePlayer = Bukkit.getOfflinePlayer(uuid));
|
||||||
|
name = mcname;
|
||||||
|
this.module = module;
|
||||||
|
uniqueId = uuid;
|
||||||
|
displayName = mcname;
|
||||||
try {
|
try {
|
||||||
vanillaCmdListener = new VanillaCommandListener<>(this);
|
vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener<>(this));
|
||||||
} catch (NoClassDefFoundError e) {
|
} catch (NoClassDefFoundError e) {
|
||||||
DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
|
DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOp(boolean value) { //CraftPlayer-compatible implementation
|
||||||
|
this.origPerm.setOp(value);
|
||||||
|
this.perm.recalculatePermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOp() { return this.origPerm.isOp(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean teleport(Location location) {
|
||||||
|
if (module.allowFakePlayerTeleports().get())
|
||||||
|
this.location = location;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) {
|
||||||
|
if (module.allowFakePlayerTeleports().get())
|
||||||
|
this.location = location;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean teleport(Entity destination) {
|
||||||
|
if (module.allowFakePlayerTeleports().get())
|
||||||
|
this.location = destination.getLocation();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean teleport(Entity destination, PlayerTeleportEvent.TeleportCause cause) {
|
||||||
|
if (module.allowFakePlayerTeleports().get())
|
||||||
|
this.location = destination.getLocation();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation(Location loc) {
|
||||||
|
if (loc != null) {
|
||||||
|
loc.setWorld(getWorld());
|
||||||
|
loc.setX(location.getX());
|
||||||
|
loc.setY(location.getY());
|
||||||
|
loc.setZ(location.getZ());
|
||||||
|
loc.setYaw(location.getYaw());
|
||||||
|
loc.setPitch(location.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Server getServer() {
|
||||||
|
return Bukkit.getServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRawMessage(String message) {
|
||||||
|
sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void chat(String msg) {
|
||||||
|
Bukkit.getPluginManager()
|
||||||
|
.callEvent(new AsyncPlayerChatEvent(true, this, msg, new HashSet<>(Bukkit.getOnlinePlayers())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
return Bukkit.getWorlds().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnline() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation() {
|
||||||
|
return new Location(getWorld(), location.getX(), location.getY(), location.getZ(),
|
||||||
|
location.getYaw(), location.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
public static DiscordConnectedPlayer create(User user, MessageChannel channel, UUID uuid, String mcname,
|
||||||
|
MinecraftChatModule module) {
|
||||||
|
return Mockito.mock(DiscordConnectedPlayer.class, Mockito.withSettings()
|
||||||
|
.defaultAnswer(Answers.CALLS_REAL_METHODS).useConstructor(user, channel, uuid, mcname, module));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package buttondevteam.discordplugin;
|
package buttondevteam.discordplugin;
|
||||||
|
|
||||||
|
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
|
||||||
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
||||||
import discord4j.core.object.entity.MessageChannel;
|
import discord4j.core.object.entity.MessageChannel;
|
||||||
import discord4j.core.object.entity.User;
|
import discord4j.core.object.entity.User;
|
||||||
|
@ -36,13 +37,13 @@ import java.util.*;
|
||||||
public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer<DiscordPlayerSender> {
|
public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer<DiscordPlayerSender> {
|
||||||
|
|
||||||
protected Player player;
|
protected Player player;
|
||||||
private @Getter VanillaCommandListener<DiscordPlayerSender> vanillaCmdListener;
|
private @Getter VCMDWrapper<DiscordPlayerSender> vanillaCmdListener;
|
||||||
|
|
||||||
public DiscordPlayerSender(User user, MessageChannel channel, Player player) {
|
public DiscordPlayerSender(User user, MessageChannel channel, Player player) {
|
||||||
super(user, channel);
|
super(user, channel);
|
||||||
this.player = player;
|
this.player = player;
|
||||||
try {
|
try {
|
||||||
vanillaCmdListener = new VanillaCommandListener<DiscordPlayerSender>(this);
|
vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener<DiscordPlayerSender>(this, player));
|
||||||
} catch (NoClassDefFoundError e) {
|
} catch (NoClassDefFoundError e) {
|
||||||
DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
|
DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package buttondevteam.discordplugin;
|
package buttondevteam.discordplugin;
|
||||||
|
|
||||||
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
import buttondevteam.discordplugin.playerfaker.VCMDWrapper;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public interface IMCPlayer<T extends DiscordSenderBase & IMCPlayer<T>> extends Player {
|
public interface IMCPlayer<T extends DiscordSenderBase & IMCPlayer<T>> extends Player {
|
||||||
VanillaCommandListener<T> getVanillaCmdListener();
|
VCMDWrapper<T> getVanillaCmdListener();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,12 @@ public class GeneralEventBroadcasterModule extends Component<DiscordPlugin> {
|
||||||
PlayerListWatcher.hookUp();
|
PlayerListWatcher.hookUp();
|
||||||
DPUtils.getLogger().info("Finished hooking into the player list");
|
DPUtils.getLogger().info("Finished hooking into the player list");
|
||||||
hooked = true;
|
hooked = true;
|
||||||
} catch (Exception | NoClassDefFoundError e) {
|
} catch (Exception e) {
|
||||||
TBMCCoreAPI.SendException("Error while hacking the player list! Disable this module if you're on an incompatible version.", e);
|
TBMCCoreAPI.SendException("Error while hacking the player list! Disable this module if you're on an incompatible version.", e);
|
||||||
|
} catch (NoClassDefFoundError e) {
|
||||||
|
DPUtils.getLogger().warning("Error while hacking the player list! Disable this module if you're on an incompatible version.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,8 +32,9 @@ public class GeneralEventBroadcasterModule extends Component<DiscordPlugin> {
|
||||||
else
|
else
|
||||||
DPUtils.getLogger().info("Didn't have the player list hooked.");
|
DPUtils.getLogger().info("Didn't have the player list hooked.");
|
||||||
hooked = false;
|
hooked = false;
|
||||||
} catch (Exception | NoClassDefFoundError e) {
|
} catch (Exception e) {
|
||||||
TBMCCoreAPI.SendException("Error while hacking the player list!", e);
|
TBMCCoreAPI.SendException("Error while hacking the player list!", e);
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ public class ChannelconCommand extends ICommand2DC {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
val channel = message.getChannel().block();
|
val channel = message.getChannel().block();
|
||||||
DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module);
|
DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module);
|
||||||
//Using a fake player with no login/logout, should be fine for this event
|
//Using a fake player with no login/logout, should be fine for this event
|
||||||
String groupid = chan.get().getGroupID(dcp);
|
String groupid = chan.get().getGroupID(dcp);
|
||||||
if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later
|
if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class MCChatPrivate {
|
||||||
val op = Bukkit.getOfflinePlayer(mcp.getUUID());
|
val op = Bukkit.getOfflinePlayer(mcp.getUUID());
|
||||||
val mcm = ComponentManager.getIfEnabled(MinecraftChatModule.class);
|
val mcm = ComponentManager.getIfEnabled(MinecraftChatModule.class);
|
||||||
if (start) {
|
if (start) {
|
||||||
val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName(), mcm);
|
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUUID(), op.getName(), mcm);
|
||||||
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender);
|
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender);
|
||||||
if (p == null)// Player is offline - If the player is online, that takes precedence
|
if (p == null)// Player is offline - If the player is online, that takes precedence
|
||||||
MCChatUtils.callLoginEvents(sender);
|
MCChatUtils.callLoginEvents(sender);
|
||||||
|
|
|
@ -180,7 +180,10 @@ public class MCChatUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Consumer<Mono<MessageChannel>> send(String message) {
|
public static Consumer<Mono<MessageChannel>> send(String message) {
|
||||||
return ch -> ch.flatMap(mc -> mc.createMessage(DPUtils.sanitizeString(message))).subscribe();
|
return ch -> ch.flatMap(mc -> {
|
||||||
|
resetLastMessage(mc);
|
||||||
|
return mc.createMessage(DPUtils.sanitizeString(message));
|
||||||
|
}).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void forAllowedMCChat(Consumer<Mono<MessageChannel>> action, TBMCSystemChatEvent event) {
|
public static void forAllowedMCChat(Consumer<Mono<MessageChannel>> action, TBMCSystemChatEvent event) {
|
||||||
|
|
|
@ -104,7 +104,7 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
|
||||||
if (!mcch.isPresent() || ch == null || user == null || groupid == null)
|
if (!mcch.isPresent() || ch == null || user == null || groupid == null)
|
||||||
continue;
|
continue;
|
||||||
Bukkit.getScheduler().runTask(getPlugin(), () -> { //<-- Needed because of occasional ConcurrentModificationExceptions when creating the player (PermissibleBase)
|
Bukkit.getScheduler().runTask(getPlugin(), () -> { //<-- Needed because of occasional ConcurrentModificationExceptions when creating the player (PermissibleBase)
|
||||||
val dcp = new DiscordConnectedPlayer(user, (MessageChannel) ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"), this);
|
val dcp = DiscordConnectedPlayer.create(user, (MessageChannel) ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"), this);
|
||||||
MCChatCustom.addCustomChat((MessageChannel) ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toSet()));
|
MCChatCustom.addCustomChat((MessageChannel) ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toSet()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package buttondevteam.discordplugin.playerfaker;
|
||||||
|
|
||||||
|
import buttondevteam.discordplugin.DiscordSenderBase;
|
||||||
|
import buttondevteam.discordplugin.IMCPlayer;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VCMDWrapper<T extends DiscordSenderBase & IMCPlayer<T>> {
|
||||||
|
@Getter //Needed to mock the player
|
||||||
|
private final VanillaCommandListener<T> listener;
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ public class VanillaCommandListener<T extends DiscordSenderBase & IMCPlayer<T>>
|
||||||
if (!vcmd.testPermission(sender))
|
if (!vcmd.testPermission(sender))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
ICommandListener icommandlistener = sender.getVanillaCmdListener();
|
ICommandListener icommandlistener = sender.getVanillaCmdListener().getListener();
|
||||||
String[] args = cmdstr.split(" ");
|
String[] args = cmdstr.split(" ");
|
||||||
args = Arrays.copyOfRange(args, 1, args.length);
|
args = Arrays.copyOfRange(args, 1, args.length);
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue