replace staffchat payload with a better ver (i hate the toggle)

This commit is contained in:
2026-05-29 13:29:16 -04:00
parent 5e245c1054
commit fc5d0639b8
7 changed files with 73 additions and 87 deletions
@@ -29,7 +29,6 @@ import net.kewwbec.staff.listener.StaffPresenceListener;
import net.kewwbec.staff.service.MuteCache; import net.kewwbec.staff.service.MuteCache;
import net.kewwbec.staff.service.PunishmentService; import net.kewwbec.staff.service.PunishmentService;
import net.kewwbec.staff.service.StaffChatService; import net.kewwbec.staff.service.StaffChatService;
import net.kewwbec.staff.service.StaffChatToggleService;
import net.kewwbec.staff.util.PlayerResolver; import net.kewwbec.staff.util.PlayerResolver;
import net.kewwbec.staff.util.StaffPermissions; import net.kewwbec.staff.util.StaffPermissions;
@@ -45,7 +44,6 @@ public final class StaffPlugin extends JavaPlugin {
private StaffConfig config; private StaffConfig config;
private StaffPermissions permissions; private StaffPermissions permissions;
private MuteCache muteCache; private MuteCache muteCache;
private StaffChatToggleService chatToggle;
private PunishmentService punishmentService; private PunishmentService punishmentService;
private StaffChatService staffChat; private StaffChatService staffChat;
private StaffPresenceListener staffPresenceListener; private StaffPresenceListener staffPresenceListener;
@@ -64,7 +62,6 @@ public final class StaffPlugin extends JavaPlugin {
} }
this.permissions = new StaffPermissions(); this.permissions = new StaffPermissions();
this.muteCache = new MuteCache(); this.muteCache = new MuteCache();
this.chatToggle = new StaffChatToggleService();
LOGGER.at(Level.INFO).log("Staff setup complete"); LOGGER.at(Level.INFO).log("Staff setup complete");
} }
@@ -111,8 +108,8 @@ public final class StaffPlugin extends JavaPlugin {
punishmentService.start(); punishmentService.start();
BanEnforcer banEnforcer = new BanEnforcer(punishmentService); BanEnforcer banEnforcer = new BanEnforcer(punishmentService);
ChatEnforcer chatEnforcer = new ChatEnforcer(muteCache, chatToggle, staffChat); ChatEnforcer chatEnforcer = new ChatEnforcer(muteCache);
PlayerSeenTracker seenTracker = new PlayerSeenTracker(seenRepo, muteCache, punishmentService, chatToggle, core.getServerId()); PlayerSeenTracker seenTracker = new PlayerSeenTracker(seenRepo, muteCache, punishmentService, core.getServerId());
getEventRegistry().registerGlobal(PlayerSetupConnectEvent.class, banEnforcer::onSetupConnect); getEventRegistry().registerGlobal(PlayerSetupConnectEvent.class, banEnforcer::onSetupConnect);
getEventRegistry().registerGlobal(PlayerChatEvent.class, chatEnforcer::onChat); getEventRegistry().registerGlobal(PlayerChatEvent.class, chatEnforcer::onChat);
@@ -139,7 +136,7 @@ public final class StaffPlugin extends JavaPlugin {
getCommandRegistry().registerCommand(new PunishmentCommands.Warn(punishmentService, staffChat, resolver)); getCommandRegistry().registerCommand(new PunishmentCommands.Warn(punishmentService, staffChat, resolver));
getCommandRegistry().registerCommand(new PunishmentCommands.Unban(punishmentService, staffChat, resolver)); getCommandRegistry().registerCommand(new PunishmentCommands.Unban(punishmentService, staffChat, resolver));
getCommandRegistry().registerCommand(new PunishmentCommands.Unmute(punishmentService, staffChat, resolver)); getCommandRegistry().registerCommand(new PunishmentCommands.Unmute(punishmentService, staffChat, resolver));
getCommandRegistry().registerCommand(new StaffChatCommand(chatToggle, staffChat)); getCommandRegistry().registerCommand(new StaffChatCommand(staffChat));
getCommandRegistry().registerCommand(new LookupCommand(resolver, seenRepo, punishmentService)); getCommandRegistry().registerCommand(new LookupCommand(resolver, seenRepo, punishmentService));
getCommandRegistry().registerCommand(new HistoryCommand(resolver, punishmentRepo)); getCommandRegistry().registerCommand(new HistoryCommand(resolver, punishmentRepo));
@@ -4,7 +4,7 @@ import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg; import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.PlayerRef;
@@ -12,26 +12,20 @@ import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import net.kewwbec.staff.StaffPermissionsNodes; import net.kewwbec.staff.StaffPermissionsNodes;
import net.kewwbec.staff.service.StaffChatService; import net.kewwbec.staff.service.StaffChatService;
import net.kewwbec.staff.service.StaffChatToggleService;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.awt.Color; import java.awt.Color;
/** /**
* /sc [message...] * /sc <message...> - send one staff-chat line.
*
* If a body is supplied, sends it once to staff chat without changing your chat mode.
* If no body, toggles staff chat mode - all subsequent chat goes to staff until /sc is run again.
*/ */
public final class StaffChatCommand extends AbstractPlayerCommand { public final class StaffChatCommand extends AbstractPlayerCommand {
private final StaffChatToggleService toggle;
private final StaffChatService staffChat; private final StaffChatService staffChat;
private final OptionalArg<String> bodyArg = withOptionalArg("message", "Message body (optional)", ArgTypes.GREEDY_STRING); private final RequiredArg<String> bodyArg = withRequiredArg("message", "Message body", ArgTypes.GREEDY_STRING);
public StaffChatCommand(@Nonnull StaffChatToggleService toggle, @Nonnull StaffChatService staffChat) { public StaffChatCommand(@Nonnull StaffChatService staffChat) {
super("sc", "Send a one-shot staff message, or toggle staff chat mode if no message given"); super("sc", "Send a staff chat message");
this.toggle = toggle;
this.staffChat = staffChat; this.staffChat = staffChat;
requirePermission(StaffPermissionsNodes.CHAT); requirePermission(StaffPermissionsNodes.CHAT);
} }
@@ -45,16 +39,10 @@ public final class StaffChatCommand extends AbstractPlayerCommand {
@Nonnull PlayerRef sender, @Nonnull PlayerRef sender,
@Nonnull World world) { @Nonnull World world) {
String body = bodyArg.get(ctx); String body = bodyArg.get(ctx);
if (body != null && !body.isBlank()) { if (body == null || body.isBlank()) {
staffChat.send(sender, body.trim()); ctx.sendMessage(Message.raw("Usage: /sc <message...>").color(Color.YELLOW));
return; return;
} }
staffChat.send(sender, body.trim());
boolean nowOn = toggle.toggle(sender.getUuid());
if (nowOn) {
ctx.sendMessage(Message.raw("Staff chat ON. Your chat now broadcasts to staff. Run /sc again to turn off.").color(Color.GREEN));
} else {
ctx.sendMessage(Message.raw("Staff chat OFF. Your chat is back to normal.").color(Color.YELLOW));
}
} }
} }
@@ -5,25 +5,21 @@ import com.hypixel.hytale.server.core.event.events.player.PlayerChatEvent;
import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.PlayerRef;
import net.kewwbec.staff.model.Punishment; import net.kewwbec.staff.model.Punishment;
import net.kewwbec.staff.service.MuteCache; import net.kewwbec.staff.service.MuteCache;
import net.kewwbec.staff.service.StaffChatService;
import net.kewwbec.staff.service.StaffChatToggleService;
import net.kewwbec.staff.util.DurationParser; import net.kewwbec.staff.util.DurationParser;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.awt.Color; import java.awt.Color;
/**
* Cancels chat if the speaker is muted. Staff chat is opt-in via /sc; this listener does not
* re-route any normal chat events.
*/
public final class ChatEnforcer { public final class ChatEnforcer {
private final MuteCache muteCache; private final MuteCache muteCache;
private final StaffChatToggleService toggle;
private final StaffChatService staffChat;
public ChatEnforcer(@Nonnull MuteCache muteCache, public ChatEnforcer(@Nonnull MuteCache muteCache) {
@Nonnull StaffChatToggleService toggle,
@Nonnull StaffChatService staffChat) {
this.muteCache = muteCache; this.muteCache = muteCache;
this.toggle = toggle;
this.staffChat = staffChat;
} }
public void onChat(@Nonnull PlayerChatEvent event) { public void onChat(@Nonnull PlayerChatEvent event) {
@@ -37,12 +33,6 @@ public final class ChatEnforcer {
? "permanently" ? "permanently"
: "for " + DurationParser.formatRemaining(mute.expiresAt() - System.currentTimeMillis()); : "for " + DurationParser.formatRemaining(mute.expiresAt() - System.currentTimeMillis());
sender.sendMessage(Message.raw("You are muted " + suffix + ": " + mute.reason()).color(Color.RED)); sender.sendMessage(Message.raw("You are muted " + suffix + ": " + mute.reason()).color(Color.RED));
return;
}
if (toggle.isOn(sender.getUuid())) {
event.setCancelled(true);
staffChat.send(sender, event.getContent());
} }
} }
} }
@@ -7,7 +7,6 @@ import com.hypixel.hytale.server.core.universe.PlayerRef;
import net.kewwbec.staff.db.PlayerSeenRepository; import net.kewwbec.staff.db.PlayerSeenRepository;
import net.kewwbec.staff.service.MuteCache; import net.kewwbec.staff.service.MuteCache;
import net.kewwbec.staff.service.PunishmentService; import net.kewwbec.staff.service.PunishmentService;
import net.kewwbec.staff.service.StaffChatToggleService;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.sql.SQLException; import java.sql.SQLException;
@@ -20,18 +19,15 @@ public final class PlayerSeenTracker {
private final PlayerSeenRepository seen; private final PlayerSeenRepository seen;
private final MuteCache muteCache; private final MuteCache muteCache;
private final PunishmentService punishments; private final PunishmentService punishments;
private final StaffChatToggleService toggle;
private final String serverId; private final String serverId;
public PlayerSeenTracker(@Nonnull PlayerSeenRepository seen, public PlayerSeenTracker(@Nonnull PlayerSeenRepository seen,
@Nonnull MuteCache muteCache, @Nonnull MuteCache muteCache,
@Nonnull PunishmentService punishments, @Nonnull PunishmentService punishments,
@Nonnull StaffChatToggleService toggle,
@Nonnull String serverId) { @Nonnull String serverId) {
this.seen = seen; this.seen = seen;
this.muteCache = muteCache; this.muteCache = muteCache;
this.punishments = punishments; this.punishments = punishments;
this.toggle = toggle;
this.serverId = serverId; this.serverId = serverId;
} }
@@ -57,6 +53,5 @@ public final class PlayerSeenTracker {
.log("Failed to record leave for %s", ref.getUuid()); .log("Failed to record leave for %s", ref.getUuid());
} }
muteCache.remove(ref.getUuid()); muteCache.remove(ref.getUuid());
toggle.clear(ref.getUuid());
} }
} }
@@ -3,6 +3,7 @@ package net.kewwbec.staff.service;
public final class StaffChatPayload { public final class StaffChatPayload {
public String fromServerId; public String fromServerId;
public String fromUuid;
public String fromUsername; public String fromUsername;
public String message; public String message;
public long ts; public long ts;
@@ -3,7 +3,10 @@ package net.kewwbec.staff.service;
import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.Universe;
import net.kewwbec.networkcore.NetworkCore;
import net.kewwbec.networkcore.api.MessageBus; import net.kewwbec.networkcore.api.MessageBus;
import net.kewwbec.networkcore.api.ranks.RankInfo;
import net.kewwbec.networkcore.api.ranks.RankLookup;
import net.kewwbec.staff.StaffPermissionsNodes; import net.kewwbec.staff.StaffPermissionsNodes;
import net.kewwbec.staff.config.StaffConfig; import net.kewwbec.staff.config.StaffConfig;
import net.kewwbec.staff.util.StaffPermissions; import net.kewwbec.staff.util.StaffPermissions;
@@ -11,9 +14,12 @@ import net.kewwbec.staff.util.StaffPermissions;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.awt.Color; import java.awt.Color;
import java.util.UUID;
public final class StaffChatService { public final class StaffChatService {
private static final Color AQUA = new Color(0x55FFFF);
private final MessageBus bus; private final MessageBus bus;
private final StaffConfig.ChatSection cfg; private final StaffConfig.ChatSection cfg;
private final StaffPermissions perms; private final StaffPermissions perms;
@@ -45,6 +51,7 @@ public final class StaffChatService {
public void send(@Nonnull PlayerRef sender, @Nonnull String message) { public void send(@Nonnull PlayerRef sender, @Nonnull String message) {
StaffChatPayload p = new StaffChatPayload(); StaffChatPayload p = new StaffChatPayload();
p.fromServerId = serverId; p.fromServerId = serverId;
p.fromUuid = sender.getUuid().toString();
p.fromUsername = sender.getUsername(); p.fromUsername = sender.getUsername();
p.message = message; p.message = message;
p.ts = System.currentTimeMillis(); p.ts = System.currentTimeMillis();
@@ -58,6 +65,7 @@ public final class StaffChatService {
public void announce(@Nonnull String text) { public void announce(@Nonnull String text) {
StaffChatPayload p = new StaffChatPayload(); StaffChatPayload p = new StaffChatPayload();
p.fromServerId = serverId; p.fromServerId = serverId;
p.fromUuid = null;
p.fromUsername = "SYSTEM"; p.fromUsername = "SYSTEM";
p.message = text; p.message = text;
p.ts = System.currentTimeMillis(); p.ts = System.currentTimeMillis();
@@ -70,19 +78,60 @@ public final class StaffChatService {
Universe universe = Universe.get(); Universe universe = Universe.get();
if (universe == null) return; if (universe == null) return;
String formatted = formatLine(p); RankInfo senderRank = null;
if (!p.systemAnnouncement && p.fromUuid != null) {
try {
UUID uuid = UUID.fromString(p.fromUuid);
senderRank = lookupRank(uuid);
} catch (IllegalArgumentException ignored) {}
}
Message line = buildLine(p.fromServerId, senderRank, p.fromUsername, p.message);
for (PlayerRef ref : universe.getPlayers()) { for (PlayerRef ref : universe.getPlayers()) {
if (!perms.has(ref, StaffPermissionsNodes.CHAT)) continue; if (!perms.has(ref, StaffPermissionsNodes.CHAT)) continue;
ref.sendMessage(Message.raw(formatted).color(p.systemAnnouncement ? Color.YELLOW : Color.LIGHT_GRAY)); ref.sendMessage(line);
}
}
@Nullable
private static RankInfo lookupRank(@Nonnull UUID uuid) {
try {
RankLookup ranks = NetworkCore.getInstance().getRankLookup();
return ranks == null ? null : ranks.getPrimaryRank(uuid);
} catch (RuntimeException ignored) {
return null;
} }
} }
@Nonnull @Nonnull
private String formatLine(@Nonnull StaffChatPayload p) { private static Message buildLine(@Nullable String originServerId,
String origin = (p.fromServerId == null) ? "?" : p.fromServerId; @Nullable RankInfo senderRank,
if (p.systemAnnouncement) { @Nonnull String senderName,
return cfg.prefix + " " + origin + " | " + p.message; @Nonnull String body) {
String origin = (originServerId == null) ? "?" : originServerId;
String prefix = (senderRank == null || senderRank.prefix() == null || senderRank.prefix().isBlank())
? "" : senderRank.prefix();
Color nameColor = (senderRank == null) ? null : parseHex(senderRank.color());
Message line = Message.empty()
.insert(Message.raw("[Staff (" + origin + ")] ").color(AQUA));
if (!prefix.isEmpty()) {
Message prefixMsg = Message.raw(prefix + " ");
line = line.insert(nameColor == null ? prefixMsg : prefixMsg.color(nameColor));
} }
return cfg.prefix + " " + p.fromUsername + " (" + origin + "): " + p.message; Message nameMsg = Message.raw(senderName);
line = line.insert(nameColor == null ? nameMsg : nameMsg.color(nameColor));
line = line.insert(Message.raw(": ").color(AQUA));
line = line.insert(Message.raw(body).color(Color.WHITE));
return line;
}
@Nullable
private static Color parseHex(@Nullable String hex) {
if (hex == null || hex.isBlank()) return null;
String s = hex.startsWith("#") ? hex.substring(1) : hex;
if (s.length() != 6) return null;
try { return new Color(Integer.parseInt(s, 16)); }
catch (NumberFormatException ignored) { return null; }
} }
} }
@@ -1,34 +0,0 @@
package net.kewwbec.staff.service;
import javax.annotation.Nonnull;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* Tracks which players have "staff chat mode" toggled on. When on, the player's regular chat
* messages are intercepted in {@link net.kewwbec.staff.listener.ChatEnforcer} and routed
* through {@link StaffChatService} instead.
*
* State is per-server and in-memory only. Cleared on disconnect.
*/
public final class StaffChatToggleService {
private final Set<UUID> enabled = ConcurrentHashMap.newKeySet();
public boolean toggle(@Nonnull UUID uuid) {
if (enabled.remove(uuid)) {
return false;
}
enabled.add(uuid);
return true;
}
public boolean isOn(@Nonnull UUID uuid) {
return enabled.contains(uuid);
}
public void clear(@Nonnull UUID uuid) {
enabled.remove(uuid);
}
}