Let moderators read all fight chats automatically

/chat arenas join|leave lets moderators read the fight and team chats
of every arena and event spectate server; the choice is saved across
relogs. /chat <arena> leave excludes a single arena for the session.
This commit is contained in:
2026-10-16 11:09:52 +02:00
parent 7f47d687d3
commit 62850b2e11
4 changed files with 53 additions and 6 deletions
@@ -618,6 +618,9 @@ CHAT_FIGHT_NO_TEAM = §cYou are not in a fight team.
GLOBAL_USAGE = §8/§7global §8[§emessage§8] GLOBAL_USAGE = §8/§7global §8[§emessage§8]
CHAT_USAGE = §8/§7chat §8[§echannel§8] [§ejoin§8|§eleave§8] CHAT_USAGE = §8/§7chat §8[§echannel§8] [§ejoin§8|§eleave§8]
CHAT_MSG_USAGE = §8/§7chat §8[§echannel§8] §7msg §8[§emessage§8] CHAT_MSG_USAGE = §8/§7chat §8[§echannel§8] §7msg §8[§emessage§8]
CHAT_ARENAS_USAGE = §8/§7chat §7arenas §8[§ejoin§8|§eleave§8]
CHAT_ARENAS_JOINED = §7You now read the chats of all fights.
CHAT_ARENAS_LEFT = §7You no longer read the chats of all fights.
CHAT_CHANNEL_UNKNOWN = §cUnknown chat channel. CHAT_CHANNEL_UNKNOWN = §cUnknown chat channel.
CHAT_CHANNEL_JOINED = §7You are reading §e{0} §7again. CHAT_CHANNEL_JOINED = §7You are reading §e{0} §7again.
CHAT_CHANNEL_LEFT = §7You no longer read §e{0}§7. CHAT_CHANNEL_LEFT = §7You no longer read §e{0}§7.
@@ -583,6 +583,9 @@ CHAT_FIGHT_NO_TEAM = §cDu bist in keinem Kampfteam.
GLOBAL_USAGE = §8/§7global §8[§eNachricht§8] GLOBAL_USAGE = §8/§7global §8[§eNachricht§8]
CHAT_USAGE = §8/§7chat §8[§eKanal§8] [§ejoin§8|§eleave§8] CHAT_USAGE = §8/§7chat §8[§eKanal§8] [§ejoin§8|§eleave§8]
CHAT_MSG_USAGE = §8/§7chat §8[§eKanal§8] §7msg §8[§eNachricht§8] CHAT_MSG_USAGE = §8/§7chat §8[§eKanal§8] §7msg §8[§eNachricht§8]
CHAT_ARENAS_USAGE = §8/§7chat §7arenas §8[§ejoin§8|§eleave§8]
CHAT_ARENAS_JOINED = §7Du liest jetzt die Chats aller Fights mit.
CHAT_ARENAS_LEFT = §7Du liest die Chats aller Fights nicht mehr mit.
CHAT_CHANNEL_UNKNOWN = §cUnbekannter Chatkanal. CHAT_CHANNEL_UNKNOWN = §cUnbekannter Chatkanal.
CHAT_CHANNEL_JOINED = §7Du liest §e{0} §7wieder mit. CHAT_CHANNEL_JOINED = §7Du liest §e{0} §7wieder mit.
CHAT_CHANNEL_LEFT = §7Du liest §e{0} §7nicht mehr mit. CHAT_CHANNEL_LEFT = §7Du liest §e{0} §7nicht mehr mit.
@@ -57,6 +57,7 @@ public class ChatManager extends BasicListener {
private static final String CONFIG_KEY = "chat.channel"; private static final String CONFIG_KEY = "chat.channel";
private static final String HIDDEN_KEY = "chat.hidden"; private static final String HIDDEN_KEY = "chat.hidden";
private static final String ARENAS_KEY = "chat.arenas";
private static final long REFEREE_CACHE_MILLIS = 60_000; private static final long REFEREE_CACHE_MILLIS = 60_000;
@Getter @Getter
@@ -76,6 +77,8 @@ public class ChatManager extends BasicListener {
private static final Set<UUID> globalOnArena = ConcurrentHashMap.newKeySet(); private static final Set<UUID> globalOnArena = ConcurrentHashMap.newKeySet();
private static final Set<UUID> announced = ConcurrentHashMap.newKeySet(); private static final Set<UUID> announced = ConcurrentHashMap.newKeySet();
private static final Map<UUID, Set<RegisteredServer>> spies = new ConcurrentHashMap<>(); private static final Map<UUID, Set<RegisteredServer>> spies = new ConcurrentHashMap<>();
private static final Map<UUID, Boolean> allArenas = new ConcurrentHashMap<>();
private static final Map<UUID, Set<RegisteredServer>> leftArenas = new ConcurrentHashMap<>();
private static final Map<UUID, Set<String>> hidden = new ConcurrentHashMap<>(); private static final Map<UUID, Set<String>> hidden = new ConcurrentHashMap<>();
private static int refereeEvent = -1; private static int refereeEvent = -1;
@@ -159,16 +162,41 @@ public class ChatManager extends BasicListener {
return !currentServer(player).map(ChatManager::isArena).orElse(false) || globalOnArena.contains(player.getUniqueId()); return !currentServer(player).map(ChatManager::isArena).orElse(false) || globalOnArena.contains(player.getUniqueId());
} }
/**
* @return the moderators reading the fight chats of the server without being on it
*/
static Stream<Chatter> spies(RegisteredServer server) { static Stream<Chatter> spies(RegisteredServer server) {
return spies.entrySet().stream() return Chatter.allPlayers()
.filter(entry -> entry.getValue().contains(server))
.map(entry -> VelocityCore.getProxy().getPlayer(entry.getKey()).orElse(null))
.filter(Objects::nonNull)
.map(Chatter::of) .map(Chatter::of)
.filter(chatter -> !onServer(chatter, server))
.filter(chatter -> chatter.user().hasPerm(UserPerm.MODERATION)) .filter(chatter -> chatter.user().hasPerm(UserPerm.MODERATION))
.filter(chatter -> readsArena(chatter.user().getUUID(), server))
.map(Chatter.class::cast); .map(Chatter.class::cast);
} }
private static boolean readsArena(UUID uuid, RegisteredServer server) {
Set<RegisteredServer> joined = spies.get(uuid);
if (joined != null && joined.contains(server)) return true;
Set<RegisteredServer> left = leftArenas.get(uuid);
return readsAllArenas(uuid) && (left == null || !left.contains(server));
}
private static boolean readsAllArenas(UUID uuid) {
return allArenas.computeIfAbsent(uuid, u -> "true".equals(UserConfig.getConfig(u, ARENAS_KEY)));
}
/**
* Lets a moderator read the fight chats of every fight server automatically, saved across relogs.
*/
public static void setReadAllArenas(PlayerChatter player, boolean read) {
UUID uuid = player.user().getUUID();
allArenas.put(uuid, read);
leftArenas.remove(uuid);
UserConfig.updatePlayerConfig(uuid, ARENAS_KEY, read ? "true" : null);
player.system(read ? "CHAT_ARENAS_JOINED" : "CHAT_ARENAS_LEFT");
}
/** /**
* @return true if the user is a referee of the event fight running on the server * @return true if the user is a referee of the event fight running on the server
*/ */
@@ -223,7 +251,10 @@ public class ChatManager extends BasicListener {
public static void join(PlayerChatter player, ChatChannel channel) { public static void join(PlayerChatter player, ChatChannel channel) {
UUID uuid = player.user().getUUID(); UUID uuid = player.user().getUUID();
if (isForeignArena(player, channel)) { if (isForeignArena(player, channel)) {
spies.computeIfAbsent(uuid, u -> ConcurrentHashMap.newKeySet()).add(((LocalChannel) channel).getServer()); RegisteredServer server = ((LocalChannel) channel).getServer();
spies.computeIfAbsent(uuid, u -> ConcurrentHashMap.newKeySet()).add(server);
Set<RegisteredServer> left = leftArenas.get(uuid);
if (left != null) left.remove(server);
player.system("CHAT_CHANNEL_JOINED", channel.tag(player)); player.system("CHAT_CHANNEL_JOINED", channel.tag(player));
return; return;
} }
@@ -237,8 +268,11 @@ public class ChatManager extends BasicListener {
public static void leave(PlayerChatter player, ChatChannel channel) { public static void leave(PlayerChatter player, ChatChannel channel) {
UUID uuid = player.user().getUUID(); UUID uuid = player.user().getUUID();
if (isForeignArena(player, channel)) { if (isForeignArena(player, channel)) {
RegisteredServer server = ((LocalChannel) channel).getServer();
Set<RegisteredServer> servers = spies.get(uuid); Set<RegisteredServer> servers = spies.get(uuid);
if (servers != null) servers.remove(((LocalChannel) channel).getServer()); if (servers != null) servers.remove(server);
// Excludes the arena for this session while reading all arenas
leftArenas.computeIfAbsent(uuid, u -> ConcurrentHashMap.newKeySet()).add(server);
player.system("CHAT_CHANNEL_LEFT", channel.tag(player)); player.system("CHAT_CHANNEL_LEFT", channel.tag(player));
return; return;
} }
@@ -445,6 +479,8 @@ public class ChatManager extends BasicListener {
globalOnArena.remove(uuid); globalOnArena.remove(uuid);
announced.remove(uuid); announced.remove(uuid);
spies.remove(uuid); spies.remove(uuid);
allArenas.remove(uuid);
leftArenas.remove(uuid);
hidden.remove(uuid); hidden.remove(uuid);
directs.removeIf(channel -> channel.contains(uuid)); directs.removeIf(channel -> channel.contains(uuid));
@@ -61,6 +61,11 @@ public class ChatCommand extends SWCommand {
} }
} }
@Register(value = "arenas", description = "CHAT_ARENAS_USAGE")
public void arenas(@Validator("moderator") PlayerChatter sender, @StaticValue(value = {"leave", "join"}, allowISE = true) boolean join) {
ChatManager.setReadAllArenas(sender, join);
}
@Register(description = "CHAT_MSG_USAGE") @Register(description = "CHAT_MSG_USAGE")
public void msg(@Validator("moderator") PlayerChatter sender, ChatChannel channel, @StaticValue("msg") String msg, @ErrorMessage(value = "CHAT_MSG_USAGE", allowEAs = false) String... message) { public void msg(@Validator("moderator") PlayerChatter sender, ChatChannel channel, @StaticValue("msg") String msg, @ErrorMessage(value = "CHAT_MSG_USAGE", allowEAs = false) String... message) {
channel.send(sender, String.join(" ", message)); channel.send(sender, String.join(" ", message));