Remove duplicated chat channel logic

- Shared send-or-switch helper for /global, /local, /tc and /stc
- Shared helpers for "is on server" and the player's current local
  channel
- Read fight infos from TablistManager instead of keeping a second map
- /chat resolves fight servers (arenas and spectate servers) by name in
  one place
- Reuse the global and participant formats instead of identical keys
This commit is contained in:
2026-10-16 09:17:01 +02:00
parent 4c75879915
commit 904a850a3f
13 changed files with 74 additions and 77 deletions
@@ -578,8 +578,6 @@ CHAT_SERVERTEAM_SENDER = §e{0}
CHAT_SERVERTEAM = §8» §f{2}
CHAT_GLOBAL_SENDER = {3}{4}{5}{6}{0}
CHAT_GLOBAL = §8» {7}{2}
CHAT_LOCAL_SENDER = {3}{4}{5}{6}{0}
CHAT_LOCAL = §8» {7}{2}
CHAT_TEAM_SENDER = §e{0}
CHAT_TEAM = §8» §f{2}
CHAT_MSG_SENDER = §e{0}
@@ -591,7 +589,6 @@ CHAT_FIGHT_SPECTATOR_SENDER = §7{1}
CHAT_FIGHT_SPECTATOR = §8» §7{0}
CHAT_FIGHT_REFEREE_SENDER = §e{1}
CHAT_FIGHT_REFEREE = §8» §e{0}
CHAT_FIGHT_TEAM_SENDER = {0}{1}
CHAT_FIGHT_TEAM = §8» §f{0}
CHAT_ICON = {0}{1}
CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Prefix: §r{1}{2}
@@ -543,8 +543,6 @@ CHAT_SERVERTEAM_SENDER = §e{0}
CHAT_SERVERTEAM = §8» §f{2}
CHAT_GLOBAL_SENDER = {3}{4}{5}{6}{0}
CHAT_GLOBAL = §8» {7}{2}
CHAT_LOCAL_SENDER = {3}{4}{5}{6}{0}
CHAT_LOCAL = §8» {7}{2}
CHAT_TEAM_SENDER = §e{0}
CHAT_TEAM = §8» §f{2}
CHAT_MSG_SENDER = §e{0}
@@ -556,7 +554,6 @@ CHAT_FIGHT_SPECTATOR_SENDER = §7{1}
CHAT_FIGHT_SPECTATOR = §8» §7{0}
CHAT_FIGHT_REFEREE_SENDER = §e{1}
CHAT_FIGHT_REFEREE = §8» §e{0}
CHAT_FIGHT_TEAM_SENDER = {0}{1}
CHAT_FIGHT_TEAM = §8» §f{0}
CHAT_ICON = {0}{1}
CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Kürzel: §r{1}{2}
@@ -76,7 +76,7 @@ public class ChatFormat {
*
* @param coloredTeamName the fight team of the sender, null if the sender is not in a fight team
*/
public static Component fight(Chatter receiver, RegisteredServer server, Chatter sender, String coloredTeamName, String format, String message) {
public static Component fight(Chatter receiver, RegisteredServer server, Chatter sender, String coloredTeamName, String senderFormat, String format, String message) {
TextComponent.Builder line = Component.text();
String nameColor = "";
if (coloredTeamName != null) {
@@ -89,7 +89,7 @@ public class ChatFormat {
nameColor = coloredTeamName.length() >= 2 && coloredTeamName.charAt(0) == '§' ? coloredTeamName.substring(0, 2) : "";
}
line.append(withTeamHover(receiver, sender.user(), receiver.parse(new Message(format + "_SENDER", nameColor, sender.user()))));
line.append(withTeamHover(receiver, sender.user(), receiver.parse(new Message(senderFormat, nameColor, sender.user()))));
line.append(receiver.parse(new Message(format, message)));
return line.build();
}
@@ -41,6 +41,7 @@ import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.EventStarter;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.listeners.BasicListener;
import de.steamwar.velocitycore.tablist.TablistManager;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
@@ -68,7 +69,6 @@ public class ChatManager extends BasicListener {
private static final Map<RegisteredServer, LocalChannel> locals = new ConcurrentHashMap<>();
private static final Map<RegisteredServer, FightTeamChannel[]> fightTeams = new ConcurrentHashMap<>();
private static final Map<RegisteredServer, FightInfoPacket> fightInfos = new ConcurrentHashMap<>();
private static final Map<Integer, TeamChannel> teams = new ConcurrentHashMap<>();
private static final Set<DirectChannel> directs = ConcurrentHashMap.newKeySet();
@@ -120,6 +120,38 @@ public class ChatManager extends BasicListener {
return Subserver.isArena(Subserver.getSubserver(server.getServerInfo())) || EventStarter.isSpectateServer(server.getServerInfo().getName());
}
/**
* @return all servers using a fight chat (arenas and event spectate servers)
*/
public static Stream<RegisteredServer> fightServers() {
return VelocityCore.getProxy().getAllServers().stream().filter(ChatManager::isArena);
}
/**
* @return the local channel of the server the player is on, null while the player is on no server
*/
public static LocalChannel currentLocal(Player player) {
return currentServer(player).map(ChatManager::local).orElse(null);
}
static boolean onServer(Chatter chatter, RegisteredServer server) {
Player player = chatter.getPlayer();
return player != null && server.getPlayersConnected().contains(player);
}
/**
* Sends the message into the channel or makes it the default channel of the player if there is no message.
*/
public static void sendOrSwitch(Chatter sender, ChatChannel channel, String[] message, String usage) {
if (message.length > 0) {
channel.send(sender, String.join(" ", message));
} else if (sender instanceof PlayerChatter player) {
switchTo(player, channel);
} else {
sender.system(usage);
}
}
private static Optional<RegisteredServer> currentServer(Player player) {
return player.getCurrentServer().map(ServerConnection::getServer);
}
@@ -186,7 +218,7 @@ public class ChatManager extends BasicListener {
* @return true if the channel is the fight chat of an arena the player is not on, which moderators can read without joining the arena
*/
private static boolean isForeignArena(PlayerChatter player, ChatChannel channel) {
return channel instanceof LocalChannel local && local.isArena() && !local.getServer().getPlayersConnected().contains(player.getPlayer());
return channel instanceof LocalChannel local && local.isArena() && !onServer(player, local.getServer());
}
public static void join(PlayerChatter player, ChatChannel channel) {
@@ -225,7 +257,7 @@ public class ChatManager extends BasicListener {
}
public static FightInfoPacket getFightInfo(RegisteredServer server) {
return fightInfos.get(server);
return TablistManager.getFightInfo(server);
}
/**
@@ -248,9 +280,7 @@ public class ChatManager extends BasicListener {
/**
* Updates the fight teams of an arena. Players who just joined a fight team write into the fight chat by default.
*/
public static void updateFightInfo(RegisteredServer server, FightInfoPacket packet) {
fightInfos.keySet().removeIf(s -> s.getPlayersConnected().isEmpty());
FightInfoPacket previous = fightInfos.put(server, packet);
public static void updateFightInfo(RegisteredServer server, FightInfoPacket previous, FightInfoPacket packet) {
Set<Integer> joined = new HashSet<>(packet.getBluePlayers());
joined.addAll(packet.getRedPlayers());
@@ -77,7 +77,7 @@ public class FightTeamChannel extends ChatChannel {
protected Message icon(Chatter receiver) {
String teamName = teamName();
String color = teamName.length() >= 2 && teamName.charAt(0) == '§' ? teamName.substring(0, 2) : "§7";
if (receiver.getPlayer() != null && server.getPlayersConnected().contains(receiver.getPlayer())) {
if (ChatManager.onServer(receiver, server)) {
return new Message("CHAT_ICON_FIGHT_TEAM", color);
}
return new Message("CHAT_ICON_FIGHT_TEAM_FOREIGN", color, server.getServerInfo().getName());
@@ -93,7 +93,7 @@ public class FightTeamChannel extends ChatChannel {
@Override
public boolean canWrite(Chatter sender) {
if (!isMember(sender) || sender.getPlayer() == null || !server.getPlayersConnected().contains(sender.getPlayer())) {
if (!isMember(sender) || !ChatManager.onServer(sender, server)) {
sender.system("CHAT_FIGHT_NO_TEAM");
return false;
}
@@ -102,7 +102,7 @@ public class FightTeamChannel extends ChatChannel {
@Override
protected Component format(Chatter receiver, Chatter sender, String message) {
return ChatFormat.fight(receiver, server, sender, teamName(), "CHAT_FIGHT_TEAM", ChatFormat.highlightMentions(message, "§f", receiver));
return ChatFormat.fight(receiver, server, sender, teamName(), "CHAT_FIGHT_PARTICIPANT_SENDER", "CHAT_FIGHT_TEAM", ChatFormat.highlightMentions(message, "§f", receiver));
}
@Override
@@ -68,7 +68,7 @@ public class LocalChannel extends ChatChannel {
if (!isArena()) return new Message("CHAT_ICON_LOCAL");
// Moderators reading an arena they are not on need to know which arena it is
if (receiver.getPlayer() != null && server.getPlayersConnected().contains(receiver.getPlayer())) {
if (ChatManager.onServer(receiver, server)) {
return new Message("CHAT_ICON_FIGHT");
}
return new Message("CHAT_ICON_FIGHT_FOREIGN", server.getServerInfo().getName());
@@ -85,9 +85,8 @@ public class LocalChannel extends ChatChannel {
@Override
public boolean canWrite(Chatter sender) {
boolean onServer = sender.getPlayer() != null && server.getPlayersConnected().contains(sender.getPlayer());
// Moderators can write into fight chats they are not on (/chatspy)
if (!onServer && !(isArena() && sender.user().hasPerm(UserPerm.MODERATION))) {
// Moderators can write into fight chats they are not on (/chat <arena> msg)
if (!ChatManager.onServer(sender, server) && !(isArena() && sender.user().hasPerm(UserPerm.MODERATION))) {
sender.system("CHAT_NO_WRITE");
return false;
}
@@ -97,20 +96,20 @@ public class LocalChannel extends ChatChannel {
@Override
protected Component format(Chatter receiver, Chatter sender, String message) {
if (!isArena()) {
return ChatFormat.player("CHAT_LOCAL", receiver, sender, null, message);
return ChatFormat.player("CHAT_GLOBAL", receiver, sender, null, message);
}
String highlighted = ChatFormat.highlightMentions(message, "§7", receiver);
FightInfoPacket info = ChatManager.getFightInfo(server);
int id = sender.user().getId();
if (info != null && info.getBluePlayers().contains(id)) {
return ChatFormat.fight(receiver, server, sender, info.getBlueName(), "CHAT_FIGHT_PARTICIPANT", highlighted);
return ChatFormat.fight(receiver, server, sender, info.getBlueName(), "CHAT_FIGHT_PARTICIPANT_SENDER", "CHAT_FIGHT_PARTICIPANT", highlighted);
} else if (info != null && info.getRedPlayers().contains(id)) {
return ChatFormat.fight(receiver, server, sender, info.getRedName(), "CHAT_FIGHT_PARTICIPANT", highlighted);
return ChatFormat.fight(receiver, server, sender, info.getRedName(), "CHAT_FIGHT_PARTICIPANT_SENDER", "CHAT_FIGHT_PARTICIPANT", highlighted);
} else if (ChatManager.isReferee(server, id)) {
return ChatFormat.fight(receiver, server, sender, null, "CHAT_FIGHT_REFEREE", highlighted);
return ChatFormat.fight(receiver, server, sender, null, "CHAT_FIGHT_REFEREE_SENDER", "CHAT_FIGHT_REFEREE", highlighted);
}
return ChatFormat.fight(receiver, server, sender, null, "CHAT_FIGHT_SPECTATOR", highlighted);
return ChatFormat.fight(receiver, server, sender, null, "CHAT_FIGHT_SPECTATOR_SENDER", "CHAT_FIGHT_SPECTATOR", highlighted);
}
@Override
@@ -20,17 +20,13 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.persistent.Subserver;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.chat.ChatChannel;
import de.steamwar.velocitycore.chat.ChatManager;
@@ -81,7 +77,7 @@ public class ChatCommand extends SWCommand {
public ChatChannel map(Chatter sender, PreviousArguments previousArguments, String s) {
return switch (s.toLowerCase()) {
case "global" -> ChatManager.getGlobal();
case "local" -> sender.getPlayer() == null ? null : sender.getPlayer().getCurrentServer().map(ServerConnection::getServer).map(ChatManager::local).orElse(null);
case "local" -> sender.getPlayer() == null ? null : ChatManager.currentLocal(sender.getPlayer());
case "team", "tc" -> sender.user().getTeam() != 0 ? ChatManager.team(sender.user().getTeam()) : null;
case "serverteam", "stc" -> sender.user().hasPerm(UserPerm.TEAM) ? ChatManager.getServerTeam() : null;
default -> arena(sender, s);
@@ -99,10 +95,7 @@ public class ChatCommand extends SWCommand {
if (sender.user().getTeam() != 0) channels.add("team");
if (sender.user().hasPerm(UserPerm.TEAM)) channels.add("serverteam");
if (sender.user().hasPerm(UserPerm.MODERATION)) {
List<Subserver> subserverList = Subserver.getServerList();
synchronized (subserverList) {
subserverList.stream().filter(Subserver::isArena).map(subserver -> subserver.getServer().getName()).forEach(channels::add);
}
ChatManager.fightServers().map(server -> server.getServerInfo().getName()).forEach(channels::add);
}
return channels;
}
@@ -110,14 +103,15 @@ public class ChatCommand extends SWCommand {
}
/**
* Moderators can address the fight chat of every arena by its server name.
* Moderators can address the fight chat of every fight server by its server name.
*/
private static ChatChannel arena(Chatter sender, String name) {
if (!sender.user().hasPerm(UserPerm.MODERATION)) return null;
Subserver subserver = Subserver.getSubserver(VelocityCore.getProxy().getServer(name).map(RegisteredServer::getServerInfo).orElse(null));
if (!Subserver.isArena(subserver)) return null;
return ChatManager.local(subserver.getRegisteredServer());
return ChatManager.fightServers()
.filter(server -> server.getServerInfo().getName().equalsIgnoreCase(name))
.findFirst()
.map(ChatManager::local)
.orElse(null);
}
}
@@ -23,7 +23,6 @@ package de.steamwar.velocitycore.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.velocitycore.chat.ChatManager;
@Linked
@@ -35,12 +34,6 @@ public class GlobalCommand extends SWCommand {
@Register(description = "GLOBAL_USAGE")
public void genericCommand(Chatter sender, String... message) {
if (message.length > 0) {
ChatManager.getGlobal().send(sender, String.join(" ", message));
} else if (sender instanceof PlayerChatter player) {
ChatManager.switchTo(player, ChatManager.getGlobal());
} else {
sender.system("GLOBAL_USAGE");
}
ChatManager.sendOrSwitch(sender, ChatManager.getGlobal(), message, "GLOBAL_USAGE");
}
}
@@ -19,7 +19,6 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.proxy.ServerConnection;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.PlayerChatter;
@@ -35,13 +34,9 @@ public class LocalCommand extends SWCommand {
@Register(description = "CHAT_BC_USAGE")
public void genericCommand(PlayerChatter sender, String... message) {
ChatChannel channel = sender.getPlayer().getCurrentServer().map(ServerConnection::getServer).map(ChatManager::local).orElse(null);
ChatChannel channel = ChatManager.currentLocal(sender.getPlayer());
if (channel == null) return;
if (message.length == 0) {
ChatManager.switchTo(sender, channel);
} else {
channel.send(sender, String.join(" ", message));
}
ChatManager.sendOrSwitch(sender, channel, message, "CHAT_BC_USAGE");
}
}
@@ -22,7 +22,6 @@ package de.steamwar.velocitycore.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.chat.ChatManager;
@@ -35,12 +34,6 @@ public class ServerTeamchatCommand extends SWCommand {
@Register(description = "STC_USAGE")
public void genericCommand(Chatter sender, String... message) {
if (message.length > 0) {
ChatManager.getServerTeam().send(sender, String.join(" ", message));
} else if (sender instanceof PlayerChatter player) {
ChatManager.switchTo(player, ChatManager.getServerTeam());
} else {
sender.system("STC_USAGE");
}
ChatManager.sendOrSwitch(sender, ChatManager.getServerTeam(), message, "STC_USAGE");
}
}
@@ -22,8 +22,6 @@ package de.steamwar.velocitycore.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.velocitycore.chat.ChatChannel;
import de.steamwar.velocitycore.chat.ChatManager;
@Linked
@@ -41,13 +39,6 @@ public class TeamchatCommand extends SWCommand {
return;
}
ChatChannel channel = ChatManager.team(team);
if (args.length > 0) {
channel.send(sender, String.join(" ", args));
} else if (sender instanceof PlayerChatter player) {
ChatManager.switchTo(player, channel);
} else {
sender.system("TC_USAGE");
}
ChatManager.sendOrSwitch(sender, ChatManager.team(team), args, "TC_USAGE");
}
}
@@ -51,8 +51,8 @@ public class FightInfoHandler extends PacketHandler {
FightInfoPacket lobbyPacket = packet.withServerName(server.getServerInfo().getName());
TablistManager.newFightInfo(server, packet);
ChatManager.updateFightInfo(server, packet);
FightInfoPacket previous = TablistManager.newFightInfo(server, packet);
ChatManager.updateFightInfo(server, previous, packet);
lobbys.removeIf(s -> s.getPlayersConnected().isEmpty());
lobbys.forEach(lobby -> NetworkSender.send(lobby, lobbyPacket));
@@ -45,9 +45,17 @@ public class TablistManager extends BasicListener implements Disable {
private static final Map<RegisteredServer, FightInfoPacket> fightInfos = new HashMap<>();
public static synchronized void newFightInfo(RegisteredServer info, FightInfoPacket packet) {
fightInfos.put(info, packet);
/**
* @return the previous fight info of the server, null if there was none
*/
public static synchronized FightInfoPacket newFightInfo(RegisteredServer info, FightInfoPacket packet) {
FightInfoPacket previous = fightInfos.put(info, packet);
fightInfos.keySet().removeIf(serverInfo -> serverInfo.getPlayersConnected().isEmpty());
return previous;
}
public static synchronized FightInfoPacket getFightInfo(RegisteredServer server) {
return fightInfos.get(server);
}
private final Map<Player, Tablist> tablists = new HashMap<>();