Add team hovers to fight chat and make DMs non-default

- Names in the fight chat show the sender's team on hover like
  everywhere else; the Blue/Red team prefix is only hoverable in event
  fights, where it is the actual team
- Server team members using the SW prefix show the SteamWar team
- Direct messages can no longer be the default channel; /msg and /r
  require a message again
This commit is contained in:
2026-10-16 08:59:26 +02:00
parent 317cb0adf8
commit 975d42c17f
9 changed files with 90 additions and 43 deletions
@@ -585,10 +585,14 @@ CHAT_TEAM = §8» §f{2}
CHAT_MSG_SENDER = §e{0} CHAT_MSG_SENDER = §e{0}
CHAT_MSG = §8»§e{1} §7{2} CHAT_MSG = §8»§e{1} §7{2}
CHAT_SPECIAL_ALERT = §e{0}§8»§e{1} §7{2} CHAT_SPECIAL_ALERT = §e{0}§8»§e{1} §7{2}
CHAT_FIGHT_PARTICIPANT = {0} {1}§8» §7{2} CHAT_FIGHT_PARTICIPANT_SENDER = {0}{1}
CHAT_FIGHT_SPECTATOR = §7{0}§8» §7{1} CHAT_FIGHT_PARTICIPANT = §8» §7{0}
CHAT_FIGHT_REFEREE = §e{0}§8» §e{1} CHAT_FIGHT_SPECTATOR_SENDER = §7{1}
CHAT_FIGHT_TEAM = {0} {1}§8» §f{2} 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_ICON = {0}{1}
CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Prefix: §r{1}{2} CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Prefix: §r{1}{2}
CHAT_ICON_GLOBAL = 🌍 CHAT_ICON_GLOBAL = 🌍
@@ -610,7 +614,6 @@ CHAT_CHANNEL_ALERT = §cAlert
CHAT_CHANNEL_LOCAL = §eLocal CHAT_CHANNEL_LOCAL = §eLocal
CHAT_CHANNEL_CURRENT = §7You are writing into §e{0}§7. CHAT_CHANNEL_CURRENT = §7You are writing into §e{0}§7.
CHAT_CHANNEL_SWITCHED = §7You are now writing into §e{0}§7. CHAT_CHANNEL_SWITCHED = §7You are now writing into §e{0}§7.
CHAT_CHANNEL_CLOSED = §e{0} §7was closed.
CHAT_CHANNEL_NOT_SWITCHABLE = §cYou cannot write into this channel by default. CHAT_CHANNEL_NOT_SWITCHABLE = §cYou cannot write into this channel by default.
CHAT_NO_WRITE = §cYou cannot write into this channel. CHAT_NO_WRITE = §cYou cannot write into this channel.
CHAT_FIGHT_NO_TEAM = §cYou are not in a fight team. CHAT_FIGHT_NO_TEAM = §cYou are not in a fight team.
@@ -550,10 +550,14 @@ CHAT_TEAM = §8» §f{2}
CHAT_MSG_SENDER = §e{0} CHAT_MSG_SENDER = §e{0}
CHAT_MSG = §8»§e{1} §7{2} CHAT_MSG = §8»§e{1} §7{2}
CHAT_SPECIAL_ALERT = §e{0}§8»§e{1} §7{2} CHAT_SPECIAL_ALERT = §e{0}§8»§e{1} §7{2}
CHAT_FIGHT_PARTICIPANT = {0} {1}§8» §7{2} CHAT_FIGHT_PARTICIPANT_SENDER = {0}{1}
CHAT_FIGHT_SPECTATOR = §7{0}§8» §7{1} CHAT_FIGHT_PARTICIPANT = §8» §7{0}
CHAT_FIGHT_REFEREE = §e{0}§8» §e{1} CHAT_FIGHT_SPECTATOR_SENDER = §7{1}
CHAT_FIGHT_TEAM = {0} {1}§8» §f{2} 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_ICON = {0}{1}
CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Kürzel: §r{1}{2} CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Kürzel: §r{1}{2}
CHAT_ICON_GLOBAL = 🌍 CHAT_ICON_GLOBAL = 🌍
@@ -575,7 +579,6 @@ CHAT_CHANNEL_ALERT = §cAlert
CHAT_CHANNEL_LOCAL = §eLokal CHAT_CHANNEL_LOCAL = §eLokal
CHAT_CHANNEL_CURRENT = §7Du schreibst in §e{0}§7. CHAT_CHANNEL_CURRENT = §7Du schreibst in §e{0}§7.
CHAT_CHANNEL_SWITCHED = §7Du schreibst jetzt in §e{0}§7. CHAT_CHANNEL_SWITCHED = §7Du schreibst jetzt in §e{0}§7.
CHAT_CHANNEL_CLOSED = §e{0} §7wurde geschlossen.
CHAT_CHANNEL_NOT_SWITCHABLE = §cIn diesen Kanal kannst du nicht standardmäßig schreiben. CHAT_CHANNEL_NOT_SWITCHABLE = §cIn diesen Kanal kannst du nicht standardmäßig schreiben.
CHAT_NO_WRITE = §cDu kannst nicht in diesen Kanal schreiben. CHAT_NO_WRITE = §cDu kannst nicht in diesen Kanal schreiben.
CHAT_FIGHT_NO_TEAM = §cDu bist in keinem Kampfteam. CHAT_FIGHT_NO_TEAM = §cDu bist in keinem Kampfteam.
@@ -20,6 +20,7 @@
package de.steamwar.velocitycore.chat; package de.steamwar.velocitycore.chat;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import de.steamwar.messages.Chatter; import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message; import de.steamwar.messages.Message;
import de.steamwar.network.packets.server.PingPacket; import de.steamwar.network.packets.server.PingPacket;
@@ -29,6 +30,7 @@ import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.network.NetworkSender; import de.steamwar.velocitycore.network.NetworkSender;
import de.steamwar.velocitycore.util.SteamwarPrefix; import de.steamwar.velocitycore.util.SteamwarPrefix;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEvent;
import java.util.Arrays; import java.util.Arrays;
@@ -65,14 +67,49 @@ public class ChatFormat {
prefix.getChatPrefix().length() == 0 ? "§f" : prefix.getChatPrefix() + " ", prefix.getChatPrefix().length() == 0 ? "§f" : prefix.getChatPrefix() + " ",
chatColorCode}; chatColorCode};
Component senderPart = receiver.parse(new Message(format + "_SENDER", params)); Component senderPart = withTeamHover(receiver, user, receiver.parse(new Message(format + "_SENDER", params)));
if (user.getTeam() != 0) {
Team team = Team.byId(user.getTeam());
senderPart = senderPart.hoverEvent(HoverEvent.showText(receiver.parse(new Message("CHAT_HOVER_TEAM", team.getTeamName(), "§" + team.getTeamColor(), team.getTeamKuerzel()))));
}
return Component.text().append(senderPart).append(receiver.parse(new Message(format, params))).build(); return Component.text().append(senderPart).append(receiver.parse(new Message(format, params))).build();
} }
/**
* Formats a fight chat message. The fight team name is only hoverable in event fights, where it is the actual team.
*
* @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) {
TextComponent.Builder line = Component.text();
String nameColor = "";
if (coloredTeamName != null) {
Component team = Chatter.SERIALIZER.deserialize(coloredTeamName);
Team eventTeam = ChatManager.eventTeam(server, coloredTeamName);
if (eventTeam != null) {
team = team.hoverEvent(HoverEvent.showText(teamHover(receiver, eventTeam)));
}
line.append(team).append(Component.text(" "));
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(receiver.parse(new Message(format, message)));
return line.build();
}
/**
* Shows the team of the user when hovering the component, the SteamWar team for server team members using the SW prefix.
*/
public static Component withTeamHover(Chatter receiver, SteamwarUser user, Component component) {
if (useSwPrefix(user)) {
return component.hoverEvent(HoverEvent.showText(receiver.parse(new Message("CHAT_HOVER_TEAM", "SteamWar", "§e", "S§8W"))));
}
if (user.getTeam() == 0) return component;
return component.hoverEvent(HoverEvent.showText(teamHover(receiver, Team.byId(user.getTeam()))));
}
private static Component teamHover(Chatter receiver, Team team) {
return receiver.parse(new Message("CHAT_HOVER_TEAM", team.getTeamName(), "§" + team.getTeamColor(), team.getTeamKuerzel()));
}
private static boolean useSwPrefix(SteamwarUser user) { private static boolean useSwPrefix(SteamwarUser user) {
if (!user.hasPerm(UserPerm.TEAM)) { if (!user.hasPerm(UserPerm.TEAM)) {
return false; return false;
@@ -33,6 +33,7 @@ import de.steamwar.network.packets.common.FightInfoPacket;
import de.steamwar.persistent.Subserver; import de.steamwar.persistent.Subserver;
import de.steamwar.sql.Event; import de.steamwar.sql.Event;
import de.steamwar.sql.Referee; import de.steamwar.sql.Referee;
import de.steamwar.sql.Team;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserConfig; import de.steamwar.sql.UserConfig;
import de.steamwar.sql.UserPerm; import de.steamwar.sql.UserPerm;
@@ -221,6 +222,23 @@ public class ChatManager extends BasicListener {
return fightInfos.get(server); return fightInfos.get(server);
} }
/**
* @return the team of an event fight on the server whose colored name is shown, null if the server runs no event fight
*/
static Team eventTeam(RegisteredServer server, String coloredTeamName) {
Subserver subserver = Subserver.getSubserver(server.getServerInfo());
if (subserver == null) return null;
String kuerzel = coloredTeamName.replaceAll("§.", "");
for (Map.Entry<Integer, Subserver> entry : new ArrayList<>(EventStarter.getEventServer().entrySet())) {
if (entry.getValue() != subserver) continue;
Team team = Team.byId(entry.getKey());
if (team != null && team.getTeamKuerzel().equals(kuerzel)) return team;
}
return null;
}
/** /**
* Updates the fight teams of an arena. Players who just joined a fight team write into the fight chat by default. * Updates the fight teams of an arena. Players who just joined a fight team write into the fight chat by default.
*/ */
@@ -382,19 +400,6 @@ public class ChatManager extends BasicListener {
spies.remove(uuid); spies.remove(uuid);
hidden.remove(uuid); hidden.remove(uuid);
Iterator<DirectChannel> it = directs.iterator(); directs.removeIf(channel -> channel.contains(uuid));
while (it.hasNext()) {
DirectChannel channel = it.next();
if (!channel.contains(uuid)) continue;
it.remove();
Player partner = VelocityCore.getProxy().getPlayer(channel.partner(uuid)).orElse(null);
if (partner != null && defaults.get(partner.getUniqueId()) == channel) {
PlayerChatter chatter = Chatter.of(partner);
chatter.system("CHAT_CHANNEL_CLOSED", channel.tag(chatter));
defaults.put(partner.getUniqueId(), resolvePersisted(partner, currentServer(partner).orElse(null)));
chatter.system("CHAT_CHANNEL_SWITCHED", defaults.get(partner.getUniqueId()).tag(chatter));
}
}
} }
} }
@@ -60,6 +60,11 @@ public class DirectChannel extends ChatChannel {
return new Message("CHAT_CHANNEL_MSG", SteamwarUser.get(partner(receiver.user().getUUID()))); return new Message("CHAT_CHANNEL_MSG", SteamwarUser.get(partner(receiver.user().getUUID())));
} }
@Override
public boolean switchable() {
return false;
}
@Override @Override
protected Message icon(Chatter receiver) { protected Message icon(Chatter receiver) {
return new Message("CHAT_ICON_MSG"); return new Message("CHAT_ICON_MSG");
@@ -102,7 +102,7 @@ public class FightTeamChannel extends ChatChannel {
@Override @Override
protected Component format(Chatter receiver, Chatter sender, String message) { protected Component format(Chatter receiver, Chatter sender, String message) {
return receiver.parse(new Message("CHAT_FIGHT_TEAM", teamName(), sender.user(), ChatFormat.highlightMentions(message, "§f", receiver))); return ChatFormat.fight(receiver, server, sender, teamName(), "CHAT_FIGHT_TEAM", ChatFormat.highlightMentions(message, "§f", receiver));
} }
@Override @Override
@@ -104,13 +104,13 @@ public class LocalChannel extends ChatChannel {
FightInfoPacket info = ChatManager.getFightInfo(server); FightInfoPacket info = ChatManager.getFightInfo(server);
int id = sender.user().getId(); int id = sender.user().getId();
if (info != null && info.getBluePlayers().contains(id)) { if (info != null && info.getBluePlayers().contains(id)) {
return receiver.parse(new Message("CHAT_FIGHT_PARTICIPANT", info.getBlueName(), sender.user(), highlighted)); return ChatFormat.fight(receiver, server, sender, info.getBlueName(), "CHAT_FIGHT_PARTICIPANT", highlighted);
} else if (info != null && info.getRedPlayers().contains(id)) { } else if (info != null && info.getRedPlayers().contains(id)) {
return receiver.parse(new Message("CHAT_FIGHT_PARTICIPANT", info.getRedName(), sender.user(), highlighted)); return ChatFormat.fight(receiver, server, sender, info.getRedName(), "CHAT_FIGHT_PARTICIPANT", highlighted);
} else if (ChatManager.isReferee(server, id)) { } else if (ChatManager.isReferee(server, id)) {
return receiver.parse(new Message("CHAT_FIGHT_REFEREE", sender.user(), highlighted)); return ChatFormat.fight(receiver, server, sender, null, "CHAT_FIGHT_REFEREE", highlighted);
} }
return receiver.parse(new Message("CHAT_FIGHT_SPECTATOR", sender.user(), highlighted)); return ChatFormat.fight(receiver, server, sender, null, "CHAT_FIGHT_SPECTATOR", highlighted);
} }
@Override @Override
@@ -24,7 +24,6 @@ import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import de.steamwar.messages.PlayerChatter; import de.steamwar.messages.PlayerChatter;
import de.steamwar.velocitycore.VelocityCore; import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.chat.ChatChannel;
import de.steamwar.velocitycore.chat.ChatManager; import de.steamwar.velocitycore.chat.ChatManager;
import static de.steamwar.persistent.Storage.lastChats; import static de.steamwar.persistent.Storage.lastChats;
@@ -37,7 +36,7 @@ public class MsgCommand extends SWCommand {
} }
@Register(description = "MSG_USAGE") @Register(description = "MSG_USAGE")
public void genericCommand(PlayerChatter sender, @ErrorMessage(value = "MSG_OFFLINE") Player target, String... message) { public void genericCommand(PlayerChatter sender, @ErrorMessage(value = "MSG_OFFLINE") Player target, @ErrorMessage(value = "MSG_USAGE", allowEAs = false) String... message) {
msg(sender, target, message); msg(sender, target, message);
} }
@@ -47,12 +46,7 @@ public class MsgCommand extends SWCommand {
return; return;
} }
ChatChannel channel = ChatManager.direct(sender.user().getUUID(), target.getUniqueId()); ChatManager.direct(sender.user().getUUID(), target.getUniqueId()).send(sender, String.join(" ", args));
if (args.length == 0) {
ChatManager.switchTo(sender, channel);
} else {
channel.send(sender, String.join(" ", args));
}
} }
public static void remove(Player player) { public static void remove(Player player) {
@@ -33,7 +33,7 @@ public class RCommand extends SWCommand {
} }
@Register(description = "R_USAGE") @Register(description = "R_USAGE")
public void genericCommand(PlayerChatter sender, String... message) { public void genericCommand(PlayerChatter sender, @ErrorMessage(value = "R_USAGE", allowEAs = false) String... message) {
MsgCommand.msg(sender, lastChats.get(sender.getPlayer()), message); MsgCommand.msg(sender, lastChats.get(sender.getPlayer()), message);
} }
} }