Add /whois click on names and /chat <channel> <message>

- Clicking a player name or @mention suggests /whois <player>; the
  hover explains the click
- /chat <channel> <message> writes once into a channel and replaces
  /chat <channel> msg <message>
- Clicking the Global or Local/Fight icon suggests /chat, for foreign
  arenas /chat <arena>
This commit is contained in:
2026-10-31 23:24:00 +01:00
parent b8f61658f4
commit d4f4be78bb
8 changed files with 31 additions and 30 deletions
@@ -594,6 +594,7 @@ CHAT_FIGHT_TEAM = §8» §f{0}
CHAT_ICON = {0}{1}
CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Prefix: §r{1}{2}
CHAT_HOVER_TEAM_CLICK = §7Team: §e{0}\n§7Prefix: §r{1}{2}\n§8Click to insert §7/team info
CHAT_HOVER_WHOIS = §8Click to insert §7/whois
CHAT_HOVER_LOCAL = {0}\n§7Server: §e{1}
CHAT_ICON_GLOBAL = 🌍
CHAT_ICON_LOCAL = ⌂
@@ -617,8 +618,7 @@ CHAT_CHANNEL_NOT_SWITCHABLE = §cYou cannot write into this channel by default.
CHAT_NO_WRITE = §cYou cannot write into this channel.
CHAT_FIGHT_NO_TEAM = §cYou are not in a fight team.
GLOBAL_USAGE = §8/§7global §8[§emessage§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_USAGE = §8/§7chat §8[§echannel§8] [§ejoin§8|§eleave§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.
@@ -559,6 +559,7 @@ CHAT_FIGHT_TEAM = §8» §f{0}
CHAT_ICON = {0}{1}
CHAT_HOVER_TEAM = §7Team: §e{0}\n§7Kürzel: §r{1}{2}
CHAT_HOVER_TEAM_CLICK = §7Team: §e{0}\n§7Kürzel: §r{1}{2}\n§8Klicke, um §7/team info §8einzufügen
CHAT_HOVER_WHOIS = §8Klicke, um §7/whois §8einzufügen
CHAT_HOVER_LOCAL = {0}\n§7Server: §e{1}
CHAT_ICON_GLOBAL = 🌍
CHAT_ICON_LOCAL = ⌂
@@ -582,8 +583,7 @@ CHAT_CHANNEL_NOT_SWITCHABLE = §cIn diesen Kanal kannst du nicht standardmäßig
CHAT_NO_WRITE = §cDu kannst nicht in diesen Kanal schreiben.
CHAT_FIGHT_NO_TEAM = §cDu bist in keinem Kampfteam.
GLOBAL_USAGE = §8/§7global §8[§eNachricht§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_USAGE = §8/§7chat §8[§eKanal§8] [§ejoin§8|§eleave§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.
@@ -76,7 +76,7 @@ public abstract class ChatChannel {
* @return the text put into the chat input when clicking the channel icon to write a single message, null if there is none
*/
protected String suggestion(Chatter receiver) {
return null;
return "/chat ";
}
/**
@@ -82,7 +82,7 @@ public class ChatFormat {
prefix.getChatPrefix().length() == 0 ? "§f" : prefix.getChatPrefix() + " ",
chatColorCode};
Component senderPart = withTeamHover(receiver, user, receiver.parse(new Message(format + "_SENDER", params)));
Component senderPart = withPlayerInfo(receiver, user, receiver.parse(new Message(format + "_SENDER", params)));
return Component.text().append(teamPrefix).append(senderPart).append(receiver.parse(new Message(format, params))).build();
}
@@ -104,22 +104,27 @@ public class ChatFormat {
nameColor = coloredTeamName.length() >= 2 && coloredTeamName.charAt(0) == '§' ? coloredTeamName.substring(0, 2) : "";
}
line.append(withTeamHover(receiver, sender.user(), receiver.parse(new Message(senderFormat, nameColor, sender.user()))));
line.append(withPlayerInfo(receiver, sender.user(), receiver.parse(new Message(senderFormat, 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.
* Makes a player name suggest {@code /whois} on click and show the team of the player on hover,
* the SteamWar team for server team members using the SW prefix. The hover also explains the click.
*/
public static Component withTeamHover(Chatter receiver, SteamwarUser user, Component component) {
// Players of the public team (id 0) get no hover
if (user.getTeam() == 0) return component;
if (useSwPrefix(user)) {
return component.hoverEvent(HoverEvent.showText(receiver.parse(new Message("CHAT_HOVER_TEAM", "SteamWar", "§e", "S§8W"))));
public static Component withPlayerInfo(Chatter receiver, SteamwarUser user, Component component) {
Component hover = receiver.parse(new Message("CHAT_HOVER_WHOIS"));
// Players of the public team (id 0) show no team
if (useSwPrefix(user) && user.getTeam() != 0) {
hover = Component.text().append(receiver.parse(new Message("CHAT_HOVER_TEAM", "SteamWar", "§e", "S§8W"))).append(Component.newline()).append(hover).build();
} else if (user.getTeam() != 0) {
hover = Component.text().append(teamHover(receiver, Team.byId(user.getTeam()))).append(Component.newline()).append(hover).build();
}
return component.hoverEvent(HoverEvent.showText(teamHover(receiver, Team.byId(user.getTeam()))));
return component
.hoverEvent(HoverEvent.showText(hover))
.clickEvent(ClickEvent.suggestCommand("/whois " + user.getUserName()));
}
/**
@@ -152,14 +157,14 @@ public class ChatFormat {
}
/**
* Shows the team of every mentioned player ({@code @name}) on hover, like at the sender name.
* Gives every mentioned player ({@code @name}) the same hover and click as the sender name.
*/
public static Component withMentionHovers(Chatter receiver, Component component) {
return component.replaceText(TextReplacementConfig.builder()
.match(MENTION)
.replacement((match, builder) -> {
SteamwarUser user = SteamwarUser.get(match.group(1));
return user == null ? builder : withTeamHover(receiver, user, builder.build());
return user == null ? builder : withPlayerInfo(receiver, user, builder.build());
})
.build());
}
@@ -102,9 +102,9 @@ public class DirectChannel extends ChatChannel {
protected Component format(Chatter receiver, Chatter sender, String message) {
SteamwarUser partner = SteamwarUser.get(partner(sender.user().getUUID()));
return Component.text()
.append(ChatFormat.withTeamHover(receiver, sender.user(), receiver.parse(new Message("CHAT_MSG_SENDER", sender.user()))))
.append(ChatFormat.withPlayerInfo(receiver, sender.user(), receiver.parse(new Message("CHAT_MSG_SENDER", sender.user()))))
.append(receiver.parse(new Message("CHAT_MSG_SEPARATOR")))
.append(ChatFormat.withTeamHover(receiver, partner, receiver.parse(new Message("CHAT_MSG_RECEIVER", partner))))
.append(ChatFormat.withPlayerInfo(receiver, partner, receiver.parse(new Message("CHAT_MSG_RECEIVER", partner))))
.append(Component.text(" "))
.append(receiver.parse(new Message("CHAT_MSG", ChatFormat.highlightMentions(message, "§7", receiver))))
.build();
@@ -44,11 +44,6 @@ public class GlobalChannel extends ChatChannel {
return new Message("CHAT_ICON_GLOBAL");
}
@Override
protected String suggestion(Chatter receiver) {
return "/global ";
}
@Override
public Stream<Chatter> readers() {
return Stream.concat(Stream.of(Chatter.console()), Chatter.allPlayers().filter(ChatManager::readsGlobal).map(Chatter::of).filter(chatter -> ChatManager.reads(chatter, persistId())));
@@ -81,10 +81,11 @@ public class LocalChannel extends ChatChannel {
@Override
protected String suggestion(Chatter receiver) {
// Moderators reading a foreign arena write into it directly
if (isArena() && !ChatManager.onServer(receiver, server)) {
return "/chat " + server.getServerInfo().getName() + " msg ";
return "/chat " + server.getServerInfo().getName() + " ";
}
return "/local ";
return super.suggestion(receiver);
}
@Override
@@ -61,16 +61,16 @@ public class ChatCommand extends SWCommand {
}
}
@Register
public void write(PlayerChatter sender, ChatChannel channel, @ErrorMessage(value = "CHAT_USAGE", allowEAs = false) String... message) {
channel.send(sender, String.join(" ", message));
}
@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")
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));
}
@Validator(value = "moderator", local = true)
public TypeValidator<PlayerChatter> moderatorValidator() {
return (sender, value, messageSender) -> !messageSender.send(!value.user().hasPerm(UserPerm.MODERATION), "CHAT_NO_WRITE");