Finished private Minecraft chat, lots of bug fixes #42

Merged
NorbiPeti merged 8 commits from dev into master 2017-07-12 23:48:03 +00:00
7 changed files with 97 additions and 75 deletions
Showing only changes of commit a501d9d457 - Show all commits

View file

@ -1,12 +1,13 @@
package buttondevteam.discordplugin;
import buttondevteam.discordplugin.listeners.MCChatListener;
import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.PlayerData;
import buttondevteam.lib.player.UserClass;
@UserClass(foldername = "discord")
public class DiscordPlayer extends ChromaGamerBase {
private String did;
// private @Getter @Setter boolean minecraftChatEnabled;
public DiscordPlayer() {
}
@ -17,7 +18,11 @@ public class DiscordPlayer extends ChromaGamerBase {
return did;
}
public PlayerData<Boolean> minecraftChat() {
return data(false);
/**
* Returns true if player has the private Minecraft chat enabled. For setting the value, see
* {@link MCChatListener#privateMCChat(sx.blah.discord.handle.obj.IChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)}
*/
public boolean isMinecraftChatEnabled() {
return MCChatListener.isMinecraftChatEnabled(this);
}
}

View file

@ -256,7 +256,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
if (channel == chatchannel)
MCChatListener.resetLastMessage(); // If this is a chat message, it'll be set again
final String content = TBMCCoreAPI.IsTestServer() && channel != chatchannel || channel == botroomchannel // Both are the same for testing
? "*The following message is from a test server*\n" + message : message;
|| channel.isPrivate() //
? "*The following message is from a test server*\n" + message : message;
return perform(
() -> embed == null ? channel.sendMessage(content) : channel.sendMessage(content, embed, false));
} catch (Exception e) {

View file

@ -1,9 +1,9 @@
package buttondevteam.discordplugin.commands;
import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.listeners.MCChatListener;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.player.PlayerData;
import sx.blah.discord.handle.obj.IMessage;
public class MCChatCommand extends DiscordCommandBase {
@ -16,17 +16,18 @@ public class MCChatCommand extends DiscordCommandBase {
@Override
public void run(IMessage message, String args) {
if (!message.getChannel().isPrivate()) {
message.reply("This command can only be issued in a direct message with the bot.");
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"This command can only be issued in a direct message with the bot.");
return;
}
try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) {
PlayerData<Boolean> mcchat = user.minecraftChat();
mcchat.set(!mcchat.get());
MCChatListener.privateMCChat(message.getChannel(), mcchat.get(), message.getAuthor(), user);
message.reply("Minecraft chat " + (mcchat.get() //
? "enabled. Use '" + message.getClient().getOurUser().mention()
+ " mcchat' (with the mention) to disable." //
: "disabled."));
boolean mcchat = !user.isMinecraftChatEnabled();
MCChatListener.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user);
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Minecraft chat " + (mcchat //
? "enabled. Use '" + message.getClient().getOurUser().mention()
+ " mcchat' (with the mention) to disable." //
: "disabled."));
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e);
}

View file

@ -59,13 +59,10 @@ public class CommandListener {
if (event.getMessage().getAuthor().isBot())
return;
final IChannel channel = event.getMessage().getChannel();
if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID())
&& (!channel.isPrivate() || DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent()))
if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()))
return;
if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID()))
return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel
if (DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class).minecraftChat().get()) // Let the MCChatListener handle it
return;
event.getMessage().getChannel().setTypingStatus(true); // Fun
runCommand(event.getMessage(), true);
}
@ -84,8 +81,8 @@ public class CommandListener {
DiscordPlugin.sendMessageToChannel(event.getMessage().getChannel(), serverReadyStrings[next]);
}
if (!event.getMessage().getChannel().isPrivate() //
|| DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class).minecraftChat()
.get()
|| DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class)
.isMinecraftChatEnabled()
|| DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent())
return;
if (event.getMessage().getAuthor().isBot())

View file

@ -4,11 +4,12 @@ import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -75,7 +76,7 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
final IUser iUser = data.channel.getUsersHere().stream()
.filter(u -> u.getLongID() != u.getClient().getOurUser().getLongID()).findFirst().get(); // Doesn't support group DMs
final DiscordPlayer user = DiscordPlayer.getUser(iUser.getStringID(), DiscordPlayer.class);
if (user.minecraftChat().get() && e.shouldSendTo(getSender(data.channel, iUser, user)))
if (user.isMinecraftChatEnabled() && e.shouldSendTo(getSender(data.channel, iUser, user)))
doit.accept(data);
}
} // TODO: Author URL
@ -132,11 +133,11 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
if (start) {
val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID());
ConnectedSenders.put(user.getStringID(), sender);
if (p == null)// If the player is online, that takes precedence
if (p == null)// Player is offline - If the player is online, that takes precedence
Bukkit.getPluginManager().callEvent(new PlayerJoinEvent(sender, ""));
} else {
val sender = ConnectedSenders.remove(user.getStringID());
if (p == null)// If the player is online, that takes precedence
if (p == null)// Player is offline - If the player is online, that takes precedence
Bukkit.getPluginManager().callEvent(new PlayerQuitEvent(sender, ""));
}
}
@ -145,7 +146,6 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
: lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID());
}
//
// ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender
// Offline public chat......x............................................
// Online public chat.......x...........................................x
@ -155,10 +155,21 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
// If leaving the server and private chat is enabled (has ConnectedPlayer), call login in a task on lowest priority
// If private chat is enabled and joining the server, logout the fake player on highest priority
// If online and disabling private chat, don't logout
// The maps may not contain the senders except for DiscordPlayerSender
// The maps may not contain the senders for UnconnectedSenders
public static boolean isMinecraftChatEnabled(DiscordPlayer dp) {
return lastmsgPerUser.stream().anyMatch(
lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(dp.getDiscordID()));
}
/**
* May contain P&lt;DiscordID&gt; as key for public chat
*/
public static final HashMap<String, DiscordSender> UnconnectedSenders = new HashMap<>();
public static final HashMap<String, DiscordConnectedPlayer> ConnectedSenders = new HashMap<>();
/**
* May contain P&lt;DiscordID&gt; as key for public chat
*/
public static final HashMap<String, DiscordPlayerSender> OnlineSenders = new HashMap<>();
public static short ListC = 0;
@ -166,12 +177,18 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
(lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel) : lastmsgdata).message = null; // Don't set the whole object to null, the player and channel information should
} // be preserved
public static void sendSystemMessageToChat(String msg) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, msg);
for (LastMsgData data : lastmsgPerUser)
DiscordPlugin.sendMessageToChannel(data.channel, msg);
}
@Override // Discord
public void handle(MessageReceivedEvent event) {
val author = event.getMessage().getAuthor();
val user = DiscordPlayer.getUser(author.getStringID(), DiscordPlayer.class);
if (!event.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID())
&& !(event.getMessage().getChannel().isPrivate() && user.minecraftChat().get()
&& !(event.getMessage().getChannel().isPrivate() && user.isMinecraftChatEnabled()
&& !DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent()))
return;
resetLastMessage();
@ -200,12 +217,13 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
if (dsender instanceof DiscordSender && !Arrays.stream(UnconnectedCmds)
.anyMatch(s -> cmd.equals(s) || cmd.startsWith(s + " "))) {
// Command not whitelisted
dsender.sendMessage( // TODO
"Sorry, you need to be online on the server and have your accounts connected, you can only access these commands:\n"
+ Arrays.stream(UnconnectedCmds).map(uc -> "/" + uc)
.collect(Collectors.joining(", "))
+ "\nTo connect your accounts, use @ChromaBot connect in "
+ DiscordPlugin.botchannel.mention());
dsender.sendMessage("Sorry, you can only access these commands:\n"
+ Arrays.stream(UnconnectedCmds).map(uc -> "/" + uc).collect(Collectors.joining(", "))
+ (user.getConnectedID(TBMCPlayer.class) == null
? "\nTo access your commands, first please connect your accounts, using @ChromaBot connect in "
+ DiscordPlugin.botchannel.mention()
+ "\nThen you can access all of your regular commands (even offline) in private chat: DM me `mcchat`!"
: "\nYou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!"));
return;
}
if (lastlist > 5) {
@ -248,29 +266,18 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
}
}
@SuppressWarnings("unchecked")
private <T extends DiscordSenderBase> DiscordSenderBase getSender(IChannel channel, final IUser author,
DiscordPlayer dp) {
final DiscordSenderBase dsender;
final Player mcp;
final String cid;
BiFunction<HashMap<String, T>, Supplier<T>, DiscordSenderBase> getsender = (senders, maker) -> {
if (!senders.containsKey(author.getStringID()))
senders.put(author.getStringID(), maker.get());
return senders.get(author.getStringID());
};
if ((cid = dp.getConnectedID(TBMCPlayer.class)) != null) { // Connected?
if ((mcp = Bukkit.getPlayer(UUID.fromString(cid))) != null) // Online? - Execute as ingame player
dsender = getsender.apply((HashMap<String, T>) OnlineSenders,
() -> (T) new DiscordPlayerSender(author, channel, mcp));
else // Offline
dsender = getsender.apply((HashMap<String, T>) ConnectedSenders,
() -> (T) new DiscordConnectedPlayer(author, channel, UUID.fromString(cid)));
} else { // Not connected
TBMCPlayer p = dp.getAs(TBMCPlayer.class);
dsender = getsender.apply((HashMap<String, T>) UnconnectedSenders,
() -> (T) new DiscordSender(author, channel, p == null ? null : p.PlayerName().get())); // Display the playername, if found
}
return dsender;
/**
* This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc.
*/
private DiscordSenderBase getSender(IChannel channel, final IUser author, DiscordPlayer dp) {
val key = (channel.isPrivate() ? "" : "P") + author.getStringID();
return Stream.<Supplier<Optional<DiscordSenderBase>>>of( // https://stackoverflow.com/a/28833677/2703239
() -> Optional.ofNullable(OnlineSenders.get(key)), // Find first non-null
() -> Optional.ofNullable(ConnectedSenders.get(author.getStringID())), // This doesn't support it
() -> Optional.ofNullable(UnconnectedSenders.get(key)), () -> {
val dsender = new DiscordSender(author, channel);
UnconnectedSenders.put(key, dsender);
return Optional.of(dsender);
}).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get();
}
}

View file

@ -1,10 +1,13 @@
package buttondevteam.discordplugin.listeners;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
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.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.ServerCommandEvent;
import com.earth2me.essentials.CommandSource;
@ -16,6 +19,7 @@ import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.commands.ConnectCommand;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.player.*;
import lombok.val;
import net.ess3.api.events.*;
import sx.blah.discord.handle.obj.IRole;
import sx.blah.discord.handle.obj.IUser;
@ -23,14 +27,22 @@ import sx.blah.discord.util.DiscordException;
import sx.blah.discord.util.MissingPermissionsException;
public class MCListener implements Listener {
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(TBMCPlayerJoinEvent e) {
if (e.getPlayer() instanceof DiscordConnectedPlayer)
return; // Don't show the joined message for the fake player
final Player p = e.getPlayer();
DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class);
// if(dp!=null) //TODO
// MCChatListener.OnlineSenders.put(dp.getDiscordID(), new DiscordPlayerSender(DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()), channel, player))
if (dp != null) {
val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()));
MCChatListener.OnlineSenders.put(dp.getDiscordID(),
new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p));
MCChatListener.OnlineSenders.put("P" + dp.getDiscordID(),
new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p));
MCChatListener.ConnectedSenders.values().stream()
.filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny()
.ifPresent(dcp -> Bukkit.getPluginManager().callEvent(new PlayerQuitEvent(dcp, "")));
}
if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) {
IUser user = DiscordPlugin.dc
.getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get())));
@ -38,18 +50,20 @@ public class MCListener implements Listener {
+ " do /discord accept");
p.sendMessage("§bIf it wasn't you, do /discord decline");
}
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel,
e.GetPlayer().PlayerName().get() + " joined the game");
MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " joined the game");
MCChatListener.ListC = 0;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerLeave(TBMCPlayerQuitEvent e) {
if (MCChatListener.OnlineSenders.entrySet()
.removeIf(entry -> entry.getValue().getUniqueId().equals(e.getPlayer().getUniqueId())))
; // TODO
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel,
e.GetPlayer().PlayerName().get() + " left the game");
if (e.getPlayer() instanceof DiscordConnectedPlayer)
return; // Only care about real users
MCChatListener.OnlineSenders.entrySet()
.removeIf(entry -> entry.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()));
MCChatListener.ConnectedSenders.values().stream()
.filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny()
.ifPresent(dcp -> Bukkit.getPluginManager().callEvent(new PlayerJoinEvent(dcp, "")));
MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " left the game");
}
@EventHandler
@ -70,16 +84,15 @@ public class MCListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onPlayerDeath(PlayerDeathEvent e) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, e.getDeathMessage());
MCChatListener.sendSystemMessageToChat(e.getDeathMessage());
}
@EventHandler
public void onPlayerAFK(AfkStatusChangeEvent e) {
if (e.isCancelled())
if (e.isCancelled() || !e.getAffected().getBase().isOnline())
return;
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel,
DiscordPlugin.sanitizeString(e.getAffected().getBase().getDisplayName()) + " is "
+ (e.getValue() ? "now" : "no longer") + " AFK.");
MCChatListener.sendSystemMessageToChat(DiscordPlugin.sanitizeString(e.getAffected().getBase().getDisplayName())
+ " is " + (e.getValue() ? "now" : "no longer") + " AFK.");
}
@EventHandler

View file

@ -9,7 +9,6 @@ import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.entity.*;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.map.MapView;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.ServerOperator;
@ -29,7 +28,6 @@ public class DiscordFakePlayer extends DiscordHumanEntity implements Player {
perm = new PermissibleBase(new ServerOperator() {
private @Getter @Setter boolean op;
});
Bukkit.getPluginManager().callEvent(new PlayerJoinEvent(this, "Discord fake player joined"));
}
@Delegate