Fix some mcchat and a reset issue

Using ConcurrentHashMaps (#62)
Add custom /list to hide vanished players (#120)
Fixed /discord reset for non-Paper servers (#103)
This commit is contained in:
Norbi Peti 2020-10-08 00:02:49 +02:00
parent 56d13ebf9f
commit 891be91d69
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
6 changed files with 98 additions and 70 deletions

View file

@ -100,7 +100,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
ListC = 0;
lastlist = 0;
}
if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
if (msglowercased.equals("/list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
{
DPUtils.reply(message, Mono.empty(), "stop it. You know the answer.").subscribe();
lastlist = 0;

View file

@ -20,15 +20,17 @@ public class MCChatCustom {
/**
* Used for town or nation chats or anything else
*/
static ArrayList<CustomLMD> lastmsgCustom = new ArrayList<>();
static final ArrayList<CustomLMD> lastmsgCustom = new ArrayList<>();
public static void addCustomChat(MessageChannel channel, String groupid, Channel mcchannel, User user, DiscordConnectedPlayer dcp, int toggles, Set<TBMCSystemChatEvent.BroadcastTarget> brtoggles) {
if (mcchannel instanceof ChatRoom) {
((ChatRoom) mcchannel).joinRoom(dcp);
if (groupid == null) groupid = mcchannel.getGroupID(dcp);
synchronized (lastmsgCustom) {
if (mcchannel instanceof ChatRoom) {
((ChatRoom) mcchannel).joinRoom(dcp);
if (groupid == null) groupid = mcchannel.getGroupID(dcp);
}
val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles, brtoggles);
lastmsgCustom.add(lmd);
}
val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles, brtoggles);
lastmsgCustom.add(lmd);
}
public static boolean hasCustomChat(Snowflake channel) {
@ -41,14 +43,16 @@ public class MCChatCustom {
}
public static boolean removeCustomChat(Snowflake channel) {
MCChatUtils.lastmsgfromd.remove(channel.asLong());
return lastmsgCustom.removeIf(lmd -> {
if (lmd.channel.getId().asLong() != channel.asLong())
return false;
if (lmd.mcchannel instanceof ChatRoom)
((ChatRoom) lmd.mcchannel).leaveRoom(lmd.dcp);
return true;
});
synchronized (lastmsgCustom) {
MCChatUtils.lastmsgfromd.remove(channel.asLong());
return lastmsgCustom.removeIf(lmd -> {
if (lmd.channel.getId().asLong() != channel.asLong())
return false;
if (lmd.mcchannel instanceof ChatRoom)
((ChatRoom) lmd.mcchannel).leaveRoom(lmd.dcp);
return true;
});
}
}
public static List<CustomLMD> getCustomChats() {

View file

@ -131,17 +131,19 @@ public class MCChatListener implements Listener {
doit.accept(data);
}
val iterator = MCChatCustom.lastmsgCustom.iterator();
while (iterator.hasNext()) {
val lmd = iterator.next();
if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel.getId())) //Test if msg is from Discord
&& e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it
&& e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58
if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions
doit.accept(lmd);
else {
iterator.remove(); //If the user no longer has permission, remove the connection
lmd.channel.createMessage("The user no longer has permission to view the channel, connection removed.").subscribe();
synchronized (MCChatCustom.lastmsgCustom) {
val iterator = MCChatCustom.lastmsgCustom.iterator();
while (iterator.hasNext()) {
val lmd = iterator.next();
if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel.getId())) //Test if msg is from Discord
&& e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it
&& e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58
if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions
doit.accept(lmd);
else {
iterator.remove(); //If the user no longer has permission, remove the connection
lmd.channel.createMessage("The user no longer has permission to view the channel, connection removed.").subscribe();
}
}
}
}
@ -217,7 +219,7 @@ public class MCChatListener implements Listener {
}
private BukkitTask rectask;
private LinkedBlockingQueue<MessageCreateEvent> recevents = new LinkedBlockingQueue<>();
private final LinkedBlockingQueue<MessageCreateEvent> recevents = new LinkedBlockingQueue<>();
private Runnable recrun;
private static Thread recthread;
@ -368,6 +370,7 @@ public class MCChatListener implements Listener {
return true;
}
module.log(dsender.getName() + " ran from DC: /" + cmd);
if (runCustomCommand(dsender, cmdlowercased)) return true;
val channel = clmd == null ? user.channel().get() : clmd.mcchannel;
val ev = new TBMCCommandPreprocessEvent(dsender, channel, dmessage, clmd == null ? dsender : clmd.dcp);
Bukkit.getScheduler().runTask(DiscordPlugin.plugin, //Commands need to be run sync
@ -396,6 +399,17 @@ public class MCChatListener implements Listener {
return true;
}
private boolean runCustomCommand(DiscordSenderBase dsender, String cmdlowercased) {
if (cmdlowercased.startsWith("list")) {
var players = Bukkit.getOnlinePlayers();
dsender.sendMessage("There are " + players.size() + " out of " + Bukkit.getMaxPlayers() + " players online.");
dsender.sendMessage("Players: " + players.stream().filter(MCChatUtils::checkEssentials)
.map(Player::getDisplayName).collect(Collectors.joining(", ")));
return true;
}
return false;
}
@FunctionalInterface
private interface InterruptibleConsumer<T> {
void accept(T value) throws TimeoutException, InterruptedException;

View file

@ -20,32 +20,34 @@ public class MCChatPrivate {
static ArrayList<MCChatUtils.LastMsgData> lastmsgPerUser = new ArrayList<>();
public static boolean privateMCChat(MessageChannel channel, boolean start, User user, DiscordPlayer dp) {
TBMCPlayer mcp = dp.getAs(TBMCPlayer.class);
if (mcp != null) { // If the accounts aren't connected, can't make a connected sender
val p = Bukkit.getPlayer(mcp.getUUID());
val op = Bukkit.getOfflinePlayer(mcp.getUUID());
val mcm = ComponentManager.getIfEnabled(MinecraftChatModule.class);
if (start) {
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUUID(), op.getName(), mcm);
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender);
MCChatUtils.LoggedInPlayers.put(mcp.getUUID(), sender);
if (p == null) // Player is offline - If the player is online, that takes precedence
MCChatUtils.callLoginEvents(sender);
} else {
val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId(), user);
assert sender != null;
MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId());
if (p == null // Player is offline - If the player is online, that takes precedence
&& sender.isLoggedIn()) //Don't call the quit event if login failed
MCChatUtils.callLogoutEvent(sender, true);
sender.setLoggedIn(false);
}
} // ---- PermissionsEx warning is normal on logout ----
if (!start)
MCChatUtils.lastmsgfromd.remove(channel.getId().asLong());
return start //
? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs
: lastmsgPerUser.removeIf(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong());
synchronized (MCChatUtils.ConnectedSenders) {
TBMCPlayer mcp = dp.getAs(TBMCPlayer.class);
if (mcp != null) { // If the accounts aren't connected, can't make a connected sender
val p = Bukkit.getPlayer(mcp.getUUID());
val op = Bukkit.getOfflinePlayer(mcp.getUUID());
val mcm = ComponentManager.getIfEnabled(MinecraftChatModule.class);
if (start) {
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUUID(), op.getName(), mcm);
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender);
MCChatUtils.LoggedInPlayers.put(mcp.getUUID(), sender);
if (p == null) // Player is offline - If the player is online, that takes precedence
MCChatUtils.callLoginEvents(sender);
} else {
val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId(), user);
assert sender != null;
MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId());
if (p == null // Player is offline - If the player is online, that takes precedence
&& sender.isLoggedIn()) //Don't call the quit event if login failed
MCChatUtils.callLogoutEvent(sender, true);
sender.setLoggedIn(false);
}
} // ---- PermissionsEx warning is normal on logout ----
if (!start)
MCChatUtils.lastmsgfromd.remove(channel.getId().asLong());
return start //
? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs
: lastmsgPerUser.removeIf(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong());
}
}
public static boolean isMinecraftChatEnabled(DiscordPlayer dp) {
@ -59,11 +61,13 @@ public class MCChatPrivate {
}
public static void logoutAll() {
for (val entry : MCChatUtils.ConnectedSenders.entrySet())
for (val valueEntry : entry.getValue().entrySet())
if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey(), valueEntry.getValue().getUser()) == null) //If the player is online then the fake player was already logged out
MCChatUtils.callLogoutEvent(valueEntry.getValue(), false); //This is sync
MCChatUtils.ConnectedSenders.clear();
synchronized (MCChatUtils.ConnectedSenders) {
for (val entry : MCChatUtils.ConnectedSenders.entrySet())
for (val valueEntry : entry.getValue().entrySet())
if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey(), valueEntry.getValue().getUser()) == null) //If the player is online then the fake player was already logged out
MCChatUtils.callLogoutEvent(valueEntry.getValue(), false); //This is sync
MCChatUtils.ConnectedSenders.clear();
}
}
}

View file

@ -34,6 +34,7 @@ import reactor.core.publisher.Mono;
import javax.annotation.Nullable;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -45,13 +46,13 @@ public class MCChatUtils {
/**
* May contain P&lt;DiscordID&gt; as key for public chat
*/
public static final HashMap<String, HashMap<Snowflake, DiscordSender>> UnconnectedSenders = new HashMap<>();
public static final HashMap<String, HashMap<Snowflake, DiscordConnectedPlayer>> ConnectedSenders = new HashMap<>();
public static final ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, DiscordSender>> UnconnectedSenders = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, DiscordConnectedPlayer>> ConnectedSenders = new ConcurrentHashMap<>();
/**
* May contain P&lt;DiscordID&gt; as key for public chat
*/
public static final HashMap<String, HashMap<Snowflake, DiscordPlayerSender>> OnlineSenders = new HashMap<>();
public static final HashMap<UUID, DiscordConnectedPlayer> LoggedInPlayers = new HashMap<>();
public static final ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, DiscordPlayerSender>> OnlineSenders = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<UUID, DiscordConnectedPlayer> LoggedInPlayers = new ConcurrentHashMap<>();
static @Nullable LastMsgData lastmsgdata;
static LongObjectHashMap<Message> lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks
private static MinecraftChatModule module;
@ -104,28 +105,28 @@ public class MCChatUtils {
((TextChannel) lmd.channel).edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait
}
private static boolean checkEssentials(Player p) {
static boolean checkEssentials(Player p) {
var ess = MainPlugin.ess;
if (ess == null) return true;
return !ess.getUser(p).isHidden();
}
public static <T extends DiscordSenderBase> T addSender(HashMap<String, HashMap<Snowflake, T>> senders,
public static <T extends DiscordSenderBase> T addSender(ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, T>> senders,
User user, T sender) {
return addSender(senders, user.getId().asString(), sender);
}
public static <T extends DiscordSenderBase> T addSender(HashMap<String, HashMap<Snowflake, T>> senders,
public static <T extends DiscordSenderBase> T addSender(ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, T>> senders,
String did, T sender) {
var map = senders.get(did);
if (map == null)
map = new HashMap<>();
map = new ConcurrentHashMap<>();
map.put(sender.getChannel().getId(), sender);
senders.put(did, map);
return sender;
}
public static <T extends DiscordSenderBase> T getSender(HashMap<String, HashMap<Snowflake, T>> senders,
public static <T extends DiscordSenderBase> T getSender(ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, T>> senders,
Snowflake channel, User user) {
var map = senders.get(user.getId().asString());
if (map != null)
@ -133,7 +134,7 @@ public class MCChatUtils {
return null;
}
public static <T extends DiscordSenderBase> T removeSender(HashMap<String, HashMap<Snowflake, T>> senders,
public static <T extends DiscordSenderBase> T removeSender(ConcurrentHashMap<String, ConcurrentHashMap<Snowflake, T>> senders,
Snowflake channel, User user) {
var map = senders.get(user.getId().asString());
if (map != null)

View file

@ -74,7 +74,7 @@ public class DiscordMCCommand extends ICommand2MC {
"This command disables and then enables the plugin." //
})
public void reset(CommandSender sender) {
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
Runnable task = () -> {
if (!DiscordPlugin.plugin.tryReloadConfig()) {
sender.sendMessage("§cFailed to reload config so not resetting. Check the console.");
return;
@ -87,7 +87,12 @@ public class DiscordMCCommand extends ICommand2MC {
Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin);
if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors
sender.sendMessage("§bReset finished!");
});
};
if (!Bukkit.getName().equals("Paper")) {
getPlugin().getLogger().warning("Async plugin events are not supported by the server, running on main thread");
Bukkit.getScheduler().runTask(DiscordPlugin.plugin, task);
} else
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, task);
}
@Command2.Subcommand(helpText = {